I'm writing a node/express application, using mysql as a database.
One question upfront, that i can't really figure out yet: Is it possible to make multiple querys in one route?
Nevertheless, my problem is, that i want to use multiple variables in the database-query as follows, which does not work.
router.get('/:route_name', (req, res) => {
const route_name = req.params.route_name;
const route_name_join = req.params.route_name+".comp_id";
const queryhelper = [route_name, route_name_join];
const dbquery = "SELECT * FROM ? INNER JOIN users ON ? = users.id;";
sqldb.query(dbquery, queryhelper, function (err, result, fields) {
if (err) throw err;
res.render('categories/category',{
items : result
});
console.log(JSON.stringify(result));
});
I'm expecting to, for example in case of
.../categories/customers
"SELECT * FROM customers INNER JOIN users ON customers.comp_id = users.id;".
If i type in exactly that into dbquery, it does work, but as soon as i'm doing it using '?', i get an error that i'm having a mistake in my mysql syntax at
"SELECT * FROM 'customers' INNER JOIN users ON 'customers.comp_id' = users.id;"
I assume that there is a problem at customers.comp_id, but i simply can't figure out how to fix it.
You need to perform string substitution for this. Parameters can only be used for expressions -- they're replaced with the supplied value as a literal. You can't use a parameter to supply a table or column name.
So do:
const dbquery = `SELECT * FROM ${route_name} INNER JOIN users ON ${route_name_join} = users.id;`;
If these variables are coming from user input, make sure you whitelist them before using them in the query, to prevent SQL-injection.
Related
I'm following Node.js with sql examples on W3schools. here
It said the following code prevents SQL injections.
var adr = 'Mountain 21';
var sql = 'SELECT * FROM customers WHERE address = ' + mysql.escape(adr);
con.query(sql, function (err, result) {
if (err) throw err;
console.log(result);
});
When query values are variables provided by the user, you should escape the values.This is to prevent SQL injections, which is a common web hacking technique to destroy or misuse your database.
This was the explanation.
I want to understand how this is safe. (how this prevents SQL injections).
Also, how is the following code dangerous?
var sql = 'SELECT * FROM customers WHERE address = "Mountain 21"';
Unprotected string concatenation to generate a SQL statement is dangerous if the injected value (i.e. "Mountain 21") is source from an uncontrolled external source. For example, it is entered by a user.
Consider a plain string concatenation as follows:
var adr = <something accepted from an external source>
var sql = `SELECT * FROM customers WHERE address = "${adr}"`;
Then consider what might happen if the user entered the following into the text field:
Mountain 21"; delete all from customers; //
The query would become:
SELECT * FROM customers WHERE address = "Mountain 21"; delete all from customers; //"
If you ran that, you would probably end up with no customers in your table.
I am not personally familiar with the operation of the node.js mysql.escape function, but typically these sorts of functions "escape" special characters so they lose their "special-ness". For example, it might put a \ in front of the ; to remove it's significance as a statement separator.
Another more common example of what the escape function will typically do is convert a piece of text such as "O'Brien" to "O''Brien" (two single quotes is the way to specify a single quote in an SQL text string). A query that uses the "O'Brien" name would look something like this:
select *
from customers
where name = 'O''Brien';
The mySql.escape function will almost certainly provide the necessary conversion of "O'Brien" into "O''Brien" so that it can properly be run in an SQL query. Without the escape, the last line of the query would read:
where name = 'O'Brien';
which would result in a syntax error.
FWIW, The safest way is to use ? placeholders in your query for user supplied values (e.g. the address). This is a bit more cumbersome as you need to prepare your query, supply all of the values and then execute it. However, the benefit is that this is (should be?) completely immune to most, if not all, forms of "injection attack".
The basic flow for a parameterised query as per your example is (in java'ish pseudocode - as I don't about node.js's capabilities in this area) is:
val sql = "SELECT * FROM customers WHERE address = ?";
val preparedStatement = conn.prepareStatement(sql);
preparedStatement.setString (1, adr);
val resultSet = preparedStatement.executeQuery();
Most if not all databases support parameterised queries, most languages expose this capability, but not all do expose it (or at least not easily). Again, I'm not sure about node.js.
I hope this helps you.
var adr = 'Mountain 21';
var sql = `SELECT * FROM customers WHERE address = "${mysql.escape(adr)}"`;
con.query(sql, function (err, result) {
if (err) throw err;
console.log(result);
});
var sql = 'SELECT * FROM customers WHERE address = Mountain 21';
To
var sql = 'SELECT * FROM customers WHERE address = "Mountain 21"';
https://stackoverflow.com/a/33679883/11343720
The Grave accent is better quote, double quote
I am working on nodejs/express app. In my routes i need to query data from MySQL database. It's working fine with exceptions for the queries that have parameters in them.
Any query without parameters work as expected:
SELECT * FROM table WHERE col = 'b'
But the one below returns undefined
SET #a = 'b'
SELECT * FROM table where col = #a
I generate string for queries in separate function (not sure if that makes any difference).
Any help will be greatly appreciated.
I think you may be looking for the ? placeholder method, described at
https://www.w3schools.com/nodejs/nodejs_mysql_where.asp
var adr = 'Mountain 21';
var sql = 'SELECT * FROM customers WHERE address = ?';
con.query(sql, [adr], function (err, result) {
if (err) throw err;
console.log(result);
});
There's also multiple placeholders too, passed in as an array:
var name = 'Amy';
var adr = 'Mountain 21';
var sql = 'SELECT * FROM customers WHERE name = ? OR address = ?';
con.query(sql, [name, adr], function (err, result) {
if (err) throw err;
console.log(result);
});
I have a simple query that I want to pass an array inside which has 5 items. I am using the mysql module so I know it can be done but am not doing the synatx right and therefore getting a syntax error.
Below is the query:
`UPDATE table1 SET table1.col=0 WHERE (table1.col2) IN = (?) AND table1.id=(SELECT ...);`,[arr]
//arr = [1,2,3,4,5];
I have tried:
`UPDATE table1 SET table1.col=0 WHERE (table1.col2) IN = (?,?,?,?,?) AND table1.id=(SELECT ...);`,[arr]`
but I still get a syntax error.
Adding on to Bill Karwin's answer, you can also pass an array to the MySQL query against the '?' placeholder in the same way
WHERE table1.col2 IN (?)
//arr = [1,2,3,4,5];
Passing arr along with the query will convert it to the required SQL string. The mysql module uses the 'SqlString.arrayToList' function from 'sqlstring' module internally for the transformation:
https://github.com/mysqljs/sqlstring/blob/8f193cae10a2208010102fd50f0b61e869e14dcb/lib/SqlString.js#L60
In my case, array inside of array is needed to get this working. Just array variable as parameter passed only first number to sql.
Here is an example: (Notice ids inside of array as the second parameter)
var sql = "SELECT * FROM table WHERE ID IN (?)";
var ids = [1,2,3];
pool.query(sql, [ids], function (err, result, fields) {
if(err) {
console.log(err);
}
else {
console.log(result);
}
}
The syntax of the IN() predicate does not use =.
WHERE (table1.col2) IN = (?,?,?,?,?)
should be
WHERE table1.col2 IN (?,?,?,?,?)
Tip: you can (and should) check syntax yourself in the documentation, so you can get answers more easily than posting to Stack Overflow.
https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_in
I have a simple nodejs application which executes the following query.
select * from User where userid in (?)
The userids i get is a JSON array send from client side. How can i use that in this select query ? I tried
1. As itself but not working.
2. Convert this to Javascript array, not working
If you are using node module like mysql, the 2nd approach should work.
var query=select * from User where userid in (?);
var data=['a','b','c'];
var queryData=[data];
conn.query(query, queryData, function (err, results) {})
According to the documentation, "Arrays are turned into list, e.g. ['a', 'b'] turns into 'a', 'b'". So this approach should work (I have used it practically).
If you pass an array to the parameter it works with node mysql2. Parameters are already passed as arrays, so your first parameter needs to be an array [[1,2,3]].
select * from User where userid in (?)
const mysql = require('mysql2/promise');
async function main(){
let db = await mysql.createPool(process.env.MYSQL_URL);
let SQL = 'select * from User where userid in (?)';
let [res, fields] = await db.query(SQL, [[1,2,3]]);
console.log(res)
return res;
}
main().then(() => {process.exit()})
Revisiting this, since the original approach on the question is valid, but with some caveats. If your only escaped argument is the one on the IN clause, then you have to specify it as nested array; something like: [['usrId1', 'usrId2', 'usrIdN']]. This is because the un-escaping functionality expects an array, replacing each '?' with the corresponding array element. So, if you want to replace your only '?' with an array, that array should be the first element of all arguments passed. If you had more than one '?', the syntax is more intuitive, but at the end consistent and the same; in this case, you could have your arguments similar to: ['myOtherArgument1', 'myOtherArgument2', ['usrId1', 'usrId2', 'usrIdN'], 'myOtherArgument3']
Something like this could work!
// get your possible IDs in an array
var ids = [1,2,3,4,5];
// then, create a dynamic list of comma-separated question marks
var tokens = new Array(ids.length).fill('?').join(',');
// create the query, passing in the `tokens` variable to the IN() clause
var query = `SELECT * FROM User WHERE userid IN (${tokens})`;
// perform the query
connection.query(query, ids, (err, data) => {
// do something with `err` or `data`
});
You can do like this:
select * from User where userid in (?,?,?,?)
var array = [];
array.push(value);
array.push(value);
array.push(value);
array.push(value);
then use array as parameter that should be bind.
// get query string data with commas
var param=req.params['ids'];
//damy data var param = [1,2,3,4,5];
var array = params.split(",").map(Number);
//Note in select query don't use " and ' ( inverted commas & Apostrophe)
// Just use ` (Grave accent) first key off numeric keys on keyboard before one
con.query(`select * from TB_NAME where COL IN(?)`,[array],(err,rows,fields)=>{
res.json(rows);
});
let val = ["asd","asd"]
let query = 'select * from testTable where order_id in (?)';
connection.query(query, [val], function (err, rows) {
});
In Node, you need to put array in the array.
Update: Please see this answer. It is the correct way to do what is asked in the question.
The methods I have tried are:
Expand JSON array to a string in the required format. Concatenate it with query using '+'. (Beware of SQL injections)
Dynamically add '?' using length of JSON array holding user ids. Then use the array to provide user ids.
Both works. I then changed my logic with a better approach so now i don't need then 'in' clause anymore.
I am trying to figure how to create a "repository" file (for the symfony2 users) where i will put all my special behaviour queries.
I have a simple db shema with :
User (email)
RelationType (name)
UserXUserXRelation (fromUser, toUser, relation)
I want to retrieve the user with relation X on my user Y, so in sql it will looks like :
var sql = 'SELECT u.email, u.id
FROM user u
INNER JOIN UserXUser uxu ON uxu.toUser_id = u.id
WHERE uxu.relation_id = 1 AND uxu.fromUser_id = '+id
Where should i create this method ? I tried in the db/shema.js and app/models/user.js without success.
I found here Using arbitrary mySQL Query with JugglingDB? that i should use the shema object to use "query", where and how could I use it ?
Does the callback will look like this :
function(err, data) {...}
Is there some best practice about code separation in that case ?
Additional question : is there a way to bind parameters the PHP PDO way with jugglingdb ?
Thanks for all.
It is possible to execute any arbitrary query using jugglingdb and compoundjs. Providing you are using compoundjs, you can just use the compound.models.user.schema.adapter.query(). The compound object should be parsed into your user model, meaning you have access to many other methods. The way you would use this query in your model would be by creating a method inside the users model with the following code:
var sql = 'SELECT u.email, u.id
FROM user u
INNER JOIN UserXUser uxu ON uxu.toUser_id = u.id
WHERE uxu.relation_id = 1 AND uxu.fromUser_id = '+id
compound.models.user.schema.adapter.query(sql, function(err, data) {
if(error) {
console.log(error)
} else {
//Enjoy your data
}
})
As this overrides the jugglingdb quote escaper, beware of sql injection, make sure your id variable is checked and sanitised.