Unknown SQL syntax error for ScalikeJDBC with SQL interpolation - mysql

To avoid DRY, I'm attempting to create an sql INSERT statement with variable column names and the data to fill those columns via ScalikeJDBC's sql interpolation:
case class MySQLInsertMessage(tableName:String, columns:List[String], values:List[String])
def depositMessage(msg: MySQLInsertMessage): Unit = {
NamedDB('MySQLMsgDepositor) localTx { implicit session =>
val sqlStmt = sql"INSERT INTO ${msg.tableName} (${msg.columns}) VALUES (${msg.values})"
println("The sql statement is: " + sqlStmt.statement)
println("The parameters are: " + sqlStmt.parameters)
sqlStmt.update().apply()
}
}
And when I call this with:
depositMessage(MySQLInsertMessage("My_Table", List("key", "email"), List("42", "user#email.com")))
the resulting console printout is:
The sql statement is: INSERT INTO ? (?, ?) VALUES (?, ?)
The
parameters are: List(My_Table, key, email, 42, user#email.com)
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_Table'
('key', 'email') VALUES ('42', 'user#emai' at line 1
java.sql.SQLSyntaxErrorException: 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_Table' ('key', 'email') VALUES
('42', 'user#emai' at line 1
I've tried wrapping the sql"..." as such instead:sql"""...""", but that doesn't seem to make a difference. I can execute the expected statement just fine in my MySQL workbench GUI. Any idea what my syntax error is?

Stemming from the hint from #scaisEdge, it seems ScalikeJDBC, when using its syntax, will always place single quotes around any parameterized values. And judging from here - https://github.com/scalikejdbc/scalikejdbc/issues/320 - this is a known issue.
With a MySQL INSERT statement (or others), your table name or column values may not have single quotes around them, though they are allowed to have backticks.
You can use their SQLSyntax.createUnsafely(str:String) method, or, if I wanted to do this as I was doing above, instead of using sql"...", I could use the old way of SQL(s"INSERT INTO ${msg.tableName} (${msg.columns.mkString(",")})")
Note - I believe both of these leave you open to injection attacks. Since, for me, this is a local API and you'd have to have the DB's username and password regardless to use it, I'm going with the createUnsafely way of doing things, with a little regex "cleaner" for a little inelegant piece of mind:
def depositMessage(msg: MySQLInsertMessage): Unit = {
NamedDB('MySQLMsgDepositor) localTx { implicit session =>
val unsafeSQLRegex = "[`'\"]".r
val table = SQLSyntax.createUnsafely(s"`${unsafeSQLRegex.replaceAllIn(msg.tableName, "")}`")
val columns = SQLSyntax.createUnsafely(msg.columns.map(value => unsafeSQLRegex.replaceAllIn(value, "")).mkString("`", "`, `", "`"))
val sqlStmt = sql"INSERT INTO $table ($columns) VALUES (${msg.values})".update().apply()
}
}
}

Related

MySQL Syntax with FROM with a var

I got some problems with my MySQL Syntax.
This is my code:
Config.SocietyMoneyTable = 'addon_account_data'
local result = MySQL.Sync.fetchAll("SELECT money FROM #account_table WHERE account_name = #society", {
['#account_table'] = Config.SocietyMoneyTable,
['#society'] = society
})
Error:
[ERROR] [MySQL] [maze_management] An error happens on MySQL for query "SELECT money FROM
'addon_account_data' WHERE account_name = 'society_police'": ER_PARSE_ERROR: You have an
error in your SQL syntax; check the manual that corresponds to your MariaDB server version
for the right syntax to use near ''addon_account_data' WHERE account_name = 'society_police''
at line 1
The Syntax does work when I change the #account_table to the string which is in Config.SocietyMoneyTable. But I need this configed so this is no solution for me.
A query parameter annotated with the # sigil can only be used in place of a scalar value, not a table name or other identifier. You need to use string formatting to get your configurable table name into the query, not a query parameter.
Something like the following:
Config.SocietyMoneyTable = 'addon_account_data'
local queryString = string.format("SELECT money FROM `%s` WHERE account_name = #society",
Config.SocietyMoneyTable)
local result = MySQL.Sync.fetchAll(queryString, {
['#society'] = society
})
I have not tested this code, and I don't use Lua often, so if there are mistakes I will have to leave it to you to resolve them. But it should at least show the principle: identifiers (like table names) must be fixed in the query string, not added as query parameters.

I cannot make binding work with Diesel on MariaDB

I simply wanted to pass an argument to my sql query.
let query = sql("SELECT resa_comment FROM reservation WHERE resa_id = ? ");
let query2 = query.bind::<Integer, _>(1286);
let result : Result<std::vec::Vec<String>, _> = query2.load(&connection);
dbg!(result);
But the result is
[src/bin/show_posts.rs:36] result = Err(
DatabaseError(
__Unknown,
"You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near \'?\' at line 1"
)
)
The SQL query is correct because when I replace the "?" with a constant and remove the "bind", I get a correct result.
I know that I can map the table to a Rust structure but my goal is to pass complex requests with arguments so I was testing Rust and Diesel.
Is there something I missed ? Thanks.
The bind method does not replace question mark, it appends the value to the end of the query. So it should look like this:
let query = sql("SELECT resa_comment FROM reservation WHERE resa_id = ");
// ...
If you need to put value in the middle of the query, then you need to chain bind and sql calls, such as:
sql("SELECT resa_comment FROM reservation WHERE resa_id = ")
.bind::<Integer, _>(1286)
.sql(" AND something > ")
.bind::<Integer, _>(1);
But note that you should avoid writing raw sql if it is not necessary.

Escaping values in Mysqljs

https://github.com/mysqljs/mysql#introduction
mysqljs is pretty inconsistent with escaping values, or I am not understanding the docs.
Error:
this.table = 'elections';
mysql.query('SELECT * FROM ? where name = ?', [this.table, this.votesTable]
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax error:
'SELECT * FROM \'elections\' where name = \'prim1000\''
But this works:
`mysql.query('UPDATE elections SET updated_at = ? WHERE name = ?', [this.getTimeStamp(), this.votesTable])
But if I remove "elections" in the query above and put "?" instead it will throw an error. So the following won't work.
mysql.query('UPDATE ? SET updated_at = ? WHERE name = ?', [this.table, this.getTimeStamp(), this.votesTable])
Referring to the documentation page you linked to, under the section "Escaping query identifiers", you should be able to do this:
mysql.query('SELECT * FROM ?? where name = ?', [this.table, this.votesTable]
Most SQL frameworks do not allow parameters to be used for anything besides individual values. I.e. not table identifies, column identifiers, lists of values, or SQL keywords. The mysqljs library is uncommon in that it has support for quoting identifiers and key/value pairs.
Re your comment:
The ?? placeholder is for identifiers. Identifiers must be quoted differently from values. In MySQL, a string value is quoted like 'string' but an identifier is quoted with back-ticks.
SELECT * FROM `mytable` where name = 'myname'
The mysqljs class uses the ?? as a special placeholder for an identifier, so you can tell the class it must be quoted with back-ticks.

Quering with Python Connector with variables

i am new in python and i have a simple issue that i cannot resolve.
I am in windows platform and unfortunately i cannot change this cause of work. I have to connect to many mysql tables and do sort of things with the extracted data. The code that i have:
conn = mysql.connector.Connect(host='<ip>',user='<user>',\
password='',database='<my database>')
c = conn.cursor()
c.execute ("select field from TABLE")
results = c.fetchall()
for row in results:
c.execute("select * from otherTable where nodo = %s",(str(row[0])))
if c.rowcount == 0:
doSomething()
else:
doOtherThing()
c.close()
when I run this with Python34 i got the error:
"you have an error in your sql synthax; check the manual that corresponds to your mysql server version for the right synthax to use near '%s' at line 1
thanks
you need to put single quotes around your %s like this: c.execute("select * from otherTable where nodo = '%s'",(str(row[0])))
you should also consider putting your query in a variable and then executing it like so:
query = ("select * from otherTable where nodo = '%s'",(str(row[0])))
c.execute(query)
This way helps prevents potential sql injection attacks and allows you to do a print(query) so you can debug the sql statement if you are getting errors.

SQL query dosnt know variables

I am trying to query some tables in my database using a simple dropdown in which the name of the tables are listed. the query has only one record result showing the name and age of the youngest institute registered in the database!
$table = $_GET['table'];
$query = "select max('$table'.est_year) as 'establish_year' from '$table' ";
I need to send the name of the table as variable to the querier php file. no matter the method is GET or POST in both ways when I put the variable name in the query statement, it gives the 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 '.order) as 'last' from 'customers'' "
You are wrapping the table name in single quotes, which is not valid SQL (that's the syntax for strings, not table names). You should either not wrap the name at all or else wrap it in backticks (on the american keyboard layout, that's the key above TAB).
You should also not quote the alias established_year:
select max(`$table`.est_year) as establish_year from `$table`
Also, your code is vulnerable to SQL injection. Fix this immediately!
Update (sql injection defense):
In this case the most appropriate action would likely be to validate the table name against a whitelist:
if (!in_array($table, array('allowed_table_1', '...'))) {
die("Invalid table name");
}
single quote ('), in mysql, it represents string value.
SELECT *, 'table' FROM `table`;
Demo
So your query should be
$table = $_GET['table'];
$query = "select max($table.est_year) as 'establish_year' from $table ";
Also read old post, phpmyadmin sql apostrophe not working.
Also your code is vulnerable to SQL Injection. You can use something like this
//Function to sanitize values received from the form. Prevents SQL injection
function clean($str) {
    $str = #trim($str);
if(get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
return mysql_real_escape_string($str);
}
$firstName = clean($_POST['firstName']);
$lastName = clean($_POST['lastName']);
.
.
.