Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is there some string escaping or preparing? #33

Closed
unikoid opened this issue Jun 3, 2011 · 9 comments
Closed

Is there some string escaping or preparing? #33

unikoid opened this issue Jun 3, 2011 · 9 comments

Comments

@unikoid
Copy link

unikoid commented Jun 3, 2011

Hello. I'm using node-postgres. And I want to insert some strings into some table.
If I'm using single query, I can do like this and everything is working ok:

client.query('INSERT INTO sometbl VALUES ($1, $2)', ['foo', 'bar']);

But since I am using transactions and trying to do like this:

client.query('BEGIN; INSERT INTO sometbl VALUES ($1, $2); UPDATE sometable SET somevalue = $3; END;', ['foo', 'bar', 'foobar']);

I am getting an error with code 42601: 'cannot insert multiple commands into a prepared statement'.

Yes, I know that I can use simple string concatenation or some realizations of sprintf() to insert these parameters into the query string, but, I think, it isn't safe to do it without any preparation like escaping.
Is there some convinient way to do such preparation before inserting string values into the query string?

For example, I have found PQescapeLiteral function in the libpq, maybe there is some interface to this or similar function exists?
If no, can it be implemented?
//Sorry if the question is silly, I'm newbie in postgresql and node.

@brianc
Copy link
Owner

brianc commented Jun 5, 2011

There is no built-in string escaping in node-postgres. The pure javascript version cannot rely on PQescapeLiteral being present and since the pure javsacript & native libpq bindings need to share the same API it hasn't been added.

You can use a transaction with parameterized sql by issuing each sql statement as their own command as follows:

//assume `client` is a connected instance of a postgres client
client.query('begin');
client.query('INSERT INTO somtbl VALUES($1, $2);', ['foo', 'bar']);
client.query('UPDATE sometable SET somevalue = $1', ['foobar'], function(err, result) {
  if(err) {
    //if there was an error postgres has already & automatically rolled back changes from the INSERT command
    //so execute any application error handling here
  }
  else {
    client.query('COMMIT');  //I guess 'END' works as well, but COMMIT is what's documented by Postgres
  }
});

Any node-postgres client instance will ensure each query is executed in order. For more information:

https://github.com/brianc/node-postgres/blob/master/test/integration/client/transaction-tests.js

@unikoid
Copy link
Author

unikoid commented Jun 6, 2011

Thank you for your answer. The problem is solved.

@unikoid unikoid closed this as completed Jun 6, 2011
@williamkapke
Copy link

@brianc - don't mess with me like this!

I don't think you ment to use $3 in your example. I had to throw together a sanity test...

pg.connect(function(err, client, done) {
    client.query('BEGIN');
    client.query('SELECT $1::text t1, $2::text t2', ['a', 'b'], function(err, qry){
        console.log(err || qry.rows);
    });
    client.query('SELECT $1::text t3', ['c'], function(err, qry){
        console.log(err || qry.rows);
    });
    client.query('COMMIT', function(err, qry){
        console.log("done");
        done();
    });
});

THAT code works. 👍
Using $3 in the second SELECT does not. 👎
(as far as I can tell)

@shaunc
Copy link

shaunc commented Feb 18, 2015

If you don't need to wrap in a transaction, but need atomic execution, the particular problem could be solved with a CTE as well:

...
client.query("with s as (INSERT INTO sometbl VALUES ($1, $2) returning 1) UPDATE sometable SET somevalue = $3 from s", ['a', 'b', 'c'])

@brianc
Copy link
Owner

brianc commented Feb 21, 2015

haha @williamkapke sorry about that! Will edit my response to not suck!

@benjie
Copy link
Contributor

benjie commented Jan 17, 2020

(NOTE: the current pg supports both escapeIdentifier and escapeLiteral on client instances:

// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
Client.prototype.escapeIdentifier = function (str) {
return '"' + str.replace(/"/g, '""') + '"'
}
// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
Client.prototype.escapeLiteral = function (str) {
var hasBackslash = false
var escaped = '\''
for (var i = 0; i < str.length; i++) {
var c = str[i]
if (c === '\'') {
escaped += c + c
} else if (c === '\\') {
escaped += c + c
hasBackslash = true
} else {
escaped += c
}
}
escaped += '\''
if (hasBackslash === true) {
escaped = ' E' + escaped
}
return escaped
}
)

@jayarjo
Copy link

jayarjo commented May 27, 2020

@benjie I do not recognize the logic can you elaborate on what escapeIdentifier and escapeLiteral are for?

@benjie
Copy link
Contributor

benjie commented May 27, 2020

Sure; escapeIdentifier is for escaping identifiers as documented here: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS "(To include a double quote, write two double quotes.)"

escapeLiteral is for escaping string constants as documented here: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS

@dschinkel
Copy link

dschinkel commented Dec 2, 2020

screw all that just use this by TJ: https://github.com/segmentio/pg-escape

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants