Pup*_*nij 2 c postgresql bytea
我为Postgresql编写了自己的C函数,它有bytea参数.该功能定义如下
CREATE OR REPLACE FUNCTION putDoc(entity_type int, entity_id int,
doc_type text, doc_data bytea) RETURNS text
AS 'proj_pg', 'call_putDoc'
LANGUAGE C STRICT;
Run Code Online (Sandbox Code Playgroud)
我的函数call_putDoc写在C上,读取doc_data并将其数据传递给另一个函数,比如file_magic确定数据的mime类型,然后将数据传递给适当的文件转换器.
我从php脚本调用这个postgresql函数,它将文件内容加载到最后一个参数.所以,我应该传递文件内容pg_escape_bytea.
当数据传递给call_putDocC函数时,它的数据是否已经转义,如果没有 - 如何取消它们?
编辑:正如我发现的那样,没有,传递给C函数的数据未被转义.如何取消它?
在为PostgreSQL编写C函数时,文档解释了一些基础知识,但其余的通常是阅读PostgreSQL服务器的源代码.
值得庆幸的是,代码通常结构良好且易于阅读.我希望它有更多的文档评论.
导航源代码的一些重要工具是:
find和git grep命令.在这种情况下,在看了之后我认为你的bytea论证正在被解码 - 至少在Pg 9.2中,8.4(尽管不太可能)8.4表现不同.服务器应该在调用函数之前自动执行该操作,并且我怀疑您在如何putDoc从SQL 调用函数时遇到编程错误.没有消息来源,很难说更多.
putDoc来为您的8.4服务器psql正确escape编码byteain以确保在函数之前调用它gdb使用print函数逐步检查变量.有很多是会教你所需的GDB教程break,backtrace,cont,step,next,print,等命令,所以我不会重复所有在这里.至于什么是错的:你可能是双编码您的数据-例如,给你的意见,我想知道如果你base64的编码数据,并将其传递到Pg与bytea_output设置为escape.然后PG会对其进行解码......给你一个bytea包含bytea了代表性base64的字节数,而不是原始字节自己的编码.(编辑声音可能不是基于评论).
正确使用bytea请参阅:
要说更多,我需要源代码.
这是我做的:
find -name bytea\*源树中的快速定位src/include/utils/bytea.h.那里的评论指出函数定义在utils/adt/varlena.c- 实际上是src/backend/util/adt/varlena.c.
在bytea.h您还会注意到的定义bytea_outputGUC参数,这是你所看到的,当你SHOW bytea_output还是SET bytea_output在psql.
让我们来看看我们知道的与bytea数据有关的函数,比如bytea_substrin varlena.c.它太短了,我将在这里包含一个声明:
Datum
bytea_substr(PG_FUNCTION_ARGS)
{
PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
PG_GETARG_INT32(1),
PG_GETARG_INT32(2),
false));
}
Run Code Online (Sandbox Code Playgroud)
许多公共函数都是私有实现的包装器,因此私有实现可以与具有不同参数的函数一起使用,也可以与其他私有代码一起使用.就是这种情况; 你会看到真正的实现是bytea_substring.以上所有操作都是处理SQL函数调用接口.它根本不会Datum包含bytea输入.
真正的实现bytea_substring直接在这个部分情况下的SQL接口包装器下面,所以请继续阅读varlena.c.
实现似乎并不是指bytea_outputGUC,并且基本上只是DatumGetByteaPSlice在处理一些边界情况后调用它来完成工作.git grep DatumGetByteaPSlice向我们展示DatumGetByteaPSlice了src/include/fmgr.h,并且是一个宏定义为:
#define DatumGetByteaPSlice(X,m,n) ((bytea *) PG_DETOAST_DATUM_SLICE(X,m,n))
Run Code Online (Sandbox Code Playgroud)
这里PG_DETOAST_DATUM_SLICE是
#define PG_DETOAST_DATUM_SLICE(datum,f,c) \
pg_detoast_datum_slice((struct varlena *) DatumGetPointer(datum), \
(int32) (f), (int32) (c))
Run Code Online (Sandbox Code Playgroud)
所以它只是取消了数据并返回一个内存片.这让我感到疑惑:解码是否在其他地方完成,作为函数调用接口的一部分?还是我错过了什么?
看一下byteain输入函数bytea,表明它确实解码了数据.在该函数中设置一个断点,当你从SQL调用函数时它应该跳转,表明bytea数据真的被解码了.
例如,让我们看看byteain在调用时是否调用bytea_substr:
SELECT substring('1234'::bytea, 2,2);
Run Code Online (Sandbox Code Playgroud)
如果你想知道如何substring(bytea)变成一个C调用bytea_substr,请查看src/catalog/pg_proc.h映射.
我们将启动psql并获取后端的pid:
$ psql -q regress
regress=# select pg_backend_pid();
pg_backend_pid
----------------
18582
(1 row)
Run Code Online (Sandbox Code Playgroud)
然后在另一个终端用gdb连接到那个pid,设置一个断点,然后继续执行:
$ sudo -u postgres gdb -q -p 18582
Attaching to process 18582
... blah blah ...
(gdb) break bytea_substr
Breakpoint 1 at 0x6a9e40: file varlena.c, line 1845.
(gdb) cont
Continuing.
Run Code Online (Sandbox Code Playgroud)
在第一个终端,我们在psql中执行:
SELECT substring('1234'::bytea, 2,2);
Run Code Online (Sandbox Code Playgroud)
...并注意它在没有返回结果的情况下挂起.好.那是因为我们在gdb中跳过断点,正如你在第二个终端中看到的那样:
Breakpoint 1, bytea_substr (fcinfo=0x1265690) at varlena.c:1845
1845 PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
(gdb)
Run Code Online (Sandbox Code Playgroud)
使用该bt命令的回溯不会显示bytea_substr在调用路径中,它是所有SQL函数调用机制.所以Pg bytea在传递它之前解码它bytea_substr.
您现在可以使用分离调试器quit.这不会退出Pg后端,只能分离并退出调试器.
| 归档时间: |
|
| 查看次数: |
974 次 |
| 最近记录: |