Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

pg-native: unhandled libpq result status drops the result and the server's error

未关闭
#3,758 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
58/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
javascript, node.js, postgresql
领域
backend, database

调研方向

首先,使用 native 和 pure-JS 客户端重现所提供的 COPY … TO STDOUT 案例。阅读 packages/pg-native/index.js 中 _emitResult、_read 和 _onReadyForQuery 附近的代码,然后阅读 packages/pg/lib/native/query.js 中 after() 附近的代码。完成的标准是:未处理的 libpq 状态不再产生 undefined 的成功结果,并且服务器错误能够传递到查询回调。

由索引模型根据 Issue 内容生成。

描述

Disclaimer

This is a real issue we saw in our production environment via sequelize v6, we used claude + 2 agents to generate this report, I saw no AI/slop policy, feel free to do whatever you feel like based on this.

Summary

client.query(sql, cb) on the native client can call cb(null, undefined) — no error, no result — so anything that reads res.rows throws. The pure-JS client returns a Result for the same query.

Versions: pg 8.23.0, pg-native 3.9.0, libpq 1.11.0, Node 26.7.0. Reproduced on PostgreSQL 17.11 and CockroachDB 26.2.5 with identical output. Line numbers below are from master; the published 3.9.0 tarball is offset by ~17 lines around _onReadyForQuery.

Repro

COPY … TO STDOUT through client.query() hits it every time, no patching needed. This runs the same query through both drivers:

const CONN = process.argv[2] || 'postgres://postgres@localhost:5432/postgres';
const SQL = 'COPY (SELECT 1) TO STDOUT';

const native = require('pg').native;
const { Client: JsClient } = require('pg');

function run(Client, label) {
  return new Promise((resolve) => {
    const client = new Client(CONN);
    client.connect((connErr) => {
      if (connErr) return resolve(console.log(`[${label}] connect failed: ${connErr.message}`));
      client.query(SQL, (err, res) => {
        console.log(`[${label}] err = ${err && err.message}`);
        console.log(`[${label}] res = ${res && res.constructor.name}`);
        try {
          console.log(`[${label}] res.rows = ${JSON.stringify(res.rows)}`);
        } catch (e) {
          console.log(`[${label}] res.rows THREW ${e.constructor.name}: ${e.message}`);
        }
        client.end(() => resolve());
      });
    });
  });
}

(async () => {
  await run(JsClient, 'js    ');
  await run(native.Client, 'native');
})();
[js    ] err = null
[js    ] res = Result
[js    ] res.rows = []
[native] err = null
[native] res = undefined
[native] res.rows THREW TypeError: Cannot read properties of undefined (reading 'rows')

What's happening

_emitResult (packages/pg-native/index.js:181) emits a result event for three statuses only — PGRES_TUPLES_OK, PGRES_COMMAND_OK, PGRES_EMPTY_QUERY. COPY_OUT/COPY_BOTH break out without one, and the default: branch sends the error to the client through _readError rather than to the query. Either way _read reaches emit('readyForQuery') (:248) with _resultCount === 0, and _onReadyForQuery (:490) passes that straight through:

const results = this._results   // undefined: no 'result' event fired
cb(err, rows || [], results)

pg's NativeQuery then reads the falsy err as success and calls back with undefined (packages/pg/lib/native/query.js:121).

The case that actually bit us

COPY is just the convenient reproduction. The default: branch is the damaging one, because the server's error goes to the client's error event and never reaches the query — so you lose the result and the explanation. We spent a while on a Sequelize crash that looked like this:

TypeError: Cannot read properties of undefined (reading 'rows')
    at Query.run (sequelize/lib/dialects/postgres/query.js:62)

The transaction was left aborted, every later statement failed with current transaction is aborted, commands ignored until end of transaction block, and the error explaining why was gone. On the JS driver the same server condition arrives as an ordinary error.

Possible fixes

  • In _onReadyForQuery, when there's no result and no _queryError, call back with an error instead of undefined.
  • In the default: branch, set _queryError so the server's message reaches the caller.
  • Or defensively in pg's after() (packages/pg/lib/native/query.js:121): treat a missing results as an error.

Happy to open a PR if one of those looks like the right shape.


Possibly related, and I can file it separately: at packages/pg-native/index.js:214, if pq.consumeInput() returns false, _read calls _readError() and returns before emit('readyForQuery') — the in-flight query's callback never fires and the promise hangs. I saw this by cancelling a running statement server-side (on CockroachDB; haven't rechecked on PostgreSQL).

主要语言
JavaScript
星标
13.2k
派生
1.4k
平均合并
6 天 15 小时
30 天内合并 PR
6

贡献指南

这个仓库没有索引到贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

brianc/node-postgres 的其他 Issue

查看 brianc/node-postgres 的全部 Issue

相似的 Issue

更多 JavaScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。