Can double-hyphens in strings be escaped? - mysql

i have an delphi application that sends MySQL queries to our server. The following query fails
INSERT INTO `KPT`.`Internalorders`
(`InternalOrderId`, `UserId`, `Text`, `MailSent`,
`Done`, `PartlyDone`, `Ordered`)
VALUES (0, NULL, '- Teststring -- Teststring -', NULL, 1, 1, 1)
with this error message:
MySQL Error Code: (1064)
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 ''- Teststring' at line 1
It looks like the string gets wordwrapped internally in the third-party-components i use for database access (MySQLDAC) and forms to
'- Teststring
-- Teststring -'
which would lead to treating the second part as a comment. Because i dont have the possibility to change the third-party tools, i'm hoping that theres is a way to escape double-hyphens.
Is there?

You can solve this using parameters and it will yield you several big advantages:
no problems with strings and quotes (as you found out)
resiliency against SQL injection.
Reusable & fast update queries (just change the parameter value and execute again)
Query is easier to read and maintain.
So your query becomes:
INSERT INTO `KPT`.`Internalorders`
(`InternalOrderId`, `UserId`, `Text`, `MailSent`,
`Done`, `PartlyDone`, `Ordered`)
VALUES (0, NULL, :Text, NULL, 1, 1, 1)
Assign the Text parameter via the Params object or use the ParamByName method on the query object and execute it.

Related

JPA - Run sql NativeQuery of 'insert into' with special charters is failed

I'm using hibernate and mysql
when I run the following statement in mysql it works perfectly:
INSERT INTO table1 (name, is_visited) VALUES ('visit our site \'n\' days',true);
However, When I run with hibernate native query I get error:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: 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 'days',true)' at line 1.
Here is the java code:
String query = "INSERT INTO table1 (name, is_visited) VALUES ('visit our site \'n\' days',true)";
Query nativeQuery = getEntityManager().createNativeQuery(query);
nativeQuery.executeUpdate();
When I change the query statement to
"INSERT INTO table1 (name, is_visited) VALUES ('visit our site \'n days',true)";
it works.
looks like there is an issue with \'n\'
any idea?
What is happening here is that the following query is correctly escaping the single quotes when run directly on MySQL:
INSERT INTO table1 (name, is_visited) VALUES ('visit our site \'n\' days', true);
This works on MySQL because one valid way to escape literal quotes on MySQL is to escape them with backslash. However, doing this inside a Java string means that the \' are not being passed to MySQL. Instead, Java consumes the single backslash, and just the single quotes make it across to the database. I suggest using the other method of escaping single quotes here, which is to double them up:
String query = "INSERT INTO table1 (name, is_visited) VALUES ('visit our site ''n''x days', true)";
While it might be possible to escape the backslashes from Java, that seems confusing to me, because it requires keeping track of escaping across both your Java and database layer.
As another general comment, if you used the Hibernate ORM layer to do the insert, or used a prepared statement, you wouldn't have to worry about this escaping problem.

MySQL code to insert a username and password into a table if a licencing key exists in that table

I am trying to accomplish a simple licensing system in golang and have tried numerous ways to get it to work. Basically, I have input a couple of random licensing keys into my database and my golang program should check to see if the user-input key exists and if it does then add the user specified username and password into the database to login later.
This is the code that I have that hasn't been working:
"IF EXISTS (SELECT * FROM login WHERE LK = "+reglicenceEntry.Text()+") THEN
INSERT INTO `login` (`Username`, `Password`, `LK`) VALUES
('"+regusernameEntry.Text()+"', '"+regpasswordEntry.Text()+"', ''); "
This is the golang error:
Error 1064: 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 'IF EXISTS (SELECT * FROM login WHERE LK = '5qp515YHXEmSDzwqgoJh') THEN INSERT IN' at line 1
Thanks so much!
MySQL syntax doesn't support IF...THEN constructs except within stored routines and triggers and events. See https://dev.mysql.com/doc/refman/8.0/en/sql-syntax-compound-statements.html
I suggest an alternative solution for your code:
INSERT INTO `login` (`Username`, `Password`, `LK`)
SELECT ?, ?, ''
FROM `login`
WHERE `LK` = ?
LIMIT 1
If your login table does not have the LK value, the SELECT above will return 0 rows, therefore it will not insert anything.
If your login table has the LK value, the SELECT above will return at least 1 row (and I limit it to 1), therefore it will insert a row. The row it inserts is comprised of your username and password, and a blank string for the LK.
I showed use of parameter placeholders. You should use parameters in SQL instead of concatenating variables into your query. This is good practice to avoid accidental SQL injection. See http://go-database-sql.org/prepared.html for examples.
The purpose of using parameters is to avoid SQL injection problems. See my answer to What is SQL injection? for an explanation of SQL injection.
Or my presentation SQL Injection Myths and Fallacies (or youtube video).
When using parameters, you do two steps.
The first step to prepare a query with placeholders (?) where you would otherwise concatenate variables into your SQL query.
The second step is to execute the prepared query, and this is the time you pass the variables to fill in the placeholders.
The point is to keep variables separate from your query, so if there's anything in the variable that could unintentionally change your SQL syntax (like imbalanced quotes), it is never combined with the SQL. After you do the prepare, the SQL has already been parsed by the MySQL server, and there's no way to change the syntax after that.
MySQL remembers which parts of the query need to be filled in, and when you pass variables during the execute step, MySQL fills in the missing parts of the query using your values — but this happens within the MySQL server, not in your application.
Thus the dynamic parts of the query — your variables — are kept separate from the SQL syntax and you avoid SQL injection problems.
For your task described in your question, it would look something like this (I have not tested this Go code, but it should put you on the right path).
stmt, err := tx.Prepare("INSERT INTO `login` (`Username`, `Password`, `LK`) SELECT ?, ?, '' FROM `login` WHERE `LK` = ? LIMIT 1")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
_, err = stmt.Exec(regusernameEntry.Text(), regpasswordEntry.Text(), reglicenceEntry.Text())
if err != nil {
log.Fatal(err)
}
The order of parameters is important. The variables you pass to Exec() must be in the same order that the ? placeholders appear in your prepared SQL statement. They are matched up, one for one, in the same order, by the MySQL server.
Do not put quotes around the placeholders in your prepared SQL statement. That will work as a literal string '?' in SQL. Use an unquoted ? character for a placeholder. When it gets combined by MySQL in the server, it will work as if you had put quotes around the value like a string — but with no risk of SQL injection even if that string value containing special characters.
Here's another site that gives more code examples: https://github.com/go-sql-driver/mysql/wiki/Examples
The Exec() function is for executing SQL that has no result set, like INSERT, UPDATE, DELETE. There are other functions in the Go SQL driver like Query() and QueryRow() that also accept parameter arguments. You'd use these if your SQL returns a result set.

Getting MySQL Error #1064 when trying to insert data

I'm trying to follow a tutorial on this website, but when I try to insert the below statement I get the following error:
#1064 - 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
'`INSERT INTO login_admin (user_name, user_pass)
VALUES
(
‘admin’, SHA(‘a`' at line 7
INSERT INTO login_admin (user_name, user_pass)
VALUES
(
‘swashata’, SHA(‘swashata’)
)
INSERT INTO login_admin (user_name, user_pass)
VALUES
(
‘admin’, SHA(‘admin’)
)
You're trying to run two queries at once, not one. Each INSERT statement is a separate query. You have to separate queries with a delimiter (;).
In fact, unless you have some bad settings on your server (allowing multiple queries at once), you can't even do that and need to run them as two separate queries, or combine them using multiple VALUES lists.
Also, please note that you cannot use tick marks (‘) to indicate a string value. You need to use single quotes (') instead.
The best approach is to rewrite your queries as:
INSERT INTO login_admin (`user_name`, `user_pass`) VALUES
( 'swashata', SHA('swashata') ),
( 'admin', SHA('admin') )
Finally, I really hope you aren't using SHA to generate passwords. That's not secure. Use PHP's built-in password functionality.

Special Characters in Scriptella, jexl

I want to extract a text field from a database and insert it into some other database. So while extracting I used the REPLACE(message_text,'\'', '"') while selecting the test. I gave me an error. I changed that from my select statement and did it while initiating the global variable.
etl.globals['message_text'] = message_text;
still I'm getting an error at the insert statement
insert into lcs_al_user_likes(user_id,liked_user_id,post_content,loop_id) values('${etl.globals['posted_by']}','${etl.globals['liked_user_id']}','${etl.gl‌​obals['message_text']}',?batchLoopCounter);
saying
*You have an error in your SQL syntaxcheck the manual that corresponds to your MySQL server version for the right syntax to use near 'message_text']}')' at line 1*
I think it is not getting the global variable. That I say because when i print its value using log it just gives me
${etl.globals['message_text']}
as output. So please help me out here.
<query connection-id="lcsDBConnection">
SELECT forum_topic_post_id AS forum_topic_post_id, posted_by AS posted_by,message_text as message_text FROM lcs_tbl_forum_topic_post WHERE like_count>0 LIMIT ?batchSize OFFSET ?queryCounter ;
<script connection-id="jexl">
etl.globals['forum_topic_post_id'] = forum_topic_post_id;
etl.globals['posted_by'] = posted_by;
etl.globals['message_text'] = message_text.replace('\'', '"');
</script>
It looks like the problem is in INSERT statement, you should use prepared statement
parameters escaping:
INSERT INTO lcs_al_user_likes(user_id,liked_user_id,post_content,loop_id) values(?{etl.globals['posted_by']},?{etl.globals['liked_user_id']},?{etl.gl‌​obals['message_text']},?batchLoopCounter);
BTW As I understand, your original problem was quotes breaking the insert statement, so in this case with ?{parameter} syntax you don't need to use replace(...) function at all.

Perl script executing mysql commands?

I'm new to Perl and was attempting to write a script on a RHEL box that will auto-configure a vanilla DB for new sites we create on our host. I already have the connect statement working and I'm able to connect and create a DB from the script (Used $dbh->do( qq(CREATE DATABASE $dbcreate) ); Is this the best way???), but I have a couple that I haven't been able to figure out how to make them work.
These are the mysql commands which I'm having issues with. Any suggestions? Thanks!
$dbh = DBI->connect("DBI:mysql:$db:$host", $user, $pass);
$dbh->do( qq(CREATE DATABASE $dbcreate) );
$dbh->do(qq(GRANT SELECT , INSERT , UPDATE , DELETE , CREATE , DROP , INDEX , ALTER , CREATE TEMPORARY TABLES , CREATE VIEW , SHOW VIEW , CREATE ROUTINE, ALTER ROUTINE, EXECUTE ON `$dbcreate` . * TO 'moodle'#'%'`) );
$dbh->do( qq(FLUSH PRIVILEGES) );
$dbh->do( qq($dbcreate < MySQL_pristine.sql) );
$dbh->do( qq(USE $dbcreate) );
$dbh->do( qq(UPDATE md1_label SET content = REPLACE( content, "pristine", "$dbcreate")) );
$dbh->do( qq(UPDATE md1_label SET contents = REPLACE( contents, "pristine", "$dbcreate")) );
$dbh->do( qq(UPDATE md1_label SET questiontext = REPLACE( questiontext, "pristine", "$dbcreate")) );
DBD::mysql::db do failed: 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 'GRANT SELECT , INSERT , UPDATE , DELETE , CREATE , DROP , INDEX ,�' at line 1 at create-auto-db.pl line 52.
DBD::mysql::db do failed: 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 'test3 < MySQL_pristine.sql' at line 1 at create-auto-db.pl line 54.
DBD::mysql::db do failed: Table 'test3.md1_label' doesn't exist at create-auto-db.pl line 56.
DBD::mysql::db do failed: Table 'test3.md1_label' doesn't exist at create-auto-db.pl line 57.
DBD::mysql::db do failed: Table 'test3.md1_label' doesn't exist at create-auto-db.pl line 58.
The main issue you've encountered is interpolation of strings with containing an at-sign. If you have something like qq{Here is my email: test#hotmail.com} - this fails because it tries to put a list variable #hotmail, which doesn't exist. Either use a backslash to escape it (i.e., qq{Here is my email: test\#hotmail.com}), or if you don't need to interpolate any variables, use the non-interpolating quote q{...}.
Having said that, you need to be a little careful with some of these statements. You're putting variable values into these SQL statements, and that is a risk for SQL injection attacks. I'd use $dbh->quote($dbcreate) to get a string version, and $dbh->quote_identifier($dbcreate) to get an identifier version of the value of $dbcreate, and embed those values in. This is much safer, as it will avoid somebody doing a Bobby Tables on you and giving you a database name like: db'; DROP TABLE mysql.user; '; or similar. DBI provides both string and identifier quoting, so you can get the right kinds of quoting as needed. For example:
my $quoted_id_dbcreate = $dbh->quote_identifier($dbcreate);
$dbh->do( qq(USE $quoted_id_dbcreate) );
Placeholders are usually better, but some of these admin statements probably won't support them, so using proper quoting to inject the values is likely to be necessary.
Two things stand out to me.
$dbh->do(qq(GRANT SELECT , INSERT , (snip), EXECUTE ON '$dbcreate' . * TO 'moodle'#'%'`) );
...you've got a trailing backtick that you probably don't intend.
$dbcreate < MySQL_pristine.sql
...isn't quite what you want. I think you're trying to do is to read that file in Perl, and iterate over each contained SQL statement, calling "$dbh->do()" against it. If you're very lucky, you have one line per statement in that .sql file.