Libpq:如何获取PostgreSQL存储过程的输出参数值?
获取libpq中PostgreSQL存储过程/函数的输出参数
在libpq中处理PostgreSQL的OUT/INOUT参数,需要根据对象类型(函数/存储过程)采用不同的调用和解析方式,以下是具体实现方案:
一、处理带OUT/INOUT参数的函数
PostgreSQL的函数若定义了OUT或INOUT参数,调用时通过SELECT * FROM func(...)语句即可将所有输出参数展开为结果集的列,直接用libpq的结果集解析函数获取值。
示例步骤:
- 定义测试函数:
CREATE OR REPLACE FUNCTION test_out_func(IN input_num INT, OUT output_text TEXT, OUT output_num INT) RETURNS RECORD AS $$ BEGIN output_text := 'Processed'; output_num := input_num * 3; END; $$ LANGUAGE plpgsql;
- libpq调用代码:
#include <stdio.h> #include <stdlib.h> #include <libpq-fe.h> int main() { PGconn *conn = PQconnectdb("dbname=your_db user=your_user password=your_pass host=localhost"); if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr, "连接失败: %s\n", PQerrorMessage(conn)); PQfinish(conn); return 1; } // 调用函数并获取所有输出参数 PGresult *res = PQexec(conn, "SELECT * FROM test_out_func(5);"); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "查询失败: %s\n", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return 1; } // 解析输出参数:按定义顺序获取,或用PQfname匹配字段名 char *text_val = PQgetvalue(res, 0, PQfnumber(res, "output_text")); int num_val = atoi(PQgetvalue(res, 0, PQfnumber(res, "output_num"))); printf("output_text: %s, output_num: %d\n", text_val, num_val); PQclear(res); PQfinish(conn); return 0; }
二、处理存储过程的OUT/INOUT参数
PostgreSQL 11及以上支持存储过程(PROCEDURE),必须用CALL语句调用。存储过程的OUT/INOUT参数会以单行结果集的形式返回,若存储过程内部还有SELECT输出的结果集,需要遍历所有结果集,最后一个结果集即为输出参数。
示例步骤:
- 定义测试存储过程:
CREATE OR REPLACE PROCEDURE test_out_proc(IN input_num INT, OUT output_text TEXT, OUT output_num INT) LANGUAGE plpgsql AS $$ BEGIN -- 可选:内部返回结果集 SELECT * FROM generate_series(1, input_num); output_text := 'Procedure Done'; output_num := input_num + 20; END; $$;
- libpq调用代码:
#include <stdio.h> #include <stdlib.h> #include <libpq-fe.h> int main() { PGconn *conn = PQconnectdb("dbname=your_db user=your_user password=your_pass host=localhost"); if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr, "连接失败: %s\n", PQerrorMessage(conn)); PQfinish(conn); return 1; } PGresult *res = PQexec(conn, "CALL test_out_proc(3);"); do { if (PQresultStatus(res) == PGRES_TUPLES_OK) { int ntuples = PQntuples(res); int nfields = PQnfields(res); // 判断是否为输出参数结果集:通常是单行、字段数匹配OUT参数数量 if (ntuples == 1 && nfields == 2) { char *text_val = PQgetvalue(res, 0, PQfnumber(res, "output_text")); int num_val = atoi(PQgetvalue(res, 0, PQfnumber(res, "output_num"))); printf("OUT参数 output_text: %s, output_num: %d\n", text_val, num_val); } else { // 处理存储过程内部返回的结果集 printf("内部结果集:%d行,%d列\n", ntuples, nfields); for (int i = 0; i < ntuples; i++) { printf("第%d行值:%s\n", i+1, PQgetvalue(res, i, 0)); } } } PQclear(res); } while ((res = PQgetResult(conn)) != NULL); PQfinish(conn); return 0; }
核心注意点
- 用
PQfnumber通过字段名获取列索引,避免因参数顺序变动导致解析错误。 - 若涉及复杂类型(如数组、自定义类型),可通过
PQftype获取字段OID,结合PostgreSQL的类型函数(如array_to_string)转换为可解析的字符串,或使用libpq的PQgetvalue获取原始字符串后自行处理。 - 调用存储过程后必须遍历所有结果集,避免遗漏输出参数或导致连接状态异常。
内容的提问来源于stack exchange,提问作者NoodleCollie
相关产品推荐
相关产品推荐

