【问题标题】:Extern C-Function in SQLSQL 中的外部 C 函数
【发布时间】:2014-12-03 17:31:17
【问题描述】:

如何分割一个未知分隔符的字符串?

我需要像

这样拆分一个字符串

'3.584731 60.739211,3.590472 60.738030,3.592740: 60.736220', * *)

在**之间我要输入一个分隔符,谁会用分隔符来分割这个字符串。

举例

 If *:*
 3.584731 60.739211,3.590472 60.738030,3.592740
 60.736220

我知道 strtok() 拆分字符串。但是我必须如何使用它,代码不知道分隔符并且用户必须插入它。这是我的代码。

PG_FUNCTION_INFO_V1(benchmark);
Datum
benchmark(PG_FUNCTION_ARGS)
{

FuncCallContext     *funcctx;
int                  call_cntr;
int                  max_calls;
TupleDesc            tupdesc;
AttInMetadata       *attinmeta;
//As Counters
int i = 0, j = 0;
//To get the every SingleString from the Table
char *k = text_to_cstring(PG_GETARG_TEXT_P(0));
//The Delimiter
char *c (0);
//the temporary "memory"
char * temp = NULL;

//The final result
//Need as an Array
//From ["x1 y1,x2 y2,...xn yn"] Split on the ',' 

//to   ["x1 y1","x2 y2",..."xn yn"] Split on the ' ' 

//to the final ["x1","y1","x2","y2"..."xn","yn"]
char**result[a] = {0};

if (SRF_IS_FIRSTCALL())
    {
        {
        MemoryContext   oldcontext;

        //create a function context for cross-call persistence 
        funcctx = SRF_FIRSTCALL_INIT();

        //reqdim = (PG_NARGS()  MAXDIM)
   //         SRF_RETURN_DONE(funcctx);

        // switch to memory context appropriate for multiple function calls 
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        /* total number of tuples to be returned */
        funcctx->max_calls = PG_GETARG_UINT32(0);

        /* Build a tuple descriptor for our result type */
        if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
            ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("function returning record called in context "
                        "that cannot accept type record")));

        //Still dont know what attinmeta is
        attinmeta = TupleDescGetAttInMetadata(tupdesc);
        funcctx->attinmeta = attinmeta;
        MemoryContextSwitchTo(oldcontext);

    }

            call_cntr = funcctx->call_cntr;
            max_calls = funcctx->max_calls;
            attinmeta = funcctx->attinmeta;
            result[a] = funcctx->result[a];
            temp      = funcctx->temp;
            *k        = funcctx->*k;
            delim     = funcctx->delim;
            c         = funcctx->c;


            //here is the difficult part

            if(*k)
            {
                temp = strtok(k,delim) //the delimiter
                while (temp)
                {
                //palloc or malloc whats the difference ?
                result[a] = palloc...
                strcpy(result[a],temp)
                temp = strtok (NULL,delim)
                i++;
                }
                    for (j = 0; j < i; j++)
                    printf("[%d] sub-string is %s\n", (j+1), result[j]);

                    for (j = 0; j < i; j++)
                    SRF_RETURN_NEXT(funcctx,result[a]);


            }
            else
            {
                SRF_RETURN_DONE(funcctx);
            }
}

这是对的吗? palloc 还是 malloc ?在这种情况下有什么区别以及如何使用它? 我试着做很多笔记,因为我希望你能理解这一点:) 不要太难我刚开始使用程序:)

【问题讨论】:

  • 我不知道unnest(),但您想要的是strtok()strtok_r()
  • 您查看我在之前评论中提供的链接了吗?如果您告诉我们您不明白的部分,我们可以解释。
  • 再次用代码重新编辑,但不知道他是否正确
  • 不不,你弄错了。让我为你写一个示例代码。给我一些时间。
  • 为什么标记为plpgsql?我没有看到联系。可能重复:stackoverflow.com/questions/27148516/…

标签: c postgresql


【解决方案1】:

PostgreSQL 源代码是获取一些想法和模式的良好开端。当你喜欢编写 SETOF 函数时,你应该从一些 SETOF 函数开始。谷歌关键字是“SRF_RETURN_NEXT”。 PostgreSQL doc http://www.postgresql.org/docs/9.3/static/xfunc-c.html 中有一些示例 - 您可以找到其他示例。

几年前我写了数组迭代器:

#include “funcapi.h” typedef struct generate_iterator_fctx { int4 更低; int4 上; 布尔反向; } generate_iterator_fctx; 基准数组_下标(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(array_subscripts); /* * array_subscripts(array anyarray, dim int, reverse bool) */ 基准 数组下标(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; MemoryContext 旧上下文; generate_iterator_fctx *fctx; /* 仅在第一次调用函数时完成 */ 如果(SRF_IS_FIRSTCALL()) { ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); 内部需求; 诠释 *lb, *dimv; /* 为交叉调用持久化创建一个函数上下文 */ funcctx = SRF_FIRSTCALL_INIT(); reqdim = (PG_NARGS() MAXDIM) SRF_RETURN_DONE(funcctx); /* 完整性检查:请求的暗淡是否有效 */ if (reqdim ARR_NDIM(v)) SRF_RETURN_DONE(funcctx); /* * 切换到适合多个函数调用的内存上下文 */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); fctx = (generate_iterator_fctx *) palloc(sizeof(generate_iterator_fctx)); 磅 = ARR_LBOUND(v); 昏暗 = ARR_DIMS(v); fctx->lower = lb[reqdim - 1]; fctx->upper = dimv[reqdim - 1] + lb[reqdim - 1] - 1; fctx->reverse = (PG_NARGS() user_fctx = fctx; MemoryContextSwitchTo(oldcontext); } funcctx = SRF_PERCALL_SETUP(); fctx = funcctx->user_fctx; if (fctx->lower Upper) { if (!fctx->reverse) SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->lower++)); 别的 SRF_RETURN_NEXT(funcctx, Int32GetDatum(fctx->upper--)); } 别的 /* 当没有剩余时执行 */ SRF_RETURN_DONE(funcctx); }

注册:

创建函数 array_subscripts(anyarray) 返回 SETOF int 作为“模块路径名” 语言 C 严格; CREATE FUNCTION array_subscripts(anyarray, integer) 返回 SETOF int 作为“模块路径名” 语言 C 严格; CREATE FUNCTION array_subscripts(anyarray, integer, bool) 返回 SETOF int 作为“模块路径名” 语言 C 严格;

用法:

创建函数 array_expand(anyarray) 返回 SETOF 任何元素 作为 $$ 选择 $1[i] FROM array_subscripts($1) g(i); $$ 语言 SQL;

【讨论】:

  • 这是一个开始。我知道这个网站,我之前读过几次,但我很难写出这么大又难的代码
  • 扩展的开发并不难,但需要几周的学习。
【解决方案2】:

请检查以下代码。希望它不言自明。

如果您在理解上有任何困难,请告诉我们。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZ 128

int main()
{
    char *op[SIZ];              //array to hold the o/p
    int i = 0, j = 0;           //used as counters
    char input[] = "3.584731 60.739211, / 3.590472 60.738030,3.592740 / 60.736220"; //the input
    char *delim = "/";          //the delimiter
    char * temp = NULL;

    temp = strtok(input, delim);
    while (temp)
    {
        op[i] = malloc(SIZ);
        strcpy(op[i], temp);
        temp = strtok(NULL, delim);
        i++;
    }

    for (j = 0; j < i; j++)
    printf("[%d] sub-string is %s\n", (j+1), op[j]);

    for (j = 0; j < i; j++)
    free(op[j]);

    return 0;
}

编辑

0.5 版。希望这个split_string() 函数能解决您的问题。现在,使用fgets() 询问用户输入。阅读手册页here。它不应该太难。祝你好运。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZ 128

void split_string(char * ip, char * sep);

int main()
{
        char input[] = "3.584731 60.739211, / 3.590472 60.738030,3.592740 / 60.736220"; //the input
        char *delim = "/";          //the delimiter

        split_string(input, delim);

        return 0;
}

void split_string(char * ip, char * sep)
{
        char * op[SIZ] = {0};
        int i = 0, j = 0;           //used as counters
        char * temp = NULL;

        if (ip)
        {
                temp = strtok(ip, sep);
                while (temp)
                {
                        op[i] = malloc(SIZ);
                        strcpy(op[i], temp);
                        temp = strtok(NULL, sep);
                        i++;
                }

                for (j = 0; j < i; j++)
                        printf("[%d] sub-string is %s\n", (j+1), op[j]);

                for (j = 0; j < i; j++)
                        free(op[j]);
        }
}

【讨论】:

  • 好的,这里的问题是您提供了线串和分隔符的信息。它是一个外部 C 函数。稍后我必须编写SELECT funcname(这里是字符串这里是用户选择的分隔符)。希望你能理解我的问题
  • @sataide 您修改代码以询问用户的输入是否太难了?试试看。 strtok()的工作流程我已经给大家展示过了,不是吗?
  • 是的,因为我是编写程序的新手,在第 1 版调用中需要它。您的代码在版本-o 中。但我感谢你的帮助:)
  • 好的,让我为您制作 0.5 版,但您将制作 1.0 版,好吗?
  • 我会尽力而为。请注意,我在 3 周前开始使用程序 ^^
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-18
  • 2018-09-24
  • 2011-05-16
相关资源
最近更新 更多