Работа со строками с помощью функции языка C PostgreSQL

Я хотел бы создать функцию c-Language postgresql, аргументы и возвращаемые значения которой varchar и которая использует Char [] во время обработки.

Но это не работает, как ожидалось.

Я сделал программу c, как это.

#include <postgres.h>
#include <port.h>
#include <fmgr.h>
#include <stdlib.h>

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

// Required for windows.
extern PGDLLEXPORT Datum VARCHAR_CHAR_ARRAY_VARCHAR(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(VARCHAR_CHAR_ARRAY_VARCHAR);

Datum VARCHAR_CHAR_ARRAY_VARCHAR(PG_FUNCTION_ARGS) {
    // Get arg.
    VarChar  *arg1 = (VarChar *)PG_GETARG_VARCHAR_P(0);

    // VarChar to Char[].
    char *c = (char *)VARDATA(arg1);

    elog(NOTICE, "VarChar to Char[]."); 
    elog(NOTICE, c);//Log1

    // Do something.(e.g. replace)
    // Since it uses another system, it must be Char [].

    //Char[] to VarChar.
    VarChar *rtn = (VarChar *)VARDATA(c);
    elog(NOTICE, "Char[] to VarChar.");
    elog(NOTICE, rtn);//Log2

    // Return VarChar.
    PG_RETURN_VARCHAR_P(rtn);
}

И создал такой скрипт.

CREATE OR REPLACE FUNCTION public.VARCHAR_CHAR_ARRAY_VARCHAR(character varying)
  RETURNS character varying AS
'$libdir/test/VARCHAR_CHAR_ARRAY_VARCHAR.dll', 'VARCHAR_CHAR_ARRAY_VARCHAR'
  LANGUAGE c VOLATILE STRICT;

Результат выполнения такой.

SELECT VARCHAR_CHAR_ARRAY_VARCHAR('a');
-- Expected value: 'a'
-- Postgresql terminated abnormally... :(

SELECT VARCHAR_CHAR_ARRAY_VARCHAR('Action');
-- Expected return value: 'Action'
-- Actual return value  :'n'
-- Log1  :'NOTICE:  n'
-- Log2  :''

SELECT VARCHAR_CHAR_ARRAY_VARCHAR('ActionAction');
-- Expected return value: 'ActionAction'
-- Actual return value  : ''  <-Why?
-- Log1  :''
-- Log2  :''

SELECT VARCHAR_CHAR_ARRAY_VARCHAR('Action Action');
-- Expected return value: 'Action Action'
-- Actual return value  : 'n Action'
-- Log1  :'NOTICE:  Action Action'
-- Log2  :'NOTICE:  ction'

SELECT VARCHAR_CHAR_ARRAY_VARCHAR('1234567890');
-- Expected return value: '1234567890'
-- Actual return value  : '6789'
-- Log1  :'NOTICE:  1234567890'
-- Log2  :'NOTICE:  90'

Среда исполнения:

  • Windows Server 2012 R2 x64
  • PostgreSQL 9.5.9, скомпилированный в Visual C++ build 1800, 64-битный

Я впервые использую язык Си, поэтому я рад представить пример кода.

Извините, мой английский не очень хорош.

1 ответ

Решение

Построение вручную text или же VarChar как это не будет работать. Ты не можешь просто

VarChar *rtn = (VarChar *)VARDATA(c);

потому что то, что вы делаете там, пытается интерпретировать char* значение c как будто это было VarChar*, читая первые несколько байтов как VARLENA заголовок, а затем получить некоторую подстроку в нем в качестве значения. Не собираюсь на работу.

Это намного проще в использовании cstring_to_text а также text_to_cstring преобразовать. text* точно совместим с VarChar*, (Они в utils/builtins.h).

например

 PG_RETURN_VARCHAR_P(cstring_to_text(c));

Чтобы сделать это вручную, нужно palloc строка с strlen байт + VARHDRSIZE, SET_VARSIZE, затем strcpy данные к VARDATA смещение. Увидеть src/include/utils/varlena.h а также src/backend/utils/adt/varlena.c, Это неудобно и не нужно, когда PostgreSQL имеет вспомогательные функции для этой цели.

Лично я рекомендую игнорировать varchar полностью для программирования на уровне C. Определите свои функции как принятие и возврат text,

Другие вопросы по тегам