Short version of my question is:
PreparedStatement ps;
ps = connection.prepareStatement("Insert into T values (?)");
ps.setBoolean(1, true);
ps.executeUpdate();
What can be the reasons for this code sample to produce query with value wrapped in quotes?
Long version of my question is:
I have JavaEE application with plain JDBC for DB interactions and recently I noticed that there are some MySQLDataTruncation exceptions appearing in my logs. These exceptions were occurring on attempt to save entity into DB table which have boolean column defined as BIT(1). And it was because generated query looked like this:
Insert into T values ('1');
Note that value is wrapped with quotes. Query was logged from application with Log4J log.info(ps); statement.
Previous logs demonstrate that there where no quotes.
Furthermore, even MySQL server logs started to look different. Before this happened I had given pairs of records for each query executed:
12345 Prepare Insert into T values (?)
12345 Execute Insert into T values (1)
And after:
12345 Query Insert into T values ('1')
It is worth noting that those changes wasn`t a result of deploying new version of application or even restarting MySQL/Application server and code, responsible of query generation, is as straightforward as example in this question.
Application server restart fixed the issue for about 12 hours, and then it happened again. As a temporary solution I changed BIT columns to TINYINT
P.S. Examining both aplication and MySQL logs allowed to narrow down the time span when something went wrong to about 2 minutes, but there were nothing abnormal in the logs in this period.
P.P.S. Application server is Glassfish 2.1.1, MySQL server version is 5.5.31-1~dotdeb and MySQL Connector/J version is 5.0.3.
Well, it turned out it was actually an issue with unclosed prepared statements.
When opened statements count at MySQL server reached its allowed maximum, application was still able to continue working somehow, withoout producing sql error:
Error Code: 1461 Can’t create more than max_prepared_stmt_count statements
But in that mode it started to wrap boolean values with quotes, causing all my troubles affecting BIT(1) columns.
Related
I encountered a weird problem:
I have a column "MaxDealtDamage" which is for instance lower then 1000000 (1000k).
code is like this:
class xyz = PlayerData.GetData(player);
xyz.LoginTimes++;
PlayerData.SetData(xyz, player);
When it is 1000000 (1000k) or higher this error is beeing send:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: 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 '.000, MaxDefense = 0 WHERE UUID='d839d1f0-ad5b-4922-841c-1d6ee05d9f56'' at line 1
Its behaving like it would try to give him a String containing "4.000.000" but its an integer with the value "4000000" (4000k). For beeing sure the output in runtime is 4000000 I doublechecked it.
Here the query:
MessageFormat.format("INSERT INTO PlayerData(UUID,VIPExpirationDate,IPv4,FirstPlayTime,LastPlayTime,TotalPlayTime,TotalLogins,MaxDealtDamage,MaxDefense) "
+ "VALUES(''{0}'',''{1}'',''{2}'',''{3}'',''{4}'',{5},{6},{7},{8});", data.UUID.toString(), DBDateFormat.format(data.VIPExpirationDate), data.IPv4, DBDateFormat.format(data.FirstPlayTime), DBDateFormat.format(data.LastPlayTime), data.TotalPlayTime, data.TotalLogins, data.MaxDealtDamage, data.MaxDefense);
MessageFormat is not a tool for creating SQL statements. It's a simple utility for building text messages with correct formatting.
You are supposed to use PreparedStatement with bind parameters as explained in the Using Prepared Statements tutorial. JDBC will take care of escaping and formatting the supplied values so they can be received by the database server while preventing SQL Injections.
My code is simple
CallableStatement stmt = Conn.prepareCall ("{call Reconciliation (?)}");
stmt.setString(date);
PS.executeUpdate();
Am using Sybase (Adaptive Server Enterprise/15.7.0) and jconnect4 drivers if it is relevant to solution.
My procedure(Reconcliliation) is quite huge so I couldn't post it here but it does some updates to some 1 tables (Recon) after some comparison of data from another 2 tables (Deals1 and Deals2). It do not return any out parameters in procedure, it takes only 1 in parameter which is date.
When I run java code and run the procedure using callable statement it produces some updates data in table (Recon, count is 500) and the error I get after that is this :
java.sql.SQLException: JZ0P1: Unexpected result type.
at com.sybase.jdbc3.jdbc.ErrorMessage.raiseError(Unknown Source)
at com.sybase.jdbc3.jdbc.SybStatement.updateLoop(Unknown Source)
at com.sybase.jdbc3.jdbc.SybStatement.executeUpdate(Unknown Source)
at com.sybase.jdbc3.jdbc.SybCallableStatement.executeUpdate(Unknown
Source)
at DBConnection.ExecuteProc(DBConnection.java:88)
Am pretty sure there is no error in my procedure (Reconciliation) because when I run the same procedure in Aqua Data Studio with command exec Reconciliation '04-Dec-2016' it doesn't give any error and produces full update in tables (Recon, total count is 800).
There is no error in java as well because it is giving sql exception. If am not wrong there must be some problem in middle i.e jconnect drivers or something else.
Please help me with this, thanks in adv.
Old question, but I couldn't find any good answers to this question online when I had the same problem.
The big hint came from http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc39001.0700/html/prjdbc0700/CHDGJJIG.htm
JZ0P1 Unexpected result type.
Description: The database has returned a result that the statement cannot
return to the application, or that the application is not expecting at this
point. This generally indicates that the application is using JDBC incorrectly
to execute the query or stored procedure. If the JDBC application is connected
to an Open Server application, it may indicate an error in the Open Server
application that causes the Open Server to send unexpected sequences of results.
The stored procedure is returning tables. Don't do:
PS.executeUpdate();
But do this instead:
ResultSet rs = callableStatement.executeQuery();
For old jdbc drivers, I´ve noticed that
PS.executeUpdate();
raises this error while
PS.execute();
does not
On our production application we recently become weird error from DB2:
Caused by: com.ibm.websphere.ce.cm.StaleConnectionException: [jcc][t4][2055][11259][4.13.80] The database manager is not able to accept new requests, has terminated all requests in progress, or has terminated your particular request due to an error or a force interrupt. ERRORCODE=-4499, SQLSTATE=58009
This occurs when hibernate tries to select data from one big table(More than 6 milions records and 320 columns).
I observed that when ResultSet lower that 10 elements, hibernate selects successfully.
Our architecture:
Spring 4.0.3
Hibernate 4.3.5
DB2 v10 z/Os
Websphere 7.0.0.31(with JDBC V9.7FP5)
This select works when I tried to executed this in Data Studio or when app is started localy from Tomcat(connected to production Data Source). I suppose that Data Source on Websphere is not corectly configured, but I tried some modifications and without results. I also tried to update JDBC Driver but that not helped. Actually I become then ERRORCODE = -1244.
Ok, so now I'm looking for any help ;).
I can obviously provide additional information when needed.
Maybe someone fighted earlier with this problem?
Thanks in advance!
We have the same problem and finally solved by running REORG and RUNSTAT on the table(s). In our case, databse and tables were damaged and after running both mentioned operations, it resolved.
This occurs when hibernate tries to select data from one big table(More than 6 milions records and 320 columns)
6 million records with 320 columns seems huge to be read at once through hibernate. How you tried creating a database cursor and streaming few records at a time? In plain JDBC it is done as follows
Statement stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(50); //fetch only 50 records at a time
while with hibernate you would need the below code
Query query = session.createQuery(query);
query.setReadOnly(true);
query.setFetchSize(50);
ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY);
// iterate over results
while (results.next()) {
Object row = results.get();
// process row then release reference
// you may need to flush() as well
}
results.close();
This allows you to stream over the result set, however Hibernate will still cache results in the Session, so you’ll need to call session.flush() every so often. If you are only reading data, you might consider using a StatelessSession, though you should read its documentation beforehand.
Analyze the database table locking impact when using this approach.
This is something that I've been scratching my head with - especially since it's infuriating to deal with.
Consider the following code:
String query = "UPDATE ORDERS SET VOLUME=?,CONTRACT_ID=?,PROJECT_ID=?,WORKSITE_ID=?,DROPZONE_ID=?,DESCRIPTION_ID=?,MANAGER_ID=?,DELIVERY_DATE=?,REVISION=REVISION+1) WHERE ID=?";
jdbcTemplate.update(query, orderEntity.getVolume(), orderEntity.getContractNo(), orderEntity.getProjectID(), orderEntity.getWorksiteID(), orderEntity.getDropzoneID(), orderEntity.getDescriptionID(), orderEntity.getManagerID(), orderEntity.getDeliveryDate(), id);
We can see that the SQL query is incorrect - and will therefore throw some SQL error but one might have missed that. Spring will (for me) throw a QueryTimeoutException in response to this. I'm sort of okay with that but it's not helpful.
Now let's try
String query = "INSERT INTO ORDERS(ID,REISION,CONTRACT_ID,PROJECT_ID,WORKSITE_ID,DROPZONE_ID,DESCRIPTION_ID,MANAGER_ID,VOLUME,DELIVERY_DATE) VALUES(?,?,?,?,?,?,?,?,?,?)";
jdbcTemplate.update(query, id, revision, etc);
Another spelling mistake that's easily missed - REVISION is misspelled as REISION) Spring throws another QueryTimeoutException again. This now means that if I get that exception I don't actually know what it is. Is it a syntax error? Is it a column spelling error? Is it the (much harder to notice) fact that the foreign key constraint not being followed?
While debugging, this is quite possibly the most infuriating thing ever - all I know is that my query failed to run. How can I get something useful? Is there something I've not added to my pom.xml file?
EDIT:
Here's a nicer example. I have a DESCRIPTIONS table, with an ID, REVISION and TEXT column. All of those are marked as not being nullable.
DescriptionEntity descriptionEntity = new DescriptionEntity("newDesc", 1, null);
String query = "INSERT INTO DESCRIPTIONS (ID,REVISION,TEXT) VALUES(?,?,?)";
jdbcTemplate.update(query, descriptionEntity.getID(), 1, descriptionEntity.getText());
That will also throw a query timeout exception, when running the query in mysql gives me ERROR 1048 (23000): Column 'TEXT' cannot be null
This is, to put it politely, a bit of a pain.
It's not a spelling mistake in the first example, as you left out the opening paren. I would say this isn't an issue with Spring or JDBC, but rather your DB is trying to process the SQL, waiting for more input or something, and never returning.
In the second one, I am not sure what you are talking about since I don't know the table design. I have to assume what you mean is ID is not unique? Again, I wouldn't blame Spring or JDBC, maybe the drive, most likely the database server.
Keep in mind, in a lot of cases, the way SQL is handled in the user Client UI is not the same as how it gets handled through JDBC. For instance, in SQL Server the SQL is set as a string, the passed in parameters set as variables, and it uses sp_executesql() to run it. I discovered that when I had a report that ran PERFECTLY fine through SQL Studio Manager client, but blew up when I ran it live because the query plan optimizer took a different path due to the differences in how the SQL was ran.
This is quite possibly the most stupid error I've ever come across: the issue was in how Maven resolved all the dependencies.
The requirement for Spring Security was placed before the JDBC requirement. That made Spring Security pull down org.springframework:spring-tx:jar:3.0.7.RELEASE:compile which satisfied the dependency for JDBC. Moving the JDBC requirement up meant JDBC pulled down org.springframework:spring-tx:jar:3.2.2.RELEASE:compile.
I have a servlet/tomcat server written in java.
I have a mysql class that I have written, and I have been using the functions in it to insert prepared statements into a mysql database using jdbc.
The function I call uses java.sql.PreparedStatement.setString in order to set the paramaters of the prepared statement. This has been working perfectly for thousands of different inputs for months on end without issue.
Recently however, when trying to use the function to insert an ip address into a VARCHAR type mysql column I am getting an exception thrown as follows:
com.mysql.jdbc.MysqlDataTruncation: Data truncation: Truncated incorrect DOUBLE value: '10.1.1.101'
This is bizarre, There is no notion of a DOUBLE anywhere in my code, and a "Show Columns" on the mysql table ensures that the data type is in fact a VARCHAR. I have had my colleagues look at this as well to double check that I wasn't missing something simple. However we are all stumped.
My only theory is that the JDBC driver or the SetText function is taking a liberty and assuming a DOUBLE data type because the first part of the ip address is in the form of XX.XX
Any help would be great, please don't tell me to do obvious stuff like check my column data types etc. I have spent a lot of time double and tripple checking everything.
The problem is not with JDBC Driver. The problem lies with MySQL. Here is what i get on MySQL commadline:
mysql> INSERT INTO route_table (SYSTEM, IP, PORT) VALUES ("192.168.1.24:8080","192.168.1.24","8080") ON DUPLICATE KEY UPDATE IP=values(IP) AND PORT=values(PORT);
Query OK, 1 row affected (0.04 sec)
mysql> INSERT INTO route_table (SYSTEM, IP, PORT) VALUES ("192.168.1.24:8080","192.168.1.24","8080") ON DUPLICATE KEY UPDATE IP=values(IP) AND PORT=values(PORT);
ERROR 1292 (22007): Truncated incorrect DOUBLE value: '192.168.1.24'
mysql>
The problem is , the syntax of INSERT INTO .... ON DUPLICATE KEY UPDATE used by you is incorrect. You have used a keyword AND instead of using a ,(comma). So the query should be:
mysql> INSERT INTO route_table (SYSTEM, IP, PORT) VALUES ("192.168.1.24:8080","192.168.1.24","8080") ON DUPLICATE KEY UPDATE IP=values(IP), PORT=values(PORT);
Query OK, 2 rows affected (0.00 sec)