如何检索并使用 Postgres 类型的 outproc 将 Datum 转换为 cstring?

How to retreive and use the outproc of a Postgres type to convert a Datum to cstring?

提问人:thor 提问时间:11/1/2023 更新时间:11/1/2023 访问量:22

问:

我正在尝试用 C 编写一个 PostgreSQL (16.x) 存储过程,以将任意类型化参数打印为 C 字符串。据我了解,每种类型都有其输入和输出功能。所以,我的计划是

  1. 获取参数类型的 Oid,(extract_variadic_args)

  2. 通过 Oid(如下)检索该类型的outprocget_outproc_oid

  3. 调用 outproc 将参数的 Datum 转换为 c 字符串。(OidOutputFunctionCall)

到目前为止,我所拥有的代码(如下所列)可以编译,但给出了奇怪的结果。它不是将第一个参数打印为字符串,而是打印一些随机的大数字。我不熟悉服务器端 postgresql C 编程。因此,这里有一个问题。

有人可以帮忙解释出了什么问题以及如何使字符串转换工作吗?

到目前为止,我的代码:

Helper C 函数:

// for var2cstring
#include "utils/typcache.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"

 void
 get_outproc_oid(Oid typoid, Oid *outfuncoid) //adapted from json_categorize_type()
 {
     bool        typisvarlena;
  
     /* Look through any domain */
     typoid = getBaseType(typoid);
  
     *outfuncoid = InvalidOid;
  
     switch (typoid)
     {
         case BOOLOID:
             *outfuncoid = F_BOOLOUT;
             break;
  
         case INT2OID:
         case INT4OID:
         case INT8OID:
         case FLOAT4OID:
         case FLOAT8OID:
         case NUMERICOID:
             getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
             break;
  
         case DATEOID:
             *outfuncoid = F_DATE_OUT;
             break;
  
         case TIMESTAMPOID:
             *outfuncoid = F_TIMESTAMP_OUT;
             break;
  
         case TIMESTAMPTZOID:
             *outfuncoid = F_TIMESTAMPTZ_OUT;
             break;
  
         case JSONOID:
             getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
             break;
  
         case JSONBOID:
             getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
             break;
  
         default:
             /* Check for arrays and composites */
             if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
                 || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
             {
                 *outfuncoid = F_ARRAY_OUT;
             }
             else if (type_is_rowtype(typoid))   /* includes RECORDOID */
             {
                 *outfuncoid = F_RECORD_OUT;
             }
             else
             {
         /* any other builtin type */
         getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
             }
             break;
     }
 }

主要C功能:

PG_FUNCTION_INFO_V1(var2cstring);
//var2cstring
Datum var2cstring( PG_FUNCTION_ARGS )
{
     int         nargs;
     int         i;
     Datum      *args;
     bool       *nulls;
     Oid        *types;
     Oid        elemtype;
     Oid        outfuncoid;

     /* fetch argument values to build the object */
     nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);

     //elemtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
     elemtype = types[0];
     
     get_outproc_oid(elemtype, &outfuncoid);
     Datum val = args[0];
     char *sometext = OidOutputFunctionCall(outfuncoid, val);

     PG_RETURN_CSTRING(sometext);
}

sql 文件:

CREATE OR REPLACE FUNCTION var2cstring(VARIADIC "any") RETURNS INT
        AS '$libdir/vc_agg'
        LANGUAGE C IMMUTABLE STRICT;

测试数据:

drop table if exists t2;
create table t2(v1 text, v2 text);
insert into t2 values
  ('Bob','Tom'),
  ('Tom', 'Bob'),
  ('Rich', 'Rich');

drop table if exists t3;
create table t3(v1 int, v2 int);
insert into t3 values
  (1,2),
  (2,1),
  (3,3);

select var2cstring(v1, v2) from t2;

select var2cstring(v1, v2) from t3;

我希望得到第一列 v1,但得到了一些大数字:

 var2cstring 
-------------
  1373702072
  1373702072
  1373702072
(3 rows)

 var2cstring 
-------------
  1373702072
  1373702072
  1373702072
(3 rows)
C PostgreSQL 服务器端

评论


答: 暂无答案