Реализация функций расширения C для PostgreSQL - как мне это сделать? (передача данных между C / PostgreSQL) - PullRequest
7 голосов
/ 05 января 2012

Я пишу расширение C для PostgreSQL (v 8.4). В настоящее время я застрял в том, как передать столбчатые данные из 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 () в массив значений типа C типа double (или целых, в зависимости от обстоятельств)
  2. Как преобразовать массив целых чисел C (или двойников) обратно в int4 [] или float8 [] для использования в PostgreSQL?
  3. Принципы распределения памяти - использовать функции управления памятью PostgreSQL palloc () / pfree () или использовать calloc / free ?. Кроме того, при использовании функций PG mem я отвечаю за освобождение выделенной памяти?

1 Ответ

2 голосов
/ 31 января 2012

Во-первых, вы всегда должны использовать 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);

Есливы возвращаете данные, вы не освобождаете их.Если вы хотите разместить временное хранилище, вы должны освободить его.

Теперь MyArray - это не то, что вы хотите иметь float8[].Вам необходимо использовать ArrayType , как описано в 34.9.11.Полиморфные аргументы и возвращаемые типы .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...