Max Candocia
Max Candocia

Reputation: 4385

"expected expression before 'return'" error from fmgr.h while building a Postgres function in C

I am trying to compile a C function for use in Postgres 9.5. When I try running the makefile to compile the code, I get these messages/errors:

cc -o int_to_id.o -c int_to_id.c  -I /usr/include/postgresql/9.5/server
In file included from int_to_id.c:1:0:
int_to_id.c: In function ‘int_to_id’:
/usr/include/postgresql/9.5/server/postgres.h:613:26: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
 #define DatumGetInt64(X) ((int64) GET_8_BYTES(X))
                      ^
/usr/include/postgresql/9.5/server/fmgr.h:238:29: note: in expansion of macro ‘DatumGetInt64’
 #define PG_GETARG_INT64(n)  DatumGetInt64(PG_GETARG_DATUM(n))
                         ^
int_to_id.c:55:15: note: in expansion of macro ‘PG_GETARG_INT64’
 long *x = PG_GETARG_INT64(0);
           ^
In file included from int_to_id.c:2:0:
/usr/include/postgresql/9.5/server/fmgr.h:305:30: error: expected expression before ‘return’
 #define PG_RETURN_POINTER(x) return PointerGetDatum(x)
                          ^
/usr/include/postgresql/9.5/server/fmgr.h:316:32: note: in expansion of macro ‘PG_RETURN_POINTER’
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
                            ^
int_to_id.c:60:12: note: in expansion of macro ‘PG_RETURN_VARCHAR_P’
 return PG_RETURN_VARCHAR_P(cstring_to_text(result));
        ^
Makefile:15: recipe for target 'int_to_id.o' failed
make: *** [int_to_id.o] Error 1

It looks like one of these errors is from the syntax of "fmgr.h", and I'm not sure how to make sense of it, since this is an included library file. How do I go about fixing this error?

For reference, my makefile:

MODULES = int_to_id

PG_CONFIG = pg_config
PGXS = $(shell $(PG_CONFIG) --pgxs)
INCLUDEDIR = $(shell $(PG_CONFIG) --includedir-server)
include $(PGXS)

int_to_id.so: int_to_id.o
    cc -shared -o int_to_id.so int_to_id.o

int_to_id.o: int_to_id.c
    cc -o int_to_id.o -c int_to_id.c $(CRFLAGS) -I $(INCLUDEDIR)

Also for reference, the C source file:

#include "postgres.h"
#include "fmgr.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

const char charmap[36] = {
    '0',
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
    '7',
    '8',
    '9',
    'a',
    'b',
    'c',
    'd',
    'e',
    'f',
    'g',
    'h',
    'i',
    'j',
    'k',
    'l',
    'm',
    'n',
    'o',
    'p',
    'q',
    'r',
    's',
    't',
    'u',
    'v',
    'w',
    'x',
    'y',
    'z'
};

Datum int_to_id(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(int_to_id);

Datum int_to_id(PG_FUNCTION_ARGS){
    char result[10] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
    long base_val = 1L;
    long *x = PG_GETARG_INT64(0);
    for (int i = 1; i <= 10, i++; ){
        result[10 - i] = charmap[ ((*x) / base_val) % 36];
    }
    base_val = base_val * 36L;

    return PG_RETURN_VARCHAR_P(cstring_to_text(result));
}

Upvotes: 4

Views: 140

Answers (1)

xhienne
xhienne

Reputation: 6134

First error

PG_GETARG_INT64(0) returns a Datum value as an int64. You are assigning the value to a pointer (long *) and this makes the compiler unhappy.

If you know what you are doing, you may force the assignment by casting:

long *x = (long *)PG_GETARG_INT64(0);

But this looks very suspicious to me, and there is probably a better way to do it using PostgresQL types and macros.

For example, this would look better:

int64 x = PG_GETARG_INT64(0);
for (int i = 1; i++; i <= 10){
    result[10 - i] = charmap[(x / 36^i) % 36];
}

Second error

return PG_RETURN_VARCHAR_P(cstring_to_text(result));

ends up being expanded to

return return PointerGetDatum(cstring_to_text(result))

This is obviously wrong. Remove the extraneous return:

PG_RETURN_VARCHAR_P(cstring_to_text(result));

Upvotes: 4

Related Questions