PostgreSQL的C语言函数对字符串进行操作
String manipulation by C language function of PostgreSQL
我想创建一个 postgresql c 语言函数,其参数和 return 值为 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 服务器 2012 R2 x64
- PostgreSQL 9.5.9,由 Visual C++ build 1800 编译,64 位
我是第一次使用C语言,所以很高兴提供示例代码。
对不起,我的英文不好
像这样手动构建 text
或 VarChar
是行不通的。你不能只是
VarChar *rtn = (VarChar *)VARDATA(c);
因为你在那里所做的是试图将 char*
值 c
解释为 VarChar*
,将前几个字节读取为 VARLENA
header,然后在其中获取一些子字符串作为值。不去上班。
使用 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-level 编程。将您的函数定义为接受和返回 text
.
我想创建一个 postgresql c 语言函数,其参数和 return 值为 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 服务器 2012 R2 x64
- PostgreSQL 9.5.9,由 Visual C++ build 1800 编译,64 位
我是第一次使用C语言,所以很高兴提供示例代码。
对不起,我的英文不好
像这样手动构建 text
或 VarChar
是行不通的。你不能只是
VarChar *rtn = (VarChar *)VARDATA(c);
因为你在那里所做的是试图将 char*
值 c
解释为 VarChar*
,将前几个字节读取为 VARLENA
header,然后在其中获取一些子字符串作为值。不去上班。
使用 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-level 编程。将您的函数定义为接受和返回 text
.