@Override @RequiredPermission(Permission.MANAGE_SETTINGS) @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) public long vacuum(Subject whoami, String[] tableNames) { long duration = 0; Connection conn = null; DatabaseType dbtype = null; try { conn = dataSource.getConnection(); dbtype = DatabaseTypeFactory.getDatabaseType(conn); if (!DatabaseTypeFactory.isPostgres(dbtype)) { return -1; } if (tableNames == null) // no names given -> operate on all tables. { tableNames = new String[1]; tableNames[0] = null; } for (String tableName : tableNames) { duration += doCommand(dbtype, conn, SQL_VACUUM, tableName); } return duration; } catch (Exception e) { LOG.error("Error vacuuming database: " + e.getMessage(), e); return duration; } finally { if (dbtype != null) { dbtype.closeConnection(conn); } } }
/** * DO NOT OVERRIDE. * * <p>DO NOT DEFINE AN @BeforeMethod Instead, override {@link #beforeMethod()}. If you must * override, for example, if you need to use special attributes on your annotation, then ensure * you protect the code with and {@link #inContainer()} call. */ @BeforeMethod protected void __beforeMethod(Method method) throws Throwable { // Note that Arquillian calls the testng BeforeMethod twice (as of 1.0.2.Final, once // out of container and once in container. In general the expectation is to execute it // one time, and doing it in container allows for the expected injections and context. if (inContainer()) { try { // Make sure we set the db type for tests that may need it (normally done in StartupBean) if (null == DatabaseTypeFactory.getDefaultDatabaseType()) { Connection conn = null; try { conn = getConnection(); DatabaseTypeFactory.setDefaultDatabaseType(DatabaseTypeFactory.getDatabaseType(conn)); } catch (Exception e) { System.err.println( "!!! WARNING !!! cannot set default database type, some tests may fail"); e.printStackTrace(); } finally { if (null != conn) { conn.close(); } } } beforeMethod(); beforeMethod(method); } catch (Throwable t) { // Arquillian is eating these, make sure they show up in some way System.out.println("BEFORE METHOD FAILURE, TEST DID NOT RUN!!! [" + method.getName() + "]"); t.printStackTrace(); throw t; } } }
@Override @RequiredPermission(Permission.MANAGE_SETTINGS) @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) public long reindex(Subject whoami) { Connection conn = null; DatabaseType dbtype = null; try { conn = dataSource.getConnection(); dbtype = DatabaseTypeFactory.getDatabaseType(conn); long duration = 0; if (DatabaseTypeFactory.isPostgres(dbtype)) { for (String table : TABLES_TO_REINDEX) { duration += doCommand(dbtype, conn, SQL_REINDEX, table); } } else if (DatabaseTypeFactory.isOracle(dbtype)) { for (String index : ORA_INDEXES_TO_REBUILD) { duration += doCommand(dbtype, conn, SQL_REBUILD, index); } } else { return -1; } return duration; } catch (Exception e) { LOG.error("Error reindexing database", e); throw new RuntimeException("Error reindexing database", e); } finally { if (dbtype != null) { dbtype.closeConnection(conn); } } }
@BeforeMethod public static void startTest() { if (DatabaseTypeFactory.getDefaultDatabaseType() == null) { try { Connection conn = getConnection(); DatabaseTypeFactory.setDefaultDatabaseType(DatabaseTypeFactory.getDatabaseType(conn)); } catch (Exception e) { System.err.println("!!! WARNING !!! cannot set default database type, some tests may fail"); e.printStackTrace(); } } if (stats != null) start = stats.getQueryExecutionCount(); else start = 0; }
private void initializeServer() { // Ensure the class is loaded and the dbType is set for our current db Connection conn = null; try { conn = dataSource.getConnection(); DatabaseTypeFactory.setDefaultDatabaseType(DatabaseTypeFactory.getDatabaseType(conn)); } catch (Exception e) { log.error("Could not initialize server.", e); } finally { if (conn != null) { try { conn.close(); } catch (Exception e) { log.error("Failed to close temporary connection used for server initialization.", e); } } } // Ensure that this server is registered in the database. createDefaultServerIfNecessary(); // immediately put the server into MM if configured to do so if (ServerCommunicationsServiceUtil.getService().getMaintenanceModeAtStartup()) { log.info("Server is configured to start up in MAINTENANCE mode."); Server server = serverManager.getServer(); Integer[] serverId = new Integer[] {server.getId()}; topologyManager.updateServerMode( LookupUtil.getSubjectManager().getOverlord(), serverId, OperationMode.MAINTENANCE); } // Establish the current server mode for the server. This will move the server to NORMAL // mode from DOWN if necessary. This can also affect comm layer behavior. serverManager.establishCurrentServerMode(); if ("true".equals(System.getProperty("rhq.sync.endpoint-address", "false"))) { try { serverManager.syncEndpointAddress(); } catch (SyncEndpointAddressException e) { log.error("Failed to sync server endpoint address.", e); } } }
@Override @RequiredPermission(Permission.MANAGE_SETTINGS) @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) public long analyze(Subject whoami) { Connection conn = null; DatabaseType dbtype = null; try { conn = dataSource.getConnection(); dbtype = DatabaseTypeFactory.getDatabaseType(conn); if (!DatabaseTypeFactory.isPostgres(dbtype)) { return -1; } long duration = doCommand(dbtype, conn, SQL_ANALYZE, null); return duration; } catch (Exception e) { LOG.error("Error analyzing database", e); throw new RuntimeException("Error analyzing database", e); } finally { if (dbtype != null) { dbtype.closeConnection(conn); } } }
public StartPageResults testConnection() { Properties configurationAsProperties = getConfigurationAsProperties(configuration); // its possible the JDBC URL was changed, clear the factory cache in case the DB version is // different now DatabaseTypeFactory.clearDatabaseTypeCache(); try { serverInfo.ensureDatabaseIsSupported(configurationAsProperties); lastTest = "OK"; } catch (Exception e) { LOG.warn("Installer failed to test connection", e); lastTest = e.toString(); } return StartPageResults.STAY; }
@Override @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) public DatabaseType getDatabaseType() { Connection conn = null; DatabaseType dbtype = null; try { conn = dataSource.getConnection(); dbtype = DatabaseTypeFactory.getDatabaseType(conn); return dbtype; } catch (Exception e) { throw new RuntimeException(e); } finally { if (conn != null) { try { conn.close(); } catch (SQLException e) { LOG.warn("Failed to close temporary connection", e); } } } }
public StartPageResults save() { LOG.info("Installer raw values: " + configuration); // if auto-install is enabled, the db password will be encrypted - decrypt it internally and // we'll re-encrypt later if (isAutoinstallEnabled()) { try { PropertyItemWithValue prop = getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_PASSWORD); String pass = prop.getValue(); pass = decodePassword(pass); prop.setValue(pass); // log the unencrypted pw, but only at the trace level so it isn't put in the log file // unless someone explicitly enables the trace level so they can see the pass that is to be // used for debugging LOG.trace(">" + pass); } catch (Exception e) { LOG.fatal("Could not decrypt the password for some reason - auto-installation failed", e); lastError = I18Nmsg.getMsg(InstallerI18NResourceKeys.SAVE_ERROR, ThrowableUtil.getAllMessages(e)); return StartPageResults.ERROR; } } // its possible the JDBC URL was changed, clear the factory cache in case the DB version is // different now DatabaseTypeFactory.clearDatabaseTypeCache(); try { // update server properties with the latest ha info to keep the form and server properties // file up to date getConfigurationPropertyFromAll(ServerProperties.PROP_HIGH_AVAILABILITY_NAME) .setValue(getHaServer().getName()); getConfigurationPropertyFromAll(ServerProperties.PROP_HTTP_PORT) .setValue(getHaServer().getEndpointPortString()); getConfigurationPropertyFromAll(ServerProperties.PROP_HTTPS_PORT) .setValue(getHaServer().getEndpointSecurePortString()); // the comm bind port is a special setting - it is allowed to be blank; // if it was originally blank, it will have been set to 0 because its an integer property; // but we do not want it to be 0, so make sure we switch it back to empty PropertyItemWithValue portConfig = getConfigurationPropertyFromAll(ServerProperties.PROP_CONNECTOR_BIND_PORT); if ("0".equals(portConfig.getValue())) { portConfig.setRawValue(""); } } catch (Exception e) { LOG.fatal("Could not save the settings for some reason", e); lastError = I18Nmsg.getMsg(InstallerI18NResourceKeys.SAVE_ERROR, ThrowableUtil.getAllMessages(e)); return StartPageResults.ERROR; } try { String url = getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_CONNECTION_URL).getValue(); String db = getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_TYPE).getValue(); Pattern pattern = null; if (db.toLowerCase().indexOf("postgres") > -1) { pattern = Pattern.compile( ".*://(.*):([0123456789]+)/(.*)"); // jdbc:postgresql://host.name:5432/rhq } else if (db.toLowerCase().indexOf("oracle") > -1) { LOG.info( "Oracle does not need to have server-name, port and db-name individually set, skipping"); // if we ever find that we'll need these props set, uncomment below and it should all work // pattern = Pattern.compile(".*@(.*):([0123456789]+):(.*)"); // // jdbc:oracle:thin:@host.name:1521:rhq } else if (db.toLowerCase().indexOf("h2") > -1) { LOG.info( "H2 does not need to have server-name, port and db-name individually set, skipping"); } else if (db.toLowerCase().indexOf("sqlserver") > -1) { pattern = Pattern.compile( "(?i).*://(.*):([0123456789]+).*databaseName=([^;]*)"); // jdbc:jtds:sqlserver://localhost:7777;databaseName=rhq } else { LOG.info("Unknown database type - will not set server-name, port and db-name"); // don't bother throwing error; these three extra settings may not be necessary anyway } if (pattern != null) { Matcher match = pattern.matcher(url); if (match.find() && (match.groupCount() == 3)) { String serverName = match.group(1); String port = match.group(2); String dbName = match.group(3); getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_SERVER_NAME) .setValue(serverName); getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_PORT).setValue(port); getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_DB_NAME).setValue(dbName); } else { throw new Exception("Cannot get server, port or db name from connection URL: " + url); } } else { getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_SERVER_NAME).setValue(""); getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_PORT).setValue(""); getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_DB_NAME).setValue(""); } } catch (Exception e) { LOG.fatal("JDBC connection URL seems to be invalid", e); lastError = I18Nmsg.getMsg(InstallerI18NResourceKeys.SAVE_ERROR, ThrowableUtil.getAllMessages(e)); return StartPageResults.ERROR; } try { String db = getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_TYPE).getValue(); String dialect; String quartzDriverDelegateClass = "org.quartz.impl.jdbcjobstore.StdJDBCDelegate"; String quartzSelectWithLockSQL = "SELECT * FROM {0}LOCKS ROWLOCK WHERE LOCK_NAME = ? FOR UPDATE"; String quartzLockHandlerClass = "org.quartz.impl.jdbcjobstore.StdRowLockSemaphore"; if (db.toLowerCase().indexOf("postgres") > -1) { dialect = "org.hibernate.dialect.PostgreSQLDialect"; quartzDriverDelegateClass = "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate"; } else if (db.toLowerCase().indexOf("oracle") > -1) { dialect = "org.hibernate.dialect.Oracle10gDialect"; quartzDriverDelegateClass = "org.quartz.impl.jdbcjobstore.oracle.OracleDelegate"; } else if (db.toLowerCase().indexOf("h2") > -1) { dialect = "org.rhq.core.server.H2CustomDialect"; } else if (db.toLowerCase().indexOf("sqlserver") > -1) { dialect = "org.hibernate.dialect.SQLServerDialect"; quartzDriverDelegateClass = "org.quartz.impl.jdbcjobstore.MSSQLDelegate"; quartzSelectWithLockSQL = "SELECT * FROM {0}LOCKS ROWLOCK WITH (HOLDLOCK,XLOCK) WHERE LOCK_NAME = ?"; quartzLockHandlerClass = "org.quartz.impl.jdbcjobstore.UpdateLockRowSemaphore"; } else if (db.toLowerCase().indexOf("mysql") > -1) { dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"; quartzDriverDelegateClass = "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate"; } else { throw new Exception("Unknown db type: " + db); } getConfigurationPropertyFromAll(ServerProperties.PROP_DATABASE_HIBERNATE_DIALECT) .setValue(dialect); getConfigurationPropertyFromAll(ServerProperties.PROP_QUARTZ_DRIVER_DELEGATE_CLASS) .setValue(quartzDriverDelegateClass); getConfigurationPropertyFromAll(ServerProperties.PROP_QUARTZ_SELECT_WITH_LOCK_SQL) .setValue(quartzSelectWithLockSQL); getConfigurationPropertyFromAll(ServerProperties.PROP_QUARTZ_LOCK_HANDLER_CLASS) .setValue(quartzLockHandlerClass); } catch (Exception e) { LOG.fatal("Invalid database type", e); lastError = I18Nmsg.getMsg(InstallerI18NResourceKeys.SAVE_ERROR, ThrowableUtil.getAllMessages(e)); return StartPageResults.ERROR; } Properties configurationAsProperties = getConfigurationAsProperties(configuration); testConnection(); // so our lastTest gets set and the user will be able to get the error in the // UI if (lastTest == null || !lastTest.equals("OK")) { lastError = lastTest; return StartPageResults.ERROR; } // Ensure server info has been set if ((null == haServer) || (null == haServer.getName()) || "".equals(haServer.getName().trim())) { lastError = I18Nmsg.getMsg( InstallerI18NResourceKeys.INVALID_STRING, I18Nmsg.getMsg(InstallerI18NResourceKeys.PROP_HIGH_AVAILABILITY_NAME)); return StartPageResults.ERROR; } for (PropertyItemWithValue newValue : configuration) { if (Integer.class.isAssignableFrom(newValue.getItemDefinition().getPropertyType())) { try { Integer.parseInt(newValue.getValue()); } catch (Exception e) { // there is one special property - the connector bind port - that is allowed to be empty // ignore this error if we are looking at that property and its empty; otherwise, this is // an error if (!(newValue .getItemDefinition() .getPropertyName() .equals(ServerProperties.PROP_CONNECTOR_BIND_PORT) && newValue.getValue().length() == 0)) { lastError = I18Nmsg.getMsg( InstallerI18NResourceKeys.INVALID_NUMBER, newValue.getItemDefinition().getPropertyLabel(), newValue.getValue()); return StartPageResults.ERROR; } } } else if (Boolean.class.isAssignableFrom(newValue.getItemDefinition().getPropertyType())) { try { if (newValue.getValue() == null) { newValue.setValue(Boolean.FALSE.toString()); } Boolean.parseBoolean(newValue.getValue()); } catch (Exception e) { lastError = I18Nmsg.getMsg( InstallerI18NResourceKeys.INVALID_BOOLEAN, newValue.getItemDefinition().getPropertyLabel(), newValue.getValue()); return StartPageResults.ERROR; } } } try { // indicate that no errors occurred lastError = null; // save the properties serverInfo.setServerProperties(configurationAsProperties); // prepare the db schema if (!ExistingSchemaOption.SKIP.name().equals(existingSchemaOption)) { if (serverInfo.isDatabaseSchemaExist(configurationAsProperties)) { if (existingSchemaOption == null) { if (!isAutoinstallEnabled()) { return StartPageResults .STAY; // user didn't tell us what to do, re-display the page with the question } // we are supposed to auto-install but wasn't explicitly told what to do - the default // is "auto" // and since we know the database schema exists, that means we upgrade it } if (ExistingSchemaOption.OVERWRITE.name().equals(existingSchemaOption)) { serverInfo.createNewDatabaseSchema(configurationAsProperties); } else { serverInfo.upgradeExistingDatabaseSchema(configurationAsProperties); } } else { serverInfo.createNewDatabaseSchema(configurationAsProperties); } } // Ensure the install server info is up to date and stored in the DB serverInfo.storeServer(configurationAsProperties, haServer); // encode database password and set updated properties String pass = configurationAsProperties.getProperty(ServerProperties.PROP_DATABASE_PASSWORD); pass = encryptPassword(pass); configurationAsProperties.setProperty(ServerProperties.PROP_DATABASE_PASSWORD, pass); serverInfo.setServerProperties(configurationAsProperties); // We have changed the password of the database connection, so we need to // tell the login config about it serverInfo.restartLoginConfig(); // build a keystore whose cert has a CN of this server's public endpoint address serverInfo.createKeystore(haServer); // now deploy RHQ Server fully serverInfo.moveDeploymentArtifacts(true); } catch (Exception e) { LOG.fatal( "Failed to updated properties and fully deploy - RHQ Server will not function properly", e); lastError = I18Nmsg.getMsg(InstallerI18NResourceKeys.SAVE_FAILURE, ThrowableUtil.getAllMessages(e)); return StartPageResults.ERROR; } LOG.info("Installer: final submitted values: " + configurationAsProperties); return StartPageResults.SUCCESS; }
public boolean isPostgres() throws Exception { return DatabaseTypeFactory.getDatabaseType( getInitialContext(), RHQConstants.DATASOURCE_JNDI_NAME) instanceof PostgresqlDatabaseType; }
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) // @TransactionTimeout( 60 * 60 ) public int _calculateAutoBaselinesINSERT(long amountOfData) throws Exception { long now = System.currentTimeMillis(); long computeTime = now; long endTime = now; long startTime = endTime - amountOfData; Connection conn = null; PreparedStatement insertQuery = null; try { // calculate the baselines for schedules that have no baseline yet (or were just deleted) // do everything via JDBC - our perf testing shows that we hit entity cache locking timeouts // when the entity manager performs native queries under heavy load conn = dataSource.getConnection(); DatabaseType dbType = DatabaseTypeFactory.getDatabaseType(conn); if (dbType instanceof PostgresqlDatabaseType || dbType instanceof H2DatabaseType) { insertQuery = conn.prepareStatement( MeasurementBaseline.NATIVE_QUERY_CALC_FIRST_AUTOBASELINE_POSTGRES); insertQuery.setLong(1, computeTime); insertQuery.setLong(2, startTime); insertQuery.setLong(3, endTime); insertQuery.setLong(4, startTime); } else if (dbType instanceof OracleDatabaseType) { insertQuery = conn.prepareStatement(MeasurementBaseline.NATIVE_QUERY_CALC_FIRST_AUTOBASELINE_ORACLE); insertQuery.setLong(1, computeTime); insertQuery.setLong(2, startTime); insertQuery.setLong(3, endTime); insertQuery.setLong(4, startTime); } else if (dbType instanceof SQLServerDatabaseType) { insertQuery = conn.prepareStatement( MeasurementBaseline.NATIVE_QUERY_CALC_FIRST_AUTOBASELINE_SQLSERVER); insertQuery.setLong(1, computeTime); insertQuery.setLong(2, startTime); insertQuery.setLong(3, endTime); insertQuery.setLong(4, startTime); } else { throw new IllegalArgumentException("Unknown database type, can't continue: " + dbType); } int inserted = insertQuery.executeUpdate(); return inserted; } finally { if (insertQuery != null) { try { insertQuery.close(); } catch (Exception e) { } } if (conn != null) { try { conn.close(); } catch (Exception e) { } } } }
/* * internal method, do not expose to the remote API */ @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void insertCallTimeDataValues(Set<CallTimeData> callTimeDataSet) { int[] results; String insertValueSql; PreparedStatement ps = null; Connection conn = null; try { conn = rhqDs.getConnection(); DatabaseType dbType = DatabaseTypeFactory.getDatabaseType(conn); if (dbType instanceof Postgresql83DatabaseType) { Statement st = null; try { // Take advantage of async commit here st = conn.createStatement(); st.execute("SET synchronous_commit = off"); } finally { JDBCUtil.safeClose(st); } } if (dbType instanceof PostgresqlDatabaseType || dbType instanceof OracleDatabaseType || dbType instanceof H2DatabaseType) { String valueNextvalSql = JDBCUtil.getNextValSql(conn, "RHQ_calltime_data_value"); insertValueSql = String.format(CALLTIME_VALUE_INSERT_STATEMENT, valueNextvalSql); } else if (dbType instanceof SQLServerDatabaseType) { insertValueSql = CALLTIME_VALUE_INSERT_STATEMENT_AUTOINC; } else { throw new IllegalArgumentException("Unknown database type, can't continue: " + dbType); } ps = conn.prepareStatement(insertValueSql); for (CallTimeData callTimeData : callTimeDataSet) { ps.setInt(7, callTimeData.getScheduleId()); Set<String> callDestinations = callTimeData.getValues().keySet(); for (String callDestination : callDestinations) { CallTimeDataValue callTimeDataValue = callTimeData.getValues().get(callDestination); ps.setLong(1, callTimeDataValue.getBeginTime()); ps.setLong(2, callTimeDataValue.getEndTime()); ps.setDouble(3, callTimeDataValue.getMinimum()); ps.setDouble(4, callTimeDataValue.getMaximum()); ps.setDouble(5, callTimeDataValue.getTotal()); ps.setLong(6, callTimeDataValue.getCount()); ps.setString(8, callDestination); ps.addBatch(); } } results = ps.executeBatch(); int insertedRowCount = 0; for (int i = 0; i < results.length; i++) { if ((results[i] != 1) && (results[i] != -2)) // Oracle likes to return -2 becuase it doesn't track batch update counts { throw new MeasurementStorageException( "Failed to insert call-time data value rows - result [" + results[i] + "] for batch command [" + i + "] does not equal 1."); } insertedRowCount += results[i] == -2 ? 1 : results[i]; // If Oracle returns -2, just count 1 row; } notifyAlertConditionCacheManager( "insertCallTimeDataValues", callTimeDataSet.toArray(new CallTimeData[callTimeDataSet.size()])); if (insertedRowCount > 0) { MeasurementMonitor.getMBean().incrementCalltimeValuesInserted(insertedRowCount); log.debug("Inserted " + insertedRowCount + " call-time data value rows."); } } catch (SQLException e) { logSQLException("Failed to persist call-time data values", e); } catch (Throwable t) { log.error("Failed to persist call-time data values", t); } finally { JDBCUtil.safeClose(conn, ps, null); } }
/* * internal method, do not expose to the remote API */ @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void insertCallTimeDataKeys(Set<CallTimeData> callTimeDataSet) { int[] results; String insertKeySql; PreparedStatement ps = null; Connection conn = null; try { conn = rhqDs.getConnection(); DatabaseType dbType = DatabaseTypeFactory.getDatabaseType(conn); if (dbType instanceof Postgresql83DatabaseType) { Statement st = null; try { // Take advantage of async commit here st = conn.createStatement(); st.execute("SET synchronous_commit = off"); } finally { JDBCUtil.safeClose(st); } } if (dbType instanceof PostgresqlDatabaseType || dbType instanceof OracleDatabaseType || dbType instanceof H2DatabaseType) { String keyNextvalSql = JDBCUtil.getNextValSql(conn, "RHQ_calltime_data_key"); insertKeySql = String.format(CALLTIME_KEY_INSERT_STATEMENT, keyNextvalSql); } else if (dbType instanceof SQLServerDatabaseType) { insertKeySql = CALLTIME_KEY_INSERT_STATEMENT_AUTOINC; } else { throw new IllegalArgumentException("Unknown database type, can't continue: " + dbType); } ps = conn.prepareStatement(insertKeySql); for (CallTimeData callTimeData : callTimeDataSet) { ps.setInt(1, callTimeData.getScheduleId()); ps.setInt(3, callTimeData.getScheduleId()); Set<String> callDestinations = callTimeData.getValues().keySet(); for (String callDestination : callDestinations) { ps.setString(2, callDestination); ps.setString(4, callDestination); ps.addBatch(); } } results = ps.executeBatch(); int insertedRowCount = 0; for (int i = 0; i < results.length; i++) { if (((results[i] < 0) || (results[i] > 1)) && (results[i] != -2)) // oracle returns -2 because it can't count updated rows { throw new MeasurementStorageException( "Failed to insert call-time data key rows - result [" + results[i] + "] for batch command [" + i + "] is less than 0 or greater than 1."); } insertedRowCount += results[i] == -2 ? 1 : results[i]; // If Oracle returns -2, just count 1 row } log.debug( "Inserted new call-time data key rows for " + ((insertedRowCount >= 0) ? insertedRowCount : "?") + " out of " + results.length + " reported key-value pairs."); } catch (SQLException e) { logSQLException("Failed to persist call-time data keys", e); } catch (Throwable t) { log.error("Failed to persist call-time data keys", t); } finally { JDBCUtil.safeClose(conn, ps, null); } }