如何在C程序中捕获PostgreSQL的NOTICE信息
解决方法
首先明确:你看到的"relation already exists skipping"是PostgreSQL发送的Notice消息,而非PQnotifies捕获的LISTEN/NOTIFY异步通知,所以用PQnotifies是抓不到的。要区分表是新建还是已存在,需要捕获这类Notice消息,有两种可靠方式:
方式1:从PGresult中提取Notice消息
执行CREATE TABLE后,直接遍历当前PGresult关联的Notice,判断是否包含表已存在的提示:
PGconn* conn; PGresult* createTableRes; bool tableExisted = false; // 执行建表语句 createTableRes = PQexec(conn, "CREATE TABLE IF NOT EXISTS t_xyz (xyzId SERIAL PRIMARY KEY NOT NULL, xyz VARCHAR(100) UNIQUE NOT NULL)"); if (PQresultStatus(createTableRes) != PGRES_COMMAND_OK) { char* errorDescribed = PQerrorMessage(conn); my_logger.error("could not create table t_xyz, errorMessage:{}", errorDescribed); PQclear(createTableRes); exit_nicely(conn); } else { // 遍历所有Notice消息 const char* notice = PQresultGetNotice(createTableRes); while (notice != NULL) { if (strstr(notice, "relation \"t_xyz\" already exists") != NULL) { tableExisted = true; break; } notice = PQresultGetNotice(createTableRes); } // 根据结果输出日志 if (tableExisted) { my_logger.info("table t_xyz existed already."); } else { my_logger.info("created table t_xyz successfully."); } } PQclear(createTableRes);
方式2:全局注册Notice回调函数
如果需要全局捕获所有Notice消息(不止建表操作),可以在连接建立后注册一个回调函数,统一处理Notice:
1. 定义回调函数
// 回调函数:将Notice消息存储到传入的指针中 static void storeNotice(void* arg, const char* message) { char** noticeBuf = (char**)arg; // 释放之前的缓存 if (*noticeBuf != NULL) { free(*noticeBuf); *noticeBuf = NULL; } // 复制新的Notice消息 *noticeBuf = strdup(message); }
2. 连接后注册回调
// 在conn成功建立后执行 char* lastNotice = NULL; PQsetNoticeReceiver(conn, storeNotice, &lastNotice);
3. 建表后判断Notice
createTableRes = PQexec(conn, "CREATE TABLE IF NOT EXISTS t_xyz (xyzId SERIAL PRIMARY KEY NOT NULL, xyz VARCHAR(100) UNIQUE NOT NULL)"); if (PQresultStatus(createTableRes) != PGRES_COMMAND_OK) { char* errorDescribed = PQerrorMessage(conn); my_logger.error("could not create table t_xyz, errorMessage:{}", errorDescribed); PQclear(createTableRes); exit_nicely(conn); } else { if (lastNotice != NULL && strstr(lastNotice, "relation \"t_xyz\" already exists") != NULL) { my_logger.info("table t_xyz existed already."); } else { my_logger.info("created table t_xyz successfully."); } // 清理缓存 if (lastNotice != NULL) { free(lastNotice); lastNotice = NULL; } } PQclear(createTableRes);
为什么之前的设置无效?
client_min_messages=INFO是控制服务器发送的消息级别,但relation already exists本身就是INFO级别的Notice,问题根源是你用错了捕获方式——PQnotifies只针对LISTEN/NOTIFY机制的异步通知,和普通查询的Notice不是一回事。
内容的提问来源于stack exchange,提问作者Quiensabe
相关产品推荐
相关产品推荐

