【问题标题】:Node.js - PostgreSQL - could not determine data type of parameter $1 errorNode.js - PostgreSQL - 无法确定参数 $1 错误的数据类型
【发布时间】:2017-10-29 11:34:01
【问题描述】:

我正在尝试使用 node.js pg npm 包创建一个 PostgreSQL 准备好的语句。但是,我不断收到错误消息:

无法确定参数 $1 的数据类型

 function promiseQuery(sql, values) {
    return new Promise(function(resolve, reject) {
        pool.query('select $1 from workers', ['name'], function(err, result) {
            if (err) {console.log(err); reject(err)}
            else resolve(result.rows);   
        })
    });
}

在 db 中,name 字段设置为类型 text not null

我也尝试pg-promise,但也没有成功。

【问题讨论】:

  • 你确定你可以这样传递标识符吗?..
  • @VaoTsun 在 pg 文档中有一个非常相似的例子:npmjs.com/package/pg
  • 确切地说,文档指定了语法:pool.query('SELECT $1::int AS number', ['2'], function(err, res),您没有在代码中使用
  • 在该示例中,brianc 是一个文本值,而不是列名 - 是您的情况吗?..
  • 如果你能像那样做动态 SQL,它就不能防止 SQL 注入。

标签: javascript node.js postgresql pg pg-promise


【解决方案1】:

在查询select name from workers 中,从SQL syntax 的角度来看,name 是一个identifier,并且标识符永远不能作为$N 参数传递,它们必须逐字出现在命令中。否则无法准备查询。

$N 参数只能出现在查询中文字(常量)所在的位置。

如果在任何客户端库之外使用PREPARE SQL 命令尝试类似的操作,您会遇到同样的错误:

PREPARE p as SELECT $1 FROM pg_class;
ERROR:  could not determine data type of parameter $1

解决方案是在 javascript 中使用列名或表名的字符串替换技术构建查询,然后将其提交到数据库。

pg-promise 确实支持将标识符注入到具有特定语法的查询中。来自its documentation

db.query('SELECT $1:name FROM $2:name', ['*', 'table']);
//=> SELECT * FROM "table"

【讨论】:

  • > 字符串替换技术 不会重新打开查询到SQL注入吗?
  • @VincentBuscarello:充分引用它是安全的。似乎 pg-promise 确实支持标识符的引用/转义(不确定 3 年前是否支持)。我在答案中添加了一些内容。
【解决方案2】:

扩展 Daniel Vérité 的答案...

您不能将准备好的语句与动态列名结合起来,您必须在客户端生成查询。

SQL Names 使用pg-promise 语法,您可以像这样正确地转义您的查询:

db.any('SELECT $1~ FROM table', [colName])
// OR:
db.any('SELECT $1:name FROM table', [colName])
// OR:
db.any('SELECT ${colName~} FROM table', {colName})
// OR:
db.any('SELECT ${colName:name} FROM table', {colName})
// Etc, other variable syntax, like $[], $//, $<>, $()

如果你想为一个列列表做这件事,那么最简单的方法是这样的:

const colNames = ['one', 'two', 'three'];

db.any('SELECT $1~ FROM table', [colNames])
// etc, the same variations as above, all will generate:
// SELECT "one","two","three" FROM table

或来自所有对象属性:

const data = {
    one: 123,
    two: true,
    three: 'text'
};
db.any('SELECT $1~ FROM table', [data])
// etc, the same variations as above, all will generate:
// SELECT "one","two","three" FROM table

所有这些方法都会正确地转义查询,确保 SQL 注入是不可能的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-19
    • 1970-01-01
    • 1970-01-01
    • 2019-09-29
    • 2021-11-28
    • 1970-01-01
    • 2021-03-14
    • 1970-01-01
    相关资源
    最近更新 更多