Node.js - PostgreSQL - 无法确定参数$ 1错误的数据类型

时间:2017-05-29 08:20:08

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

我尝试使用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);   
        })
    });
}

在数据库中,name字段设置为text not null

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

2 个答案:

答案 0 :(得分:3)

在查询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中的查询,然后再将其提交到数据库。

答案 1 :(得分:2)

延伸DanielVérité的答案......

您无法将Prepared Statements与动态列名组合在一起,您必须在客户端生成查询。

使用pg-promiseSQL Names语法,您可以正确地转义您的查询:

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注入。