This commit is contained in:
blue-lemon0104
2026-04-07 13:35:22 +08:00
commit 0120fa9ce3
1530 changed files with 424864 additions and 0 deletions

46
include/crypto/crypto.h Executable file
View File

@@ -0,0 +1,46 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "crypto/openssl.h"
// #include "base64.h"
#include "settings.h"
// #define CIPHER_COUNT 5
typedef enum {
CIPHER_SAHE,
CIPHER_SMHE,
CIPHER_ORE,
CIPHER_AES,
CIPHER_AESHMAC,//for 完整性校验
CIPHER_SM4, // ECB 模式
CIPHER_SM4CK, // ECB+SM3 模式 , 提供完整性审计
CIPHER_NOCRYPT, // for such 'and', 'or' oprator or column that do not encrypt use
CIPHER_MAPPED, // for such 'table', 'column name' use
CIPHER_DET, // use CIPHER_AES instead since they are the same
CIPHER_RND,
CIPHER_RNDSM4CK, // GCM
CIPHER_COUNT
} T_Cipher;
const char *typeCipher2String(T_Cipher t);
size_t getCipherBufSize(T_Cipher t);
T_Cipher string2TypeCipher(const char *str);
uint8_t *encryptValue(T_Cipher encryptCipher, uint8_t *in_text, size_t in_size, size_t *out_size, const char *dek, bool isEncrypt = true,
bool isFloat = false);
size_t getCipherFormatSize(const char *fmt, T_Cipher t);
// string getAESKey();

15
include/crypto/openssl.h Executable file
View File

@@ -0,0 +1,15 @@
#pragma once
int genRandomBytes(uint8_t *randombytes, size_t size);
int buf2hex(const uint8_t *buf, size_t bufSize, char *str, size_t *strlen);
int hex2buf(uint8_t *buf, size_t *bufSize, const char *strhex, size_t hexstrlen);
// Error
#define ERR_OPEN_FAILED -1
#define ERR_BAD_MODE -2
#define ERR_NEW_FAILED -3
#define ERR_RUN_FAILED -4
#define ERR_READ_FAILED -5
#define ERR_STATUS_UNINIT -6

20
include/encryptsql.h Executable file
View File

@@ -0,0 +1,20 @@
#pragma once
typedef void *pAttrDescs;
typedef void **pTuples;
extern "C" const char *encryptOneSql(const char* sql, char** err_msg, const char* user_name, const char* db_name);
extern "C" void decryptResult(int numberAttr, int numTuples, pAttrDescs pattDescs, pTuples ptuples);
struct EncryptInfo {
const char *sql; // 正在处理的sql
bool isFloatCol; //当前处理的col是否是float
// bool isFloatorIntCol; //当前处理的col是否是float或int
void *father;
bool isPeerColFloat; // where col_float = 10; 这种where条件中10的AES需要放缩 isPeerColFloat为true表示在一个二元操作符中操作数为float column.
bool isALeftOps;
bool isARightOps;
bool isFromAExpr = false;
bool isFromUpdate = false;
};

2
include/encryptsql/combine.h Executable file
View File

@@ -0,0 +1,2 @@
#pragma once

54
include/encryptsql/fieldmap.h Executable file
View File

@@ -0,0 +1,54 @@
#pragma once
// #include "transform/encryptstmt.h"
#include "utils.h"
#define MAP_NAME_BUFFER_SIZE 64 / 8
#define MAP_NAME_STR_SIZE 2 * MAP_NAME_BUFFER_SIZE + 8
const char *plainDataType2String(PlainDataType t);
void getValueBy(const char *tag, const char *key, char *val);
void setValueBy(const char *tag, const char *key, const char *v);
void setCurrentNodeOnce(const char *table, const char *schema);
void setFromTable(const char *table);
void setTableAlias(const char *tablename, const char *aliasname);
void mapperInit(const char *path);
void mapperCleanup();
void mapperSave();
void mapperDestory();
int getMapperStatus();
bool isFilteredSql(const char *sql);
bool hasCipher(const char *column, T_Cipher t);
void deleteNode(const char *table, const char *schema);
void deleteColumn(const char *column);
void addColumnAndType(const char *column, const char *_typename);
void getFirstTableColumnsAlloc(char ***cols, int *size);
size_t getFirstTableColumnSize(); // 获取mapper tables.back()的column数量
void getColumnType(const char *col, char *v); // 获取指定column的typecolumn明文无后缀
void getColumnCiphers(const char *col, T_Cipher *ciphers, int *size); // 需要自行分配内存获取指定col的加密方式, 并且sort
void getFirstTableAllColumnsInfoAlloc(ColumnInfo ***pinfos, int *size);
void getSpecifyColumnsInfoAlloc(List *cols, ColumnInfo ***pinfos);
ColumnInfo *getColumnInfoAlloc(const char *col);

10
include/encryptsql/node2str.h Executable file
View File

@@ -0,0 +1,10 @@
#pragma once
#include "nodes/parsenodes.h"
#include "nodes/nodes.h"
const char *parseTree2str(Node *parseTree);

42
include/encryptsql/parser.h Executable file
View File

@@ -0,0 +1,42 @@
/*-------------------------------------------------------------------------
*
* parser.h
* Definitions for the "raw" parser (flex and bison phases only)
*
* This is the external API for the raw lexing/parsing functions.
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/parser/parser.h
*
*-------------------------------------------------------------------------
*/
#ifndef PARSER_H
#define PARSER_H
#include <ctype.h>
#include <stdbool.h>
#include <stdint.h>
#include "nodes/parsenodes.h"
typedef enum {
BACKSLASH_QUOTE_OFF,
BACKSLASH_QUOTE_ON,
BACKSLASH_QUOTE_SAFE_ENCODING
} BackslashQuoteType;
/* GUC variables in scan.l (every one of these is a bad idea :-() */
extern int backslash_quote;
extern bool escape_string_warning;
extern PGDLLIMPORT bool standard_conforming_strings;
/* Primary entry point for the raw parsing functions */
extern List *raw_parser(const char *str);
/* Utility functions exported by gram.y (perhaps these should be elsewhere) */
extern List *SystemFuncName(char *name);
extern TypeName *SystemTypeName(char *name);
#endif /* PARSER_H */

114
include/kms/ikms_core.hpp Executable file
View File

@@ -0,0 +1,114 @@
#ifndef I_KMS_CORE_HPP
#define IKMS_CORE_HPP
#include "kms_common.hpp"
#include <iostream>
#include "json.hpp"
using json = nlohmann::json;
class IKmsCore {
public:
virtual ~IKmsCore() = default;
/**
* @brief 自定义初始化逻辑
* local解析json, 随后LoadCmkByUsername
* tencent或许可以是从配置文件中读取参数
*/
virtual bool init() = 0;
/* ------------------------------------CMK 管理-----------------------------------------------*/
/**
* @brief 查询用户是否有cmk
* @param user_name 输入:用户名
* @return bool 返回 true 表示存在false 表示不存在
*/
virtual bool hasCmk(const std::string &user_name) const = 0;
/**
* @brief 创建新的客户主密钥CMK
* @param user_name 输入:用户名,用于关联 CMK
* @param rotate_period 输入CMK 轮换周期(天数)
* @param new_cmk 输出:创建的 CMK 结构体,包含密钥 ID、数据等信息
* @param ks 输入:密钥编码结构,默认为 RAW
* @param alg 输入:加密算法,默认为 AES128
* @return bool 返回 true 表示创建成功false 表示失败
*/
virtual bool createCmk(const std::string& user_name, int rotate_period,
KeyStruct ks = KeyStruct::RAW, AlgorithmType alg = AlgorithmType::AES128) = 0;
/**
* @brief 删除指定用户的 CMK
* @param user_name 输入:要删除 CMK 的用户名
* @return bool 返回 true 表示删除成功false 表示失败
*/
virtual bool deleteCmk(const std::string& user_name) = 0;
virtual bool describeCmk(const std::string &user_name, std::string &result, bool decrypt) = 0;
/* ------------------------------------ 轮转 -----------------------------------------------*/
/**
* 非纯虚函数, 可以不实现
*/
/**
* @brief 立即轮换指定用户的 CMK
* @param user_name 输入:要轮换 CMK 的用户名
* @return bool 返回 true 表示轮换成功false 表示失败
*/
virtual bool rotateCmkNow(const std::string& user_name){
std::cout << "not implement" << std::endl;
}
/**
* @brief 启用或者关闭自动轮转
* @param auto_rotate_action 输入/输出:轮换命令(如启动或停止自动轮换),可能为 nullptr
* @param user_name 输入:用户名
* @return bool 返回 true 表示命令处理成功false 表示失败
*/
virtual bool handleAutoRotateCmd(std::string* auto_rotate_action, const std::string& user_name){
std::cout << "not implement" << std::endl;
}
/**
* @brief 获取指定用户的 CMK 自动轮换状态
* @param user_name 输入:用户名
* @return bool 返回 true 表示自动轮换启用false 表示未启用或用户不存在
*/
virtual bool getCmkAutoRotateStatusByUsername(const std::string& user_name){
std::cout << "not implement" << std::endl;
}
/* ------------------------------------ 加密解密 -----------------------------------------------*/
/**
* 这里是使用哪个CMK的问题
* 在Local中, 我通过在 initialize 的时候设置好 _user_name 成员, 随后通过 init -> LoadCmkByUsername 保存在 KMS的 _cmk 变量中 中
* 此后的加密(认为一个pgConn不会切换用户, 始终使用同一个cmk, 如果轮换在轮换结尾设置新的 _cmk )
* TencentKMS 应该无法这样做(无法缓存在本地), 只能保存 _user_name 然后每次加解密都选用 _user_name 对应的 cmk
*/
/**
* @brief 使用 CMK 加密 DEK
* @param dek 输入/输出:要加密的 DEK 数据,加密后存储在原变量
* @return bool 返回 true 表示加密成功false 表示失败
*/
virtual bool encryptData(std::string& dek) = 0;
/**
* @brief 使用 CMK 解密 DEK
* @param dek 输入/输出:要解密的 DEK 密文,解密后存储在原变量
* @return bool 返回 true 表示解密成功false 表示失败
*/
virtual bool decryptData(std::string& dek) = 0;
/* ------------------------------------新建DEK -------------------------------------------------*/
/**
* @brief 通过列名与CMK 派生出 col_dek, 表级 列密钥使用 "" 空字符串派生
*/
virtual bool createDek(std::string &col_dek, const std::string &column_name) = 0;
};
#endif

24837
include/kms/json.hpp Executable file

File diff suppressed because it is too large Load Diff

123
include/kms/kms_common.hpp Executable file
View File

@@ -0,0 +1,123 @@
// common.hpp
#ifndef KMS_COMMON_HPP
#define KMS_COMMON_HPP
#include <string>
#include <queue>
#include <unordered_map>
#define AES_BLOCK_SIZE 16
// 密钥类型
typedef enum {
KEY_TYPE_AES,
KEY_TYPE_ORE,
KEY_TYPE_SAHE,
KEY_TYPE_SMHE
} KeyType;
// 编码结构
typedef enum {
RAW
} KeyStruct;
// 加密算法
typedef enum {
SM4,
AES128
} AlgorithmType;
// CMK结构体
typedef struct {
std::uint32_t _key_id; //密钥id
std::string _user_name; //数据库用户名
std::string _cmk_data; //cmk数据
time_t _create_time; //创建时间
int _length; //密钥长度
KeyStruct _struct; //编码结构
AlgorithmType _alg; //加密算法
int _rotate_period; //轮换周期(天数)
bool _is_rotated; //是否被轮转
bool _is_primary_version; //是否是主版本
bool _auto_rotate; //自动轮转状态
} CMK;
// DEK数据库存储结构体
typedef struct {
std::string _user_name; //数据库用户名
std::string _table; //数据库表名
std::string _column; //数据库列名
KeyType _type; //密钥类型(必须有吗)
std::string _dek_cipher; //dek密文数据
bool _status; //是否启用(轮换)
time_t _create_time; //创建时间(必须自动轮换吗,这个可不可以只手动轮换,合同里没写要不只允许手动轮换)
int _rotate_time; //轮换周期(如果不是自动是不是可以没有)
int _length; //密钥长度(需要吗)
KeyStruct _struct; //编码结构(需要吗)
AlgorithmType _alg; //被加密算法(安全性)
} DEK;
// DEK缓存结构体存的东西越少越好
typedef struct {
std::string _user_name; //数据库用户名
std::string _table; //数据库表名
std::string _column; //数据库列名
KeyType _type; //密钥类型(必须有吗)
std::string _dek_plain; //dek明文数据
time_t _find_time; //缓存创建时间
int _cache_time; //缓存时间
int _length; //密钥长度(必须有吗)
KeyStruct _struct; //编码结构(必须有吗)
} DEK_CACHE;
//表信息(user -> db -> table -> col?)
typedef struct {
std::string user_name;
std::string db_name;
std::string table_name;
std::queue<std::string> col_name;
std::unordered_map<std::string, std::string> dek_store_tmp;
std::unordered_map<std::string, std::string> dek_store_tmp_for_update;
std::string dek_table_level_tmp;
std::string dek_table_level_for_update;
} DbInfo;
// ============ 配置基类和具体配置类 ============
// 基础配置接口
class IKmsConfig {
public:
virtual ~IKmsConfig() = default;
virtual std::string getType() const = 0;
};
class LocalKmsConfig: public IKmsConfig {
public:
const char *file_path_;
const char *key_path_;
const char *cmk_auto_rotate_status_path_;
const char *user_name_;
const char *db_name_;
LocalKmsConfig(const char *file_path, const char *key_path, const char *cmk_auto_rotate_status_path, const char* user_name, const char* db_name)
:file_path_(file_path),key_path_(key_path),cmk_auto_rotate_status_path_(cmk_auto_rotate_status_path),user_name_(user_name),db_name_(db_name){}
std::string getType() const override { return "local"; }
};
// Tencent KMS 配置
class TencentKmsConfig : public IKmsConfig {
public:
std::string access_key;
std::string secret_key;
std::string region;
std::string endpoint;
// ... 自定义
TencentKmsConfig(const std::string& ak, const std::string& sk, const std::string& r)
: access_key(ak), secret_key(sk), region(r) {}
std::string getType() const override { return "tencent"; }
};
#endif // KMS_COMMON_HPP

109
include/kms/kms_core_local.hpp Executable file
View File

@@ -0,0 +1,109 @@
// local_kms_core.hpp
#ifndef LOCAL_KMS_CORE_HPP
#define LOCAL_KMS_CORE_HPP
#pragma once
#include <string>
#include <vector>
#include <queue>
#include <iostream>
#include <ctime>
#include <fstream>
#include <random>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <sstream>
#include <iomanip>
#include <algorithm>
//#include <libpq-fe.h>
#include "json.hpp"
#include <thread>
#include <chrono>
#include <mutex>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <map>
#include "kms_factory.hpp"
#include "kms_interface.hpp"
#include "kms_common.hpp"
#include "json.hpp"
using json = nlohmann::json;
class LocalKmsCore : public IKmsCore {
private:
json _data; // 解析出的 JSON 数据
std::string _path; // CMK 信息存储路径JSON 文件)
std::string _key_path; // 加密 CMK 的密钥路径
std::string _user_name;
std::string _db_name;
std::string _cmk; // 当前用户的 CMK
std::string _cmk_auto_rotate_status_path; // CMK 自动轮转状态存储路径
std::map<std::string, pid_t> cmk_auto_rotate_pids; // 自动轮转进程 ID
std::map<std::string, bool> cmk_auto_rotate_status; // 自动轮转状态
std::vector<unsigned char> readBinaryFile(const std::string& path);
std::vector<unsigned char> xorBuffers(const std::vector<unsigned char>& a, const std::vector<unsigned char>& b);
std::vector<unsigned char> hmac_sha256(const std::vector<unsigned char>& key, const std::vector<unsigned char>& message);
std::vector<unsigned char> getSystemIDHash16();
std::vector<unsigned char> sha256(const std::string& input);
std::string base64_encode(const unsigned char *data, size_t length);
std::string base64_decode(const std::string &encoded);
void getRootKey(unsigned char *key, size_t len);
std::string deriveKey(const std::string& master_key, const std::string& column_name);
std::string generateSalt(const std::string& column_name);
bool getRandomCmk(std::string &_cmk_data, AlgorithmType alg, int &length);
bool getRandomDek(std::string &_dek_data);
void _rand(std::string &rand, int length_in_bytes);
bool encryptKey(std::string &ori_key);
bool decryptKey(std::string &ori_key);
bool createDerivedDek(std::string& dek, const std::string& column_name);
void loadAutoRotateStatus();
void saveAutoRotateStatus();
void autoRotateProcess(const std::string &user_name);
bool storeCmk(CMK &cmk, bool rotate=false);
bool LoadCmkByUsername(const std::string &user_name);
bool save();
public:
LocalKmsCore(const IKmsConfig &config);
~LocalKmsCore();
// KMSInterface 实现
bool init() override;
// cmk 相关
bool hasCmk(const std::string &user_name) const override;
bool createCmk(const std::string& user_name, int rotate_period,
KeyStruct ks = KeyStruct::RAW, AlgorithmType alg = AlgorithmType::AES128) override;
bool deleteCmk(const std::string& user_name) override;
bool describeCmk(const std::string &user_name, std::string &result, bool decrypt) override;
// 自动轮转辅助方法
bool rotateCmkNow(const std::string& user_name) override;
bool handleAutoRotateCmd(std::string* auto_rotate_action, const std::string& user_name) override;
bool getCmkAutoRotateStatusByUsername(const std::string& user_name) override;
// 加解密
bool encryptData(std::string& dek) override;
bool decryptData(std::string& dek) override;
// 新建DEK
bool createDek(std::string &col_dek, const std::string &column_name) override;
static void registerLocalKms(){
KmsFactory::instance().registerCreator("local", [](const IKmsConfig& config) {
return myPtr::make_unique<LocalKmsCore>(config);
});
}
};
#endif // LOCAL_KMS_CORE_HPP

24
include/kms/kms_factory.hpp Executable file
View File

@@ -0,0 +1,24 @@
// kms_factory.hpp
#ifndef KMS_FACTORY_HPP
#define KMS_FACTORY_HPP
#include "kms_interface.hpp"
class KmsFactory {
public:
using CreatorFunc = std::function<std::unique_ptr<IKmsCore>(const IKmsConfig &)>;
static KmsFactory& instance();
void registerCreator(const std::string& name, CreatorFunc func);
std::unique_ptr<IKmsCore> create(const IKmsConfig& config) const;
std::vector<std::string> listRegistered() const;
private:
std::unordered_map<std::string, CreatorFunc> creators_;
};
#endif // KMS_FACTORY_HPP

54
include/kms/kms_interface.hpp Executable file
View File

@@ -0,0 +1,54 @@
// kms_interface.hpp
#ifndef KMS_INTERFACE_HPP
#define KMS_INTERFACE_HPP
#include <memory>
#include <functional>
#include "ikms_core.hpp"
namespace myPtr{
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}
// 静态库接口类
class KMSInterface {
private:
static thread_local std::unique_ptr<IKmsCore> instance_;
public:
// 初始化并"创建" IKmsCore 实例
static bool initialize( const IKmsConfig& config );
static void cleanup(); // 清理当前线程绑定的 core 实例
// 获取当前线程的 KMS 实例(如需特殊用途)
static IKmsCore* getInstance();
// 包装接口
static bool hasCmk(const std::string& user_name);
static bool createCmk(const std::string& user_name, int rotate_period,
KeyStruct ks = KeyStruct::RAW, AlgorithmType alg = AlgorithmType::AES128);
static bool deleteCmk(const std::string& user_name);
static bool describeCmk(const std::string &user_name, std::string &result, bool decrypt);
// 轮转相关
static bool rotateCmkNow(const std::string& user_name);
static bool handleAutoRotateCmd(std::string* action, const std::string& user_name);
static bool getCmkAutoRotateStatusByUsername(const std::string& user_name);
// 加解密
static bool encryptData(std::string& dek);
static bool decryptData(std::string& dek);
// 创建DEK
static bool createDek(std::string &col_dek, const std::string &column_name);
};
#endif // KMS_INTERFACE_HPP

View File

@@ -0,0 +1,255 @@
// db_interface.hpp
#ifndef DB_INTERFACE_HPP
#define DB_INTERFACE_HPP
#ifdef __cplusplus
extern "C"
{
#endif
#include "postgres.h" // 与 #include <iomanip> 冲突
//为了解决和libintl.h冲突的问题undef以下4个
#undef gettext
#undef dgettext
#undef ngettext
#undef dngettext
#include "utils/palloc.h"
#include "utils/memutils.h"
#include "nodes/nodes.h"
#include "nodes/parsenodes.h"
#include "nodes/value.h"
#include "base64.h"
#include <string.h>
#ifdef __cplusplus
}
#endif
#include "encryptsql/fieldmap.h"
#include <assert.h>
#include <stdexcept>
#include <set>
#include <vector>
#include <string>
#include "libpq-fe.h" // 改为使用引号包含
#include "crypto/crypto.h"
#include "crypto/openssl.h"
#include "encryptsql.h"
// 因为缺头文件所以直接复制过来了,肯定有很多用不上的
#include <regex>
#include <iostream>
#include <unordered_set>
#include <string>
#include <unordered_map>
#include "json.hpp"
#include "kms/kms_common.hpp"
#include "dek_manager.hpp"
// 数据库连接信息
#define DB_CONNINFO "dbname=dekmaster user=dekmaster password=secure_password hostaddr=127.0.0.1 port=5432"
#define BACKUP_TABLE_NAME "dek_store_backup"
#define ORIGINAL_TABLE_NAME "dek_store"
namespace DekInterface {
// 获取当前线程的 DBAdapter 实例
inline DekManager& getAdapter() {
return DekManager::getInstance();
}
// 初始化接口
inline void initialize(const std::string& user_name, const std::string& db_name) {
getAdapter().initialize(user_name, db_name);
}
// DEK 管理接口
// inline bool storeDek(const DEK& dek) {
// return getAdapter().storeDek(dek);
// }
// inline bool deleteDek(const std::string& user_name, const std::string& table, const std::string& column) {
// return getAdapter().deleteDek(user_name, table, column);
// }
// inline bool createDek(std::string& col_dek, const std::string& column_name) {
// return getAdapter().createDek(col_dek, column_name);
// }
// 数据库信息设置接口
inline void setInfoUser(const std::string& user_name) {
getAdapter().setInfoUser(user_name);
}
inline void setInfoDb(const std::string& db_name) {
getAdapter().setInfoDb(db_name);
}
inline void setInfoTable(const std::string& table_name) {
getAdapter().setInfoTable(table_name);
}
inline void setInfoCol(const std::string& col_name) {
getAdapter().setInfoCol(col_name);
}
// 数据库信息获取接口
inline std::string getInfoUser() {
return getAdapter().getInfoUser();
}
inline std::string getInfoDb() {
return getAdapter().getInfoDb();
}
inline std::string getInfoTable() {
return getAdapter().getInfoTable();
}
inline std::string getInfoCol() {
return getAdapter().getInfoCol();
}
// DEK 缓存管理接口
inline void setDekColLevel(const std::string& col_name, const std::string& dek_tmp) {
getAdapter().setDekColLevel(col_name, dek_tmp);
}
inline void getDekColLevel(const std::string& col_name, std::string& dek_tmp) {
getAdapter().getDekColLevel(col_name, dek_tmp);
}
inline void setDekTableLevel(const std::string& dek) {
getAdapter().setDekTableLevel(dek);
}
inline void getDekTableLevel(std::string& dek) {
getAdapter().getDekTableLevel(dek);
}
inline void setDekTableLevelForUpdate(const std::string& dek) {
getAdapter().setDekTableLevelForUpdate(dek);
}
inline void getDekTableLevelForUpdate(std::string& dek) {
getAdapter().getDekTableLevelForUpdate(dek);
}
inline void setDekColLevelForUpdate(const std::string& col_name, const std::string& dek_tmp) {
getAdapter().setDekColLevelForUpdate(col_name, dek_tmp);
}
inline void getDekColLevelForUpdate(const std::string& col_name, std::string& dek_tmp) {
getAdapter().getDekColLevelForUpdate(col_name, dek_tmp);
}
inline void getAllDekColLevelForUpdate(std::unordered_map<std::string, std::string>& column_deks) {
getAdapter().getAllDekColLevelForUpdate(column_deks);
}
inline void clearDek() {
getAdapter().clearDek();
}
inline void clearDekForUpdate() {
getAdapter().clearDekForUpdate();
}
// ORE 专用 DEK 接口
// inline void setDekOnlyForOre(const std::string& dek) {
// getAdapter().setDekOnlyForOre(dek);
// }
// inline void clearDekOnlyForOre() {
// getAdapter().clearDekOnlyForOre();
// }
// inline char* getDekOnlyForOre() {
// return getAdapter().getDekOnlyForOre();
// }
inline bool isRotateCmd(){
return getAdapter().isRotateCmd();
}
// 定义轮换类型枚举
enum RotationType {
ROTATE_ALL, // 轮换表级和所有列级密钥
ROTATE_TABLE, // 只轮换表级密钥
ROTATE_COLUMNS // 只轮换指定列的密钥
};
// 轮换命令解析结果结构
struct RotateCommandResult {
bool valid; // 命令是否有效
RotationType type; // 轮换类型
std::string tableName; // 表名
std::string enc_tableName; // 加密表名
std::set<std::string> cols_set; // 命令涉及的列名列表 用于快速检索轮换命令中是否有这个列
std::unordered_set<std::string> enc_cols_set; // 需要更新的密钥的密文列名
std::unordered_map<std::string, std::string> col_map; // 明文列名 和 密文列名的映射
std::unordered_map<std::string, std::string> col_type; // 列的类型
std::string errorMessage; // 错误信息
};
RotateCommandResult parseRotateCommand(const std::string& command,const std::string &user_name,const std::string &db_name);
// test
void printRotateCommandResult(const RotateCommandResult& result);
void connectionDelete();
void connectionUpdateDek(RotateCommandResult &result);
void connectionUpdateDek_Init(RotateCommandResult &result);
void connectionUpdateDek_Update(RotateCommandResult& result);
void connectionUpdateDek_Final(RotateCommandResult& result);
void connectionInsertTest();
void connectionSelectTest();
void connectionSelect();
using json = nlohmann::json;
// 读取 JSON 文件
json read_json_from_file(const std::string& file_path);
// 获取表中所有列
std::vector<std::string> get_columns(const std::string& table_name, const json& j);
// 获取表中所有列
std::set<std::string> get_all_columns(const std::string& table_name, const json& j);
// 获取表中列的映射关系
std::unordered_map<std::string, std::string> get_column_mapping(const std::string& table_name, const json& j);
// 获取列的数据类型
std::string get_column_type(const std::string& table_name, const std::string& column_name, const json& j);
static int executeSQL(const char *sql, const char *errorMsg);
static int tableExists(const char *tableName);
int backupDekStore();
int deleteDekStoreBackup();
int restoreDekStore();
} // namespace DekAPI
#endif // DB_INTERFACE_HPP

View File

@@ -0,0 +1,83 @@
// db_adapter.hpp
#ifndef DEK_ADAPTER_HPP
#define DEK_ADAPTER_HPP
#include <string>
#include <queue>
#include <unordered_map>
#include <memory>
#include "kms/kms_common.hpp"
class DekManager {
private:
std::string user_name_;
std::string db_name_;
std::string table_name_;
std::queue<std::string> col_name_;
std::unordered_map<std::string, std::string> col_dek_;
std::unordered_map<std::string, std::string> col_dek_update_;
std::string table_dek_;
std::string table_dek_update_;
DekManager() = default;
DekManager(const std::string& user_name, const std::string& db_name ):user_name_(user_name),db_name_(db_name){}
public:
~DekManager() = default;
DekManager(const DekManager&) = delete;
DekManager& operator=(const DekManager&) = delete;
static DekManager& getInstance() {
static thread_local DekManager instance;
return instance;
}
void initialize(const std::string& user_name, const std::string& db_name);
// DEK 管理
// bool storeDek(const DEK& dek);
// bool deleteDek(const std::string& user_name, const std::string& table, const std::string& column);
// bool createDek(std::string& col_dek, const std::string& column_name);
// 数据库信息设置
void setInfoUser(const std::string& user_name);
void setInfoDb(const std::string& db_name);
void setInfoTable(const std::string& table_name);
void setInfoCol(const std::string& col_name);
std::string getInfoUser();
std::string getInfoDb();
std::string getInfoTable();
std::string getInfoCol();
// DEK 缓存管理
// Col Level
void setDekColLevel(const std::string& col_name, const std::string& dek_tmp);
void getDekColLevel(const std::string& col_name, std::string& dek_tmp);
void setDekColLevelForUpdate(const std::string& col_name, const std::string& dek_tmp) ;
void getDekColLevelForUpdate(const std::string& col_name, std::string& dek_tmp) ;
// Tabel Level
void setDekTableLevel(const std::string& dek);
void getDekTableLevel(std::string& dek);
void setDekTableLevelForUpdate(const std::string& dek);
void getDekTableLevelForUpdate(std::string& dek) ;
void getAllDekColLevelForUpdate(std::unordered_map<std::string, std::string>& column_deks) ;
void clearDek() ;
void clearDekForUpdate() ;
// ORE 专用 DEK
// void setDekOnlyForOre(const std::string& dek) ;
// void clearDekOnlyForOre() ;
// char* getDekOnlyForOre() ;
bool isRotateCmd(){
return table_dek_update_ != "" || col_dek_update_.size() != 0;
}
};
#endif // DB_ADAPTER_HPP

24837
include/kmsAdapter/json.hpp Executable file

File diff suppressed because it is too large Load Diff

673
include/libpq-fe.h Executable file
View File

@@ -0,0 +1,673 @@
/*-------------------------------------------------------------------------
*
* libpq-fe.h
* This file contains definitions for structures and
* externs for functions used by frontend postgres applications.
*
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/interfaces/libpq/libpq-fe.h
*
*-------------------------------------------------------------------------
*/
#ifndef LIBPQ_FE_H
#define LIBPQ_FE_H
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdio.h>
/*
* postgres_ext.h defines the backend's externally visible types,
* such as Oid.
*/
#include "postgres_ext.h"
/*
* These symbols may be used in compile-time #ifdef tests for the availability
* of newer libpq features.
*/
/* Indicates presence of PQenterPipelineMode and friends */
#define LIBPQ_HAS_PIPELINING 1
/* Indicates presence of PQsetTraceFlags; also new PQtrace output format */
#define LIBPQ_HAS_TRACE_FLAGS 1
/*
* Option flags for PQcopyResult
*/
#define PG_COPYRES_ATTRS 0x01
#define PG_COPYRES_TUPLES 0x02 /* Implies PG_COPYRES_ATTRS */
#define PG_COPYRES_EVENTS 0x04
#define PG_COPYRES_NOTICEHOOKS 0x08
/* Application-visible enum types */
/*
* Although it is okay to add to these lists, values which become unused
* should never be removed, nor should constants be redefined - that would
* break compatibility with existing code.
*/
typedef enum
{
CONNECTION_OK,
CONNECTION_BAD,
/* Non-blocking mode only below here */
/*
* The existence of these should never be relied upon - they should only
* be used for user feedback or similar purposes.
*/
CONNECTION_STARTED, /* Waiting for connection to be made. */
CONNECTION_MADE, /* Connection OK; waiting to send. */
CONNECTION_AWAITING_RESPONSE, /* Waiting for a response from the
* postmaster. */
CONNECTION_AUTH_OK, /* Received authentication; waiting for
* backend startup. */
CONNECTION_SETENV, /* This state is no longer used. */
CONNECTION_SSL_STARTUP, /* Negotiating SSL. */
CONNECTION_NEEDED, /* Internal state: connect() needed */
CONNECTION_CHECK_WRITABLE, /* Checking if session is read-write. */
CONNECTION_CONSUME, /* Consuming any extra messages. */
CONNECTION_GSS_STARTUP, /* Negotiating GSSAPI. */
CONNECTION_CHECK_TARGET, /* Checking target server properties. */
CONNECTION_CHECK_STANDBY /* Checking if server is in standby mode. */
} ConnStatusType;
typedef enum
{
PGRES_POLLING_FAILED = 0,
PGRES_POLLING_READING, /* These two indicate that one may */
PGRES_POLLING_WRITING, /* use select before polling again. */
PGRES_POLLING_OK,
PGRES_POLLING_ACTIVE /* unused; keep for awhile for backwards
* compatibility */
} PostgresPollingStatusType;
typedef enum
{
PGRES_EMPTY_QUERY = 0, /* empty query string was executed */
PGRES_COMMAND_OK, /* a query command that doesn't return
* anything was executed properly by the
* backend */
PGRES_TUPLES_OK, /* a query command that returns tuples was
* executed properly by the backend, PGresult
* contains the result tuples */
PGRES_COPY_OUT, /* Copy Out data transfer in progress */
PGRES_COPY_IN, /* Copy In data transfer in progress */
PGRES_BAD_RESPONSE, /* an unexpected response was recv'd from the
* backend */
PGRES_NONFATAL_ERROR, /* notice or warning message */
PGRES_FATAL_ERROR, /* query failed */
PGRES_COPY_BOTH, /* Copy In/Out data transfer in progress */
PGRES_SINGLE_TUPLE, /* single tuple from larger resultset */
PGRES_PIPELINE_SYNC, /* pipeline synchronization point */
PGRES_PIPELINE_ABORTED /* Command didn't run because of an abort
* earlier in a pipeline */
} ExecStatusType;
typedef enum
{
PQTRANS_IDLE, /* connection idle */
PQTRANS_ACTIVE, /* command in progress */
PQTRANS_INTRANS, /* idle, within transaction block */
PQTRANS_INERROR, /* idle, within failed transaction */
PQTRANS_UNKNOWN /* cannot determine status */
} PGTransactionStatusType;
typedef enum
{
PQERRORS_TERSE, /* single-line error messages */
PQERRORS_DEFAULT, /* recommended style */
PQERRORS_VERBOSE, /* all the facts, ma'am */
PQERRORS_SQLSTATE /* only error severity and SQLSTATE code */
} PGVerbosity;
typedef enum
{
PQSHOW_CONTEXT_NEVER, /* never show CONTEXT field */
PQSHOW_CONTEXT_ERRORS, /* show CONTEXT for errors only (default) */
PQSHOW_CONTEXT_ALWAYS /* always show CONTEXT field */
} PGContextVisibility;
/*
* PGPing - The ordering of this enum should not be altered because the
* values are exposed externally via pg_isready.
*/
typedef enum
{
PQPING_OK, /* server is accepting connections */
PQPING_REJECT, /* server is alive but rejecting connections */
PQPING_NO_RESPONSE, /* could not establish connection */
PQPING_NO_ATTEMPT /* connection not attempted (bad params) */
} PGPing;
/*
* PGpipelineStatus - Current status of pipeline mode
*/
typedef enum
{
PQ_PIPELINE_OFF,
PQ_PIPELINE_ON,
PQ_PIPELINE_ABORTED
} PGpipelineStatus;
/* PGconn encapsulates a connection to the backend.
* The contents of this struct are not supposed to be known to applications.
*/
typedef struct pg_conn PGconn;
/* PGresult encapsulates the result of a query (or more precisely, of a single
* SQL command --- a query string given to PQsendQuery can contain multiple
* commands and thus return multiple PGresult objects).
* The contents of this struct are not supposed to be known to applications.
*/
typedef struct pg_result PGresult;
/* PGcancel encapsulates the information needed to cancel a running
* query on an existing connection.
* The contents of this struct are not supposed to be known to applications.
*/
typedef struct pg_cancel PGcancel;
/* PGnotify represents the occurrence of a NOTIFY message.
* Ideally this would be an opaque typedef, but it's so simple that it's
* unlikely to change.
* NOTE: in Postgres 6.4 and later, the be_pid is the notifying backend's,
* whereas in earlier versions it was always your own backend's PID.
*/
typedef struct pgNotify
{
char *relname; /* notification condition name */
int be_pid; /* process ID of notifying server process */
char *extra; /* notification parameter */
/* Fields below here are private to libpq; apps should not use 'em */
struct pgNotify *next; /* list link */
} PGnotify;
/* Function types for notice-handling callbacks */
typedef void (*PQnoticeReceiver) (void *arg, const PGresult *res);
typedef void (*PQnoticeProcessor) (void *arg, const char *message);
/* Print options for PQprint() */
typedef char pqbool;
typedef struct _PQprintOpt
{
pqbool header; /* print output field headings and row count */
pqbool align; /* fill align the fields */
pqbool standard; /* old brain dead format */
pqbool html3; /* output html tables */
pqbool expanded; /* expand tables */
pqbool pager; /* use pager for output if needed */
char *fieldSep; /* field separator */
char *tableOpt; /* insert to HTML <table ...> */
char *caption; /* HTML <caption> */
char **fieldName; /* null terminated array of replacement field
* names */
} PQprintOpt;
/* ----------------
* Structure for the conninfo parameter definitions returned by PQconndefaults
* or PQconninfoParse.
*
* All fields except "val" point at static strings which must not be altered.
* "val" is either NULL or a malloc'd current-value string. PQconninfoFree()
* will release both the val strings and the PQconninfoOption array itself.
* ----------------
*/
typedef struct _PQconninfoOption
{
char *keyword; /* The keyword of the option */
char *envvar; /* Fallback environment variable name */
char *compiled; /* Fallback compiled in default value */
char *val; /* Option's current value, or NULL */
char *label; /* Label for field in connect dialog */
char *dispchar; /* Indicates how to display this field in a
* connect dialog. Values are: "" Display
* entered value as is "*" Password field -
* hide value "D" Debug option - don't show
* by default */
int dispsize; /* Field size in characters for dialog */
} PQconninfoOption;
/* ----------------
* PQArgBlock -- structure for PQfn() arguments
* ----------------
*/
typedef struct
{
int len;
int isint;
union
{
int *ptr; /* can't use void (dec compiler barfs) */
int integer;
} u;
} PQArgBlock;
/* ----------------
* PGresAttDesc -- Data about a single attribute (column) of a query result
* ----------------
*/
typedef struct pgresAttDesc
{
char *name; /* column name */
Oid tableid; /* source table, if known */
int columnid; /* source column, if known */
int format; /* format code for value (text/binary) */
Oid typid; /* type id */
int typlen; /* type size */
int atttypmod; /* type-specific modifier info */
} PGresAttDesc;
/* ----------------
* Exported functions of libpq
* ----------------
*/
/* === in fe-connect.c === */
/* make a new client connection to the backend */
/* Asynchronous (non-blocking) */
extern PGconn *PQconnectStart(const char *conninfo);
extern PGconn *PQconnectStartParams(const char *const *keywords,
const char *const *values, int expand_dbname);
extern PostgresPollingStatusType PQconnectPoll(PGconn *conn);
/* Synchronous (blocking) */
extern PGconn *PQconnectdb(const char *conninfo);
extern PGconn *PQconnectdbParams(const char *const *keywords,
const char *const *values, int expand_dbname);
extern PGconn *PQsetdbLogin(const char *pghost, const char *pgport,
const char *pgoptions, const char *pgtty,
const char *dbName,
const char *login, const char *pwd);
#define PQsetdb(M_PGHOST,M_PGPORT,M_PGOPT,M_PGTTY,M_DBNAME) \
PQsetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, NULL, NULL)
/* close the current connection and free the PGconn data structure */
extern void PQfinish(PGconn *conn);
/* get info about connection options known to PQconnectdb */
extern PQconninfoOption *PQconndefaults(void);
/* parse connection options in same way as PQconnectdb */
extern PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg);
/* return the connection options used by a live connection */
extern PQconninfoOption *PQconninfo(PGconn *conn);
/* free the data structure returned by PQconndefaults() or PQconninfoParse() */
extern void PQconninfoFree(PQconninfoOption *connOptions);
/*
* close the current connection and reestablish a new one with the same
* parameters
*/
/* Asynchronous (non-blocking) */
extern int PQresetStart(PGconn *conn);
extern PostgresPollingStatusType PQresetPoll(PGconn *conn);
/* Synchronous (blocking) */
extern void PQreset(PGconn *conn);
/* request a cancel structure */
extern PGcancel *PQgetCancel(PGconn *conn);
/* free a cancel structure */
extern void PQfreeCancel(PGcancel *cancel);
/* issue a cancel request */
extern int PQcancel(PGcancel *cancel, char *errbuf, int errbufsize);
/* backwards compatible version of PQcancel; not thread-safe */
extern int PQrequestCancel(PGconn *conn);
/* Accessor functions for PGconn objects */
extern char *PQdb(const PGconn *conn);
extern char *PQuser(const PGconn *conn);
extern char *PQpass(const PGconn *conn);
extern char *PQhost(const PGconn *conn);
extern char *PQhostaddr(const PGconn *conn);
extern char *PQport(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
extern ConnStatusType PQstatus(const PGconn *conn);
extern PGTransactionStatusType PQtransactionStatus(const PGconn *conn);
extern const char *PQparameterStatus(const PGconn *conn,
const char *paramName);
extern int PQprotocolVersion(const PGconn *conn);
extern int PQserverVersion(const PGconn *conn);
extern char *PQerrorMessage(const PGconn *conn);
extern int PQsocket(const PGconn *conn);
extern int PQbackendPID(const PGconn *conn);
extern PGpipelineStatus PQpipelineStatus(const PGconn *conn);
extern int PQconnectionNeedsPassword(const PGconn *conn);
extern int PQconnectionUsedPassword(const PGconn *conn);
extern int PQclientEncoding(const PGconn *conn);
extern int PQsetClientEncoding(PGconn *conn, const char *encoding);
/* SSL information functions */
extern int PQsslInUse(PGconn *conn);
extern void *PQsslStruct(PGconn *conn, const char *struct_name);
extern const char *PQsslAttribute(PGconn *conn, const char *attribute_name);
extern const char *const *PQsslAttributeNames(PGconn *conn);
/* Get the OpenSSL structure associated with a connection. Returns NULL for
* unencrypted connections or if any other TLS library is in use. */
extern void *PQgetssl(PGconn *conn);
/* Tell libpq whether it needs to initialize OpenSSL */
extern void PQinitSSL(int do_init);
/* More detailed way to tell libpq whether it needs to initialize OpenSSL */
extern void PQinitOpenSSL(int do_ssl, int do_crypto);
/* Return true if GSSAPI encryption is in use */
extern int PQgssEncInUse(PGconn *conn);
/* Returns GSSAPI context if GSSAPI is in use */
extern void *PQgetgssctx(PGconn *conn);
/* Set verbosity for PQerrorMessage and PQresultErrorMessage */
extern PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
/* Set CONTEXT visibility for PQerrorMessage and PQresultErrorMessage */
extern PGContextVisibility PQsetErrorContextVisibility(PGconn *conn,
PGContextVisibility show_context);
/* Override default notice handling routines */
extern PQnoticeReceiver PQsetNoticeReceiver(PGconn *conn,
PQnoticeReceiver proc,
void *arg);
extern PQnoticeProcessor PQsetNoticeProcessor(PGconn *conn,
PQnoticeProcessor proc,
void *arg);
/*
* Used to set callback that prevents concurrent access to
* non-thread safe functions that libpq needs.
* The default implementation uses a libpq internal mutex.
* Only required for multithreaded apps that use kerberos
* both within their app and for postgresql connections.
*/
typedef void (*pgthreadlock_t) (int acquire);
extern pgthreadlock_t PQregisterThreadLock(pgthreadlock_t newhandler);
/* === in fe-trace.c === */
extern void PQtrace(PGconn *conn, FILE *debug_port);
extern void PQuntrace(PGconn *conn);
/* flags controlling trace output: */
/* omit timestamps from each line */
#define PQTRACE_SUPPRESS_TIMESTAMPS (1<<0)
/* redact portions of some messages, for testing frameworks */
#define PQTRACE_REGRESS_MODE (1<<1)
extern void PQsetTraceFlags(PGconn *conn, int flags);
/* === in fe-exec.c === */
/* Simple synchronous query */
extern PGresult *PQexec(PGconn *conn, const char *query);
extern PGresult *PQexecParams(PGconn *conn,
const char *command,
int nParams,
const Oid *paramTypes,
const char *const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
extern PGresult *PQprepare(PGconn *conn, const char *stmtName,
const char *query, int nParams,
const Oid *paramTypes);
extern PGresult *PQexecPrepared(PGconn *conn,
const char *stmtName,
int nParams,
const char *const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
/* Interface for multiple-result or asynchronous queries */
#define PQ_QUERY_PARAM_MAX_LIMIT 65535
extern int PQsendQuery(PGconn *conn, const char *query);
extern int PQsendQueryParams(PGconn *conn,
const char *command,
int nParams,
const Oid *paramTypes,
const char *const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
extern int PQsendPrepare(PGconn *conn, const char *stmtName,
const char *query, int nParams,
const Oid *paramTypes);
extern int PQsendQueryPrepared(PGconn *conn,
const char *stmtName,
int nParams,
const char *const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);
extern int PQsetSingleRowMode(PGconn *conn);
extern PGresult *PQgetResult(PGconn *conn);
/* Routines for managing an asynchronous query */
extern int PQisBusy(PGconn *conn);
extern int PQconsumeInput(PGconn *conn);
/* Routines for pipeline mode management */
extern int PQenterPipelineMode(PGconn *conn);
extern int PQexitPipelineMode(PGconn *conn);
extern int PQpipelineSync(PGconn *conn);
extern int PQsendFlushRequest(PGconn *conn);
/* LISTEN/NOTIFY support */
extern PGnotify *PQnotifies(PGconn *conn);
/* Routines for copy in/out */
extern int PQputCopyData(PGconn *conn, const char *buffer, int nbytes);
extern int PQputCopyEnd(PGconn *conn, const char *errormsg);
extern int PQgetCopyData(PGconn *conn, char **buffer, int async);
/* Deprecated routines for copy in/out */
extern int PQgetline(PGconn *conn, char *string, int length);
extern int PQputline(PGconn *conn, const char *string);
extern int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize);
extern int PQputnbytes(PGconn *conn, const char *buffer, int nbytes);
extern int PQendcopy(PGconn *conn);
/* Set blocking/nonblocking connection to the backend */
extern int PQsetnonblocking(PGconn *conn, int arg);
extern int PQisnonblocking(const PGconn *conn);
extern int PQisthreadsafe(void);
extern PGPing PQping(const char *conninfo);
extern PGPing PQpingParams(const char *const *keywords,
const char *const *values, int expand_dbname);
/* Force the write buffer to be written (or at least try) */
extern int PQflush(PGconn *conn);
/*
* "Fast path" interface --- not really recommended for application
* use
*/
extern PGresult *PQfn(PGconn *conn,
int fnid,
int *result_buf,
int *result_len,
int result_is_int,
const PQArgBlock *args,
int nargs);
/* Accessor functions for PGresult objects */
extern ExecStatusType PQresultStatus(const PGresult *res);
extern char *PQresStatus(ExecStatusType status);
extern char *PQresultErrorMessage(const PGresult *res);
extern char *PQresultVerboseErrorMessage(const PGresult *res,
PGVerbosity verbosity,
PGContextVisibility show_context);
extern char *PQresultErrorField(const PGresult *res, int fieldcode);
extern int PQntuples(const PGresult *res);
extern int PQnfields(const PGresult *res);
extern int PQbinaryTuples(const PGresult *res);
extern char *PQfname(const PGresult *res, int field_num);
extern int PQfnumber(const PGresult *res, const char *field_name);
extern Oid PQftable(const PGresult *res, int field_num);
extern int PQftablecol(const PGresult *res, int field_num);
extern int PQfformat(const PGresult *res, int field_num);
extern Oid PQftype(const PGresult *res, int field_num);
extern int PQfsize(const PGresult *res, int field_num);
extern int PQfmod(const PGresult *res, int field_num);
extern char *PQcmdStatus(PGresult *res);
extern char *PQoidStatus(const PGresult *res); /* old and ugly */
extern Oid PQoidValue(const PGresult *res); /* new and improved */
extern char *PQcmdTuples(PGresult *res);
extern char *PQgetvalue(const PGresult *res, int tup_num, int field_num);
extern int PQgetlength(const PGresult *res, int tup_num, int field_num);
extern int PQgetisnull(const PGresult *res, int tup_num, int field_num);
extern int PQnparams(const PGresult *res);
extern Oid PQparamtype(const PGresult *res, int param_num);
/* Describe prepared statements and portals */
extern PGresult *PQdescribePrepared(PGconn *conn, const char *stmt);
extern PGresult *PQdescribePortal(PGconn *conn, const char *portal);
extern int PQsendDescribePrepared(PGconn *conn, const char *stmt);
extern int PQsendDescribePortal(PGconn *conn, const char *portal);
/* Delete a PGresult */
extern void PQclear(PGresult *res);
/* For freeing other alloc'd results, such as PGnotify structs */
extern void PQfreemem(void *ptr);
/* Exists for backward compatibility. bjm 2003-03-24 */
#define PQfreeNotify(ptr) PQfreemem(ptr)
/* Error when no password was given. */
/* Note: depending on this is deprecated; use PQconnectionNeedsPassword(). */
#define PQnoPasswordSupplied "fe_sendauth: no password supplied\n"
/* Create and manipulate PGresults */
extern PGresult *PQmakeEmptyPGresult(PGconn *conn, ExecStatusType status);
extern PGresult *PQcopyResult(const PGresult *src, int flags);
extern int PQsetResultAttrs(PGresult *res, int numAttributes, PGresAttDesc *attDescs);
extern void *PQresultAlloc(PGresult *res, size_t nBytes);
extern size_t PQresultMemorySize(const PGresult *res);
extern int PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len);
/* Quoting strings before inclusion in queries. */
extern size_t PQescapeStringConn(PGconn *conn,
char *to, const char *from, size_t length,
int *error);
extern char *PQescapeLiteral(PGconn *conn, const char *str, size_t len);
extern char *PQescapeIdentifier(PGconn *conn, const char *str, size_t len);
extern unsigned char *PQescapeByteaConn(PGconn *conn,
const unsigned char *from, size_t from_length,
size_t *to_length);
extern unsigned char *PQunescapeBytea(const unsigned char *strtext,
size_t *retbuflen);
/* These forms are deprecated! */
extern size_t PQescapeString(char *to, const char *from, size_t length);
extern unsigned char *PQescapeBytea(const unsigned char *from, size_t from_length,
size_t *to_length);
/* === in fe-print.c === */
extern void PQprint(FILE *fout, /* output stream */
const PGresult *res,
const PQprintOpt *ps); /* option structure */
/*
* really old printing routines
*/
extern void PQdisplayTuples(const PGresult *res,
FILE *fp, /* where to send the output */
int fillAlign, /* pad the fields with spaces */
const char *fieldSep, /* field separator */
int printHeader, /* display headers? */
int quiet);
extern void PQprintTuples(const PGresult *res,
FILE *fout, /* output stream */
int PrintAttNames, /* print attribute names */
int TerseOutput, /* delimiter bars */
int colWidth); /* width of column, if 0, use
* variable width */
/* === in fe-lobj.c === */
/* Large-object access routines */
extern int lo_open(PGconn *conn, Oid lobjId, int mode);
extern int lo_close(PGconn *conn, int fd);
extern int lo_read(PGconn *conn, int fd, char *buf, size_t len);
extern int lo_write(PGconn *conn, int fd, const char *buf, size_t len);
extern int lo_lseek(PGconn *conn, int fd, int offset, int whence);
extern pg_int64 lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence);
extern Oid lo_creat(PGconn *conn, int mode);
extern Oid lo_create(PGconn *conn, Oid lobjId);
extern int lo_tell(PGconn *conn, int fd);
extern pg_int64 lo_tell64(PGconn *conn, int fd);
extern int lo_truncate(PGconn *conn, int fd, size_t len);
extern int lo_truncate64(PGconn *conn, int fd, pg_int64 len);
extern int lo_unlink(PGconn *conn, Oid lobjId);
extern Oid lo_import(PGconn *conn, const char *filename);
extern Oid lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId);
extern int lo_export(PGconn *conn, Oid lobjId, const char *filename);
/* === in fe-misc.c === */
/* Get the version of the libpq library in use */
extern int PQlibVersion(void);
/* Determine length of multibyte encoded char at *s */
extern int PQmblen(const char *s, int encoding);
/* Same, but not more than the distance to the end of string s */
extern int PQmblenBounded(const char *s, int encoding);
/* Determine display length of multibyte encoded char at *s */
extern int PQdsplen(const char *s, int encoding);
/* Get encoding id from environment variable PGCLIENTENCODING */
extern int PQenv2encoding(void);
/* === in fe-auth.c === */
extern char *PQencryptPassword(const char *passwd, const char *user);
extern char *PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, const char *algorithm);
/* === in encnames.c === */
extern int pg_char_to_encoding(const char *name);
extern const char *pg_encoding_to_char(int encoding);
extern int pg_valid_server_encoding_id(int encoding);
/* === in fe-secure-openssl.c === */
/* Support for overriding sslpassword handling with a callback */
typedef int (*PQsslKeyPassHook_OpenSSL_type) (char *buf, int size, PGconn *conn);
extern PQsslKeyPassHook_OpenSSL_type PQgetSSLKeyPassHook_OpenSSL(void);
extern void PQsetSSLKeyPassHook_OpenSSL(PQsslKeyPassHook_OpenSSL_type hook);
extern int PQdefaultSSLKeyPassHook_OpenSSL(char *buf, int size, PGconn *conn);
#ifdef __cplusplus
}
#endif
#endif /* LIBPQ_FE_H */

690
include/postgres.h Executable file
View File

@@ -0,0 +1,690 @@
/*-------------------------------------------------------------------------
*
* postgres.h
* Primary include file for PostgreSQL server .c files
*
* This should be the first file included by PostgreSQL backend modules.
* Client-side code should include postgres_fe.h instead.
*
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1995, Regents of the University of California
*
* src/include/postgres.h
*
*-------------------------------------------------------------------------
*/
/*
*----------------------------------------------------------------
* TABLE OF CONTENTS
*
* When adding stuff to this file, please try to put stuff
* into the relevant section, or add new sections as appropriate.
*
* section description
* ------- ------------------------------------------------
* 1) variable-length datatypes (TOAST support)
* 2) datum type + support macros
* 3) exception handling definitions
*
* NOTES
*
* In general, this file should contain declarations that are widely needed
* in the backend environment, but are of no interest outside the backend.
*
* Simple type definitions live in c.h, where they are shared with
* postgres_fe.h. We do that since those type definitions are needed by
* frontend modules that want to deal with binary data transmission to or
* from the backend. Type definitions in this file should be for
* representations that never escape the backend, such as Datum or
* TOASTed varlena objects.
*
*----------------------------------------------------------------
*/
#ifndef POSTGRES_H
#define POSTGRES_H
#include "c.h"
#include "utils/elog.h"
#include "utils/palloc.h"
/* ----------------------------------------------------------------
* Section 1: variable-length datatypes (TOAST support)
* ----------------------------------------------------------------
*/
/*
* struct varatt_external is a "TOAST pointer", that is, the information
* needed to fetch a stored-out-of-line Datum. The data is compressed
* if and only if va_extsize < va_rawsize - VARHDRSZ. This struct must not
* contain any padding, because we sometimes compare pointers using memcmp.
*
* Note that this information is stored unaligned within actual tuples, so
* you need to memcpy from the tuple into a local struct variable before
* you can look at these fields! (The reason we use memcmp is to avoid
* having to do that just to detect equality of two TOAST pointers...)
*/
struct varatt_external {
int32 va_rawsize; /* Original data size (includes header) */
int32 va_extsize; /* External saved size (doesn't) */
Oid va_valueid; /* Unique ID of value within TOAST table */
Oid va_toastrelid; /* RelID of TOAST table containing it */
};
/*
* These structs describe the header of a varlena object that may have been
* TOASTed. Generally, don't reference these structs directly, but use the
* macros below.
*
* We use separate structs for the aligned and unaligned cases because the
* compiler might otherwise think it could generate code that assumes
* alignment while touching fields of a 1-byte-header varlena.
*/
typedef union {
struct /* Normal varlena (4-byte length) */
{
uint32 va_header;
char va_data[1];
} va_4byte;
struct /* Compressed-in-line format */
{
uint32 va_header;
uint32 va_rawsize; /* Original data size (excludes header) */
char va_data[1]; /* Compressed data */
} va_compressed;
} varattrib_4b;
typedef struct {
uint8 va_header;
char va_data[1]; /* Data begins here */
} varattrib_1b;
typedef struct {
uint8 va_header; /* Always 0x80 or 0x01 */
uint8 va_len_1be; /* Physical length of datum */
char va_data[1]; /* Data (for now always a TOAST pointer) */
} varattrib_1b_e;
/*
* Bit layouts for varlena headers on big-endian machines:
*
* 00xxxxxx 4-byte length word, aligned, uncompressed data (up to 1G)
* 01xxxxxx 4-byte length word, aligned, *compressed* data (up to 1G)
* 10000000 1-byte length word, unaligned, TOAST pointer
* 1xxxxxxx 1-byte length word, unaligned, uncompressed data (up to 126b)
*
* Bit layouts for varlena headers on little-endian machines:
*
* xxxxxx00 4-byte length word, aligned, uncompressed data (up to 1G)
* xxxxxx10 4-byte length word, aligned, *compressed* data (up to 1G)
* 00000001 1-byte length word, unaligned, TOAST pointer
* xxxxxxx1 1-byte length word, unaligned, uncompressed data (up to 126b)
*
* The "xxx" bits are the length field (which includes itself in all cases).
* In the big-endian case we mask to extract the length, in the little-endian
* case we shift. Note that in both cases the flag bits are in the physically
* first byte. Also, it is not possible for a 1-byte length word to be zero;
* this lets us disambiguate alignment padding bytes from the start of an
* unaligned datum. (We now *require* pad bytes to be filled with zero!)
*/
/*
* Endian-dependent macros. These are considered internal --- use the
* external macros below instead of using these directly.
*
* Note: IS_1B is true for external toast records but VARSIZE_1B will return 0
* for such records. Hence you should usually check for IS_EXTERNAL before
* checking for IS_1B.
*/
#ifdef WORDS_BIGENDIAN
#define VARATT_IS_4B(PTR) \
((((varattrib_1b *) (PTR))->va_header & 0x80) == 0x00)
#define VARATT_IS_4B_U(PTR) \
((((varattrib_1b *) (PTR))->va_header & 0xC0) == 0x00)
#define VARATT_IS_4B_C(PTR) \
((((varattrib_1b *) (PTR))->va_header & 0xC0) == 0x40)
#define VARATT_IS_1B(PTR) \
((((varattrib_1b *) (PTR))->va_header & 0x80) == 0x80)
#define VARATT_IS_1B_E(PTR) \
((((varattrib_1b *) (PTR))->va_header) == 0x80)
#define VARATT_NOT_PAD_BYTE(PTR) \
(*((uint8 *) (PTR)) != 0)
/* VARSIZE_4B() should only be used on known-aligned data */
#define VARSIZE_4B(PTR) \
(((varattrib_4b *) (PTR))->va_4byte.va_header & 0x3FFFFFFF)
#define VARSIZE_1B(PTR) \
(((varattrib_1b *) (PTR))->va_header & 0x7F)
#define VARSIZE_1B_E(PTR) \
(((varattrib_1b_e *) (PTR))->va_len_1be)
#define SET_VARSIZE_4B(PTR,len) \
(((varattrib_4b *) (PTR))->va_4byte.va_header = (len) & 0x3FFFFFFF)
#define SET_VARSIZE_4B_C(PTR,len) \
(((varattrib_4b *) (PTR))->va_4byte.va_header = ((len) & 0x3FFFFFFF) | 0x40000000)
#define SET_VARSIZE_1B(PTR,len) \
(((varattrib_1b *) (PTR))->va_header = (len) | 0x80)
#define SET_VARSIZE_1B_E(PTR,len) \
(((varattrib_1b_e *) (PTR))->va_header = 0x80, \
((varattrib_1b_e *) (PTR))->va_len_1be = (len))
#else /* !WORDS_BIGENDIAN */
#define VARATT_IS_4B(PTR) \
((((varattrib_1b *) (PTR))->va_header & 0x01) == 0x00)
#define VARATT_IS_4B_U(PTR) \
((((varattrib_1b *) (PTR))->va_header & 0x03) == 0x00)
#define VARATT_IS_4B_C(PTR) \
((((varattrib_1b *) (PTR))->va_header & 0x03) == 0x02)
#define VARATT_IS_1B(PTR) \
((((varattrib_1b *) (PTR))->va_header & 0x01) == 0x01)
#define VARATT_IS_1B_E(PTR) \
((((varattrib_1b *) (PTR))->va_header) == 0x01)
#define VARATT_NOT_PAD_BYTE(PTR) \
(*((uint8 *) (PTR)) != 0)
/* VARSIZE_4B() should only be used on known-aligned data */
#define VARSIZE_4B(PTR) \
((((varattrib_4b *) (PTR))->va_4byte.va_header >> 2) & 0x3FFFFFFF)
#define VARSIZE_1B(PTR) \
((((varattrib_1b *) (PTR))->va_header >> 1) & 0x7F)
#define VARSIZE_1B_E(PTR) \
(((varattrib_1b_e *) (PTR))->va_len_1be)
#define SET_VARSIZE_4B(PTR, len) \
(((varattrib_4b *) (PTR))->va_4byte.va_header = (((uint32) (len)) << 2))
#define SET_VARSIZE_4B_C(PTR, len) \
(((varattrib_4b *) (PTR))->va_4byte.va_header = (((uint32) (len)) << 2) | 0x02)
#define SET_VARSIZE_1B(PTR, len) \
(((varattrib_1b *) (PTR))->va_header = (((uint8) (len)) << 1) | 0x01)
#define SET_VARSIZE_1B_E(PTR, len) \
(((varattrib_1b_e *) (PTR))->va_header = 0x01, \
((varattrib_1b_e *) (PTR))->va_len_1be = (len))
#endif /* WORDS_BIGENDIAN */
#define VARHDRSZ_SHORT 1
#define VARATT_SHORT_MAX 0x7F
#define VARATT_CAN_MAKE_SHORT(PTR) \
(VARATT_IS_4B_U(PTR) && \
(VARSIZE(PTR) - VARHDRSZ + VARHDRSZ_SHORT) <= VARATT_SHORT_MAX)
#define VARATT_CONVERTED_SHORT_SIZE(PTR) \
(VARSIZE(PTR) - VARHDRSZ + VARHDRSZ_SHORT)
#define VARHDRSZ_EXTERNAL 2
#define VARDATA_4B(PTR) (((varattrib_4b *) (PTR))->va_4byte.va_data)
#define VARDATA_4B_C(PTR) (((varattrib_4b *) (PTR))->va_compressed.va_data)
#define VARDATA_1B(PTR) (((varattrib_1b *) (PTR))->va_data)
#define VARDATA_1B_E(PTR) (((varattrib_1b_e *) (PTR))->va_data)
#define VARRAWSIZE_4B_C(PTR) \
(((varattrib_4b *) (PTR))->va_compressed.va_rawsize)
/* Externally visible macros */
/*
* VARDATA, VARSIZE, and SET_VARSIZE are the recommended API for most code
* for varlena datatypes. Note that they only work on untoasted,
* 4-byte-header Datums!
*
* Code that wants to use 1-byte-header values without detoasting should
* use VARSIZE_ANY/VARSIZE_ANY_EXHDR/VARDATA_ANY. The other macros here
* should usually be used only by tuple assembly/disassembly code and
* code that specifically wants to work with still-toasted Datums.
*
* WARNING: It is only safe to use VARDATA_ANY() -- typically with
* PG_DETOAST_DATUM_PACKED() -- if you really don't care about the alignment.
* Either because you're working with something like text where the alignment
* doesn't matter or because you're not going to access its constituent parts
* and just use things like memcpy on it anyways.
*/
#define VARDATA(PTR) VARDATA_4B(PTR)
#define VARSIZE(PTR) VARSIZE_4B(PTR)
#define VARSIZE_SHORT(PTR) VARSIZE_1B(PTR)
#define VARDATA_SHORT(PTR) VARDATA_1B(PTR)
#define VARSIZE_EXTERNAL(PTR) VARSIZE_1B_E(PTR)
#define VARDATA_EXTERNAL(PTR) VARDATA_1B_E(PTR)
#define VARATT_IS_COMPRESSED(PTR) VARATT_IS_4B_C(PTR)
#define VARATT_IS_EXTERNAL(PTR) VARATT_IS_1B_E(PTR)
#define VARATT_IS_SHORT(PTR) VARATT_IS_1B(PTR)
#define VARATT_IS_EXTENDED(PTR) (!VARATT_IS_4B_U(PTR))
#define SET_VARSIZE(PTR, len) SET_VARSIZE_4B(PTR, len)
#define SET_VARSIZE_SHORT(PTR, len) SET_VARSIZE_1B(PTR, len)
#define SET_VARSIZE_COMPRESSED(PTR, len) SET_VARSIZE_4B_C(PTR, len)
#define SET_VARSIZE_EXTERNAL(PTR, len) SET_VARSIZE_1B_E(PTR, len)
#define VARSIZE_ANY(PTR) \
(VARATT_IS_1B_E(PTR) ? VARSIZE_1B_E(PTR) : \
(VARATT_IS_1B(PTR) ? VARSIZE_1B(PTR) : \
VARSIZE_4B(PTR)))
#define VARSIZE_ANY_EXHDR(PTR) \
(VARATT_IS_1B_E(PTR) ? VARSIZE_1B_E(PTR)-VARHDRSZ_EXTERNAL : \
(VARATT_IS_1B(PTR) ? VARSIZE_1B(PTR)-VARHDRSZ_SHORT : \
VARSIZE_4B(PTR)-VARHDRSZ))
/* caution: this will not work on an external or compressed-in-line Datum */
/* caution: this will return a possibly unaligned pointer */
#define VARDATA_ANY(PTR) \
(VARATT_IS_1B(PTR) ? VARDATA_1B(PTR) : VARDATA_4B(PTR))
/* ----------------------------------------------------------------
* Section 2: datum type + support macros
* ----------------------------------------------------------------
*/
/*
* Port Notes:
* Postgres makes the following assumptions about datatype sizes:
*
* sizeof(Datum) == sizeof(void *) == 4 or 8
* sizeof(char) == 1
* sizeof(short) == 2
*
* When a type narrower than Datum is stored in a Datum, we place it in the
* low-order bits and are careful that the DatumGetXXX macro for it discards
* the unused high-order bits (as opposed to, say, assuming they are zero).
* This is needed to support old-style user-defined functions, since depending
* on architecture and compiler, the return value of a function returning char
* or short may contain garbage when called as if it returned Datum.
*/
typedef uintptr_t Datum;
#define SIZEOF_DATUM SIZEOF_VOID_P
typedef Datum *DatumPtr;
#define GET_1_BYTE(datum) (((Datum) (datum)) & 0x000000ff)
#define GET_2_BYTES(datum) (((Datum) (datum)) & 0x0000ffff)
#define GET_4_BYTES(datum) (((Datum) (datum)) & 0xffffffff)
#if SIZEOF_DATUM == 8
#define GET_8_BYTES(datum) ((Datum) (datum))
#endif
#define SET_1_BYTE(value) (((Datum) (value)) & 0x000000ff)
#define SET_2_BYTES(value) (((Datum) (value)) & 0x0000ffff)
#define SET_4_BYTES(value) (((Datum) (value)) & 0xffffffff)
#if SIZEOF_DATUM == 8
#define SET_8_BYTES(value) ((Datum) (value))
#endif
/*
* DatumGetBool
* Returns boolean value of a datum.
*
* Note: any nonzero value will be considered TRUE, but we ignore bits to
* the left of the width of bool, per comment above.
*/
#define DatumGetBool(X) ((bool) (((bool) (X)) != 0))
/*
* BoolGetDatum
* Returns datum representation for a boolean.
*
* Note: any nonzero value will be considered TRUE.
*/
#define BoolGetDatum(X) ((Datum) ((X) ? 1 : 0))
/*
* DatumGetChar
* Returns character value of a datum.
*/
#define DatumGetChar(X) ((char) GET_1_BYTE(X))
/*
* CharGetDatum
* Returns datum representation for a character.
*/
#define CharGetDatum(X) ((Datum) SET_1_BYTE(X))
/*
* Int8GetDatum
* Returns datum representation for an 8-bit integer.
*/
#define Int8GetDatum(X) ((Datum) SET_1_BYTE(X))
/*
* DatumGetUInt8
* Returns 8-bit unsigned integer value of a datum.
*/
#define DatumGetUInt8(X) ((uint8) GET_1_BYTE(X))
/*
* UInt8GetDatum
* Returns datum representation for an 8-bit unsigned integer.
*/
#define UInt8GetDatum(X) ((Datum) SET_1_BYTE(X))
/*
* DatumGetInt16
* Returns 16-bit integer value of a datum.
*/
#define DatumGetInt16(X) ((int16) GET_2_BYTES(X))
/*
* Int16GetDatum
* Returns datum representation for a 16-bit integer.
*/
#define Int16GetDatum(X) ((Datum) SET_2_BYTES(X))
/*
* DatumGetUInt16
* Returns 16-bit unsigned integer value of a datum.
*/
#define DatumGetUInt16(X) ((uint16) GET_2_BYTES(X))
/*
* UInt16GetDatum
* Returns datum representation for a 16-bit unsigned integer.
*/
#define UInt16GetDatum(X) ((Datum) SET_2_BYTES(X))
/*
* DatumGetInt32
* Returns 32-bit integer value of a datum.
*/
#define DatumGetInt32(X) ((int32) GET_4_BYTES(X))
/*
* Int32GetDatum
* Returns datum representation for a 32-bit integer.
*/
#define Int32GetDatum(X) ((Datum) SET_4_BYTES(X))
/*
* DatumGetUInt32
* Returns 32-bit unsigned integer value of a datum.
*/
#define DatumGetUInt32(X) ((uint32) GET_4_BYTES(X))
/*
* UInt32GetDatum
* Returns datum representation for a 32-bit unsigned integer.
*/
#define UInt32GetDatum(X) ((Datum) SET_4_BYTES(X))
/*
* DatumGetObjectId
* Returns object identifier value of a datum.
*/
#define DatumGetObjectId(X) ((Oid) GET_4_BYTES(X))
/*
* ObjectIdGetDatum
* Returns datum representation for an object identifier.
*/
#define ObjectIdGetDatum(X) ((Datum) SET_4_BYTES(X))
/*
* DatumGetTransactionId
* Returns transaction identifier value of a datum.
*/
#define DatumGetTransactionId(X) ((TransactionId) GET_4_BYTES(X))
/*
* TransactionIdGetDatum
* Returns datum representation for a transaction identifier.
*/
#define TransactionIdGetDatum(X) ((Datum) SET_4_BYTES((X)))
/*
* DatumGetCommandId
* Returns command identifier value of a datum.
*/
#define DatumGetCommandId(X) ((CommandId) GET_4_BYTES(X))
/*
* CommandIdGetDatum
* Returns datum representation for a command identifier.
*/
#define CommandIdGetDatum(X) ((Datum) SET_4_BYTES(X))
/*
* DatumGetPointer
* Returns pointer value of a datum.
*/
#define DatumGetPointer(X) ((Pointer) (X))
/*
* PointerGetDatum
* Returns datum representation for a pointer.
*/
#define PointerGetDatum(X) ((Datum) (X))
/*
* DatumGetCString
* Returns C string (null-terminated string) value of a datum.
*
* Note: C string is not a full-fledged Postgres type at present,
* but type input functions use this conversion for their inputs.
*/
#define DatumGetCString(X) ((char *) DatumGetPointer(X))
/*
* CStringGetDatum
* Returns datum representation for a C string (null-terminated string).
*
* Note: C string is not a full-fledged Postgres type at present,
* but type output functions use this conversion for their outputs.
* Note: CString is pass-by-reference; caller must ensure the pointed-to
* value has adequate lifetime.
*/
#define CStringGetDatum(X) PointerGetDatum(X)
/*
* DatumGetName
* Returns name value of a datum.
*/
#define DatumGetName(X) ((Name) DatumGetPointer(X))
/*
* NameGetDatum
* Returns datum representation for a name.
*
* Note: Name is pass-by-reference; caller must ensure the pointed-to
* value has adequate lifetime.
*/
#define NameGetDatum(X) PointerGetDatum(X)
/*
* DatumGetInt64
* Returns 64-bit integer value of a datum.
*
* Note: this macro hides whether int64 is pass by value or by reference.
*/
#ifdef USE_FLOAT8_BYVAL
#define DatumGetInt64(X) ((int64) GET_8_BYTES(X))
#else
#define DatumGetInt64(X) (* ((int64 *) DatumGetPointer(X)))
#endif
/*
* Int64GetDatum
* Returns datum representation for a 64-bit integer.
*
* Note: if int64 is pass by reference, this function returns a reference
* to palloc'd space.
*/
#ifdef USE_FLOAT8_BYVAL
#define Int64GetDatum(X) ((Datum) SET_8_BYTES(X))
#else
extern Datum Int64GetDatum(int64 X);
#endif
/*
* DatumGetFloat4
* Returns 4-byte floating point value of a datum.
*
* Note: this macro hides whether float4 is pass by value or by reference.
*/
#ifdef USE_FLOAT4_BYVAL
extern float4 DatumGetFloat4(Datum X);
#else
#define DatumGetFloat4(X) (* ((float4 *) DatumGetPointer(X)))
#endif
/*
* Float4GetDatum
* Returns datum representation for a 4-byte floating point number.
*
* Note: if float4 is pass by reference, this function returns a reference
* to palloc'd space.
*/
extern Datum Float4GetDatum(float4 X);
/*
* DatumGetFloat8
* Returns 8-byte floating point value of a datum.
*
* Note: this macro hides whether float8 is pass by value or by reference.
*/
#ifdef USE_FLOAT8_BYVAL
extern float8 DatumGetFloat8(Datum X);
#else
#define DatumGetFloat8(X) (* ((float8 *) DatumGetPointer(X)))
#endif
/*
* Float8GetDatum
* Returns datum representation for an 8-byte floating point number.
*
* Note: if float8 is pass by reference, this function returns a reference
* to palloc'd space.
*/
extern Datum Float8GetDatum(float8 X);
/*
* Int64GetDatumFast
* Float8GetDatumFast
* Float4GetDatumFast
*
* These macros are intended to allow writing code that does not depend on
* whether int64, float8, float4 are pass-by-reference types, while not
* sacrificing performance when they are. The argument must be a variable
* that will exist and have the same value for as long as the Datum is needed.
* In the pass-by-ref case, the address of the variable is taken to use as
* the Datum. In the pass-by-val case, these will be the same as the non-Fast
* macros.
*/
#ifdef USE_FLOAT8_BYVAL
#define Int64GetDatumFast(X) Int64GetDatum(X)
#define Float8GetDatumFast(X) Float8GetDatum(X)
#else
#define Int64GetDatumFast(X) PointerGetDatum(&(X))
#define Float8GetDatumFast(X) PointerGetDatum(&(X))
#endif
#ifdef USE_FLOAT4_BYVAL
#define Float4GetDatumFast(X) Float4GetDatum(X)
#else
#define Float4GetDatumFast(X) PointerGetDatum(&(X))
#endif
/* ----------------------------------------------------------------
* Section 3: exception handling definitions
* Assert, Trap, etc macros
* ----------------------------------------------------------------
*/
extern PGDLLIMPORT bool assert_enabled;
/*
* USE_ASSERT_CHECKING, if defined, turns on all the assertions.
* - plai 9/5/90
*
* It should _NOT_ be defined in releases or in benchmark copies
*/
/*
* Trap
* Generates an exception if the given condition is true.
*/
#define Trap(condition, errorType) \
do { \
if ((assert_enabled) && (condition)) \
ExceptionalCondition(CppAsString(condition), (errorType), \
__FILE__, __LINE__); \
} while (0)
/*
* TrapMacro is the same as Trap but it's intended for use in macros:
*
* #define foo(x) (AssertMacro(x != 0), bar(x))
*
* Isn't CPP fun?
*/
#define TrapMacro(condition, errorType) \
((bool) ((! assert_enabled) || ! (condition) || \
(ExceptionalCondition(CppAsString(condition), (errorType), \
__FILE__, __LINE__), 0)))
#ifndef USE_ASSERT_CHECKING
#define Assert(condition)
#define AssertMacro(condition) ((void)true)
#define AssertArg(condition)
#define AssertState(condition)
#else
#define Assert(condition) \
Trap(!(condition), "FailedAssertion")
#define AssertMacro(condition) \
((void) TrapMacro(!(condition), "FailedAssertion"))
#define AssertArg(condition) \
Trap(!(condition), "BadArgument")
#define AssertState(condition) \
Trap(!(condition), "BadState")
#endif /* USE_ASSERT_CHECKING */
extern void ExceptionalCondition(const char *conditionName,
const char *errorType,
const char *fileName, int lineNumber) __attribute__((noreturn));
#endif /* POSTGRES_H */

197
include/utils/catcache.h Executable file
View File

@@ -0,0 +1,197 @@
/*-------------------------------------------------------------------------
*
* catcache.h
* Low-level catalog cache definitions.
*
* NOTE: every catalog cache must have a corresponding unique index on
* the system table that it caches --- ie, the index must match the keys
* used to do lookups in this cache. All cache fetches are done with
* indexscans (under normal conditions). The index should be unique to
* guarantee that there can only be one matching row for a key combination.
*
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/utils/catcache.h
*
*-------------------------------------------------------------------------
*/
#ifndef CATCACHE_H
#define CATCACHE_H
#include "access/htup.h"
#include "access/skey.h"
#include "lib/dllist.h"
#include "utils/relcache.h"
/*
* struct catctup: individual tuple in the cache.
* struct catclist: list of tuples matching a partial key.
* struct catcache: information for managing a cache.
* struct catcacheheader: information for managing all the caches.
*/
#define CATCACHE_MAXKEYS 4
typedef struct catcache {
int id; /* cache identifier --- see syscache.h */
struct catcache *cc_next; /* link to next catcache */
const char *cc_relname; /* name of relation the tuples come from */
Oid cc_reloid; /* OID of relation the tuples come from */
Oid cc_indexoid; /* OID of index matching cache keys */
bool cc_relisshared; /* is relation shared across databases? */
TupleDesc cc_tupdesc; /* tuple descriptor (copied from reldesc) */
int cc_ntup; /* # of tuples currently in this cache */
int cc_nbuckets; /* # of hash buckets in this cache */
int cc_nkeys; /* # of keys (1..CATCACHE_MAXKEYS) */
int cc_key[CATCACHE_MAXKEYS]; /* AttrNumber of each key */
PGFunction cc_hashfunc[CATCACHE_MAXKEYS]; /* hash function for each key */
ScanKeyData cc_skey[CATCACHE_MAXKEYS]; /* precomputed key info for
* heap scans */
bool cc_isname[CATCACHE_MAXKEYS]; /* flag "name" key columns */
Dllist cc_lists; /* list of CatCList structs */
#ifdef CATCACHE_STATS
long cc_searches; /* total # searches against this cache */
long cc_hits; /* # of matches against existing entry */
long cc_neg_hits; /* # of matches against negative entry */
long cc_newloads; /* # of successful loads of new entry */
/*
* cc_searches - (cc_hits + cc_neg_hits + cc_newloads) is number of failed
* searches, each of which will result in loading a negative entry
*/
long cc_invals; /* # of entries invalidated from cache */
long cc_lsearches; /* total # list-searches */
long cc_lhits; /* # of matches against existing lists */
#endif
Dllist cc_bucket[1]; /* hash buckets --- VARIABLE LENGTH ARRAY */
} CatCache; /* VARIABLE LENGTH STRUCT */
typedef struct catctup {
int ct_magic; /* for identifying CatCTup entries */
#define CT_MAGIC 0x57261502
CatCache *my_cache; /* link to owning catcache */
/*
* Each tuple in a cache is a member of a Dllist that stores the elements
* of its hash bucket. We keep each Dllist in LRU order to speed repeated
* lookups.
*/
Dlelem cache_elem; /* list member of per-bucket list */
/*
* The tuple may also be a member of at most one CatCList. (If a single
* catcache is list-searched with varying numbers of keys, we may have to
* make multiple entries for the same tuple because of this restriction.
* Currently, that's not expected to be common, so we accept the potential
* inefficiency.)
*/
struct catclist *c_list; /* containing CatCList, or NULL if none */
/*
* A tuple marked "dead" must not be returned by subsequent searches.
* However, it won't be physically deleted from the cache until its
* refcount goes to zero. (If it's a member of a CatCList, the list's
* refcount must go to zero, too; also, remember to mark the list dead at
* the same time the tuple is marked.)
*
* A negative cache entry is an assertion that there is no tuple matching
* a particular key. This is just as useful as a normal entry so far as
* avoiding catalog searches is concerned. Management of positive and
* negative entries is identical.
*/
int refcount; /* number of active references */
bool dead; /* dead but not yet removed? */
bool negative; /* negative cache entry? */
uint32 hash_value; /* hash value for this tuple's keys */
HeapTupleData tuple; /* tuple management header */
} CatCTup;
typedef struct catclist {
int cl_magic; /* for identifying CatCList entries */
#define CL_MAGIC 0x52765103
CatCache *my_cache; /* link to owning catcache */
/*
* A CatCList describes the result of a partial search, ie, a search using
* only the first K key columns of an N-key cache. We form the keys used
* into a tuple (with other attributes NULL) to represent the stored key
* set. The CatCList object contains links to cache entries for all the
* table rows satisfying the partial key. (Note: none of these will be
* negative cache entries.)
*
* A CatCList is only a member of a per-cache list; we do not currently
* divide them into hash buckets.
*
* A list marked "dead" must not be returned by subsequent searches.
* However, it won't be physically deleted from the cache until its
* refcount goes to zero. (A list should be marked dead if any of its
* member entries are dead.)
*
* If "ordered" is true then the member tuples appear in the order of the
* cache's underlying index. This will be true in normal operation, but
* might not be true during bootstrap or recovery operations. (namespace.c
* is able to save some cycles when it is true.)
*/
Dlelem cache_elem; /* list member of per-catcache list */
int refcount; /* number of active references */
bool dead; /* dead but not yet removed? */
bool ordered; /* members listed in index order? */
short nkeys; /* number of lookup keys specified */
uint32 hash_value; /* hash value for lookup keys */
HeapTupleData tuple; /* header for tuple holding keys */
int n_members; /* number of member tuples */
CatCTup *members[1]; /* members --- VARIABLE LENGTH ARRAY */
} CatCList; /* VARIABLE LENGTH STRUCT */
typedef struct catcacheheader {
CatCache *ch_caches; /* head of list of CatCache structs */
int ch_ntup; /* # of tuples in all caches */
} CatCacheHeader;
/* this extern duplicates utils/memutils.h... */
extern PGDLLIMPORT __thread MemoryContext CacheMemoryContext;
extern void CreateCacheMemoryContext(void);
extern void AtEOXact_CatCache(bool isCommit);
extern CatCache *InitCatCache(int id, Oid reloid, Oid indexoid,
int nkeys, const int *key,
int nbuckets);
extern void InitCatCachePhase2(CatCache *cache, bool touch_index);
extern HeapTuple SearchCatCache(CatCache *cache,
Datum v1, Datum v2,
Datum v3, Datum v4);
extern void ReleaseCatCache(HeapTuple tuple);
extern uint32 GetCatCacheHashValue(CatCache *cache,
Datum v1, Datum v2,
Datum v3, Datum v4);
extern CatCList *SearchCatCacheList(CatCache *cache, int nkeys,
Datum v1, Datum v2,
Datum v3, Datum v4);
extern void ReleaseCatCacheList(CatCList *list);
extern void ResetCatalogCaches(void);
extern void CatalogCacheFlushCatalog(Oid catId);
extern void CatalogCacheIdInvalidate(int cacheId, uint32 hashValue);
extern void PrepareToInvalidateCacheTuple(Relation relation,
HeapTuple tuple,
HeapTuple newtuple,
void (*function)(int, uint32, Oid));
extern void PrintCatCacheLeakWarning(HeapTuple tuple);
extern void PrintCatCacheListLeakWarning(CatCList *list);
#endif /* CATCACHE_H */

152
include/utils/memutils.h Executable file
View File

@@ -0,0 +1,152 @@
/*-------------------------------------------------------------------------
*
* memutils.h
* This file contains declarations for memory allocation utility
* functions. These are functions that are not quite widely used
* enough to justify going in utils/palloc.h, but are still part
* of the API of the memory management subsystem.
*
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/utils/memutils.h
*
*-------------------------------------------------------------------------
*/
#ifndef MEMUTILS_H
#define MEMUTILS_H
#include "nodes/memnodes.h"
#include <pthread.h>
/*
* MaxAllocSize
* Quasi-arbitrary limit on size of allocations.
*
* Note:
* There is no guarantee that allocations smaller than MaxAllocSize
* will succeed. Allocation requests larger than MaxAllocSize will
* be summarily denied.
*
* XXX This is deliberately chosen to correspond to the limiting size
* of varlena objects under TOAST. See VARSIZE_4B() and related macros
* in postgres.h. Many datatypes assume that any allocatable size can
* be represented in a varlena header.
*
* XXX Also, various places in aset.c assume they can compute twice an
* allocation's size without overflow, so beware of raising this.
*/
#define MaxAllocSize ((Size)0x3fffffff) /* 1 gigabyte - 1 */
#define AllocSizeIsValid(size) ((Size)(size) <= MaxAllocSize)
/*
* All chunks allocated by any memory context manager are required to be
* preceded by a StandardChunkHeader at a spacing of STANDARDCHUNKHEADERSIZE.
* A currently-allocated chunk must contain a backpointer to its owning
* context as well as the allocated size of the chunk. The backpointer is
* used by pfree() and repalloc() to find the context to call. The allocated
* size is not absolutely essential, but it's expected to be needed by any
* reasonable implementation.
*/
typedef struct StandardChunkHeader {
MemoryContext context; /* owning context */
Size size; /* size of data space allocated in chunk */
#ifdef MEMORY_CONTEXT_CHECKING
/* when debugging memory usage, also store actual requested size */
Size requested_size;
#endif
} StandardChunkHeader;
#define STANDARDCHUNKHEADERSIZE MAXALIGN(sizeof(StandardChunkHeader))
/*
* Standard top-level memory contexts.
*
* Only TopMemoryContext and ErrorContext are initialized by
* MemoryContextInit() itself.
*/
extern PGDLLIMPORT __thread MemoryContext TopMemoryContext;
extern PGDLLIMPORT __thread MemoryContext ErrorContext;
extern PGDLLIMPORT __thread MemoryContext PostmasterContext;
extern PGDLLIMPORT __thread MemoryContext CacheMemoryContext;
extern PGDLLIMPORT __thread MemoryContext MessageContext;
extern PGDLLIMPORT __thread MemoryContext TopTransactionContext;
extern PGDLLIMPORT __thread MemoryContext CurTransactionContext;
/* This is a transient link to the active portal's memory context: */
extern PGDLLIMPORT __thread MemoryContext PortalContext;
/*
* Memory-context-type-independent functions in mcxt.c
*/
extern void MemoryContextInit(void);
extern void MemoryContextReset(MemoryContext context);
extern void MemoryContextDelete(MemoryContext context);
extern void MemoryContextResetChildren(MemoryContext context);
extern void MemoryContextDeleteChildren(MemoryContext context);
extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
extern void MemoryContextSetParent(MemoryContext context,
MemoryContext new_parent);
extern Size GetMemoryChunkSpace(void *pointer);
extern MemoryContext GetMemoryChunkContext(void *pointer);
extern MemoryContext MemoryContextGetParent(MemoryContext context);
extern bool MemoryContextIsEmpty(MemoryContext context);
extern void MemoryContextStats(MemoryContext context);
#ifdef MEMORY_CONTEXT_CHECKING
extern void MemoryContextCheck(MemoryContext context);
#endif
extern bool MemoryContextContains(MemoryContext context, void *pointer);
/*
* This routine handles the context-type-independent part of memory
* context creation. It's intended to be called from context-type-
* specific creation routines, and noplace else.
*/
extern MemoryContext MemoryContextCreate(NodeTag tag, Size size,
MemoryContextMethods *methods,
MemoryContext parent,
const char *name);
/*
* Memory-context-type-specific functions
*/
/* aset.c */
extern MemoryContext AllocSetContextCreate(MemoryContext parent,
const char *name,
Size minContextSize,
Size initBlockSize,
Size maxBlockSize);
/*
* Recommended default alloc parameters, suitable for "ordinary" contexts
* that might hold quite a lot of data.
*/
#define ALLOCSET_DEFAULT_MINSIZE 0
#define ALLOCSET_DEFAULT_INITSIZE (8 * 1024)
#define ALLOCSET_DEFAULT_MAXSIZE (8 * 1024 * 1024)
/*
* Recommended alloc parameters for "small" contexts that are not expected
* to contain much data (for example, a context to contain a query plan).
*/
#define ALLOCSET_SMALL_MINSIZE 0
#define ALLOCSET_SMALL_INITSIZE (1 * 1024)
#define ALLOCSET_SMALL_MAXSIZE (8 * 1024)
#endif /* MEMUTILS_H */

112
include/utils/palloc.h Executable file
View File

@@ -0,0 +1,112 @@
/*-------------------------------------------------------------------------
*
* palloc.h
* POSTGRES memory allocator definitions.
*
* This file contains the basic memory allocation interface that is
* needed by almost every backend module. It is included directly by
* postgres.h, so the definitions here are automatically available
* everywhere. Keep it lean!
*
* Memory allocation occurs within "contexts". Every chunk obtained from
* palloc()/MemoryContextAlloc() is allocated within a specific context.
* The entire contents of a context can be freed easily and quickly by
* resetting or deleting the context --- this is both faster and less
* prone to memory-leakage bugs than releasing chunks individually.
* We organize contexts into context trees to allow fine-grain control
* over chunk lifetime while preserving the certainty that we will free
* everything that should be freed. See utils/mmgr/README for more info.
*
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/utils/palloc.h
*
*-------------------------------------------------------------------------
*/
#ifndef PALLOC_H
#define PALLOC_H
/*
* Type MemoryContextData is declared in nodes/memnodes.h. Most users
* of memory allocation should just treat it as an abstract type, so we
* do not provide the struct contents here.
*/
typedef struct MemoryContextData *MemoryContext;
/*
* CurrentMemoryContext is the default allocation context for palloc().
* We declare it here so that palloc() can be a macro. Avoid accessing it
* directly! Instead, use MemoryContextSwitchTo() to change the setting.
*/
extern PGDLLIMPORT __thread MemoryContext CurrentMemoryContext;
/*
* Fundamental memory-allocation operations (more are in utils/memutils.h)
*/
extern void *MemoryContextAlloc(MemoryContext context, Size size);
extern void *MemoryContextAllocZero(MemoryContext context, Size size);
extern void *MemoryContextAllocZeroAligned(MemoryContext context, Size size);
#define palloc(sz) MemoryContextAlloc(CurrentMemoryContext, (sz))
#define palloc0(sz) MemoryContextAllocZero(CurrentMemoryContext, (sz))
/*
* The result of palloc() is always word-aligned, so we can skip testing
* alignment of the pointer when deciding which MemSet variant to use.
* Note that this variant does not offer any advantage, and should not be
* used, unless its "sz" argument is a compile-time constant; therefore, the
* issue that it evaluates the argument multiple times isn't a problem in
* practice.
*/
#define palloc0fast(sz) \
(MemSetTest(0, sz) ? MemoryContextAllocZeroAligned(CurrentMemoryContext, sz) : MemoryContextAllocZero(CurrentMemoryContext, sz))
extern void pfree(void *pointer);
extern void *repalloc(void *pointer, Size size);
/*
* MemoryContextSwitchTo can't be a macro in standard C compilers.
* But we can make it an inline function if the compiler supports it.
*
* This file has to be includable by some non-backend code such as
* pg_resetxlog, so don't expose the CurrentMemoryContext reference
* if FRONTEND is defined.
*/
#if defined(USE_INLINE) && !defined(FRONTEND)
static inline MemoryContext
MemoryContextSwitchTo(MemoryContext context) {
MemoryContext old = CurrentMemoryContext;
CurrentMemoryContext = context;
return old;
}
#else
extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
#endif /* USE_INLINE && !FRONTEND */
/*
* These are like standard strdup() except the copied string is
* allocated in a context, not with malloc().
*/
extern char *MemoryContextStrdup(MemoryContext context, const char *string);
#define pstrdup(str) MemoryContextStrdup(CurrentMemoryContext, (str))
extern char *pnstrdup(const char *in, Size len);
#if defined(WIN32) || defined(__CYGWIN__)
extern void *pgport_palloc(Size sz);
extern char *pgport_pstrdup(const char *str);
extern void pgport_pfree(void *pointer);
#endif
#endif /* PALLOC_H */