Knex not properly escaping raw postgres queries - sql

I am using Knex (with typescript) to try to query a postgres database. My database table products has a column name that I want to search through as the user types into a search box. For example, a query of just the letter 'p' should return all products with a name that contains a word that begins with 'p'. For this, I am using the ts_vector and ts_query functions. My query looks like this:
const query = ... // got from user input
const result = await knex(knex.raw('products'))
.whereRaw(`to_tsvector(name) ## to_tsquery('?:*')`, query)
.select('*')
When I run this query, I get the following error:
Unhandled error { error: select * from products where to_tsvector(name) ## to_tsquery('$1:*') - bind message supplies 1 parameters, but prepared statement "" requires 0
If I replace the whereRaw line with: .whereRaw(`to_tsvector(name) ## to_tsquery('p:*')`), it correctly runs the query, selecting products whose names contain words beginning with a P.
It seems like there is some conflict with the postgres syntax and knex's raw queries. I want to use a raw query over using `${query}:*` because I want my inputs to be sanitized and protected from SQL injection. How can I get Knex to properly escape this?
I have tried various combinations of quotes, slashes and colons, but none seem to work. Any help would be appreciated.

PostgreSQL doesn't process placeholders when they are inside quotes (and I am a little surprised that knex does).
You need to do the concatenation explicitly, either inside PostgreSQL:
.whereRaw(`to_tsvector(name) ## to_tsquery(? ||':*')`,query)
Or inside typescript:
.whereRaw(`to_tsvector(name) ## to_tsquery(?)`, query+":*")

Related

Getting parameters error when using ibm_db_dbi sql query in python

I'm trying to use the results from one query to use in the where clause of another and cannot get it to work. at the moment i'm getting an error....
ProgrammingError: ibm_db_dbi::ProgrammingError: Exception('Statement Execute Failed: [IBM][CLI Driver] CLI0100E Wrong number of parameters. SQLSTATE=07001 SQLCODE=-99999')
My code below (eventually, 'result' will just be a variable assigned to the results from another query, but for now i'm just trying to get it to work with a static variable. Thanks in advance!
import ibm_db_dbi as db
result = ['c80fS4Pn1', '9f*hzNT21']
conn = db.connect('DRIVER=DB2 zOS;'
'DATABASE=xxxx;'
'HOSTNAME=xxxx.com;'
'PORT=xxx;'
'PROTOCOL=xxxx;'
'UID=id;'
'PWD=passord;', '', '')
cur = conn.cursor()
sql = "SELECT * FROM SCHEMA.TABLE WHERE PRIM_KEY IN (?)"
cur.execute(sql, (result))
conn.close()
The reason you get error CLI0100E is because in your code-sample you show a list (called result) with two entries, while in your query there is a single parameter-marker (?)
The number of parameters to be bound (as done by the cur.execute()), must exactly match the number of parameter-markers in the query
As you usually do not know in advance the number of rows returned from a query, you usually don't know the number of parameter-markers in advance.
You could dynamically generate the number of parameter markers to match the number of rows in the previous result-set. Or you could generate the SQL string in full without parameter markers which is inefficient and might not scale.
It is wise to do in SQL the things that SQL is good at doing, such as passing the results of a sub-query into another query. Trying to do that in client side code (instead of inside the SQL engine) may be inelegant and slow.

HANA Bind JS Array as Parameter Value to WHERE IN(...) Clause

I'm using the #sap/hana-client npm module in a NodeJS project to connect to a HANA database and run queries.
I have a list of IDs that I want to include in a WHERE ID IN(...) SQL clause via parameterized queries, but cannot seem to figure out the syntax to do it.
Here's what I imagine it would look like (but this does not work, fails at the parameter binding stage)
const ids = [1,2,3,4];
const params = [ids];
const sql = "SELECT * FROM T WHERE ID IN (?)";
// this fails with => code: -20007, message: 'Can not bind parameter(0).', sqlState: 'HY000'
conn.query(sql, params, (err, result) => {
// process query results or errors
});
I know that in Postgres I can do this by using the UNNEST(...) 1 array function, but the same does not seem to work in HANA
That's a well-known difficulty with HANA.
ARRAY-like types are not natively supported in the client software.
Your (special) case of this, namely turning an array into a list of parameters for an IN clause requires some additional efforts.
See e.g. Errors with declared array/table variable values in SAP HanaDB SQL
The bottom line is that Postgres handles this special case specifically by replacing the single IN-clause parameter ? with a whole list of delimited values.
HANA does (sadly) not do something like that.
Instead, if you have to know in advance how many elements (at max) the IN-list will have so that you can prepare a statement with a parameter ? for each of those elements.
Alternatively, you can use SQLScript and the UNNEST construct that I've shown in the linked question, or you can create a temporary table, fill it with the IN-list elements and use it in the IN-clause (or join it).
Either way, it's rather cumbersome to manually do this, and I'd probably look for a framework that does that sort of stuff.

pyodbc execute command not accepting ? parameters correctly?

This code:
cursor.execute('select RLAMBD from ?', OPTable)
print cursor.fetchone().RLAMBD
produces this error:
ProgrammingError: ('42S02', '[42S02] [Oracle][ODBC][Ora]ORA-00903: invalid table name\n (903) (SQLExecDirectW)')
OPTable is an alphanumeric string which I've built from another database query which contains the table name I want to select from.
The following code works just fine within the same script.
sql = 'select RLAMBD from ' + OPTable
cursor.execute(sql)
print cursor.fetchone().RLAMBD
I guess it's not a huge deal to build the sql statements this way, but I just don't understand why it's not accepting the ? parameters. I even have another query in the same script which uses the ? parameterization and works just fine. The parameters for the working query are produced using the raw_input function, though. Is there some subtle difference between the way those two strings might be formatted that's preventing me from getting the query to work? Thank you all.
I'm running python 2.7 and pyodbc 3.0.10.
Parameter placeholders cannot be used to represent object names (e.g., table or column names) or SQL keywords. They are only used to pass data values, e.g., numbers, strings, dates, etc..

What does "SELECT INTO" do?

I'm reading sql code which has a line that looks like this:
SELECT INTO _user tag FROM login.user WHERE id = util.uuid_to_int(_user_id)::oid;
What exactly does this do? The usual way to use SELECT INTO requires specifying the columns to select after the SELECT token, e.g.
SELECT * INTO _my_new_table WHERE ...;
The database is postgresql.
This line must appear inside of a PL/pgSQL function. In that context the value from column tag is assigned to variable _user.
According to the documentation:
Tip: Note that this interpretation of SELECT with INTO is quite different from PostgreSQL's regular SELECT INTO command, wherein the INTO target is a newly created table.
and
The INTO clause can appear almost anywhere in the SQL command. Customarily it is written either just before or just after the list of select_expressions in a SELECT command, or at the end of the command for other command types. It is recommended that you follow this convention in case the PL/pgSQL parser becomes stricter in future versions.

Bind variables in the from clause for Postgres

I'm attempting to write an extension for SQL Developer to better support Postgres. These are just XML configuration files with SQL snippets in them. To display the values for a postgres sequence, I need to run a simple query of the following form:
select * from schema.sequence
The trouble with this is that the Oracle SQL Developer environment provides the correct schema and node (sequence) name as bind variables. This would mean that I should format the query as:
select * from :SCHEMA.:NAME
The trouble with this is that bind variables are only valid in the select clause or the where clause (as far as I'm aware), and using this form of the query returns a "syntax error at or near "$1" error message.
Is there a way to return the values in the sequence object without directly selecting them from the sequence? Perhaps some obtuse joined statement from pg_catalog tables?
Try this:
select *
from information_schema.sequences
where sequence_name = :name
and sequence_schema = :schema;
It's not exactly the same thing as doing a select from the sequence, but the basic information is there.