Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 364261

Summary: When connecting to MySQL, "relaxAutoCommit=true" must be specified manually
Product: z_Archived Reporter: Yu Hao <yuhaodl>
Component: EDTAssignee: Zhi Zhu <zhuzhi>
Status: CLOSED FIXED QA Contact:
Severity: major    
Priority: P3 CC: chenzhh, jspadea, jvincens, svihovec, xiaobinc, yuhaodl, zhuzhi
Version: unspecified   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:

Description Yu Hao CLA 2011-11-21 02:24:55 EST
Build Identifier: 201111202101

When Added SQL database binding in dd file with wizard, the auto generation Connection URL was like this:
jdbc:mysql://rbdtest1.raleigh.ibm.com:3306/budget
But if we use this db bind to connect to the DB, there will be following error:

Can't call commit when autocommit=true: [sqlstate:null][sqlcode:0]
eglx.persistence.sql.SQLException Can't call commit when autocommit=true: [sqlstate:null][sqlcode:0]
	at eglx.lang.AnyException.fillInStackTrace(AnyException.java:187)
	at java.lang.Throwable.<init>(Throwable.java:181)
	at java.lang.Exception.<init>(Unknown Source)
	at java.lang.RuntimeException.<init>(Unknown Source)
	at eglx.lang.AnyException.<init>(AnyException.java:32)
	at eglx.persistence.sql.SQLException.<init>(SQLException.java:25)
	at org.eclipse.edt.javart.util.JavartUtil.makeEglException(JavartUtil.java:300)
	at eglx.persistence.sql.SQLDataSource.commit(SQLDataSource.java:94)
	at org.eclipse.edt.javart.resources.ResourceManager.commit(ResourceManager.java:63)
	at org.eclipse.edt.javart.resources.RunUnitBase.commit(RunUnitBase.java:218)
	at org.eclipse.edt.javart.resources.RunUnitBase.endRunUnit(RunUnitBase.java:282)
	at org.eclipse.edt.javart.services.servlet.JsonRpcInvoker.invokeEglService(JsonRpcInvoker.java:90)
	at org.eclipse.edt.javart.services.servlet.JsonRpcInvoker.invoke(JsonRpcInvoker.java:58)
	at org.eclipse.edt.javart.services.servlet.rest.rpc.ServiceServlet.processRequest(ServiceServlet.java:131)
	at org.eclipse.edt.javart.services.servlet.Servlet.doHttp(Servlet.java:154)
	at org.eclipse.edt.javart.services.servlet.Servlet.doPost(Servlet.java:102)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
	at java.lang.Thread.run(Unknown Source)
Caused by: java.sql.SQLException: Can't call commit when autocommit=true
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:934)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931)
	at com.mysql.jdbc.ConnectionImpl.commit(ConnectionImpl.java:1655)
	at eglx.persistence.sql.SQLDataSource.commit(SQLDataSource.java:91)
	... 22 more


So I have to manually add "relaxAutoCommit=true" to the URL to :

jdbc:mysql://rbdtest1.raleigh.ibm.com:3306/budget?relaxAutoCommit=true

Then the error will disappear.

Reproducible: Always
Comment 1 Joseph Vincens CLA 2011-11-21 11:33:43 EST
When ds = new SQLDataSource(string); is used we don't know what database you are using so we can't create a URL for you. You have to set the URL properly for the application you are developing.
Comment 2 Xiao Bin Chen CLA 2011-11-21 21:00:14 EST
(In reply to comment #1)
> When ds = new SQLDataSource(string); is used we don't know what database you
> are using so we can't create a URL for you. You have to set the URL properly
> for the application you are developing.

Hi Joe, 
I think the most important is the tools we used in "Resource Binding" tab of **.egldd. 

when we add a "sql database binding", If you choose a mysql database, we may could know it's a mysql database. So the generated "Connection URL" might could be append "relaxAutoCommit=true"  for mysql. 

Because when I used the 
ads SQLDataSource?{@Resource {bindingkey = "mvclib", propertyFileName = "aproject"}};	
The error will show, Which will confused customer.(Customer used the URL our tools provided,It does not works!!!)


Second, for ds = new SQLDataSource(string).
Could we analysis the string, I don't know if the string has contain some meta data of which database was used?

like"jdbc:mysql://rbdtest1.raleigh.ibm.com:3306" contains "mysql".
Comment 3 Tony Chen CLA 2011-11-23 21:30:36 EST
bottom line is the url given by egldd (if user has not manually modified it) should work by default. It would an issue to let user identify problems like what's described here. 

The runtime/gen and the tool needs to be aligned on what auto commit status is expected. 

Since this may involve some design decision. I'm setting it the future. I also raise the severity to major because it is easily to hit, and difficult to get out. 
The component is set to IDE, but JSGen might be involved as well.
Comment 4 Zhi Zhu CLA 2011-12-12 04:09:29 EST
In our current implementation, Connection object is get from SQLDataSource:
   public Connection getConnection() throws SQLException {
		if (conn == null) {
			try {
				conn = DriverManager.getConnection(connectionUrl, properties);
			} catch (java.sql.SQLException e) {
				throw JavartUtil.makeEglException(e);
			}
		}
		return conn;
	}


   In the above method, the returned Connection object is auto-commited based on JDK document, when running SQL-related part, SQLDataSource.commit() method will be called to commit SQL statements, so it is possible to commit SQL statements more than once

  I suggested to set autoCommit property of returned Connection object to false due to below two points:
  1. SQLDataSource.commit() will be called which will commit SQL statements.
  2. The SQL part probably contains more than one statements that should be executed in one transaction; if autoCommit property of returned Connection is true, they will be executed in different transactions producing unexpected results.
Add:
   conn.setAutoCommit(false);
to SQLDataSource.commit() method 

  public Connection getConnection() throws SQLException {
		if (conn == null) {
			try {
				conn = DriverManager.getConnection(connectionUrl, properties);
				conn.setAutoCommit(false);
			} catch (java.sql.SQLException e) {
				throw JavartUtil.makeEglException(e);
			}
		}
		return conn;
	}
Comment 5 Brian Svihovec CLA 2011-12-16 10:50:10 EST
Changing this to .8 so that we can have a discussion about how this should be handled.
Comment 6 Zhi Zhu CLA 2012-01-05 02:08:29 EST
update for testing search
Comment 7 Joseph Vincens CLA 2012-01-05 16:48:43 EST
Brian and I had a discussion on this.

In comment 4 Zhi suggests that we set AutoCommit to false. Our functionality parallels Java and the java.sql.Connection defaults to autoCommit = true, so we will continue to use the Java default. Auto commit is an application specific issue, some applications rely on auto committing while other group sql statements by turning off auto commit. 

The SQLDataSource object has setAutoCommit so based on their application needs the developer can change the state of autoCommit. 

As far as having the tooling add relaxAutoCommit=true when we create the egldd entry. Take the existing eclipse/java defaults, no relaxAutoCommit and auto commit = true. If the user codes a commit then they expect an exception. If we add the relax they won't get an exception.

So keeping to the thought of paralleling Java functionality. The real problem is when the rununit ends EGL issues a connection.commit which causes the exception. The Java doc for Connection.commit says "This method should be used only when auto-commit mode has been disabled." So I have change the SQLDataSource to only issue a commit/rollback if autoCommit == false.
Comment 8 Yu Hao CLA 2012-01-12 01:12:29 EST
Verified in 201201112157