Vyhledávání na webu

javascript - Node.js - PostgreSQL - nelze určit datový typ parametru $1 chyba


Snažím se vytvořit připravený příkaz PostgreSQL pomocí balíčku pg npm v node.js. Nicméně stále dostávám chybu:

nelze určit datový typ parametru $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);   
        })
    });
}

V databázi je pole name nastaveno na typ text not null.

Také jsem zkoušel pg-promise, ale také bez úspěchu.

Odpověď č. 1

V dotazu select name from workers je z hlediska syntaxi SQL name identifikátorem a identifikátory nemohou být nikdy předávány jako parametry $N, musí se objevit doslovně v příkazu. Jinak nelze dotaz připravit.

Parametry $N se mohou v dotazu objevit pouze na místech, kde by se vyskytovaly literály (konstanty).

Měli byste stejnou chybu, pokud byste zkoušeli něco podobného s SQL příkazem PREPARE, mimo jakoukoli knihovnu na straně klienta:

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

Řešením je sestavit dotaz v JavaScriptu pomocí technik nahrazování řetězců pro názvy sloupců nebo názvy tabulek, před jeho odesláním do databáze.

pg-promise podporuje vkládání identifikátorů do dotazu se specifickou syntaxí. Z jeho dokumentace:

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

Odpověď č. 2

Navazující na odpověď Daniela Vérité...

Nelze kombinovat připravené příkazy s dynamickými názvy sloupců, museli byste dotaz generovat na straně klienta.

Při použití syntaxe pg-promise pro názvy SQL můžete svůj dotaz správně uzavřít takto:

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 $[], $//, $<>, $()

A pokud to chcete udělat pro seznam sloupců, nejjednodušší způsob, jak to udělat, je takto:

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

nebo ze všech vlastností objektu:

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

Všechny tyto metody správně ošetří dotaz, čímž zajistí, že SQL injection není možná.