init
This commit is contained in:
46
include/crypto/crypto.h
Executable file
46
include/crypto/crypto.h
Executable 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
15
include/crypto/openssl.h
Executable 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
20
include/encryptsql.h
Executable 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
2
include/encryptsql/combine.h
Executable file
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
|
||||
54
include/encryptsql/fieldmap.h
Executable file
54
include/encryptsql/fieldmap.h
Executable 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的type,column明文无后缀
|
||||
|
||||
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
10
include/encryptsql/node2str.h
Executable 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
42
include/encryptsql/parser.h
Executable 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
114
include/kms/ikms_core.hpp
Executable 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
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
123
include/kms/kms_common.hpp
Executable 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
109
include/kms/kms_core_local.hpp
Executable 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
24
include/kms/kms_factory.hpp
Executable 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
54
include/kms/kms_interface.hpp
Executable 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
|
||||
|
||||
|
||||
255
include/kmsAdapter/dek_interface.hpp
Executable file
255
include/kmsAdapter/dek_interface.hpp
Executable 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
|
||||
83
include/kmsAdapter/dek_manager.hpp
Executable file
83
include/kmsAdapter/dek_manager.hpp
Executable 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
24837
include/kmsAdapter/json.hpp
Executable file
File diff suppressed because it is too large
Load Diff
673
include/libpq-fe.h
Executable file
673
include/libpq-fe.h
Executable 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
690
include/postgres.h
Executable 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
197
include/utils/catcache.h
Executable 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
152
include/utils/memutils.h
Executable 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
112
include/utils/palloc.h
Executable 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 */
|
||||
Reference in New Issue
Block a user