| /******************************************************************************* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| *******************************************************************************/ |
| package org.apache.ofbiz.entity.jdbc; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.ObjectOutputStream; |
| import java.math.BigDecimal; |
| import java.sql.Blob; |
| import java.sql.Clob; |
| import java.sql.Connection; |
| import java.sql.PreparedStatement; |
| import java.sql.ResultSet; |
| import java.sql.ResultSetMetaData; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.sql.Types; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.apache.ofbiz.base.util.Debug; |
| import org.apache.ofbiz.entity.Delegator; |
| import org.apache.ofbiz.entity.GenericDataSourceException; |
| import org.apache.ofbiz.entity.GenericEntityException; |
| import org.apache.ofbiz.entity.config.model.Datasource; |
| import org.apache.ofbiz.entity.config.model.EntityConfig; |
| import org.apache.ofbiz.entity.datasource.GenericHelperInfo; |
| import org.apache.ofbiz.entity.transaction.GenericTransactionException; |
| import org.apache.ofbiz.entity.transaction.TransactionFactoryLoader; |
| import org.apache.ofbiz.entity.transaction.TransactionUtil; |
| |
| /** |
| * SQLProcessor - provides utility functions to ease database access |
| * |
| */ |
| public class SQLProcessor { |
| |
| /** Module Name Used for debugging */ |
| public static final String module = SQLProcessor.class.getName(); |
| |
| /** Used for testing connections when test is enabled */ |
| public static List<String> CONNECTION_TEST_LIST = new ArrayList<String>(); |
| public static int MAX_CONNECTIONS = 1000; |
| public static boolean ENABLE_TEST = false; |
| |
| private final Delegator delegator; |
| |
| /** The datasource helper (see entityengine.xml <datasource name="..">) */ |
| private GenericHelperInfo helperInfo; |
| |
| // / The database resources to be used |
| private Connection _connection = null; |
| |
| // / The database resources to be used |
| private PreparedStatement _ps = null; |
| |
| // / The database resources to be used |
| private ResultSet _rs = null; |
| |
| private ResultSetMetaData _rsmd = null; |
| |
| // / The SQL String used. Use for debugging only |
| private String _sql; |
| |
| // / Index to be used with preparedStatement.setValue(_ind, ...) |
| private int _ind; |
| |
| // / true in case of manual transactions |
| private boolean _manualTX; |
| |
| // / true in case the connection shall be closed. |
| private boolean _bDeleteConnection = false; |
| |
| /** |
| * Construct an object based on the helper/datasource |
| * |
| * @param helperInfo The datasource helper (see entityengine.xml <datasource name="..">) |
| */ |
| public SQLProcessor(Delegator delegator, GenericHelperInfo helperInfo) { |
| this.delegator = delegator; |
| this.helperInfo = helperInfo; |
| this._manualTX = true; |
| } |
| |
| /** |
| * Construct an object with an connection given. The connection will not |
| * be closed by this SQLProcessor, but may be by some other. |
| * |
| * @param helperInfo The datasource helper (see entityengine.xml <datasource name="..">) |
| * @param connection The connection to be used |
| */ |
| public SQLProcessor(Delegator delegator, GenericHelperInfo helperInfo, Connection connection) { |
| this.delegator = delegator; |
| this.helperInfo = helperInfo; |
| this._connection = connection; |
| |
| // Do not commit while closing |
| if (_connection != null) { |
| _manualTX = false; |
| } |
| } |
| |
| public Delegator getDelegator() { |
| return delegator; |
| } |
| |
| ResultSetMetaData getResultSetMetaData() { |
| if (_rsmd == null) { |
| // try the ResultSet, if not null, or try the PreparedStatement, also if not null |
| try { |
| if (_rs != null) { |
| _rsmd = _rs.getMetaData(); |
| } else if (_ps != null) { |
| _rsmd = _ps.getMetaData(); |
| } |
| } catch (SQLException sqle2) { |
| Debug.logWarning("[SQLProcessor.rollback]: SQL Exception while rolling back insert. Error was:" + sqle2, module); |
| Debug.logWarning(sqle2, module); |
| } |
| } |
| return _rsmd; |
| } |
| |
| /** |
| * Commit all modifications |
| * |
| * @throws GenericDataSourceException |
| */ |
| public void commit() throws GenericDataSourceException { |
| if (_connection == null) { |
| return; |
| } |
| |
| if (Debug.verboseOn()) Debug.logVerbose("SQLProcessor:commit() _manualTX=" + _manualTX, module); |
| |
| if (_manualTX) { |
| try { |
| _connection.commit(); |
| if (Debug.verboseOn()) Debug.logVerbose("SQLProcessor:commit() : called commit on connection", module); |
| } catch (SQLException sqle) { |
| Debug.logError(sqle, "Error committing transaction: " + sqle.toString()); |
| try { |
| rollback(); |
| } catch (GenericDataSourceException rbsqle) { |
| Debug.logError(rbsqle, "Got another error when trying to rollback after error committing transaction: " + sqle.toString()); |
| } |
| throw new GenericDataSourceException("SQL Exception occurred on commit", sqle); |
| } |
| } |
| } |
| |
| /** |
| * Rollback all modifications |
| */ |
| public void rollback() throws GenericDataSourceException { |
| if (_connection == null) { |
| return; |
| } |
| |
| if (Debug.verboseOn()) Debug.logVerbose("SQLProcessor:rollback() _manualTX=" + _manualTX, module); |
| |
| try { |
| if (_manualTX) { |
| _connection.rollback(); |
| if (Debug.verboseOn()) Debug.logVerbose("SQLProcessor:rollback() : _manualTX=" + _manualTX, module); |
| } else { |
| try { |
| TransactionUtil.setRollbackOnly("rollback called in Entity Engine SQLProcessor", new Exception("Current Location Stack")); |
| if (Debug.verboseOn()) Debug.logVerbose("SQLProcessor:rollback() : _manualTX=" + _manualTX, module); |
| } catch (GenericTransactionException e) { |
| Debug.logError(e, "Error setting rollback only", module); |
| throw new GenericDataSourceException("Error setting rollback only", e); |
| } |
| } |
| } catch (SQLException sqle2) { |
| Debug.logWarning("[SQLProcessor.rollback]: SQL Exception while rolling back insert. Error was:" + sqle2, module); |
| Debug.logWarning(sqle2, module); |
| } |
| } |
| |
| /** |
| * Commit if required and remove all allocated resources |
| * |
| * @throws GenericDataSourceException |
| */ |
| public void close() throws GenericDataSourceException { |
| if (_manualTX) { |
| if (Debug.verboseOn()) Debug.logVerbose("SQLProcessor:close() calling commit : _manualTX=" + _manualTX, module); |
| commit(); |
| } |
| |
| _sql = null; |
| |
| if (_rs != null) { |
| try { |
| _rs.close(); |
| if (Debug.verboseOn()) Debug.logVerbose("SQLProcessor:close() result close : _manualTX=" + _manualTX, module); |
| } catch (SQLException sqle) { |
| Debug.logWarning(sqle.getMessage(), module); |
| } |
| |
| _rs = null; |
| } |
| |
| if (_ps != null) { |
| try { |
| _ps.close(); |
| if (Debug.verboseOn()) Debug.logVerbose("SQLProcessor:close() preparedStatement close : _manualTX=" + _manualTX, module); |
| } catch (SQLException sqle) { |
| Debug.logWarning(sqle.getMessage(), module); |
| } |
| |
| _ps = null; |
| } |
| |
| if ((_connection != null) && _bDeleteConnection) { |
| try { |
| _connection.close(); |
| if (Debug.verboseOn()) Debug.logVerbose("SQLProcessor:close() connection close : _manualTX=" + _manualTX, module); |
| } catch (SQLException sqle) { |
| Debug.logWarning(sqle.getMessage(), module); |
| } |
| |
| _connection = null; |
| } |
| } |
| |
| /** |
| * Get a connection from the TransactionFactoryLoader |
| * |
| * @return The connection created |
| * |
| * @throws GenericDataSourceException |
| * @throws GenericEntityException |
| */ |
| public Connection getConnection() throws GenericDataSourceException, GenericEntityException { |
| if (_connection != null) |
| return _connection; |
| |
| _manualTX = true; |
| |
| try { |
| _connection = TransactionFactoryLoader.getInstance().getConnection(helperInfo); |
| if (Debug.verboseOn()) Debug.logVerbose("SQLProcessor:connection() : manualTx=" + _manualTX, module); |
| } catch (SQLException sqle) { |
| throw new GenericDataSourceException("Unable to establish a connection with the database.", sqle); |
| } |
| |
| // make sure we actually did get a connection |
| if (_connection == null) { |
| throw new GenericDataSourceException("Unable to establish a connection with the database. Connection was null!"); |
| } |
| |
| // test the connection |
| testConnection(_connection); |
| |
| /* causes problems w/ postgres ?? |
| if (Debug.verboseOn()) { |
| int isoLevel = -999; |
| try { |
| isoLevel = _connection.getTransactionIsolation(); |
| } catch (SQLException e) { |
| Debug.logError(e, "Problems getting the connection's isolation level", module); |
| } |
| if (isoLevel == Connection.TRANSACTION_NONE) { |
| Debug.logVerbose("Transaction isolation level set to 'None'.", module); |
| } else if (isoLevel == Connection.TRANSACTION_READ_COMMITTED) { |
| Debug.logVerbose("Transaction isolation level set to 'ReadCommited'.", module); |
| } else if (isoLevel == Connection.TRANSACTION_READ_UNCOMMITTED) { |
| Debug.logVerbose("Transaction isolation level set to 'ReadUncommitted'.", module); |
| } else if (isoLevel == Connection.TRANSACTION_REPEATABLE_READ) { |
| Debug.logVerbose("Transaction isolation level set to 'RepeatableRead'.", module); |
| } else if (isoLevel == Connection.TRANSACTION_SERIALIZABLE) { |
| Debug.logVerbose("Transaction isolation level set to 'Serializable'.", module); |
| } |
| } |
| */ |
| |
| // always try to set auto commit to false, but if we can't then later on we won't commit |
| try { |
| if (_connection.getAutoCommit()) { |
| try { |
| _connection.setAutoCommit(false); |
| if (Debug.verboseOn()) Debug.logVerbose("SQLProcessor:setAutoCommit(false) : manualTx=" + _manualTX, module); |
| } catch (SQLException sqle) { |
| _manualTX = false; |
| } |
| } |
| } catch (SQLException e) { |
| throw new GenericDataSourceException("Cannot get autoCommit status from connection", e); |
| } |
| |
| try { |
| if (TransactionUtil.getStatus() == TransactionUtil.STATUS_ACTIVE) { |
| if (Debug.verboseOn()) Debug.logVerbose("[SQLProcessor.getConnection] : active transaction", module); |
| _manualTX = false; |
| } |
| } catch (GenericTransactionException e) { |
| // nevermind, don't worry about it, but print the exc anyway |
| Debug.logWarning("[SQLProcessor.getConnection]: Exception was thrown trying to check " + |
| "transaction status: " + e.toString(), module); |
| } |
| |
| if (Debug.verboseOn()) Debug.logVerbose("[SQLProcessor.getConnection] : con=" + _connection, module); |
| |
| _bDeleteConnection = true; |
| return _connection; |
| } |
| |
| /** |
| * Prepare a statement. In case no connection has been given, allocate a |
| * new one. |
| * |
| * @param sql The SQL statement to be executed |
| * |
| * @throws GenericDataSourceException |
| * @throws GenericEntityException |
| */ |
| public void prepareStatement(String sql) throws GenericDataSourceException, GenericEntityException { |
| this.prepareStatement(sql, false, 0, 0, -1, -1); |
| } |
| |
| /** |
| * Prepare a statement. In case no connection has been given, allocate a |
| * new one. |
| * |
| * @param sql The SQL statement to be executed |
| * |
| * @throws GenericDataSourceException |
| * @throws GenericEntityException |
| */ |
| public void prepareStatement(String sql, boolean specifyTypeAndConcur, int resultSetType, int resultSetConcurrency) throws GenericDataSourceException, GenericEntityException { |
| this.prepareStatement(sql, specifyTypeAndConcur, resultSetType, resultSetConcurrency, -1, -1); |
| } |
| |
| /** |
| * Prepare a statement. In case no connection has been given, allocate a |
| * new one. |
| * |
| * @param sql The SQL statement to be executed |
| * |
| * @throws GenericDataSourceException |
| * @throws GenericEntityException |
| */ |
| public void prepareStatement(String sql, boolean specifyTypeAndConcur, int resultSetType, int resultSetConcurrency, int fetchSize, int maxRows) throws GenericDataSourceException, GenericEntityException { |
| if (Debug.verboseOn()) Debug.logVerbose("[SQLProcessor.prepareStatement] sql=" + sql, module); |
| |
| if (_connection == null) { |
| getConnection(); |
| } |
| |
| try { |
| _sql = sql; |
| _ind = 1; |
| if (specifyTypeAndConcur) { |
| _ps = _connection.prepareStatement(sql, resultSetType, resultSetConcurrency); |
| if (Debug.verboseOn()) Debug.logVerbose("[SQLProcessor.prepareStatement] _ps=" + _ps, module); |
| } else { |
| _ps = _connection.prepareStatement(sql); |
| if (Debug.verboseOn()) Debug.logVerbose("[SQLProcessor.prepareStatement] (def) _ps=" + _ps, module); |
| } |
| if (maxRows > 0) { |
| _ps.setMaxRows(maxRows); |
| if (Debug.verboseOn()) Debug.logVerbose("[SQLProcessor.prepareStatement] max rows set : " + maxRows, module); |
| } |
| this.setFetchSize(_ps, fetchSize); |
| } catch (SQLException sqle) { |
| throw new GenericDataSourceException("SQL Exception while executing the following:" + sql, sqle); |
| } |
| } |
| |
| /** |
| * Execute a query based on the prepared statement |
| * |
| * @return The result set of the query |
| * @throws GenericDataSourceException |
| */ |
| public ResultSet executeQuery() throws GenericDataSourceException { |
| try { |
| // if (Debug.verboseOn()) Debug.logVerbose("[SQLProcessor.executeQuery] ps=" + _ps.toString(), module); |
| _rs = _ps.executeQuery(); |
| } catch (SQLException sqle) { |
| this.checkLockWaitInfo(sqle); |
| throw new GenericDataSourceException("SQL Exception while executing the following:" + _sql, sqle); |
| } |
| |
| return _rs; |
| } |
| |
| /** |
| * Execute a query based on the SQL string given |
| * |
| * @param sql The SQL string to be executed |
| * @return The result set of the query |
| * @throws GenericEntityException |
| * @throws GenericDataSourceException |
| */ |
| public ResultSet executeQuery(String sql) throws GenericDataSourceException, GenericEntityException { |
| prepareStatement(sql); |
| return executeQuery(); |
| } |
| |
| /** |
| * Execute updates |
| * |
| * @return The number of rows updated |
| * @throws GenericDataSourceException |
| */ |
| public int executeUpdate() throws GenericDataSourceException { |
| try { |
| // if (Debug.verboseOn()) Debug.logVerbose("[SQLProcessor.executeUpdate] ps=" + _ps.toString(), module); |
| //TransactionUtil.printAllThreadsTransactionBeginStacks(); |
| return _ps.executeUpdate(); |
| } catch (SQLException sqle) { |
| this.checkLockWaitInfo(sqle); |
| // don't display this here, may not be critical, allow handling further up... Debug.logError(sqle, "SQLProcessor.executeUpdate() : ERROR : ", module); |
| throw new GenericDataSourceException("SQL Exception while executing the following:" + _sql, sqle); |
| } |
| } |
| |
| /** |
| * Execute update based on the SQL statement given |
| * |
| * @param sql SQL statement to be executed |
| * @throws GenericDataSourceException |
| */ |
| public int executeUpdate(String sql) throws GenericDataSourceException { |
| Statement stmt = null; |
| |
| try { |
| stmt = _connection.createStatement(); |
| return stmt.executeUpdate(sql); |
| } catch (SQLException sqle) { |
| // passing on this exception as nested, no need to log it here: Debug.logError(sqle, "SQLProcessor.executeUpdate(sql) : ERROR : ", module); |
| throw new GenericDataSourceException("SQL Exception while executing the following:" + _sql, sqle); |
| } finally { |
| if (stmt != null) { |
| try { |
| stmt.close(); |
| } catch (SQLException sqle) { |
| Debug.logWarning("Unable to close 'statement': " + sqle.getMessage(), module); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Test if there more records available |
| * |
| * @return true, if there more records available |
| * |
| * @throws GenericDataSourceException |
| */ |
| public boolean next() throws GenericDataSourceException { |
| try { |
| return _rs.next(); |
| } catch (SQLException sqle) { |
| throw new GenericDataSourceException("SQL Exception while executing the following:" + _sql, sqle); |
| } |
| } |
| |
| /** |
| * Getter: get the currently active ResultSet |
| * |
| * @return ResultSet |
| */ |
| public ResultSet getResultSet() { |
| return _rs; |
| } |
| |
| /** |
| * Getter: get the prepared statement |
| * |
| * @return PreparedStatement |
| */ |
| public PreparedStatement getPreparedStatement() { |
| return _ps; |
| } |
| |
| /** |
| * Execute a query based on the SQL string given. For each record |
| * of the ResultSet return, execute a callback function |
| * |
| * @param sql The SQL string to be executed |
| * @param aListener The callback function object |
| * |
| * @throws GenericEntityException |
| */ |
| public void execQuery(String sql, ExecQueryCallbackFunctionIF aListener) throws GenericEntityException { |
| if (_connection == null) { |
| getConnection(); |
| } |
| |
| try { |
| if (Debug.verboseOn()) Debug.logVerbose("[SQLProcessor.execQuery]: " + sql, module); |
| executeQuery(sql); |
| |
| // process the results by calling the listener for |
| // each row... |
| boolean keepGoing = true; |
| |
| while (keepGoing && _rs.next()) { |
| keepGoing = aListener.processNextRow(_rs); |
| } |
| |
| if (_manualTX) { |
| _connection.commit(); |
| } |
| |
| } catch (SQLException sqle) { |
| Debug.logWarning("[SQLProcessor.execQuery]: SQL Exception while executing the following:\n" + |
| sql + "\nError was:", module); |
| Debug.logWarning(sqle.getMessage(), module); |
| throw new GenericEntityException("SQL Exception while executing the following:" + _sql, sqle); |
| } finally { |
| close(); |
| } |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement. |
| * |
| * @param handler |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public <T> void setValue(JdbcValueHandler<T> handler, T field) throws SQLException { |
| handler.setValue(_ps, _ind, field); |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement. |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(String field) throws SQLException { |
| //ResultSetMetaData rsmd = this.getResultSetMetaData(); |
| //this doesn't seem to work, query not yet parsed: int colType = rsmd.getColumnType(_ind); |
| if (field != null) { |
| //if (field.length() > 4000) { |
| //Clob clb = new Cl |
| // doesn't work with Oracle drivers, need the funky work-around: _ps.setCharacterStream(_ind, new StringReader(field), field.length()); |
| //_needClobWorkAroundWrite.put(Integer.valueOf(_ind), field); |
| //_ps.setString(_ind, " "); |
| //} else { |
| _ps.setString(_ind, field); |
| //} |
| } else { |
| // silly workaround for Derby (Cloudscape 10 beta Bug #5928) |
| // this should be removed after the know bug is fixed |
| try { |
| _ps.setNull(_ind, Types.VARCHAR); |
| } catch (SQLException e) { |
| try { |
| _ps.setString(_ind, null); |
| } catch (SQLException e2) { |
| Debug.logError(e2, module); |
| throw e; |
| } |
| } |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement. |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(java.sql.Timestamp field) throws SQLException { |
| if (field != null) { |
| _ps.setTimestamp(_ind, field); |
| } else { |
| _ps.setNull(_ind, Types.TIMESTAMP); |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement. |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(java.sql.Time field) throws SQLException { |
| if (field != null) { |
| _ps.setTime(_ind, field); |
| } else { |
| _ps.setNull(_ind, Types.TIME); |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement. |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(java.sql.Date field) throws SQLException { |
| if (field != null) { |
| _ps.setDate(_ind, field); |
| } else { |
| _ps.setNull(_ind, Types.DATE); |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement. |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(Integer field) throws SQLException { |
| if (field != null) { |
| _ps.setInt(_ind, field.intValue()); |
| } else { |
| _ps.setNull(_ind, Types.NUMERIC); |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement. |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(Long field) throws SQLException { |
| if (field != null) { |
| _ps.setLong(_ind, field.longValue()); |
| } else { |
| _ps.setNull(_ind, Types.NUMERIC); |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement. |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(Float field) throws SQLException { |
| if (field != null) { |
| _ps.setFloat(_ind, field.floatValue()); |
| } else { |
| _ps.setNull(_ind, Types.NUMERIC); |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement. |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(Double field) throws SQLException { |
| if (field != null) { |
| _ps.setDouble(_ind, field.doubleValue()); |
| } else { |
| _ps.setNull(_ind, Types.NUMERIC); |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement. |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(BigDecimal field) throws SQLException { |
| if (field != null) { |
| _ps.setBigDecimal(_ind, field); |
| } else { |
| _ps.setNull(_ind, Types.NUMERIC); |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement. |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(Boolean field) throws SQLException { |
| if (field != null) { |
| _ps.setBoolean(_ind, field.booleanValue()); |
| } else { |
| _ps.setNull(_ind, Types.BOOLEAN); |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement. |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(Object field) throws SQLException { |
| if (field != null) { |
| _ps.setObject(_ind, field, Types.JAVA_OBJECT); |
| } else { |
| _ps.setNull(_ind, Types.JAVA_OBJECT); |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(Blob field) throws SQLException { |
| if (field != null) { |
| _ps.setBlob(_ind, field); |
| } else { |
| Datasource datasourceInfo = EntityConfig.getDatasource(this.helperInfo.getHelperBaseName()); |
| if (datasourceInfo.getUseBinaryTypeForBlob()) { |
| _ps.setNull(_ind, Types.BINARY); |
| } else { |
| _ps.setNull(_ind, Types.BLOB); |
| } |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setValue(Clob field) throws SQLException { |
| if (field != null) { |
| _ps.setClob(_ind, field); |
| } else { |
| _ps.setNull(_ind, Types.CLOB); |
| } |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement |
| * to write the serialized data of 'field' to a BLOB. |
| * |
| * @param field |
| * |
| * @throws SQLException |
| */ |
| public void setBinaryStream(Object field) throws SQLException { |
| if (field != null) { |
| try { |
| ByteArrayOutputStream os = new ByteArrayOutputStream(); |
| ObjectOutputStream oos = new ObjectOutputStream(os); |
| oos.writeObject(field); |
| oos.close(); |
| |
| byte[] buf = os.toByteArray(); |
| os.close(); |
| ByteArrayInputStream is = new ByteArrayInputStream(buf); |
| _ps.setBinaryStream(_ind, is, buf.length); |
| is.close(); |
| } catch (IOException ex) { |
| throw new SQLException(ex.getMessage()); |
| } |
| } else { |
| Datasource datasourceInfo = EntityConfig.getDatasource(this.helperInfo.getHelperBaseName()); |
| if (datasourceInfo.getUseBinaryTypeForBlob()) { |
| _ps.setNull(_ind, Types.BINARY); |
| } else { |
| _ps.setNull(_ind, Types.BLOB); |
| } |
| } |
| |
| _ind++; |
| } |
| |
| /** |
| * Set the next binding variable of the currently active prepared statement |
| * to write the serialized data of 'field' to a Blob with the given bytes. |
| * |
| * @param bytes |
| * |
| * @throws SQLException |
| */ |
| public void setBytes(byte[] bytes) throws SQLException { |
| if (bytes != null) { |
| _ps.setBytes(_ind, bytes); |
| } else { |
| Datasource datasourceInfo = EntityConfig.getDatasource(this.helperInfo.getHelperBaseName()); |
| if (datasourceInfo.getUseBinaryTypeForBlob()) { |
| _ps.setNull(_ind, Types.BINARY); |
| } else { |
| _ps.setNull(_ind, Types.BLOB); |
| } |
| } |
| _ind++; |
| } |
| |
| @Override |
| protected void finalize() throws Throwable { |
| try { |
| this.close(); |
| } catch (Exception e) { |
| Debug.logError(e, "Error closing the result, connection, etc in finalize SQLProcessor", module); |
| } |
| super.finalize(); |
| } |
| |
| protected void testConnection(Connection con) throws GenericEntityException { |
| if (SQLProcessor.ENABLE_TEST) { |
| if (SQLProcessor.CONNECTION_TEST_LIST.contains(con.toString())) { |
| throw new GenericEntityException("Connection the exact same as index " + SQLProcessor.CONNECTION_TEST_LIST.indexOf(con.toString())); |
| } |
| SQLProcessor.CONNECTION_TEST_LIST.add(con.toString()); |
| if (SQLProcessor.CONNECTION_TEST_LIST.size() > SQLProcessor.MAX_CONNECTIONS) { |
| SQLProcessor.CONNECTION_TEST_LIST.remove(0); |
| } |
| } |
| } |
| |
| protected void setFetchSize(Statement stmt, int fetchSize) throws SQLException { |
| // do not set fetch size when using the cursor connection |
| if (_connection instanceof CursorConnection) return; |
| |
| // check if the statement was called with a specific fetch size, if not grab the default from the datasource |
| if (fetchSize < 0) { |
| Datasource ds = EntityConfig.getDatasource(this.helperInfo.getHelperBaseName()); |
| if (ds != null) { |
| fetchSize = ds.getResultFetchSize(); |
| } else { |
| Debug.logWarning("Datasource is null, not setting fetch size!", module); |
| } |
| } |
| |
| // otherwise only set if the size is > -1 (0 is sometimes used to note ALL rows) |
| if (fetchSize > -1) { |
| stmt.setFetchSize(fetchSize); |
| } |
| } |
| |
| private void checkLockWaitInfo(Exception sqle) { |
| String eMsg = sqle.getMessage(); |
| |
| // see if there is a lock wait timeout error, if so try to get and print more info about it |
| // the string for Derby is "A lock could not be obtained within the time requested" |
| // the string for MySQL is "Lock wait timeout exceeded; try restarting transaction" |
| if (eMsg.indexOf("A lock could not be obtained within the time requested") >= 0 || |
| eMsg.indexOf("Lock wait timeout exceeded") >= 0) { |
| Debug.logWarning(sqle, "Lock wait timeout error found in thread [" + Thread.currentThread().getId() + "]: (" + eMsg + ") when executing the SQL [" + _sql + "]", module); |
| TransactionUtil.printAllThreadsTransactionBeginStacks(); |
| } |
| } |
| } |