3

I'm using my internal C function which doesn't know about postgresql's text struct, how do I pass text argument when char * expected?

#include <stdio.h>
#include <string.h>
#include "postgres.h"
#include "fmgr.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

PG_FUNCTION_INFO_V1(fun);

Datum fun(PG_FUNCTION_ARGS)
{
    text    *str1, *str2;

    str1 = PG_GETARG_TEXT_P(0);
    str2 = PG_GETARG_TEXT_P(1);

    FILE *fp = fopen("/tmp/fun.log", "w");
    fprintf(fp, "%s\n", VARDATA_ANY(str1));
    fprintf(fp, "%s\n", VARDATA_ANY(str2));
    fclose(fp);

    PG_RETURN_INT32(0);
}

Here's what xxd sees in log file:

0000000: 666f 6f74 6261 6c6c c88d 7409 70d3 6b09  football..t.p.k.
0000010: 080a 7a6f 6f6d 0a                        ..zoom.

After executing:

SELECT * FROM fun('football','zoom');

Why junk after football?

Moe
  • 41
  • 1
  • 3

2 Answers2

3

The data pointed to by the text structure isn't null-terminated, so you can't use it with C "string" functions directly.

To determine the length of the text, you can use VARSIZE(your_text)-VARHDRSZ.

In your example, you could use fwrite instead of printf to output the string (passing in the length), or copy the text to a char* and terminate it manually if you intend to use C string functions.

Here's a sample of how either could be done:

#include <stdio.h>
#include <string.h>
#include "postgres.h"
#include "fmgr.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

PG_FUNCTION_INFO_V1(fun);

size_t log_pgtext(FILE *to, text *what)
{
    return fwrite(VARDATA(what), 1, VARSIZE(what)-VARHDRSZ, to);
}

char *dup_pgtext(text *what)
{
    size_t len = VARSIZE(what)-VARHDRSZ;
    char *dup = palloc(len+1);
    memcpy(dup, VARDATA(what), len);
    dup[len] = 0;
    return dup;
}

Datum fun(PG_FUNCTION_ARGS)
{
    text    *str1, *str2;

    str1 = PG_GETARG_TEXT_P(0);
    str2 = PG_GETARG_TEXT_P(1);

    FILE *fp = fopen("/tmp/fun.log", "w");

    log_pgtext(fp, str1);
    fprintf(fp, "\n");

    char *str = dup_pgtext(str2);
    fprintf(fp, "%s\n", str);
    pfree(str);

    fclose(fp);

    PG_RETURN_INT32(0);
}

Reference documentation for PostgreSQL 9.2.

Mat
  • 10,289
  • 4
  • 43
  • 40
1

The PostgreSQL text type is a variable length data structure, but is not a C string. There is a convenience function text_to_cstring that will determine the correct size and return a null-terminated C string. Assuming the first parameter of your custom function is a string, e.g.

SELECT my_pg_function('some string');
#include "utils/builtins.h"

PG_FUNCTION_INFO_V1(my_pg_function);
Datum
my_pg_function(PG_FUNCTION_ARGS)
{
    char* my_string = text_to_cstring(PG_GETARG_TEXT_PP(0));
    // ...
}

Note the use of PG_GETARG_TEXT_PP versus PG_GETARG_TEXT_P (two "P"s instead of one); the latter in an obsolescent variant (see notes in include/fmgr.h in the PostgreSQL source).

Demitri
  • 231
  • 2
  • 4