DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=20631>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=20631

[PATCH] Support for transactions in SQLTransformer

           Summary: [PATCH] Support for transactions in SQLTransformer
           Product: Cocoon 2
           Version: 2.0.4
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: Normal
          Priority: Other
         Component: sitemap components
        AssignedTo: [EMAIL PROTECTED]
        ReportedBy: [EMAIL PROTECTED]


I asked about transaction support in the SQLTransformer and got some good
suggestions about using some DB specific SQL. I might have gone that way (we use
Oracle 9i), but I wanted something more portable.

Daniel Fagerstrom posted about a patch he wrote that allowed the SQLTransformer
to share a connection among top level queries. Great, half way there! (Here's
the link for that patch... http://issues.apache.org/bugzilla/show_bug.cgi?id=16718).

I added in code to support setting a parameter like this;

               <map:transform type="sql">
                   <map:parameter name="use-connection" value="mbrdb"/>
                   <map:parameter name="enable-transaction" value="true"/>
               </map:transform>

I put the code in the SQLTransformer to turn off the auto-commit flag and to
issue the appropriate commit/rollback calls (on error). It works for a couple
inserts I threw together. If I put an error in the second insert, the first is
rolled back. If both are good, they both are commited. :-)
I'm attaching the revised SQLTransformer. I know you guys like to see patches,
so I attached that also. For now, this code has Daniel's patch applied (onto the
2.0.4 version) and my additions are bounded by comments (i.e. // DAK:
Transaction and // DAK)
Is this something that can be put into the scratchpad? We could give it a
different package so people could just choose it in the sitemap.xmap 
Here is the context diff with the 2.0.4 SQLTransformer (I added comments
surrounding my new code to make it easy to spot 
....
*** SQLTransformer.java Sun May 18 17:48:50 2003
--- SQLTransformer.java.orig    Tue May 13 22:20:36 2003
***************
*** 102,110 ****
      public static final String MAGIC_PASSWORD = "password";
      public static final String MAGIC_NR_OF_ROWS = "show-nr-of-rows";
      public static final String MAGIC_QUERY = "query";
-       // DAK: Transaction
-     public static final String MAGIC_TRANSACTION = "enable-transaction";
-       // DAK
      public static final String MAGIC_VALUE = "value";
      public static final String MAGIC_DOC_ELEMENT = "doc-element";
      public static final String MAGIC_ROW_ELEMENT = "row-element";
--- 102,107 ----
***************
*** 186,194 ****
      protected XMLDeserializer interpreter;
      protected Parser parser;
  
-       /** The connection used by all top level queries */
-       protected Connection conn;
- 
      /**
       * Constructor
       */
--- 183,188 ----
***************
*** 220,237 ****
       */
      public void recycle() {
          super.recycle();
-               try {
-                       // Close the connection used by all top level queries
-                       if (this.conn != null) {
-                               // DAK: Transaction
-                               this.conn.commit();
-                               // DAK
-                               this.conn.close();
-                               this.conn = null;
-                       }
-               } catch ( SQLException e ) {
-                       getLogger().warn( "Could not close the connection", e );
-               }
          this.queries.clear();
          this.outUri = null;
          this.outPrefix = null;
--- 214,219 ----
***************
*** 292,300 ****
              getLogger().debug( "ROW-ELEMENT: " + parameters.getParameter(
SQLTransformer.MAGIC_ROW_ELEMENT, "row" ) );
              getLogger().debug( "NS-URI: " + parameters.getParameter(
SQLTransformer.MAGIC_NS_URI_ELEMENT, NAMESPACE ) );
              getLogger().debug( "NS-PREFIX: " + parameters.getParameter(
SQLTransformer.MAGIC_NS_PREFIX_ELEMENT, "" ) );
-                       // DAK: Transaction
-             getLogger().debug( "TRANSACTION: " + parameters.getParameter(
SQLTransformer.MAGIC_TRANSACTION, "" ) );
-                       // DAK
          }
     }
  
--- 274,279 ----
***************
*** 317,335 ****
          AttributesImpl attr = new AttributesImpl();
          Query query = (Query) queries.elementAt( index );
          boolean query_failure = false;
-               Connection conn = null;
          try {
              try {
-                               if (index == 0) {
-                                       if (this.conn == null) // The first top level 
execute-query
-                                               this.conn = query.getConnection();
-                                               // reuse the global connection for all 
top level queries
-                                               conn = this.conn;
-                               }
-                               else // index > 0, sub queries are always executed in 
an own connection
-                                       conn = query.getConnection();
- 
-                               query.setConnection(conn);
                  query.execute();
              } catch ( SQLException e ) {
                  if (getLogger().isDebugEnabled()) {
--- 296,303 ----
***************
*** 372,403 ****
  
                  this.end( query.rowset_name );
              }
-                       // DAK: Transaction
-                       else {
-                               if (conn.getAutoCommit() == false)
-                                       conn.rollback();
-                       }
-                       // DAK
          } catch ( SQLException e ) {
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug( "SQLTransformer.executeQuery()", e );
              }
-                       // DAK: Transaction
-                       try {
-                               if (conn.getAutoCommit() == false)
-                                       conn.rollback();
-                       } catch (SQLException ex) {
-                               if (getLogger().isDebugEnabled()) {
-                                       getLogger().debug( 
"SQLTransformer.executeQuery()", e );
-                               }
-                       }
-                       // DAK
              throw new SAXException( e );
          } finally {
              try {
                  query.close();
-                               if (index > 0) // close the connection used by a sub 
query
-                                       conn.close();
              } catch ( SQLException e ) {
                  getLogger().warn( "SQLTransformer: Could not close JDBC
connection", e );
              }
--- 340,353 ----
***************
*** 1018,1027 ****
              }
          }
  
-               protected void setConnection(Connection conn) {
-                       this.conn = conn;
-               }
- 
          /** Get a Connection. Made this a separate method to separate the
logic from the actual execution. */
          protected Connection getConnection() throws SQLException {
              Connection result = null;
--- 968,973 ----
***************
*** 1074,1088 ****
                                                                password );
                      }
                  }
-                               // DAK: Transaction
-                 String transaction = properties.getParameter(
SQLTransformer.MAGIC_TRANSACTION, null );
-                               if (transaction != null || 
transaction.trim().toLowerCase().equals("true")) {
-                                       result.setAutoCommit(false);
-                       if (getLogger().isDebugEnabled()) {
-                                               getLogger().debug("So, someone fetched 
a connection and transactions are
enabled...");
-                                       }
-                               }
-                               // DAK
              } catch ( SQLException e ) {
                  transformer.getTheLogger().error( "Caught a SQLException", e );
                  throw e;
--- 1020,1025 ----
***************
*** 1092,1101 ****
          }
  
          protected void execute() throws SQLException {
-                       if (this.conn == null) {
-                               throw new SQLException("A connection must be set 
before executing a query");
-                       }
- 
              this.rowset_name = properties.getParameter(
SQLTransformer.MAGIC_DOC_ELEMENT, "rowset" );
              this.row_name = properties.getParameter(
SQLTransformer.MAGIC_ROW_ELEMENT, "row" );
  
--- 1029,1034 ----
***************
*** 1123,1128 ****
--- 1056,1063 ----
                  transformer.getTheLogger().debug( "EXECUTING " + query );
              }
  
+             conn = getConnection();
+ 
              try {
                  if ( !isstoredprocedure ) {
                      if ( oldDriver ) {
***************
*** 1155,1160 ****
--- 1090,1098 ----
              } catch ( SQLException e ) {
                  transformer.getTheLogger().error( "Caught a SQLException", e );
                  throw e;
+             } finally {
+                 conn.close();
+                 conn = null;        // To make sure we don't use this
connection again.
              }
          }
  
***************
*** 1233,1238 ****
--- 1171,1178 ----
                      cst.close();
                  cst = null;        // Prevent using cst again.
              } finally {
+                 if ( conn != null )
+                     conn.close();
                  conn = null;
              }
          }

Reply via email to