Ihsan Haikal Ihsan Haikal - 3 months ago 11
Java Question

EclipseLink MySQLSyntaxErrorException can't find the error

I have a code that runs like this:

S3Logs s3Logs = new S3Logs();
s3Logs.setBucketOwner(a.getBucketOwner());
s3Logs.setBucket(a.getBucket());
s3Logs.setTime(a.getTime().toString());
s3Logs.setRemoteIpAddress(a.getRemoteIpAddress());
s3Logs.setRequester(a.getRequester());
s3Logs.setRequestId(a.getRequestId());
s3Logs.setOperation(a.getOperation());
s3Logs.setKey(a.getKey());
s3Logs.setRequestUri(a.getRequestUri());
s3Logs.setHttpStatus(a.getHttpStatus());
s3Logs.setErrorCode(a.getErrorCode());
s3Logs.setBytesSent(a.getBytesSent());
s3Logs.setObjectSize(a.getObjectSize());
s3Logs.setTotalTime(a.getTotalTime());
s3Logs.setTurnAroundTime(a.getTurnAroundTime());
if(a.getReferrer() == "-"){
s3Logs.setReferrer(null);
}else{
s3Logs.setReferrer(a.getReferrer());}
if(a.getUserAgent().contains(",")){
String s = a.getUserAgent().replace(",", "");
s3Logs.setUserAgent(s);
}else{
s3Logs.setUserAgent(a.getUserAgent());
}

s3Logs.setVersionId(a.getVersionId());
LogsDAO.em.persist(s3Logs);
LogsDAO.em.getTransaction().commit();


But when I tried to run, it gave me error like so:

Internal 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 'KEY, OBJECTSIZE, OPERATION, REFERRER, REMOTEIPADDRESS, REQUESTID, REQUESTURI, RE' at line 1
Error Code: 1064
Call: INSERT INTO S3LOGS (BUCKET, BUCKETOWNER, BYTESSENT, ERRORCODE, EXTRAS, HTTPSTATUS, KEY, OBJECTSIZE, OPERATION, REFERRER, REMOTEIPADDRESS, REQUESTID, REQUESTURI, REQUESTER, TIME, TOTALTIME, TURNAROUNDTIME, USERAGENT, VERSIONID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [seminar2017, 5abc648552c5f, 0, null, null, 200, null, 0, REST.PUT.LOGGING_STATUS, -, 10.0.0.100, C785888F31E34747, PUT /seminar2017?logging= HTTP/1.1, 5abc648552c5f, 2017-05-10T15:42:40.000Z, 198, 0, aws-internal/3 S3Console/0.4, null]
Query: InsertObjectQuery(de.logsparsing.S3Logs@74ea2410)
Exception in thread "main" javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.4.v20160829-44060b6): org.eclipse.persistence.exceptions.DatabaseException
Internal 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 'KEY, OBJECTSIZE, OPERATION, REFERRER, REMOTEIPADDRESS, REQUESTID, REQUESTURI, RE' at line 1
Error Code: 1064
Call: INSERT INTO S3LOGS (BUCKET, BUCKETOWNER, BYTESSENT, ERRORCODE, EXTRAS, HTTPSTATUS, KEY, OBJECTSIZE, OPERATION, REFERRER, REMOTEIPADDRESS, REQUESTID, REQUESTURI, REQUESTER, TIME, TOTALTIME, TURNAROUNDTIME, USERAGENT, VERSIONID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [cpabecloudseminar2017, 5abc648552c5f, 0, null, null, 200, null, 0, REST.PUT.LOGGING_STATUS, -, 54.239.6.71, C785888F31E34747, PUT /seminar2017?logging= HTTP/1.1, 5abc648552c5f, 2017-05-10T15:42:40.000Z, 198, 0, aws-internal/3 S3Console/0.4, null]
Query: InsertObjectQuery(de.logsparsing.S3Logs@74ea2410)
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:159)
at de.awsmonitor.AWSLogsMapper.main(AWSLogsMapper.java:176)
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.4.v20160829-44060b6): org.eclipse.persistence.exceptions.DatabaseException
Internal 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 'KEY, OBJECTSIZE, OPERATION, REFERRER, REMOTEIPADDRESS, REQUESTID, REQUESTURI, RE' at line 1
Error Code: 1064
Call: INSERT INTO S3LOGS (BUCKET, BUCKETOWNER, BYTESSENT, ERRORCODE, EXTRAS, HTTPSTATUS, KEY, OBJECTSIZE, OPERATION, REFERRER, REMOTEIPADDRESS, REQUESTID, REQUESTURI, REQUESTER, TIME, TOTALTIME, TURNAROUNDTIME, USERAGENT, VERSIONID) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [seminar2017, 5abc648552c5f291cc61eb5cbcb347c3074ed816d2a8bd140e598b3e30595338, 0, null, null, 200, null, 0, REST.PUT.LOGGING_STATUS, -, 10.0.0.100, C785888F31E34747, PUT /seminar2017?logging= HTTP/1.1, 5abc648552c5f291cc61eb5cbcb347c3074ed816d2a8bd140e598b3e30595338, 2017-05-10T15:42:40.000Z, 198, 0, aws-internal/3 S3Console/0.4, null]
Query: InsertObjectQuery(de.logsparsing.S3Logs@74ea2410)
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:902)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:964)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:633)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:560)
at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2056)
at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:306)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.insertObject(DatasourceCallQueryMechanism.java:377)
at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:165)
at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:180)
at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:489)
at org.eclipse.persistence.queries.InsertObjectQuery.executeCommit(InsertObjectQuery.java:80)
at org.eclipse.persistence.queries.InsertObjectQuery.executeCommitWithChangeSet(InsertObjectQuery.java:90)
at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:301)
at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:904)
at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:803)
at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108)
at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1857)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1839)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1790)
at org.eclipse.persistence.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:227)
at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:126)
at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:4264)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1441)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1531)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:278)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1169)
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:134)
... 1 more
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 'KEY, OBJECTSIZE, OPERATION, REFERRER, REMOTEIPADDRESS, REQUESTID, REQUESTURI, RE' at line 1
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.Util.getInstance(Util.java:408)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:943)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3970)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3906)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2524)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2677)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2549)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2073)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2009)
at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5098)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1994)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:892)
... 32 more


I tried to find out what's the error but couldn't figure it out until now. I even tried to instantiate the S3Log object without putting anything in it but it still gave the same error.

Here is my S3Log object:

@Entity
public class S3Logs {

public S3Logs() {

}

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
public long id;

private String bucketOwner;
private String bucket;
private String time;
private String remoteIpAddress;
private String requester;
private String requestId;
private String operation;
private String key;
private String requestUri;
private int httpStatus;
private String errorCode;
private long bytesSent;
private long objectSize;
private long totalTime;
private long turnAroundTime;
private String referrer;
private String userAgent;
private String versionId;
}

Answer Source

THE PROBLEM

MySQL is giving you a hint about where the problem is, here:

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

'KEY, OBJECTSIZE, OPERATION, REFERRER, REMOTEIPADDRESS, REQUESTID, REQUESTURI, RE' at line 1

KEY is a Reserved Word in MySQL. And a reserved word cannot be used as an identifier (e.g. table name, column name)

To use a reserved word as an identifier (or to use a string that contains invalid characters, such as a space), the identifier can be escaped by enclosing it in backtick characters.

For example:

INSERT INTO `mytable` (`mycol`, `key`, ... 
            ^       ^  ^     ^  ^   ^

THE FIX

One quick way to fix this is to add a JPA 2.0 directive in the source, to override the default column name, specifying the column name enclosed in backticks, like this:

private String operation;
@Column(name="`key`")
private String key;
private String requestUri;

Changing the column name to something other than a reserved word would be another (preferred) choice.

And some will (rightly) argue that this is a MySQL specific fix. (MySQL uses the single backticks, SQL Server uses square brackets to escape identifiers, Oracle uses double quotes, etc.) So this "fix" flies in the face of database portability.

There should be some general setting in the JPA configuration that effectively says "escape all identifiers", which wouldn't be database specific.