]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-5943: Execute multiple prepared statements, including a mix of queries and...
authorAron Roberts <aron@socrates.berkeley.edu>
Mon, 8 Apr 2013 18:53:17 +0000 (11:53 -0700)
committerAron Roberts <aron@socrates.berkeley.edu>
Mon, 8 Apr 2013 18:53:17 +0000 (11:53 -0700)
services/common/src/main/java/org/collectionspace/services/common/storage/JDBCTools.java
services/common/src/main/java/org/collectionspace/services/nuxeo/client/java/RepositoryJavaClientImpl.java

index 60ee9fca94bf3c6a957efbc0dfc3eb92b8b0aafd..c9c6f89e48e256471f1252a5e11ef37756c64fcc 100644 (file)
@@ -211,7 +211,7 @@ public class JDBCTools {
     }\r
     \r
     public static CachedRowSet executePreparedQuery(final PreparedStatementBuilder builder,\r
-            String dataSourceName, String repositoryName, String sql) throws Exception {\r
+            String dataSourceName, String repositoryName) throws Exception {\r
         Connection conn = null;\r
         PreparedStatement ps = null;\r
         try {\r
@@ -252,7 +252,7 @@ public class JDBCTools {
     // FIXME: This method's code significantly overlaps that of executePrepareQuery(), above,\r
     // and the two could be refactored into a single method, if desired.\r
     public static List<CachedRowSet> executePreparedQueries(final List<PreparedStatementBuilder> builders,\r
-            String dataSourceName, String repositoryName, String sql, Boolean executeWithinTransaction) throws Exception {\r
+            String dataSourceName, String repositoryName, Boolean executeWithinTransaction) throws Exception {\r
         Connection conn = null;\r
         PreparedStatement ps = null;\r
         List<CachedRowSet> results = new ArrayList<>();\r
@@ -271,10 +271,17 @@ public class JDBCTools {
                     statementCount++;\r
                     logger.info("prepared statement " + statementCount + "=" + ps.toString());\r
                 }\r
-                try (ResultSet resultSet = ps.executeQuery()) {\r
-                    crs.populate(resultSet);\r
+                // Try executing each statement, first as a query, then as an update\r
+                try {\r
+                    ResultSet resultSet = ps.executeQuery();\r
+                    if (resultSet != null) {\r
+                        crs.populate(resultSet);\r
+                        results.add(crs);\r
+                    }\r
+                } catch (Exception e) {\r
+                    int rowcount = ps.executeUpdate();\r
+                    // Throw uncaught exception here if update attempt also fails\r
                 }\r
-                results.add(crs);\r
             }\r
             return results;\r
         } catch (SQLException sqle) {\r
index 3a1fd1adb9b6bc1c05ff508ad15a06ae38ccc8a5..b6f025a6dae8fda62e98acc5c8b7c904cc039097 100644 (file)
@@ -85,6 +85,7 @@ import org.collectionspace.services.common.api.Tools;
 import org.collectionspace.services.common.config.ConfigUtils;
 import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
 import org.collectionspace.services.common.config.TenantBindingUtils;
+import org.collectionspace.services.common.storage.PreparedStatementBuilder;
 import org.collectionspace.services.config.tenant.TenantBindingType;
 import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoCmisService;
 import org.nuxeo.ecm.core.opencmis.impl.server.NuxeoRepository;
@@ -930,8 +931,23 @@ public class RepositoryJavaClientImpl implements RepositoryClient<PoxPayloadIn,
         final String TERM_GROUP_TABLE_NAME_PARAM = "TERM_GROUP_TABLE_NAME";
         final String IN_AUTHORITY_PARAM = "IN_AUTHORITY";
         // Get this from a constant in AuthorityResource or equivalent
-        final String PARENT_WILDCARD = "_ALL_"; 
+        final String PARENT_WILDCARD = "_ALL_";
         
+        // Build two SQL statements, to be executed within a single transaction:
+        // the first statement to control join order, and the second statement
+        // representing the actual 'get filtered' query
+        
+        // Build the join control statement
+        //
+        // Per http://www.postgresql.org/docs/9.2/static/runtime-config-query.html#GUC-JOIN-COLLAPSE-LIMIT
+        // "Setting [this value] to 1 prevents any reordering of explicit JOINs.
+        // Thus, the explicit join order specified in the query will be the
+        // actual order in which the relations are joined."
+        // See CSPACE-5945 for further discussion of why this setting is needed.
+        String joinControlSql = "SET LOCAL join_collapse_limit TO 1;";
+        
+        // Build the query statement
+        //
         // Start with the default query
         String selectStatement =
                 "SELECT DISTINCT hierarchy_termgroup.parentid as id"
@@ -1035,39 +1051,54 @@ public class RepositoryJavaClientImpl implements RepositoryClient<PoxPayloadIn,
         }
         
         // Piece together the SQL query from its parts
-        String sql = selectStatement + joinClauses + whereClause + orderByClause + limitClause;
+        String querySql = selectStatement + joinClauses + whereClause + orderByClause + limitClause;
         
         // Note: PostgreSQL 9.2 introduced a change that may improve performance
         // of certain queries using JDBC PreparedStatements.  See comments on
         // CSPACE-5943 for details.
-        PreparedStatementSimpleBuilder jdbcFilterQueryBuilder = new PreparedStatementSimpleBuilder(sql, params);
+        PreparedStatementBuilder joinControlBuilder = new PreparedStatementBuilder(joinControlSql);
+        PreparedStatementSimpleBuilder queryBuilder = new PreparedStatementSimpleBuilder(querySql, params);
+        List<PreparedStatementBuilder> builders = new ArrayList<>();
+        builders.add(joinControlBuilder);
+        builders.add(queryBuilder);
         String dataSourceName = JDBCTools.NUXEO_DATASOURCE_NAME;
         String repositoryName = ctx.getRepositoryName();
+        final Boolean EXECUTE_WITHIN_TRANSACTION = true;
         Set<String> docIds = new HashSet<>();
-        try (CachedRowSet crs = JDBCTools.executePreparedQuery(jdbcFilterQueryBuilder,
-                dataSourceName, repositoryName, sql)) {
+        try {
+            List<CachedRowSet> resultsList = JDBCTools.executePreparedQueries(builders,
+                dataSourceName, repositoryName, EXECUTE_WITHIN_TRANSACTION);
 
-            // If the response to the query is null or contains zero rows,
+            // One set of results are expected, from the second prepared statement executed.
+            // If fewer results are returned, return an empty list of document models
+            if (resultsList == null || resultsList.size() < 1) {
+                return result;
+            }
+            // Join control query will not return results, so query results will
+            // be the first set of results (rowSet) returned in the list
+            CachedRowSet queryResults = resultsList.get(0);
+            
+            // If the result from executing the query is null or contains zero rows,
             // return an empty list of document models
-            if (crs == null) {
+            if (queryResults == null) {
                 return result;
             }
-            crs.last();
-            if (crs.getRow() == 0) {
+            queryResults.last();
+            if (queryResults.getRow() == 0) {
                 return result; // empty list of document models
             }
 
             // Otherwise, get the document IDs from the results of the query
             String id;
-            crs.beforeFirst();
-            while (crs.next()) {
-                id = crs.getString(1);
+            queryResults.beforeFirst();
+            while (queryResults.next()) {
+                id = queryResults.getString(1);
                 if (Tools.notBlank(id)) {
                     docIds.add(id);
                 }
             }
         } catch (SQLException sqle) {
-            logger.warn("Could not obtain document IDs via SQL query '" + sql + "': " + sqle.getMessage());
+            logger.warn("Could not obtain document IDs via SQL query '" + querySql + "': " + sqle.getMessage());
             return result; // return an empty list of document models
         }