Bug 217255 - [DB] DBStore does not store Date type correctly
Summary: [DB] DBStore does not store Date type correctly
Status: CLOSED FIXED
Alias: None
Product: EMF
Classification: Modeling
Component: cdo.db (show other bugs)
Version: 2.0   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: M5   Edit
Assignee: Stefan Winkler CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 214487
Blocks:
  Show dependency tree
 
Reported: 2008-01-31 08:55 EST by Stefan Winkler CLA
Modified: 2010-06-29 04:18 EDT (History)
1 user (show)

See Also:
stepper: galileo+
stepper: review+


Attachments
Suggested patch (3.54 KB, patch)
2008-02-05 10:24 EST, Stefan Winkler CLA
no flags Details | Diff
alternative patch (1.56 KB, patch)
2008-11-26 06:30 EST, Victor Roldan Betancort CLA
no flags Details | Diff
Merged Patch (6.05 KB, patch)
2009-01-08 05:16 EST, Stefan Winkler CLA
no flags Details | Diff
Patch v4 - ready to be committed (6.06 KB, patch)
2009-01-08 05:54 EST, Eike Stepper CLA
no flags Details | Diff
Additional-Patch-for-prepared-statements (1.35 KB, patch)
2009-01-29 10:29 EST, Stefan Winkler CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Stefan Winkler CLA 2008-01-31 08:55:52 EST
Build ID:  I20071213-1700

Steps To Reproduce:
1. Make a model element with a date field:

<eClassifiers xsi:type="ecore:EClass" xmi:id="_xC6GM8mMEdyFYs0aM9mFfg" name="TestClass">
    <eStructuralFeatures xsi:type="ecore:EAttribute" xmi:id="_xC6GNsmMEdyFYs0aM9mFfg"
        name="timestamp" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"/>
</eClassifiers>

2. Create a container, session, transaction, 
3. Create an instance of above class and do setTimestamp(new java.util.Date());
4. Add instance to resource
5. commit transaction

leads to 


[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 'Jan 31 14:32:36 CET 2008, 0)' at line 1
org.eclipse.net4j.db.DBException: 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 'Jan 31 14:32:36 CET 2008, 0)' at line 1
	at org.eclipse.emf.cdo.server.internal.db.ClassMapping.sqlUpdate(ClassMapping.java:178)
	at org.eclipse.emf.cdo.server.internal.db.ClassMapping.writeAttributes(ClassMapping.java:493)
	at org.eclipse.emf.cdo.server.internal.db.ClassMapping.writeRevision(ClassMapping.java:449)
	at org.eclipse.emf.cdo.server.internal.db.HorizontalClassMapping.writeRevision(HorizontalClassMapping.java:37)
	at org.eclipse.emf.cdo.server.internal.db.DBStoreWriter.writeRevision(DBStoreWriter.java:177)
	at org.eclipse.emf.cdo.internal.server.RevisionManager$AddRevisionOperation.phase1(RevisionManager.java:283)
	at org.eclipse.emf.cdo.internal.server.RevisionManager$AddRevisionOperation.phase1(RevisionManager.java:1)
	at org.eclipse.net4j.internal.util.transaction.Transaction.execute(Transaction.java:66)
	at org.eclipse.emf.cdo.internal.server.RevisionManager.addRevision(RevisionManager.java:64)
	at org.eclipse.emf.cdo.internal.server.protocol.CommitTransactionIndication.addRevisions(CommitTransactionIndication.java:279)
	at org.eclipse.emf.cdo.internal.server.protocol.CommitTransactionIndication.indicating(CommitTransactionIndication.java:123)
	at org.eclipse.net4j.signal.IndicationWithResponse.execute(IndicationWithResponse.java:46)
	at org.eclipse.net4j.signal.Signal.runSync(Signal.java:143)
	at org.eclipse.net4j.signal.Signal.run(Signal.java:124)Thread-4 [debug] INSERT INTO ArtifactContent VALUES (10, 1, 4, 1201786356874, 0, 2, 8, -1, Thu Jan 31 14:32:36 CET 2008, 0)

	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
	at java.lang.Thread.run(Thread.java:619)
Caused by: 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 'Jan 31 14:32:36 CET 2008, 0)' at line 1
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
	at com.mysql.jdbc.Util.getInstance(Util.java:381)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1031)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957)Thread-4 [debug] Rolling back transaction: View(1, TRANSACTION)

	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3376)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3308)
	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1837)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1961)
	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2537)
	at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1564)
	at com.mysql.jdbc.StatementImpl.executeUpdate(StatementImpl.java:1485)
	at org.eclipse.emf.cdo.server.internal.db.ClassMapping.sqlUpdate(ClassMapping.java:174)
	... 16 more
[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 'Jan 31 14:32:36 CET 2008, 0)' at line 1


More information:
Problem is twofold:

1. Date is mapped to mysql column type DATE which is not quite correct, because java.util.Date stores also the time and thus the correct type would be DATETIME.

2. The statement is created with a wrong syntax. This is generated:

INSERT INTO TestClass VALUES (14, 1, 4, 1201782690532, 0, 2, 12, -1, Jan 31 14:32:36 CET 2008);

correct would be:

INSERT INTO TestClass VALUES (14, 1, 4, 1201782690532, 0, 2, 12, -1, '2008-01-31 14:32:36');

-> use single quotes
-> use format yyyy-mm-dd hh:mm:ss

Also, I don't think that this is a MySQL specific problem. I doubt that this syntax works with any other database as the date is usually enclosed in single quotes ...
Comment 1 Stefan Winkler CLA 2008-02-05 10:24:02 EST
Created attachment 88881 [details]
Suggested patch

Here's a patch, that works for me but sadly affects the other databases as well and I did not test it with other databases. 

It fixes the issue of erroneous sql syntax by explicitly adding the date formatting to the mysql adapter.

It also stores the date in a datetime field and uses getTimestamp() in the revision retrieval part in order to address the issue with not storing the time of day.
Comment 2 Eike Stepper CLA 2008-06-10 02:29:23 EDT
Reversioned due to graduation
Comment 3 Stefan Winkler CLA 2008-11-22 04:25:44 EST
see Bug 244290: there is also JDBC escape syntax to express dates and timestamps in a database-dependent way. 

Eike, in AttributeMapping around 212, it says:

    @Override
    protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException
    {
      // TODO Is getDate() correct? <---------------
      return resultSet.getDate(column);
    }

In MySQL this is equal to only reading the date, setting the time of day to 00:00:00.

What is the semantics of the EDate data type? Is it date-only or date-plus-time?
If the latter, then this should be changed to getDateTime() or getTimeStamp() and the timestamp should also be stored in the database. (I need to check and test column types as well, as I think I remember that the MySQL column type for Date mappings was also DATE, which ignores the time-of-day.



    
Comment 4 Victor Roldan Betancort CLA 2008-11-26 06:30:17 EST
Created attachment 118772 [details]
alternative patch

Hi Stefan,

I fixed this in my workspace some time ago, didn't know ther was a bugzilla already filled! I just overrode the DATE.appendValue() method. Seems to work fo MySQL (at least the exception is not thrown anymore), dont know if this would work for other databases.
Comment 5 Eike Stepper CLA 2009-01-08 00:27:21 EST
Stefan, your old patch contains merge conflicts. Could you have a look at Vik's approach, too, and then decide how to fix it?
Comment 6 Stefan Winkler CLA 2009-01-08 05:16:09 EST
Created attachment 121928 [details]
Merged Patch

I merged both patches - Vik's patch did not include reading the timestamp from the result set.

Also changed the default date mapping from DATE to TIMESTAMP (else HsqlDB would not store time of day), moved Vik's code from DATE to TIMESTAMP, added UnsupportedOperationException to DATE and TIME, and added testcase. Date is now stored and retrieved correctly in all three databases.
Comment 7 Eike Stepper CLA 2009-01-08 05:54:27 EST
Created attachment 121933 [details]
Patch v4 - ready to be committed

Stefan, Vik, Well done!! ;-)
Comment 8 Stefan Winkler CLA 2009-01-08 07:35:04 EST
Committed to HEAD.
Comment 9 Stefan Winkler CLA 2009-01-08 07:35:44 EST
... and now even set the RESOLVED state ;)
Comment 10 Eike Stepper CLA 2009-01-13 01:08:29 EST
Fix available in CDO 2.0.0 I200901090729
Comment 11 Stefan Winkler CLA 2009-01-29 10:10:07 EST
:-P fix does not work for prepared statements. Don't know why I missed that. 
Testcase testStoreDate of DBStoreTests fails if a delegate with prepared statements is used (tested derby and hsql)
Comment 12 Stefan Winkler CLA 2009-01-29 10:29:31 EST
Created attachment 124152 [details]
Additional-Patch-for-prepared-statements

Handled the special case directly in the PreparedStatementJDBCDelegate. 
Works now. 

Committed to HEAD.
Comment 13 Stefan Winkler CLA 2009-01-29 10:29:56 EST
Fixed again.
Comment 14 Eike Stepper CLA 2009-02-13 01:22:26 EST
Fix available in CDO 2.0.0M5
Comment 15 Eike Stepper CLA 2009-06-27 11:47:56 EDT
Generally available.