[MDEV-13925] CONNECT engine table_type=JDBC error with UPDATE statements having single quotes Created: 2017-09-27 Updated: 2018-01-24 Resolved: 2017-11-03 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Storage Engine - Connect |
| Affects Version/s: | 10.1.27 |
| Fix Version/s: | 10.0.34, 10.1.29, 10.2.11, 10.3.3 |
| Type: | Bug | Priority: | Major |
| Reporter: | Robert Dyas | Assignee: | Olivier Bertrand |
| Resolution: | Fixed | Votes: | 0 |
| Labels: | centos7 | ||
| Description |
|
If I try to update a JDBC connect table with a string that includes a single quote I get the following error: (conn:299) Got error 122 'ExecuteUpdate: com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near 's'. n=-1' from CONNECT) #1296 We are sending the UPDATE statement to MariaDB with a prepared statement if that makes any difference. |
| Comments |
| Comment by Robert Dyas [ 2017-09-27 ] | |||||
|
Note this happens with both the Postgres and Microsoft SQL server drivers... so not driver specific. Further still, CONNECT appears to be escaping the single quote character with \' rather than doubling the single quote character as is normal in SQL ("Single quotes are escaped by doubling them up"). | |||||
| Comment by Robert Dyas [ 2017-10-29 ] | |||||
|
Olivier... What is the status of this? | |||||
| Comment by Olivier Bertrand [ 2017-10-29 ] | |||||
|
Could you publish the query you are using? | |||||
| Comment by Robert Dyas [ 2017-10-29 ] | |||||
|
You can see below it is doing a \' instead of doubling up on the single quote character.
| |||||
| Comment by Robert Dyas [ 2017-10-29 ] | |||||
|
Woops. I'm being stupid here. I'll try and fix on my end and verify the right behavior. | |||||
| Comment by Olivier Bertrand [ 2017-10-29 ] | |||||
|
It should be fixed for UPDATE, depending on the version you're using (see However, some servers, including Oracle, do not accept escaping the quote with a backslash. Just doubling the quote is accepted by all servers. Checking further, I realize that the problem still exists with select statements and where clauses containing a quote (doubled). Waiting for a fix, the turnaround is to specify it by 4 quotes!
Maybe doing \'\' also work (I did not try yet) | |||||
| Comment by Robert Dyas [ 2017-10-30 ] | |||||
|
Yes, I was generating the \' in the where clause NOT connect. I just fixed our code, but unfortunately still not right. This is what our code is now submitting:
You can see the doubled up single quote in the LIKE expression... Microsoft SQL Server, Postgres, and even a remote MySQL via JDBC connect doesn't like that. Your connection to this Azure test instance should still be valid for testing. So it must be transforming it somehow? | |||||
| Comment by Olivier Bertrand [ 2017-10-31 ] | |||||
|
Indeed, there is no turnaround. When specifying four quotes, the query send to the external server is allright but when MariaDB applies this false where clause, no lines are returned. BTW, when telling that some servers "don't like that" what do you mean? That the query is not accepted or just that no lines are returned? I have made a fix locally and tested in on the test_Nvarchar_type table in which I had inserted a row by:
and executed successfully with SQL Server the following queries:
My fix doubles the quote in the query that is sent to the server but it remains single in the original MariaDB query. | |||||
| Comment by Olivier Bertrand [ 2017-10-31 ] | |||||
|
Actually, there is a turnaround. This is to prevent the where clause to be included in the query sent to the remote server and have it executed locally by MariaDB:
Of course, this is not as good performance wise but the part of the where clause not containing a single quote can still be sent to the remote server:
| |||||
| Comment by Robert Dyas [ 2017-10-31 ] | |||||
|
Your example above won't work with ANSI QUOTES turned on, correct? (this is our default configuration) I think we can forget about the WHERE clause issues for now... and just get UPDATE statements with single quote characters working (100x more common for us). In the current version, the following generates an error if the data being SET contains a single quote. This is with bound variables, so we don't control the escaping.
The error from connect is:
This is the main one to deal with (at least for our use case). Trying to keep it simple to not introduce more bugs. | |||||
| Comment by Olivier Bertrand [ 2017-11-01 ] | |||||
|
But it does as well with either:
About the UPDATE case, could you publish the exact sequence of statements you're using? So I can try to reproduce and debug it. | |||||
| Comment by Robert Dyas [ 2017-11-02 ] | |||||
|
On MS SQL when I do an update to a varchar column that has a single quote, I get the following error:
The SQL shows as the prepared statement like this:
The Java code that binds looks like this (using 1.6 series driver if that matters):
| |||||
| Comment by Olivier Bertrand [ 2017-11-02 ] | |||||
|
You did not tell me what command you used. Normally CONNECT is not using prepared statements. | |||||
| Comment by Robert Dyas [ 2017-11-02 ] | |||||
|
Very interesting... When I use the mysql command line tool and issue the following command it WORKS! (and shows the correct result on query)
But when I change it to:
it fails with the same error:
So clearly the MariaDB JDBC driver is escaping single quotes like \' before sending it to the server.... which is valid for MariaDB but not optimal when sending to a remote server via CONNECT. Maybe the solution is to change our code base so that we don't use prepared statements, or maybe this is or can be fixed in a MariaDB JDBC driver update? Note this also explains some of the other strange behavior such as with double quotes where a \ is added. For example updating a record (with a prepared statement) that has a " (double quote char) in it causes it to save as \" From the mysql command line tool, the following works and gives the correct result when you select it:
but the prepared statement adds a backslash before the double quote: which stores it in the remote database as \" !!! This all makes sense now. Also \n inserts on the remote system as a \ and n character - i.e. not newline. I don't see the need to escape ANY character in a single quoted string EXCEPT the single quote char itself? Do you agree? Also, I don't see how CONNECT can tell if \" really means backslash quote or is an escaped double quote. So two possible fixes I can see: | |||||
| Comment by Olivier Bertrand [ 2017-11-02 ] | |||||
|
I am more and more puzzled by your comments. First of all CONNECT does not use prepared statement for UPDATE. When you say: updating a record (with a prepared statement) what do you mean? Show me how you do it. | |||||
| Comment by Robert Dyas [ 2017-11-02 ] | |||||
|
In Java, via the JDBC driver:
The MariaDB JDBC driver that the client app uses to connect to MariaDB obviously escapes certain characters in the string. The prepared statement is at the CLIENT level, the MariaDB JDBC driver encodes the data and passes it to the server, then I assume it calls CONNECT. So the problem is WAY upstream from CONNECT. Instead of using prepared statements, our client application could generate the SQL statements directly and escape the values itself (rather than rely on the client JDBC driver). Maybe I'm not explaining this well - nothing to do with CONNECT and nothing to do with CONNECT's use of JDBC... its the CLEINT app's use of JDBC is where this is going wrong. Then again, IF connect has access to the unescaped values, maybe it could use the JDBC prepared statement calls to issue the remote commands.... this way the escaping would be handled by the driver and should take into account database-specific encoding requirements. | |||||
| Comment by Olivier Bertrand [ 2017-11-02 ] | |||||
|
If I understand well, your client does not use a MariaDB client and a JDBC CONNECT table, but directly access JDBC from a Java client. Right? If so, this is not the place for this case here, it should be placed in a MDEV case against the MariaDB JDBC driver. About the way CONNECT handles UPDATE, it was buggy because the way the original query was retrieved, the quotes were escaped. However, it is now fixed (see |