c - 为 PostgreSQL 实现 C 扩展函数 - 我该怎么做? (在 C/PostgreSQL 之间传递数据)

标签 c postgresql

我正在为 PostgreSQL (v 8.4) 编写 C 扩展。我目前一直在研究如何将列式数据从 PostgreSQL 传递到我的 C 函数。我还有一个内存所有权的问题,因为 PostgreSQL 似乎在幕后做了很多内存管理。

如果有人可以帮助我“加入点”,以获得一个基本的框架代码库,我将不胜感激,我可以以此为基础构建库。

这是我目前所拥有的:

/*******************************************************/
/*                  C header file                      */
/*******************************************************/
typedef struct _myarray
{
    double *data;
    size_t len;
} MyArray;


MyArray * NEW_MyArray(const size_t len);
void Destroy_MyArray(MyArray * arr);
size_t NumElements_MyArray(MyArray * arr);      /* trivial function returns number of elements */
MyArray * NotTrivial_MyArray(MyArray * arr);    /* non trivial function returns MyArray (a float8[] in PG) */
double HeapFunc_MyArray(MyArray * arr);         /* allocs from heap */


/*******************************************************/
/*                   C Source file                     */
/*******************************************************/

/* utility conversion funcs */
/* How do I convert from the structure returned by array_agg to float8[] (or int4[] ?) */


MyArray * NEW_MyArray(const size_t len){
    /* Do I use palloc0() or calloc() here ? */
}

void Destroy_MyArray(MyArray * arr){
    /* Do I use pfree() or free() here ? */
}

size_t NumElements_MyArray(MyArray * arr){
    assert(arr != 0);
    return arr->len;
}

MyArray * NotTrivial_MyArray(MyArray * arr){
    assert(arr != 0);
    MyArray * ptr = NEW_MyArray(arr->len);
    return ptr;
}

double HeapFunc_MyArray(MyArray * arr){
    /* Create temporary variables on heap (use palloc0() or calloc()?) */
    /* Cleanup temp variables (use pfree() or free() ? */
    return 42/1.0;
}



/*******************************************************/
/* PostgreSQL wrapper funcs implementation source file */
/*******************************************************/

/* Prototypes */
PG_FUNCTION_INFO_V1(test_num_elements);
PG_FUNCTION_INFO_V1(test_not_trivial);
PG_FUNCTION_INFO_V1(test_heapfunc);

Datum test_num_elements(PG_FUNCTION_ARGS);
Datum test_not_trivial(PG_FUNCTION_ARGS);
Datum test_heapfunc(PG_FUNCTION_ARGS);


Datum
test_num_elements(PG_FUNCTION_ARGS)
{
    /* Convert data returned by array_agg() into MyArray * (how?) */
    /* invoke NumElements_MyArray() */
    /* Do I free temporary MyArray * ptr or will PG clean up 
       - if I have to clean up (like I suspect), do I use pfree() or free() ?*/
    PG_RETURN_INT32(result);
}

Datum
test_not_trivial(PG_FUNCTION_ARGS)
{
    /* Ditto, as above */
    PG_RETURN_POINTER(/* utility function to convert MyArray* to float8[] equiv for PG (how) */); 
}

Datum
test_heapfunc(PG_FUNCTION_ARGS)
{
    /* Ditto, as above */
    PG_RETURN_FLOAT8(result);
}


-- SQL FUNCTIONS

CREATE OR REPLACE FUNCTION test_num_elements(float8[])  RETURNS int4
AS '$libdir/pg_testlib.so' LANGUAGE 'c';

CREATE OR REPLACE FUNCTION test_not_trivial(float8[])  RETURNS float8[]
AS '$libdir/pg_testlib.so' LANGUAGE 'c';

CREATE OR REPLACE FUNCTION test_heapfunc(float8[])  RETURNS float8
AS '$libdir/pg_testlib.so' LANGUAGE 'c';


-- SQL TEST
SELECT test_num_elements(array_agg(salary)) FROM employees;
SELECT test_not_trivial(array_agg(salary)) FROM employees;
SELECT test_heapfunc(array_agg(salary)) FROM employees;

总而言之,我的问题是:

  1. 如何将 array_agg() 中的柱状数据转换为 double (或整数,视情况而定)的 C 数组
  2. 如何将整数(或 double )的 C 数组转换回 int4[] 或 float8[] 以便在 PostgreSQL 中使用?
  3. 内存分配原则——我是使用 PostgreSQL 内存管理函数 palloc()/pfree() 还是可以使用 calloc/free?此外,在使用 PG 内存函数时,我是否负责释放我分配的内存?

最佳答案

首先,您应该始终使用 palloc/pfree 来管理内存。 PostgreSQL 不会为您管理内存,但每个连接都由一个独立的进程处理,因此如果您泄漏内存,它只会持续一个连接的生命周期(当然,这可能会很长)。

通常,一个人将数据分配为:

void *data = palloc(size_of_your_data + VARHDRSZ);
SET_VARSIZE(data, size_of_your_data + VARHDRSZ);

然后使用以下方式访问您的数据:

MyArray *myarr = (MyArray*) VARDATA(data);

完成后,您可以:

PG_RETURN_POINTER(data);

如果您返回数据,则不会释放它。如果你想 palloc 临时存储,你必须 pfree 它。

现在,MyArray 不是您想要的 float8[]。您需要使用 ArrayType ,如中所述 34.9.11. Polymorphic Arguments and Return Types .

关于c - 为 PostgreSQL 实现 C 扩展函数 - 我该怎么做? (在 C/PostgreSQL 之间传递数据),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8740027/

相关文章:

c - 在 C 中为字符串数组实现快速排序 - 为什么我会收到 SIGABRT 错误?

sql - 转储到 CSV/Postgres 内存

postgresql - AWS RDS 上的高 CPU 使用率 - Postgres

sql - psycopg2 相当于 mysqldb.escape_string?

c - 如何从命令提示符编译和运行汇编程序源代码?

c++ - 快速序列有序 Walsh-Hadamard 变换

c - lwIP 是否支持 Zeroconf?

c++ - 如何链接到共享库的旧版本

sql - 如何创建一个有效的查询来按特定时间间隔计算记录?

sql - 改进连接查询 postgresql/postgis