I'm optimizing some SQL queries. And I've written them to use batches. Integration tests run fine, and everything is happy. But then I learn that MySQL doesn't give a performance increase unless rewriteBatchedStatements is enabled.
So I modified my connection string to include rewriteBatchedStatement, but I start getting a MySQLSytaxErrorException. When I remove rewriteBatchedStatement from the connection String, the exception goes away.
SQL: INSERT INTO rawdata.scales (ID, NAME) VALUES (?, ?)
Exception:
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 ';INSERT INTO rawdata.scales` at line 1
Curiously, this only happens on the first SQL statement that runs in the tests I've setup. All the others run fine.
Why would enabling this feature add a semi-colon to the front of my SQL?
There is a known issue in Connector/J 5.1.40 up to and including at least 5.1.43 which causes MySQLSytaxErrorException to be thrown on inserts when rewriteBatchedStatement is enabled.
See https://bugs.mysql.com/bug.php?id=84813
I have been able to reproduce this in statements with a trailing semicolon, e.g.
INSERT INTO rawdata.scales (ID, NAME) VALUES (?, ?);
Removing the trailing semicolon fixes the issue in my case.
Related
I recently updated a project's jooq version from 3.13.5 to 3.14.15. I've rerun jooq-codegen. I'm using MySQL 5.7.
When running one of my tests - it performs a DAOImpl.exists. That call generates the following exception:
org.jooq.exception.DataAccessException: SQL [select `count`(*) from `users` where `users`.`id` = ?]; 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 '*) from `users` where `users`.`id` = 1094' at line 1
at org.jooq_3.14.15.MYSQL.debug(Unknown Source)
at org.jooq.impl.Tools.translate(Tools.java:2903)
at org.jooq.impl.DefaultExecuteContext.sqlException(DefaultExecuteContext.java:757)
at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:389)
at org.jooq.impl.AbstractResultQuery.fetchLazy(AbstractResultQuery.java:453)
at org.jooq.impl.AbstractResultQuery.fetchLazy(AbstractResultQuery.java:422)
at org.jooq.impl.AbstractResultQuery.fetchLazyNonAutoClosing(AbstractResultQuery.java:436)
at org.jooq.impl.AbstractResultQuery.fetchOne(AbstractResultQuery.java:613)
at org.jooq.impl.AbstractResultQuery.fetchOne(AbstractResultQuery.java:565)
at org.jooq.impl.SelectImpl.fetchOne(SelectImpl.java:3034)
at org.jooq.impl.DAOImpl.existsById(DAOImpl.java:300)
at org.jooq.impl.DAOImpl.exists(DAOImpl.java:288)
The problem is that count has backticks. It should be select count(*) from `users` where `users`.`id` = ?
Has anyone run into this before and know how to fix it? TIA
You probably specified RenderQuotedNames.ALWAYS and ran into this problem? https://github.com/jOOQ/jOOQ/issues/9931
The setting ALWAYS is misleading. It really means literally always, though people probably read it as ALWAYSISH_I_E_ONLY_WHEN_IT_MAKES_SENSE. Probably a naming design error, but what you want is EXPLICIT_DEFAULT_QUOTED, see the documentation:
https://www.jooq.org/doc/latest/manual/sql-building/dsl-context/custom-settings/settings-name-style/
RenderQuotedNames
ALWAYS: This will quote all identifiers.
EXPLICIT_DEFAULT_QUOTED: This will quote all identifiers, which are not explicitly unquoted using DSL.unquotedName().
EXPLICIT_DEFAULT_UNQUOTED: This will not quote any identifiers, unless they are explicitly quoted using DSL.quotedName().
NEVER: This will not quote any identifiers.
COUNT in DSL.count()is an explicitly unquoted name, and ALWAYS will override that.
I'm running a script to insert some data in a MySQL database, and it runs properly in the MySQL workbench. However, when I try to run it from Java via the JDBC, I get an error. The script is:
INSERT INTO `pa_record` (`username`, `pa_record_type`, `record_time`) VALUES (?, ?, CURRENT_TIMESTAMP);
SET #record_id := 1;
INSERT INTO `pa_crud` (`pa_record_id`, `table_name`) VALUES (#record_id, ?);
The error I get from the JDBC is
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 'SET #record_id := 1;
INSERT INTO pa_crud (pa_record_id, table_name) VALUES' at line 2
Any ideas?
Many (most?) database access libraries do not allow multiple statements in a single execute; those that do, usually need to have the feature activated with a setting change. It's likely not complaining about the SET, but that you had anything after the end of the first query at all.
Whenever I try to execute a prepared statement, it throws a MySQLSyntaxErrorException with:
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 Information (stamp) VALUES ('2017-01-24 1' at
**line 1
It looks like it's getting cut off at the colon ":' of the time part of the format.
String sql = "INSERT INTO Information (stamp) VALUES (?);"
...
statement.setTimeStamp(1, new Timestamp(system.currentTimeMillis()));
I've tried a bunch of different ways of getting a system time stamp and converting it to java.sql.Timestamp, but it continues to throw that same error.
My table has a column stamp of type TIMESTAMP.
Ah I found the problem. I didn't realize that prepared statements did not allow multiple queries. My options were to use two statements or add on a connection parameter while sending my connection request
?allowMultipleQueries=true. This allows multiple queries separated by a semi-colon. Thanks yall! –
I have a strange problem. I'm executing insert using prepared statement like this:
try (Connection connection = connectionPool.getConnection();
PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { //TODO: caching of PS
int i = 1;
ParameterMetaData pmd = ps.getParameterMetaData();
...
} catch (SQLException e) {
throw new TGFIOException("Error executing SQL command " + sql, e);
}
Insert statement is like this:
insert into dbo.CurrencyRates(RateDate, CurrencyID, Rate) values ( ?, ?, ? )
Unfortunately it fails with following exception:
com.microsoft.sqlserver.jdbc.SQLServerException: com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near the keyword 'WHERE'.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:190)
at com.microsoft.sqlserver.jdbc.SQLServerParameterMetaData.<init>(SQLServerParameterMetaData.java:426)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.getParameterMetaData(SQLServerPreparedStatement.java:1532)
at com.jolbox.bonecp.PreparedStatementHandle.getParameterMetaData(PreparedStatementHandle.java:246)
There is no WHERE in the statement, so I am puzzled why it fails on metadata extraction...
EDIT:
SQL Server = 10.50.2500.0 Express Edition,
Driver = sqljdbc4.jar from 4.0 package
Also, I am using getParameterMetaData because I need to set some params to null and the preferred method is to use setNull() where you need SQLType.
EDIT2:
I've tested with Driver sqljdbc41 from newest 6.0 package - results are the same
EDIT3:
I've removed call to getParameterMetaData() and it worked, unfortunately it is a generic part that should max portable, yet it does not work with this single table (inserts to other tables on the same database works fine !!!)
EDIT4:
I've tried with different insert statements for this table and all of them works fine if I skip ps.getParameterMetaData() and fail when I call it. If I try with 2 or more params I get usual near WHERE error. If I try one column insert I get an error stating that the column name is incorrect, even if it is correct and without the meta data call it works perfectly fine. I will try to trace what driver tries to do underneath...
After some tracing on what actually the driver does (many thanks a_horse_with_no_name), I've come to some funny conclusion.
The solution for my question is to:
Replace following insert statement
INSERT INTO CurrencyRates(RateDate, CurrencyID, Rate) VALUES ( ?, ?, ? )
With this statement
INSERT INTO CurrencyRates (RateDate, CurrencyID, Rate) VALUES ( ?, ?, ? )
Logic behind that is that SQL driver does some metadata extraction in the background, and it creates a query with following fragment: ... FROM CurrencyRates(RateDate WHERE ... if you do not put space after table name, yet for the ordinary call this is perfectly possible!
EDIT:
This is obviously an inconsistency as (putting aside what actually is a valid insert) it should consistently accept or reject this query no matter if I call for meta data or not.
This query works when I input it through phpmyadmin.
INSERT INTO conversation (user_id) VALUES (?);
INSERT INTO conversation (conversation_id, user_id)
VALUES ((SELECT LAST_INSERT_ID()), ?)
However when I send that query using jdbc and java I get an 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 'INSERT INTO conversation (conversation_id, user_id) VALUES ((SELECT LAST_INSERT_' at line 1"
I am using the exact same query. I checked by calling toString on the PreparedStatement and copying and pasting it into phpmyadmin and executing it and it worked fine. It just doesn't work through java. Any ideas whats wrong?
By default, you cannot execute multiple statements in one query through JDBC. Splitting it into two calls will work, as will changing the allowMultiQueries configuration property to True.
JDBC Configuration Properties — allowMultiQueries:
Allow the use of ';' to delimit multiple queries during one statement (true/false), defaults to 'false', and does not affect the addBatch() and executeBatch() methods, which instead rely on rewriteBatchStatements.
Default value: false