question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using prepared statements in runSql fails

See original GitHub issue

Maybe the problem is there isn’t an example in the documentation for runSql, so maybe I just dont know how to call it using the ? replacement parameters mentioned.

Incidentally, the docs seems to be missing a comma for both runSql() and all(): i.e. runSql(sql, [params,] callback) and all(sql, [params,] callback) after the params]

I am trying to add a user and grant permissions, and since I dont want to do this for every db OUTSIDE of db-migrate (I just want it to happen magically), I’m putting it in db-migrate. (but whether or not that belongs in db-migrate is not the issue I need to discuss here).

Trying to use ? replacement params, seems to give an error:

The Error: [ERROR] 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 '('readonly') IDENTIFIED BY ('specialpassword')' at line 1

The Migration script:

'use strict';

require('dotenv').config({silent: true, path: '.env'});
var async = require('async');
var dbm;
var type;
var seed;

/**
  * We receive the dbmigrate dependency from dbmigrate initially.
  * This enables us to not have to rely on NODE_PATH.
  */
exports.setup = function(options, seedLink) {
  dbm = options.dbmigrate;
  type = dbm.dataType;
  seed = seedLink;
};

exports.up = function(db, callback) {
  async.series([
    db.runSql.bind(db, "CREATE USER '?' IDENTIFIED BY '?'", [process.env["MYSQL_USERNAME_READONLY"], process.env["MYSQL_PASSWORD_READONLY"]], callback),
    db.runSql.bind(db, "GRANT SELECT ON * . * TO '?'", [process.env["MYSQL_USERNAME_READONLY"]], callback)
  ], callback);
};

exports.down = function(db, callback) {
  async.series([
    db.runSql.bind(db, "DROP USER '?'", [process.env["MYSQL_USERNAME_READONLY"]], callback)
  ], callback);
};

exports._meta = {
  "version": 4
};

Dry Run:

db-migrate --dry-run up
[INFO] dry run
CREATE TABLE IF NOT EXISTS `migrations` (`id` INTEGER  PRIMARY KEY AUTO_INCREMENT NOT NULL, `name` VARCHAR (255) NOT NULL, `run_on` DATETIME  NOT NULL);
SELECT * FROM `migrations` ORDER BY run_on DESC, name DESC;
SET AUTOCOMMIT=0;;
START TRANSACTION;;
CREATE USER '?' IDENTIFIED BY '?' [ [ 'readonly', 'specialpassword' ], [Function: r] ]
GRANT SELECT ON * . * TO '?' [ [ 'readonly' ], [Function: r] ]
INSERT INTO `migrations` (`name`, `run_on`) VALUES (?, ?) [ [ '/20161027150636-readonlyuser', '2016-10-27 11:07:05' ] ]
[INFO] Processed migration 20161027150636-readonlyuser
COMMIT;;
[INFO] Done

And in mysql:

mysql> CREATE USER '?' IDENTIFIED BY '?' [ [ 'readonly', 'specialpassword' ] ];
ERROR 1064 (42000): 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 '[ [ 'readonly', 'specialpassword' ] ]' at line 1

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:15 (9 by maintainers)

github_iconTop GitHub Comments

3reactions
PRR24commented, Nov 12, 2019

I’m having the same problem. Question mark placeholders don’t seem to be replaced. I’m using If anyone finds this in the future and wants a quick workaround, use this function instead of db.runSql:

const runSql = (db, query, params) => new Promise((resolve, reject) => {
    db.runSql(query, params, (err, data) => {
        if(err) reject(err)
        else resolve(data)
    })
})

More straight forward solution would be to add null as last parameter

db.runSql('INSERT INTO groups (id, isActive, isLocked, name, description, created) VALUES(?, TRUE, TRUE, ?, ?, NOW())', [id, name, description], null)
0reactions
wzrdtalescommented, May 23, 2019

And as a last node: db-migrate always uses the prepared statement like queries (so “replacement characters”). It is on the driver beneath what it does with that. Some use the escaping capabilities directly. Others automatically use prep statements by default.

What you do with runSql is completely on to you though. And it is just a direct pass through to the default query method of the concerned driver.

Read more comments on GitHub >

github_iconTop Results From Across the Web

MySQL prepared statements causing SQL syntax error
I am using prepared statements for my SQL insert query, and I am receiving the message that there is an error in the...
Read more >
Message SQL0516 Prepared Statement Not Found When ...
Database host server clients such as ODBC and JDBC might report message SQL0516 - Prepared Statement not found error.
Read more >
Prepared Statement Failure | MacLochlainns Weblog
I put together a quick example, which compiled fine but failed at run time. With some investigation it appears that either the MySQL...
Read more >
Avoid DoCmd.RunSQL in Microsoft Access - No Longer Set
execute? As I said if I don't use dbFailOnError, SQL Profiler shows it is updated with a prepared statement (and done properly, is...
Read more >
Mysqli SELECT query with prepared statements
To avoid even a possibility of the SQL injection or a syntax error caused by the input data, the query and the data...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found