public void executeClear(ObjectProvider ownerOP) {
    String clearStmt = getClearStmt();
    try {
      ExecutionContext ec = ownerOP.getExecutionContext();
      ManagedConnection mconn = storeMgr.getConnection(ec);
      SQLController sqlControl = storeMgr.getSQLController();
      try {
        PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, clearStmt, false);
        try {
          int jdbcPosition = 1;
          jdbcPosition =
              BackingStoreHelper.populateOwnerInStatement(ownerOP, ec, ps, jdbcPosition, this);
          if (getRelationDiscriminatorMapping() != null) {
            BackingStoreHelper.populateRelationDiscriminatorInStatement(ec, ps, jdbcPosition, this);
          }

          sqlControl.executeStatementUpdate(ec, mconn, clearStmt, ps, true);
        } finally {
          sqlControl.closeStatement(mconn, ps);
        }
      } finally {
        mconn.release();
      }
    } catch (SQLException e) {
      throw new NucleusDataStoreException(Localiser.msg("056013", clearStmt), e);
    }
  }
  @Override
  public NucleusConnection getNucleusConnection(ExecutionContext ec) {
    ConnectionFactory cf = connectionMgr.lookupConnectionFactory(primaryConnectionFactoryName);

    final ManagedConnection mc;
    final boolean enlisted;
    enlisted = ec.getTransaction().isActive();
    mc =
        cf.getConnection(
            enlisted ? ec : null,
            ec.getTransaction(),
            null); // Will throw exception if already locked

    // Lock the connection now that it is in use by the user
    mc.lock();

    Runnable closeRunnable =
        new Runnable() {
          public void run() {
            // Unlock the connection now that the user has finished with it
            mc.unlock();
            if (!enlisted) {
              // TODO Anything to do here?
            }
          }
        };
    return new NucleusConnectionImpl(mc.getConnection(), closeRunnable);
  }
  /**
   * Clear the association from owner to all elements. Provides cascade-delete when the elements
   * being deleted are PC types.
   *
   * @param ownerOP ObjectProvider for the container.
   */
  public void clear(ObjectProvider ownerOP) {
    Collection dependentElements = null;
    CollectionMetaData collmd = ownerMemberMetaData.getCollection();
    boolean dependent = collmd.isDependentElement();
    if (ownerMemberMetaData.isCascadeRemoveOrphans()) {
      dependent = true;
    }
    if (dependent && !collmd.isEmbeddedElement() && !collmd.isSerializedElement()) {
      // Retain the dependent elements that need deleting after clearing
      dependentElements = new HashSet();
      Iterator iter = iterator(ownerOP);
      while (iter.hasNext()) {
        dependentElements.add(iter.next());
      }
    }

    String clearStmt = getClearStmt();
    try {
      ExecutionContext ec = ownerOP.getExecutionContext();
      ManagedConnection mconn = storeMgr.getConnection(ec);
      SQLController sqlControl = storeMgr.getSQLController();
      try {
        PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, clearStmt, false);
        try {
          int jdbcPosition = 1;
          jdbcPosition =
              BackingStoreHelper.populateOwnerInStatement(ownerOP, ec, ps, jdbcPosition, this);
          if (relationDiscriminatorMapping != null) {
            BackingStoreHelper.populateRelationDiscriminatorInStatement(ec, ps, jdbcPosition, this);
          }

          sqlControl.executeStatementUpdate(ec, mconn, clearStmt, ps, true);
        } finally {
          sqlControl.closeStatement(mconn, ps);
        }
      } finally {
        mconn.release();
      }
    } catch (SQLException e) {
      throw new NucleusDataStoreException(Localiser.msg("056013", clearStmt), e);
    }

    // Cascade-delete
    if (dependentElements != null && dependentElements.size() > 0) {
      Iterator iter = dependentElements.iterator();
      while (iter.hasNext()) {
        Object obj = iter.next();
        if (ownerOP.getExecutionContext().getApiAdapter().isDeleted(obj)) {
          // Element is tagged for deletion so will be deleted at flush(), and we dont need it
          // immediately
        } else {
          ownerOP.getExecutionContext().deleteObjectInternal(obj);
        }
      }
    }
  }
  public int getSize(ObjectProvider ownerOP) {
    int numRows;

    String sizeStmt = getSizeStmt();
    try {
      ExecutionContext ec = ownerOP.getExecutionContext();
      ManagedConnection mconn = storeMgr.getConnection(ec);
      SQLController sqlControl = storeMgr.getSQLController();
      try {
        PreparedStatement ps = sqlControl.getStatementForQuery(mconn, sizeStmt);
        try {
          int jdbcPosition = 1;
          jdbcPosition =
              BackingStoreHelper.populateOwnerInStatement(ownerOP, ec, ps, jdbcPosition, this);
          if (getElementInfo() != null && getElementInfo().length == 1) {
            // TODO Allow for multiple element types (e.g interface implementations)
            for (int i = 0; i < getElementInfo().length; i++) {
              if (getElementInfo()[i].getDiscriminatorMapping() != null) {
                jdbcPosition =
                    BackingStoreHelper.populateElementDiscriminatorInStatement(
                        ec, ps, jdbcPosition, true, getElementInfo()[i], clr);
              }
            }
          }
          if (getRelationDiscriminatorMapping() != null) {
            jdbcPosition =
                BackingStoreHelper.populateRelationDiscriminatorInStatement(
                    ec, ps, jdbcPosition, this);
          }

          ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, sizeStmt, ps);
          try {
            if (!rs.next()) {
              throw new NucleusDataStoreException(Localiser.msg("056007", sizeStmt));
            }

            numRows = rs.getInt(1);
            JDBCUtils.logWarnings(rs);
          } finally {
            rs.close();
          }
        } finally {
          sqlControl.closeStatement(mconn, ps);
        }
      } finally {
        mconn.release();
      }
    } catch (SQLException e) {
      throw new NucleusDataStoreException(Localiser.msg("056007", sizeStmt), e);
    }

    return numRows;
  }
  /**
   * Convenience method to create a new PreparedStatement for a query.
   *
   * @param conn The Connection to use for the statement
   * @param stmtText Statement text
   * @param resultSetType Type of result set
   * @param resultSetConcurrency Concurrency for the result set
   * @return The PreparedStatement
   * @throws SQLException thrown if an error occurs creating the statement
   */
  public PreparedStatement getStatementForQuery(
      ManagedConnection conn, String stmtText, String resultSetType, String resultSetConcurrency)
      throws SQLException {
    Connection c = (Connection) conn.getConnection();
    if (supportsBatching) {
      // Check for a waiting batched statement that is ready for processing
      ConnectionStatementState state = getConnectionStatementState(conn);
      if (state != null && state.processable) {
        // Process the batch statement before returning our new query statement
        processConnectionStatement(conn);
      }
    }

    // Create a new PreparedStatement for this query
    PreparedStatement ps = null;
    if (resultSetType != null || resultSetConcurrency != null) {
      int rsTypeValue = ResultSet.TYPE_FORWARD_ONLY;
      if (resultSetType != null) {
        if (resultSetType.equals("scroll-sensitive")) {
          rsTypeValue = ResultSet.TYPE_SCROLL_SENSITIVE;
        } else if (resultSetType.equals("scroll-insensitive")) {
          rsTypeValue = ResultSet.TYPE_SCROLL_INSENSITIVE;
        }
      }

      int rsConcurrencyValue = ResultSet.CONCUR_READ_ONLY;
      if (resultSetConcurrency != null && resultSetConcurrency.equals("updateable")) {
        rsConcurrencyValue = ResultSet.CONCUR_UPDATABLE;
      }
      ps = c.prepareStatement(stmtText, rsTypeValue, rsConcurrencyValue);
      ps
          .clearBatch(); // In case using statement caching and given one with batched statements
                         // left hanging (C3P0)
    } else {
      ps = c.prepareStatement(stmtText);
      ps
          .clearBatch(); // In case using statement caching and given one with batched statements
                         // left hanging (C3P0)
    }

    if (queryTimeout > 0) {
      // Apply any query timeout
      ps.setQueryTimeout(queryTimeout / 1000); // queryTimeout is in milliseconds
    }
    if (NucleusLogger.DATASTORE.isDebugEnabled()) {
      NucleusLogger.DATASTORE.debug(LOCALISER.msg("052110", StringUtils.toJVMIDString(ps)));
    }

    if (!jdbcStatements) {
      // Wrap with our parameter logger
      ps = new ParamLoggingPreparedStatement(ps, stmtText);
      ((ParamLoggingPreparedStatement) ps).setParamsInAngleBrackets(paramValuesInBrackets);
    }

    return ps;
  }
Exemple #6
0
  @SuppressWarnings({"rawtypes", "unchecked"})
  protected Object performExecute(Map parameters) {
    AbstractClassMetaData cmd =
        ec.getMetaDataManager().getMetaDataForClass(candidateClass, ec.getClassLoaderResolver());
    ManagedConnection mconn = getStoreManager().getConnection(ec);

    try {
      // get all stored instances of class candidateClass
      Collection candidates;
      if (candidateCollection == null) {
        candidates = ScalarisUtils.getObjectsOfCandidateType(ec, mconn, candidateClass, cmd);
      } else {
        candidates = new ArrayList<Object>(candidateCollection);
      }

      // JDOQLEvaluator's ResultClassMapper (needed when using JDOQLs INTO keyword)
      // does not support alias

      // execute query
      JavaQueryEvaluator resultMapper =
          new JDOQLEvaluator(
              this, candidates, compilation, parameters, ec.getClassLoaderResolver());
      Collection result = resultMapper.execute(true, true, true, false, true);

      // apply a custom ResultClassMapper because the mapper used by
      // DataNucleus does not support alias' while wrapping

      Expression[] expResult = compilation.getExprResult();
      if (expResult != null
          && getResultClass() != null
          && !(expResult[0] instanceof CreatorExpression)) {
        return mapResultClass(result, expResult);
      }

      return result;
    } finally {
      mconn.release();
    }
  }
  /**
   * Convenience method to set the state for this connection.
   *
   * @param conn The Connection
   * @param state The state
   */
  protected void setConnectionStatementState(
      final ManagedConnection conn, ConnectionStatementState state) {
    connectionStatements.put(conn, state);
    conn.addListener(
        new ManagedConnectionResourceListener() {
          public void transactionFlushed() {
            try {
              processStatementsForConnection(conn);
            } catch (SQLException e) {
              // cleanup state
              ConnectionStatementState state = getConnectionStatementState(conn);
              if (state != null) {
                // Remove the current connection statement
                removeConnectionStatementState(conn);

                // Close the statement if it is registered for closing after processing
                if (state.closeStatementOnProcess) {
                  try {
                    state.stmt.close();
                  } catch (SQLException ex) {
                    // ignore
                  }
                }
              }

              throw new NucleusDataStoreException(LOCALISER.msg("052108"), e);
            }
          }

          public void transactionPreClose() {}

          public void managedConnectionPreClose() {}

          public void managedConnectionPostClose() {}

          public void resourcePostClose() {}
        });
  }
 /**
  * Accessor for the current DatastoreService for this ExecutionContext. Each PM/EM has its own
  * DatastoreService.
  *
  * @param ec ExecutionContext
  * @return The DatastoreService
  */
 public DatastoreService getDatastoreService(ExecutionContext ec) {
   ManagedConnection mconn = ec.getStoreManager().getConnection(ec);
   return ((EmulatedXAResource) mconn.getXAResource()).getDatastoreService();
 }
 /**
  * Accessor for the current DatastoreTransaction for this ExecutionContext. Each PM/EM has its own
  * DatastoreService, and consequently can have a current DatastoreTransaction.
  *
  * @param ec ExecutionContext
  * @return The DatastoreTransaction if active, or null
  */
 public DatastoreTransaction getDatastoreTransaction(ExecutionContext ec) {
   ManagedConnection mconn = ec.getStoreManager().getConnection(ec);
   return ((EmulatedXAResource) mconn.getXAResource()).getCurrentTransaction();
 }
  /**
   * Utility that does a discriminator candidate query for the specified candidate and subclasses
   * and returns the class name of the instance that has the specified identity (if any).
   *
   * @param storeMgr RDBMS StoreManager
   * @param ec execution context
   * @param id The id
   * @param cmd Metadata for the root candidate class
   * @return Name of the class with this identity (or null if none found)
   */
  public static String getClassNameForIdUsingDiscriminator(
      RDBMSStoreManager storeMgr, ExecutionContext ec, Object id, AbstractClassMetaData cmd) {
    // Check for input error
    if (cmd == null || id == null) {
      return null;
    }

    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    DatastoreClass primaryTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr);

    // Form the query to find which one of these classes has the instance with this id
    DiscriminatorStatementGenerator stmtGen =
        new DiscriminatorStatementGenerator(
            storeMgr, clr, clr.classForName(cmd.getFullClassName()), true, null, null);
    stmtGen.setOption(SelectStatementGenerator.OPTION_RESTRICT_DISCRIM);
    SelectStatement sqlStmt = stmtGen.getStatement();

    // Select the discriminator
    JavaTypeMapping discrimMapping = primaryTable.getDiscriminatorMapping(true);
    SQLTable discrimSqlTbl =
        SQLStatementHelper.getSQLTableForMappingOfTable(
            sqlStmt, sqlStmt.getPrimaryTable(), discrimMapping);
    sqlStmt.select(discrimSqlTbl, discrimMapping, null);

    // Restrict to this id
    JavaTypeMapping idMapping = primaryTable.getIdMapping();
    JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
    SQLExpression sqlFldExpr =
        exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
    SQLExpression sqlFldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
    sqlStmt.whereAnd(sqlFldExpr.eq(sqlFldVal), true);

    // Perform the query
    try {
      ManagedConnection mconn = storeMgr.getConnection(ec);
      SQLController sqlControl = storeMgr.getSQLController();
      if (ec.getSerializeReadForClass(cmd.getFullClassName())) {
        sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
      }

      try {
        PreparedStatement ps =
            SQLStatementHelper.getPreparedStatementForSQLStatement(sqlStmt, ec, mconn, null, null);
        String statement = sqlStmt.getSQLText().toSQL();
        try {
          ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, statement, ps);
          try {
            if (rs != null) {
              while (rs.next()) {
                DiscriminatorMetaData dismd = discrimMapping.getTable().getDiscriminatorMetaData();
                return RDBMSQueryUtils.getClassNameFromDiscriminatorResultSetRow(
                    discrimMapping, dismd, rs, ec);
              }
            }
          } finally {
            rs.close();
          }
        } finally {
          sqlControl.closeStatement(mconn, ps);
        }
      } finally {
        mconn.release();
      }
    } catch (SQLException sqe) {
      NucleusLogger.DATASTORE.error("Exception thrown on querying of discriminator for id", sqe);
      throw new NucleusDataStoreException(sqe.toString(), sqe);
    }

    return null;
  }
  /**
   * Utility that does a union candidate query for the specified candidate(s) and subclasses and
   * returns the class name of the instance that has the specified identity (if any).
   *
   * @param storeMgr RDBMS StoreManager
   * @param ec execution context
   * @param id The id
   * @param rootCmds Metadata for the classes at the root
   * @return Name of the class with this identity (or null if none found)
   */
  public static String getClassNameForIdUsingUnion(
      RDBMSStoreManager storeMgr,
      ExecutionContext ec,
      Object id,
      List<AbstractClassMetaData> rootCmds) {
    // Check for input error
    if (rootCmds == null || rootCmds.isEmpty() || id == null) {
      return null;
    }

    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    ClassLoaderResolver clr = ec.getClassLoaderResolver();

    // Form a query UNIONing all possible root candidates (and their subclasses)
    Iterator<AbstractClassMetaData> rootCmdIter = rootCmds.iterator();

    AbstractClassMetaData sampleCmd =
        null; // Metadata for sample class in the tree so we can check if needs locking
    SelectStatement sqlStmtMain = null;
    while (rootCmdIter.hasNext()) {
      AbstractClassMetaData rootCmd = rootCmdIter.next();
      DatastoreClass rootTbl = storeMgr.getDatastoreClass(rootCmd.getFullClassName(), clr);
      if (rootTbl == null) {
        // Class must be using "subclass-table" (no table of its own) so find where it is
        AbstractClassMetaData[] subcmds = storeMgr.getClassesManagingTableForClass(rootCmd, clr);
        if (subcmds == null || subcmds.length == 0) {
          // No table for this class so ignore
        } else {
          for (int i = 0; i < subcmds.length; i++) {
            UnionStatementGenerator stmtGen =
                new UnionStatementGenerator(
                    storeMgr,
                    clr,
                    clr.classForName(subcmds[i].getFullClassName()),
                    true,
                    null,
                    null);
            stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_NUCLEUS_TYPE);
            if (sqlStmtMain == null) {
              sampleCmd = subcmds[i];
              sqlStmtMain = stmtGen.getStatement();

              // WHERE (object id) = ?
              JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping();
              JavaTypeMapping idParamMapping =
                  new PersistableIdMapping((PersistableMapping) idMapping);
              SQLExpression fieldExpr =
                  exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping);
              SQLExpression fieldVal =
                  exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID");
              sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true);
            } else {
              SelectStatement sqlStmt = stmtGen.getStatement();

              // WHERE (object id) = ?
              JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
              JavaTypeMapping idParamMapping =
                  new PersistableIdMapping((PersistableMapping) idMapping);
              SQLExpression fieldExpr =
                  exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
              SQLExpression fieldVal =
                  exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
              sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true);

              sqlStmtMain.union(sqlStmt);
            }
          }
        }
      } else {
        UnionStatementGenerator stmtGen =
            new UnionStatementGenerator(
                storeMgr, clr, clr.classForName(rootCmd.getFullClassName()), true, null, null);
        stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_NUCLEUS_TYPE);
        if (sqlStmtMain == null) {
          sampleCmd = rootCmd;
          sqlStmtMain = stmtGen.getStatement();

          // WHERE (object id) = ?
          JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping();
          JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
          SQLExpression fieldExpr =
              exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping);
          SQLExpression fieldVal =
              exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID");
          sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true);
        } else {
          SelectStatement sqlStmt = stmtGen.getStatement();

          // WHERE (object id) = ?
          JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
          JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
          SQLExpression fieldExpr =
              exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
          SQLExpression fieldVal =
              exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
          sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true);

          sqlStmtMain.union(sqlStmt);
        }
      }
    }

    // Perform the query
    try {
      ManagedConnection mconn = storeMgr.getConnection(ec);
      SQLController sqlControl = storeMgr.getSQLController();
      if (ec.getSerializeReadForClass(sampleCmd.getFullClassName())) {
        sqlStmtMain.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
      }

      try {
        PreparedStatement ps =
            SQLStatementHelper.getPreparedStatementForSQLStatement(
                sqlStmtMain, ec, mconn, null, null);
        String statement = sqlStmtMain.getSQLText().toSQL();
        try {
          ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, statement, ps);
          try {
            if (rs != null) {
              while (rs.next()) {
                try {
                  return rs.getString(UnionStatementGenerator.NUC_TYPE_COLUMN).trim();
                } catch (SQLException sqle) {
                }
              }
            }
          } finally {
            rs.close();
          }
        } finally {
          sqlControl.closeStatement(mconn, ps);
        }
      } finally {
        mconn.release();
      }
    } catch (SQLException sqe) {
      NucleusLogger.DATASTORE.error("Exception with UNION statement", sqe);
      throw new NucleusDataStoreException(sqe.toString());
    }

    return null;
  }
  public int getSize(ObjectProvider ownerOP) {
    int numRows;

    String sizeStmt = getSizeStmt();
    try {
      ExecutionContext ec = ownerOP.getExecutionContext();
      ManagedConnection mconn = storeMgr.getConnection(ec);
      SQLController sqlControl = storeMgr.getSQLController();
      try {
        PreparedStatement ps = sqlControl.getStatementForQuery(mconn, sizeStmt);
        try {
          int jdbcPosition = 1;
          if (elementInfo == null) {
            jdbcPosition =
                BackingStoreHelper.populateOwnerInStatement(ownerOP, ec, ps, jdbcPosition, this);
          } else {
            if (usingJoinTable()) {
              jdbcPosition =
                  BackingStoreHelper.populateOwnerInStatement(ownerOP, ec, ps, jdbcPosition, this);
              if (elementInfo[0].getDiscriminatorMapping() != null) {
                jdbcPosition =
                    BackingStoreHelper.populateElementDiscriminatorInStatement(
                        ec, ps, jdbcPosition, true, elementInfo[0], clr);
              }
              if (relationDiscriminatorMapping != null) {
                jdbcPosition =
                    BackingStoreHelper.populateRelationDiscriminatorInStatement(
                        ec, ps, jdbcPosition, this);
              }
            } else {
              for (int i = 0; i < elementInfo.length; i++) {
                jdbcPosition =
                    BackingStoreHelper.populateOwnerInStatement(
                        ownerOP, ec, ps, jdbcPosition, this);
                if (elementInfo[i].getDiscriminatorMapping() != null) {
                  jdbcPosition =
                      BackingStoreHelper.populateElementDiscriminatorInStatement(
                          ec, ps, jdbcPosition, true, elementInfo[i], clr);
                }
                if (relationDiscriminatorMapping != null) {
                  jdbcPosition =
                      BackingStoreHelper.populateRelationDiscriminatorInStatement(
                          ec, ps, jdbcPosition, this);
                }
              }
            }
          }

          ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, sizeStmt, ps);
          try {
            if (!rs.next()) {
              throw new NucleusDataStoreException(Localiser.msg("056007", sizeStmt));
            }

            numRows = rs.getInt(1);

            if (elementInfo != null && elementInfo.length > 1) {
              while (rs.next()) {
                numRows = numRows + rs.getInt(1);
              }
            }

            JDBCUtils.logWarnings(rs);
          } finally {
            rs.close();
          }
        } catch (SQLException sqle) {
          NucleusLogger.GENERAL.error("Exception in size", sqle);
          throw sqle;
        } finally {
          sqlControl.closeStatement(mconn, ps);
        }
      } finally {
        mconn.release();
      }
    } catch (SQLException e) {
      throw new NucleusDataStoreException(Localiser.msg("056007", sizeStmt), e);
    }

    return numRows;
  }
  /**
   * Convenience method to create a new PreparedStatement for an update.
   *
   * @param conn The Connection to use for the statement
   * @param stmtText Statement text
   * @param batchable Whether this statement is batchable. Whether we will process the statement
   *     before any other statement
   * @param getGeneratedKeysFlag whether to request getGeneratedKeys for this statement
   * @return The PreparedStatement
   * @throws SQLException thrown if an error occurs creating the statement
   */
  public PreparedStatement getStatementForUpdate(
      ManagedConnection conn, String stmtText, boolean batchable, boolean getGeneratedKeysFlag)
      throws SQLException {
    Connection c = (Connection) conn.getConnection();
    if (supportsBatching) {
      ConnectionStatementState state = getConnectionStatementState(conn);
      if (state != null) {
        if (state.processable) {
          // We have a batchable statement in the queue that could be processed now if necessary
          if (!batchable) {
            // This new statement isnt batchable so process the existing one before returning our
            // new statement
            processConnectionStatement(conn);
          } else {
            // Check if we could batch onto this existing statement
            if (state.stmtText.equals(stmtText)) {
              // We can batch onto this statement
              if (maxBatchSize == -1 || state.batchSize < maxBatchSize) {
                state.batchSize++;
                state.processable =
                    false; // Have to wait til we process this part til processable again
                if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) {
                  NucleusLogger.DATASTORE_PERSIST.debug(
                      LOCALISER.msg("052100", stmtText, "" + state.batchSize));
                }
                return state.stmt;
              } else {
                // Reached max batch size so process it now and start again for this one
                if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) {
                  NucleusLogger.DATASTORE_PERSIST.debug(LOCALISER.msg("052101", state.stmtText));
                }
                processConnectionStatement(conn);
              }
            } else {
              // We cant batch using the current batch statement so process it first and return our
              // new one
              processConnectionStatement(conn);
            }
          }
        } else {
          if (batchable) {
            // The current statement is being batched so we cant batch this since cant process the
            // current statement now
            if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) {
              NucleusLogger.DATASTORE_PERSIST.debug(
                  LOCALISER.msg("052102", state.stmtText, stmtText));
            }
            batchable = false;
          }
        }
      }
    }

    PreparedStatement ps =
        (getGeneratedKeysFlag
            ? c.prepareStatement(stmtText, Statement.RETURN_GENERATED_KEYS)
            : c.prepareStatement(stmtText));
    ps
        .clearBatch(); // In case using statement caching and given one with batched statements left
                       // hanging (C3P0)
    if (!jdbcStatements) {
      // Wrap with our parameter logger
      ps = new ParamLoggingPreparedStatement(ps, stmtText);
      ((ParamLoggingPreparedStatement) ps).setParamsInAngleBrackets(paramValuesInBrackets);
    }
    if (NucleusLogger.DATASTORE.isDebugEnabled()) {
      NucleusLogger.DATASTORE.debug(LOCALISER.msg("052109", ps, StringUtils.toJVMIDString(c)));
    }

    if (batchable && supportsBatching) {
      // This statement is batchable so save it as the current batchable
      if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) {
        NucleusLogger.DATASTORE_PERSIST.debug(LOCALISER.msg("052103", stmtText));
      }
      ConnectionStatementState state = new ConnectionStatementState();
      state.stmt = ps;
      state.stmtText = stmtText;
      state.batchSize = 1;
      setConnectionStatementState(conn, state);
    }

    return ps;
  }