PostgreSQL C函数:libpq不链接?

the*_*n29 6 c postgresql

我想为PostgreSQL编写一个C函数。对于此功能,我将需要使用libpq查询一些数据,因此我首先编写了一个虚拟函数来测试此部分:

#define _XOPEN_SOURCE

#include <libpq-fe.h>
#include <postgres.h>
#include <fmgr.h>
#include <funcapi.h>
#include <executor/executor.h>

#include "test.h"

PG_FUNCTION_INFO_V1(getAnnotation);
Datum getAnnotation(PG_FUNCTION_ARGS) {
    // Connection to the database
    PGconn *conn = PQsetdbLogin("localhost",
                         "5432",
                         "",
                         "",
                         "postgres",
                         "postgres",
                         "password");

    // Databases names
    PGresult *res = PQexec (conn, "SELECT user FROM activity LIMIT 1;");
    VarChar* i = PQgetvalue(res, 0, 0);
    PG_RETURN_VARCHAR_P(i);
}
Run Code Online (Sandbox Code Playgroud)

它只是应该返回我的一个表的第一行的第一列。很简单吧?好吧,它不起作用。

当我尝试在psql中使用它时,它说:

ERROR:  could not load library "/usr/local/lib/postgresql/test.so": Error relocating /usr/local/lib/postgresql/test.so: PQexec: symbol not found
Run Code Online (Sandbox Code Playgroud)

奇怪的是,两者PQsetdbLoginPQexec都在libpq-fe.h文件中,但是只有第二个会导致错误。如果我评论这一PQexec行,那么PQsetdbLogin也会引发一个错误。

这是我用来构建代码的Makefile:

PG_CPPFLAGS = -I$(libpq_srcdir)
LDFLAGS_INTERNAL = -L$(libdir)
SHLIB_LINK_INTERNAL = $(libpq)
SHLIB_PREREQS = submake-libpq

EXTENSION = test
DATA = test--0.1.sql
MODULES = test

# REGRESS = ... # Script for tests

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
Run Code Online (Sandbox Code Playgroud)

如您所见,我在其中链接了libpq,因此一切正常。

我在Docker容器中使用PostgreSQL 9.6。

Lau*_*lbe 3

如果您想链接到外部库,则需要SHLIB_LINK,但只有当您使用MODULE_big而不是 时才有效MODULES

一个工作Makefile将是

PG_CPPFLAGS = -I$(libpq_srcdir)
SHLIB_LINK = $(libpq)

EXTENSION = test
DATA = test--0.1.sql
MODULE_big = test
OBJS = test.o

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
Run Code Online (Sandbox Code Playgroud)

但是您的功能还存在其他问题:

  • VarChar是 a varlena,但PQgetvalue返回 a char *

    您必须varlena使用类似于以下的代码将该值转换为 a :

    VarChar *result;
    char *c = PQgetvalue(res, 0, 0);
    result = (VarChar *) palloc(strlen(c) + VARHDRSZ);
    strncpy(VARDATA(result), c, strlen(c));
    SET_VARSIZE(result, strlen(c) + VARHDRSZ);
    
    Run Code Online (Sandbox Code Playgroud)
  • 在服务器函数中编写客户端代码通常是错误的想法。

    如果您需要的只是在当前会话内运行查询,请使用服务器编程接口

  • 我猜你的函数只是示例代码,但是你需要在后端终止之前关闭连接,否则会出现连接泄漏。