首页 > 解决方案 > 在 C 中构建 Postgres 函数时,来自 fmgr.h 的“'return' 之前的预期表达式”错误

问题描述

我正在尝试编译一个用于 Postgres 9.5 的 C 函数。当我尝试运行 makefile 来编译代码时,我收到以下消息/错误:

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

看起来这些错误之一来自“fmgr.h”的语法,我不确定如何理解它,因为这是一个包含的库文件。我该如何解决这个错误?

作为参考,我的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)

也供参考,C源文件:

#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));
}

标签: cpostgresql

解决方案


第一个错误

PG_GETARG_INT64(0)以 . 形式返回一个Datumint64。您正在将值分配给指针 ( long *),这会使编译器不高兴。

如果您知道自己在做什么,则可以通过强制转换来强制分配:

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

但这对我来说看起来很可疑,并且可能有更好的方法来使用 PostgresQL 类型和宏。

例如,这看起来会更好:

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

第二个错误

return PG_RETURN_VARCHAR_P(cstring_to_text(result));

最终扩展到

return return PointerGetDatum(cstring_to_text(result))

这显然是错误的。删除多余的return

PG_RETURN_VARCHAR_P(cstring_to_text(result));

推荐阅读