Code Monkey home page Code Monkey logo

sqlstring's Introduction

sqlstring

NPM Version NPM Downloads Node.js Version Build Status Coverage Status

Simple SQL escape and format for MySQL

Install

$ npm install sqlstring

Usage

var SqlString = require('sqlstring');

Escaping query values

Caution These methods of escaping values only works when the NO_BACKSLASH_ESCAPES SQL mode is disabled (which is the default state for MySQL servers).

Caution This library performs client-side escaping, as this is a library to generate SQL strings on the client side. The syntax for functions like SqlString.format may look similar to a prepared statement, but it is not and the escaping rules from this module are used to generate a resulting SQL string. The purpose of escaping input is to avoid SQL Injection attacks. In order to support enhanced support like SET and IN formatting, this module will escape based on the shape of the passed in JavaScript value, and the resulting escaped string may be more than a single value. When structured user input is provided as the value to escape, care should be taken to validate the shape of the input to validate the output will be what is expected.

In order to avoid SQL Injection attacks, you should always escape any user provided data before using it inside a SQL query. You can do so using the SqlString.escape() method:

var userId = 'some user provided value';
var sql    = 'SELECT * FROM users WHERE id = ' + SqlString.escape(userId);
console.log(sql); // SELECT * FROM users WHERE id = 'some user provided value'

Alternatively, you can use ? characters as placeholders for values you would like to have escaped like this:

var userId = 1;
var sql    = SqlString.format('SELECT * FROM users WHERE id = ?', [userId]);
console.log(sql); // SELECT * FROM users WHERE id = 1

Multiple placeholders are mapped to values in the same order as passed. For example, in the following query foo equals a, bar equals b, baz equals c, and id will be userId:

var userId = 1;
var sql    = SqlString.format('UPDATE users SET foo = ?, bar = ?, baz = ? WHERE id = ?',
  ['a', 'b', 'c', userId]);
console.log(sql); // UPDATE users SET foo = 'a', bar = 'b', baz = 'c' WHERE id = 1

This looks similar to prepared statements in MySQL, however it really just uses the same SqlString.escape() method internally.

Caution This also differs from prepared statements in that all ? are replaced, even those contained in comments and strings.

Different value types are escaped differently, here is how:

  • Numbers are left untouched
  • Booleans are converted to true / false
  • Date objects are converted to 'YYYY-mm-dd HH:ii:ss' strings
  • Buffers are converted to hex strings, e.g. X'0fa5'
  • Strings are safely escaped
  • Arrays are turned into list, e.g. ['a', 'b'] turns into 'a', 'b'
  • Nested arrays are turned into grouped lists (for bulk inserts), e.g. [['a', 'b'], ['c', 'd']] turns into ('a', 'b'), ('c', 'd')
  • Objects that have a toSqlString method will have .toSqlString() called and the returned value is used as the raw SQL.
  • Objects are turned into key = 'val' pairs for each enumerable property on the object. If the property's value is a function, it is skipped; if the property's value is an object, toString() is called on it and the returned value is used.
  • undefined / null are converted to NULL
  • NaN / Infinity are left as-is. MySQL does not support these, and trying to insert them as values will trigger MySQL errors until they implement support.

You may have noticed that this escaping allows you to do neat things like this:

var post  = {id: 1, title: 'Hello MySQL'};
var sql = SqlString.format('INSERT INTO posts SET ?', post);
console.log(sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'

And the toSqlString method allows you to form complex queries with functions:

var CURRENT_TIMESTAMP = { toSqlString: function() { return 'CURRENT_TIMESTAMP()'; } };
var sql = SqlString.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]);
console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42

To generate objects with a toSqlString method, the SqlString.raw() method can be used. This creates an object that will be left un-touched when using in a ? placeholder, useful for using functions as dynamic values:

Caution The string provided to SqlString.raw() will skip all escaping functions when used, so be careful when passing in unvalidated input.

var CURRENT_TIMESTAMP = SqlString.raw('CURRENT_TIMESTAMP()');
var sql = SqlString.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]);
console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42

If you feel the need to escape queries by yourself, you can also use the escaping function directly:

var sql = 'SELECT * FROM posts WHERE title=' + SqlString.escape('Hello MySQL');
console.log(sql); // SELECT * FROM posts WHERE title='Hello MySQL'

Escaping query identifiers

If you can't trust an SQL identifier (database / table / column name) because it is provided by a user, you should escape it with SqlString.escapeId(identifier) like this:

var sorter = 'date';
var sql    = 'SELECT * FROM posts ORDER BY ' + SqlString.escapeId(sorter);
console.log(sql); // SELECT * FROM posts ORDER BY `date`

It also supports adding qualified identifiers. It will escape both parts.

var sorter = 'date';
var sql    = 'SELECT * FROM posts ORDER BY ' + SqlString.escapeId('posts.' + sorter);
console.log(sql); // SELECT * FROM posts ORDER BY `posts`.`date`

If you do not want to treat . as qualified identifiers, you can set the second argument to true in order to keep the string as a literal identifier:

var sorter = 'date.2';
var sql    = 'SELECT * FROM posts ORDER BY ' + SqlString.escapeId(sorter, true);
console.log(sql); // SELECT * FROM posts ORDER BY `date.2`

Alternatively, you can use ?? characters as placeholders for identifiers you would like to have escaped like this:

var userId = 1;
var columns = ['username', 'email'];
var sql     = SqlString.format('SELECT ?? FROM ?? WHERE id = ?', [columns, 'users', userId]);
console.log(sql); // SELECT `username`, `email` FROM `users` WHERE id = 1

Please note that this last character sequence is experimental and syntax might change

When you pass an Object to .escape() or .format(), .escapeId() is used to avoid SQL injection in object keys.

Formatting queries

You can use SqlString.format to prepare a query with multiple insertion points, utilizing the proper escaping for ids and values. A simple example of this follows:

var userId  = 1;
var inserts = ['users', 'id', userId];
var sql     = SqlString.format('SELECT * FROM ?? WHERE ?? = ?', inserts);
console.log(sql); // SELECT * FROM `users` WHERE `id` = 1

Following this you then have a valid, escaped query that you can then send to the database safely. This is useful if you are looking to prepare the query before actually sending it to the database. You also have the option (but are not required) to pass in stringifyObject and timeZone, allowing you provide a custom means of turning objects into strings, as well as a location-specific/timezone-aware Date.

This can be further combined with the SqlString.raw() helper to generate SQL that includes MySQL functions as dynamic vales:

var userId = 1;
var data   = { email: '[email protected]', modified: SqlString.raw('NOW()') };
var sql    = SqlString.format('UPDATE ?? SET ? WHERE `id` = ?', ['users', data, userId]);
console.log(sql); // UPDATE `users` SET `email` = '[email protected]', `modified` = NOW() WHERE `id` = 1

License

MIT

sqlstring's People

Contributors

adrivanhoudt avatar dougwilson avatar fengmk2 avatar kevinmartin avatar kiprobinson avatar nwoltman avatar seregpie avatar uiteoi avatar xadillax avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sqlstring's Issues

single quote bad escape

I am using postgres.

This is a heavily simplified example and not sure if this runs. But the issue is demonstrated here.
The issue can be seen in col3value escaping of the single quote inside the string

I am using it like:

const col1value = 5
const col2value = 'hello world'
const col3value = "You'll find the world"

const escaped1value = escape(col1value)
const escaped2value = escape(col2value)
const escaped3value = escape(col3value)

 const query = `WITH temp_table ("col1","col2","col3") AS (
      VALUES (${escaped1value}::integer,${escaped2value}::text,${escaped3value}::text)
    )
select * from temp_table`

this becomes

WITH temp_table ("col1","col2","col3") AS (
      VALUES (5::integer,'hello world::text,'You\'ll find the world'::text)
    )
select * from temp_table

What it should become

WITH temp_table ("col1","col2","col3") AS (
      VALUES (5::integer,'hello world::text,'You''ll find the world'::text)
    )
select * from temp_table

I put in a function for replacement but essentially it does the below
const escaped3value = escape(col3value).replace(/\\'/g, "''");

But I am wondering if there should be an option added to escape that we can change the escaping of single quotes from \' to ''?

Buffers should be converted .toSting() with the original Buffer.prototype.toString()

var x = Buffer.from('lol');
x.toString = () => "00\' OR '1' = '1";
SqlString.format("SELECT * FROM user WHERE user = ?", x);

results in

SELECT * FROM user WHERE user = X'00' OR '1' = '1'

This doesn't look like a security issue to me, because whomever allows user-supplied .toString() override has much bigger problems than a potential SQLi.

When Recieving Key-Value pair, Where the Value is Array. Use IN Instead of =

Feature Request: Enhanced object value substitution for WHERE clauses
It would be nice if this same query could be mapped to either = or IN depending on the type of input (array vs string/number)

SELECT * FROM users WHERE ?;
const userIds = [1, 2, 3, 4]; // or const userIds = 1; 
const users = (await con.query(sql, [{userId: userIds}]))[0]

This currently maps to the following string

SELECT * FROM users WHERE `userId` = 1, 2, 3, 4;

Which works fine for the single value example. But it would be nice if the value was an array it could map to:

 SELECT * FROM users WHERE `userId` in (1, 2, 3, 4);

This seems like it wouldn't be too hard, but I am unaware of any security vulnerabilities such a change could make.

I just want to cut down on the amount of functions I need to have to call specific tables.

For the first query I could obviously call it with a different key and it would still work such as

const emails = "[email protected]";
const users = (await con.query(sql, [{email: emails}]))[0]

This would prevent the need to have a file for emails IN (?) and userIds IN (?) etc.
But to my knowledge you cannot currently dynamically change the search param when using IN.

Escaping date sometimes results in empty string

This is a very weird issue that I was not able to fully debug to find the cause.

Part of my project's code looks like this:

const mysql = require("mysql");
const db = mysql.createConnection(...);

When I run a query with {Date} objects, some of them resulted in a query like (demo)
image
image
Running
mysql.escape(new Date()) I get empty string.

I installed mysql and sqlstring on a new plain project and could not reproduce this. mysql.escape(...) seems to work with any other type.

Any ideas what could be the cause for this?

image

can you add function for SELECT sql query

if (Object.keys(values).length > 1 && sql.toLowerCase().indexOf('select ') > -1 && (query.split(' ? ').length - 1) == 1) {
                sql = sql.replace('?', Object.keys(values).map((i) => {
                    return `${i}='${values[i]}'`;
                }).join(' AND '));
                values = 0;
            }

when i put some values for SELECT sql query, i get error !
so this add "and " between the parameters.
1)If SELECT sql query
2)If there are over 2 values (Because one works great)
3)If just one ? symbol (support in full query)

example

SELECT * FROM `customers` WHERE ?,{id:12345} =SELECT * FROM `customers` WHERE id='12345' //WORK

SELECT * FROM `customers` WHERE ?,{id:12345,pass:'pass'} =SELECT * FROM `customers` WHERE id='12345'**,** pass='pass',
error! so need replace the comma in "AND". like
SELECT * FROM `customers` WHERE ?,{id:12345,pass:'pass'} =SELECT * FROM `customers` WHERE id='12345' AND  pass='pass', 

SELECT * FROM `customers` WHERE id=? OR pass=?,{id:12345,pass:'pass'} =SELECT * FROM `customers` WHERE id='12345' OR pass='pass', //WORK (keep the old integration)

Handling Arrays in a JSON

Hi,
MySql supports JSON data type: https://dev.mysql.com/doc/refman/5.7/en/json.html .

Use Case

I want to run an update command on my db with the following data:
var post = { a: 1, b: [2, 3, 4], c: 5}
where the column b has JSON data type.

Actual Behavior

var sql = "UPDATE tb SET " + SqlString.escape(post) + " WHERE id= " + SqlString.escape(242);
The formatted query would be
UPDATE tb SET a= 1,b= 2, 3, 4,c= 5 WHERE id= 242
This command would fail.

Expected Behavior

I want to store JSON data in column b. So, the query should be formatted as:
UPDATE tb SET a= 1,b= '[2, 3, 4]',c= 5 WHERE id= 242

Escaping single quote

Currently, sqlstring.escape("jo'hn") results in 'jo\\'hn' which is not the correct escape for single quote, the correct escape for single quote should be 2 single quote next to each other and the correct end result is 'jo''hn'

Unexpected results when using WHERE together with ? and null

Using WHERE + ? + null may lead to unexpected results

var sql = SqlString.format('DELETE FROM posts WHERE ?', {id: null});
console.log(sql); //DELETE FROM posts WHERE `id` = NULL
//will do nothing (unexpected), need to use IS NULL instead
var sql = SqlString.format('DELETE FROM posts WHERE ?', {id: 1});
console.log(sql); //DELETE FROM posts WHERE `id` = 1
//will do (expected)

I know it's not exactly this package problem, because the query is still correct, but it may be worth mentioning this in the docs.

Support for MSSQL

Hi Team,

Any thoughts for brining support for SQL Server too? Or any alternative?

Strange behavior in map

I noticed some strange behavior when escaping objects in an array using map. Only the first object is escaped as I would expect and the rest are strings of the type?

For example,

const sqlstring = require('sqlstring')
[{ id:1, name:'alice' }, { id:2, name:'bob' }, { id:3, name:'charlie' }].map(sqlstring.escape)

produces:

[ '`id` = 1, `name` = \'alice\'',
  '\'[object Object]\'',
  '\'[object Object]\'' ]

Do you know why this is happening?

If this is not expected behavior in some way I can try to put together a PR after I complete my current project if you like.

TypeError: val.toString is not a function

When I'm trying to log in it is throwing me the error...
here is error...

TypeError: val.toString is not a function
    at Object.escape (/home/mohd/Desktop/codebucket/loginsystem/node_modules/sqlstring/lib/SqlString.js:52:33)
    at Object.objectToValues (/home/mohd/Desktop/codebucket/loginsystem/node_modules/sqlstring/lib/SqlString.js:180:89)
    at Object.escape (/home/mohd/Desktop/codebucket/loginsystem/node_modules/sqlstring/lib/SqlString.js:54:26)
    at Object.format (/home/mohd/Desktop/codebucket/loginsystem/node_modules/sqlstring/lib/SqlString.js:100:19)
    at Connection.format (/home/mohd/Desktop/codebucket/loginsystem/node_modules/mysql/lib/Connection.js:274:20)
    at Connection.query (/home/mohd/Desktop/codebucket/loginsystem/node_modules/mysql/lib/Connection.js:192:22)
    at Strategy._verify (/home/mohd/Desktop/codebucket/loginsystem/config/passport.js:16:28)
    at Strategy.authenticate (/home/mohd/Desktop/codebucket/loginsystem/node_modules/passport-local/lib/strategy.js:88:12)
    at attempt (/home/mohd/Desktop/codebucket/loginsystem/node_modules/passport/lib/middleware/authenticate.js:361:16)
    at authenticate (/home/mohd/Desktop/codebucket/loginsystem/node_modules/passport/lib/middleware/authenticate.js:362:7)

AND MY LOG IN CODE IS GIVEN BELOWcan you please resolve this issue

const localStrategy = require('passport-local').Strategy;
const bcrypt = require('bcryptjs');
const mysql = require('mysql');

const connection = require('./database');

module.exports = function (passport) {
    passport.use(
        new localStrategy(
            {usernameField:'email',
            passwordField:'password',
            passReqToCallback:true
            },
            (email, password, done)=>{
                var sql = 'SELECT * FROM user WHERE email = ?';
                connection.query(sql,email,(error,results,fields)=>{
                    if(error) throw error;
                    //Match user
                    if(!results.length)
                        return done(null, false, {message:'That email is not register'});

                    //Match
                    bcrypt.compare(password,results[0].password,(err,isMatch)=>{
                        if(err) throw err;
                        if (isMatch) {
                            console.log(results[0]);
                            console.log('every thing is fine');
                            
                            //return done(null,results[0]);
                        }else{
                            return done(null, false, {message:'Password incorrect'});
                        }
                    });
                });
            })
    );

    //serializeuser
    passport.serializeUser(function (user,done) {
        console.log(user.id);
        done(null,user.id);
    });

    //deserializeuser
    passport.deserializeUser(function (id,done) {
        connection.query('SELECT * FROM user WHERE id = ?',id,(err,results,fields)=>{
            done(err,results[0]);
        });
    });

};

format() returns object string instead of value

When using the format function to prepare a statement, if the data is an object, it is returning [object object] instead of stringifying the object.

for example:

const sqlStr = require(sqlstring);

let query = "INSERT INTO table (cola, colb, colc) VALUES ?";
let data = [["text",0,{test1: "text", val1: 1 }]];
let pquery = sqlStr.format(query,data);

Here is what sqlStr.format returns: "INSERT INTO table (cola, colb, colc) VALUES ('text',0,'[object Object]')"

Here is what it SHOULD return:

"INSERT INTO table (cola, colb, colc) VALUES ('text',0,'{"test1":"text","val1":1}')

Parameterized Identifiers

I'm trying to run the following query for dynamic sorting.

SELECT * FROM tenant ORDER BY ??column DESC
{ column: 'industry' }

I get the following error though.

BadRequestException: ERROR: operator does not exist: ` character varying
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.

I found out this is because the escapeId escapes these identifiers as column and postgres does not support backticks. From postgres's website:

MySQL uses ` (accent mark or backtick) to quote system identifiers, which is decidedly non-standard.

Can the ID_GLOBAL_REGEXP constant be configurable?

[SUPPORT] Is this escape function still needed?

Hi,

I still see this mysql_real_escape_string still being used:
https://stackoverflow.com/questions/7744912/making-a-javascript-string-sql-friendly

For example in this mysql restapi project in NodeJs:
https://github.com/jitendra5984/mysql-restapi/blob/master/lib/api.js#L105

Combination with your connection.escape/pool.escape which executes your sqlstring.escape function.

Is it still valid to use BOTH escapes functions together? Meaning this escape function for converting URL strings into SQL, covers more cases than your sqlstring escape function alone?

Or can we fully trust your escape function only?

Kind regards,
Melroy

Nested arrays aren't formatted correctly

Nested arrays are turned into grouped lists (for bulk inserts), e.g. [['a', 'b'], ['c', 'd']] turns into ('a', 'b'), ('c', 'd')

However, this is the behaviour:

require('sqlstring').format('?', [ [12, 34], [56, 78] ])
// => '12, 34'

It works correctly when using escape:

require('sqlstring').escape([ [12, 34], [56, 78] ])
// => '(12, 34), (56, 78)'

Question about the Regex literals in Google App Script

This is a great utility. I copied it into a Google App Scripts project and defined it as an immediate execute function. It required a little tweaking, like removing Buffer, but works fine.

When I called String.format with an Array, as for an IN clause, subsequent calls no longer work, even simple substitutions, i.e.

console.log(SqlString.format('employees in (?)', [[5, 6, 7, 8, 9]])); // OK
console.log(SqlString.format('employee_id = ?', 97)); // No substitution happens

FYI, Quokka doesn't exhibit this issue locally, interestingly.

I finally found it to be related to the literal regex and by making it a new object every time the issue was resolved. I am scratching my head why, though. Perhaps it's a bug in Google App Script Environment?

// var placeholdersRegex = /\?\??/g; 
var placeholdersRegex = new RegExp(/\?\??/g);

I am not asking for support, since clearly it's no longer the same code base, but I am just curious why the state of the match seems to be preserved after these two calls?

Thanks for making this utility. Really makes life easier.

Merging hazard for adjacent placeholders in format

This might be a corner case that's not worth addressing.

require('sqlstring').format('SELECT FROM ????', ['a', 'b']) === 'SELECT FROM `a``b`'

That 2 escaped arguments merge into a single token seems like a violation of an unspoken invariant, but probably only in code that has larger problems.


One liner to replicate:

$ npm install --no-save sqlstring && node -e 'console.log(require("sqlstring").format("SELECT FROM ????", ["a", "b"]))'
npm WARN enoent ENOENT: no such file or directory, open '/private/tmp/package.json'
npm WARN tmp No description
npm WARN tmp No repository field.
npm WARN tmp No README data
npm WARN tmp No license field.

+ [email protected]
removed 1 package and updated 1 package in 0.898s
SELECT `a``b`

Escape : charachter

Hi,

I tried to insert some string in my db using mysqljs,

String looks like this: ?/*-:;@!#$$%^&

Expected behavior : '?/*-:;@!#$$%^&'

Result: '?/*-'

Nothing included after ":" in any string input.

Bring up-to-date with [email protected]

We should get this module up-to-date with the new msyql coming up soon, get this module used in there, and start proceeding forward from there.

Hey @fengmk2, do you mind if I take this on, or do you want to? We also would want to support Node.js 0.6 to get used by [email protected], and there are probably a bunch of packaging changes I would like to make.

Because of this, I just wanted to get on the same page as you: do you want to keep maintaing this module, or did you intend to just donate it to the mysqljs organization to take over (and, do you want to participate in mysqljs organization at all)?

UnExpect Sql Format Result

Hi~I use this node-modules for my project ,I want to format SQL like this

use itop;
SELECT a.first_name,b.first_name AS b FROM person AS a LEFT JOIN person AS b ON a.id=b.id 

After I Use the SqlString Format it ,I get the Result like this:

use itop;SELECT a.first_name,
         b.first_name AS b
FROM person AS a
LEFT JOIN person AS b
    ON a.id=b.id 

But Not Like This

use itop;
SELECT a.first_name,
         b.first_name AS b
FROM person AS a
LEFT JOIN person AS b
    ON a.id=b.id 

No idea to escape single quote' and double quote".

const sql = sqlstring.format('SELECT * FROM `terms` WHERE `name` = ?', [
    `single'double"`,
  ])
console.log(sql)
// output: SELECT * FROM `terms` WHERE `name` = 'single\'double\"'
// near "double": syntax error

Looks like single\'double\" shoud be single''double""
Need I create a user function to replace the quote?

How to use "?" placeholders with bigint values?

Some of our columns are bigints and we're currently using BigNumber.js to work with those values.

My first attempt:

const n = new BigNumber('26000000000000000')
connection.query(`SELECT ?;`, [n], ...)
// SELECT `s` = 1, `e` = 16, `c` = 260, `_isBigNumber` = true

DoingBigNumber.toString() fixes that:

connection.query(`SELECT ?;`, [n.toString()], ...)
// SELECT '26000000000000000'

But the problem is that quoting numbers causes MySQL to treat the value differently, and lose precision when doing arithmetic (bug):

SELECT 26000000000012345;            // 26000000000012345
SELECT '26000000000012345';          // 26000000000012345
SELECT 12345 + 26000000000000000;    // 26000000000012345
SELECT 12345 + '26000000000000000';  // 2.6000000000012344e16

Is there a way to use a "?" placeholder to produce an unquoted bigint value?

can it support set alias?

for example

var userId = 1;
var columns = ['username AS 用户名', 'email AS 邮箱'];
var sql     = SqlString.format('SELECT ?? FROM ?? WHERE id = ?', [columns, 'users', userId]);

How to make this work correctly?

Adding basic support for POINT

Does this make sense? I'm overwriting the function locally but perhaps this could land upstream. It's not the most elegant but enables one to insert or update a record with a point, just the way mysql retrieved it.

sqlstring.objectToValues = (obj, tz) => {
	let sql = "";

	for (let key in obj) {
		let val = obj[key];

		if (typeof val === "function") continue;

		if (typeof val == "object" && Object.keys(val).length == 2 && typeof val.x == "number" && typeof val.y == "number") {
			sql += (sql.length === 0 ? "" : ", ") + sqlstring.escapeId(key) + " = " + "GeomFromText('POINT(" + val.x + " " + val.y + ")')";
		} else {
			sql += (sql.length === 0 ? "" : ", ") + sqlstring.escapeId(key) + " = " + sqlstring.escape(val, true, tz);
		}
	}

	return sql;
};

Of course, it only works with 2D points, but for me it's 90% of geometries I use.

If the search word includes `%`...

const { format, escape } = require('sqlstring')
const searchWord = 'word%' // Only want to search end of like "abcword%".
const sql = format(
  `
SELECT * FROM ?? WHERE ?? LIKE ?
`,
  ['table', 'content', `%${escape(searchWord)}`]
)
console.log(sql)
// SELECT * FROM `table` WHERE `content` LIKE '%\'word%\''

Expected output

// SELECT * FROM tableWHEREcontentLIKE '%word\%'

Actual output

// SELECT * FROM tableWHEREcontentLIKE '%\'word%\''

Any idea?

Add API for unquoted escaped strings

My first attempt to use Node's mysql package went like this [paraphrasing code]:

const mysql = require('mysql');
const result = mysql.query('SELECT * FROM table LIMIT 3');
console.log(result);

This worked fine. My second attempt to use Node's mysql package went somewhat downhill:

const mysql = require('mysql');
const result = mysql.query('SELECT * FROM table WHERE description LIKE "%?%" LIMIT 3', [req.query.q]);
console.log(result);

I traced the problem back to this package. It can be characterised as one of two things:

  1. The question mark substitution is context-unaware. It should not wrap quote marks around strings if there already are quote marks around the question mark (i.e. it is preceded by an uneven number of any quote character). Or,
  2. There needs to be a second API exposed via node's mysql package which lets programmers perform an unquoted escape (and yes, I've seen #19). This will allow programmers to put escaped, user-sourced values within larger strings without having to strip off the quote marks.

As an aside, I looked at the code of this package and all three points of return from escapeString() duplicitously wrap the escaped string in quote characters, à la return "'" + val + "'"; — you ought to refactor to have this happen in a single place, e.g.:

function escapeString(val) {
  return "'" + escapeUnquotedString(val) + "'";
}

function escapeUnquotedString(val) {
  var chunkIndex = CHARS_GLOBAL_REGEXP.lastIndex = 0;
  var escapedVal = '';
  var match;

  while ((match = CHARS_GLOBAL_REGEXP.exec(val))) {
    escapedVal += val.slice(chunkIndex, match.index) + CHARS_ESCAPE_MAP[match[0]];
    chunkIndex = CHARS_GLOBAL_REGEXP.lastIndex;
  }

  if (chunkIndex === 0) {
    // Nothing was escaped
    return val;
  }

  if (chunkIndex < val.length) {
    return escapedVal + val.slice(chunkIndex);
  }

  return escapedVal;
}

This removes duplication and reduces the chances of bugs being introduced (e.g. a new return point being added but forgetting to wrap in quotes).

How to use a literal `?` in a formatted query?

If I use the format function on a query that contains a literal ? this gets replaced, as per the documentation. How can I escape the ? character so it doesn't get replaced?

const { format }  = require('sqlstring')

format(`select * from mytable where foo = 'https://example.com?a=b' and bar = ?`, ['xyz'])

The resulting output from this would be

select * from mytable where foo = 'https://example.com'xyz'a=b' and bar = ?

whereas I want

select * from mytable where foo = 'https://example.com?a=b' and bar = 'xyz'

Doc says ".query()" but that is error

Your documentation page has:

    var sql = SqlString.query('INSERT INTO posts SET ?', post);

But there is no ".query" function; this should say ".format".

sqlstring.escape() wraps input with double quotes, mysql driver throwing ER_PARSE_ERROR when queried.

I'm using sqlstring.escape() to escape unpredicted input, this function wraps the input with quotes '' which is causing node mysql driver to throw ER_PARSE_ERROR.

mysql server version: 8.0.23-0ubuntu0.20.04.1
sqlstring version: 2.3.2

Here is a code example:

let sqlstring = require("sqlstring")

let query = "CREATE DATABASE IF NOT EXISTS ?;"
let input = "my_new_db"

query = sqlstring.format(query, input) // turns into "CREATE DATABASE IF NOT EXISTS 'my_new_db';"
sqldriver.query(query) // Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''my_new_db'' at line 1

Thank you.

Formatting a SELECT list for INSERT INTO SELECT usage

If you have complex queries and you want to INSERT from a SELECT query, then you need to be able to set a SELECT list like this:

INSERT INTO `table`
SELECT
  NULL `id`,
  'Thomas' `name`,
  34 `age`
WHERE 1

What is currently the best way to create such a SELECT list from an object? The following statement does not work in this scenario and creates a key = value list:

sqlstring.format('INSERT INTO `table` SELECT ?? WHERE 1', { id: null, name: "Thomas", age: 34 });

Escaping without quotation marks

I'm using this library and mysql.js in a project of mine. Right now, I'm working on a usernamesearching function.

This is my current code:

/** Search for a name or part of names */
export function search ( nameScheme: string, callback: ( error: Error | void, matches?: User.Name.DB[] ) => void ): void {
    db.query( `SELECT * FROM usersNames WHERE name LIKE ${ sqlstring.escape( nameScheme ) }`, ( err, result ) => { // TODO: Insert wildcard chars in nameScheme
        if ( err ) return callback( err );

        callback( null, result );
    } );
}

After writing this, it struck me that the library doesn't give me the option to disable the automatic insertion of quotation marks around the passed string. I read through the issues here on github and understand why it's this way, but it makes the library useless in this case, which I believe to be quite common.
I would at least expect the option to disable automatic quotation marks.

How should I work around this? Is making this feature optional a possible thought for you?

Prople with json string

I parse object to string and save it to db.
But when I parse the string to object, it get error.

Example:
I save ["abc"] => '["abc"]', sqlstring format to '["abc"]'.
When I get from db again and json parse to object get a error:

VM47:1 Uncaught SyntaxError: Unexpected token \ in JSON at position 1
    at JSON.parse (<anonymous>)
    at <anonymous>:1:6

Feature: escaping html

Hi team,
First of all: thanks for this great tool.

Another cool feature would be to escape HTML tags directly from Node.js.

What do you think?

Kr,
Maxime

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.