private Object[] getFromCache(RowMetaInterface keyMeta, Object[] keyData) throws KettleValueException { if (meta.isMemoryPreservationActive()) { if (meta.isUsingSortedList()) { KeyValue keyValue = new KeyValue(keyData, null); int idx = Collections.binarySearch(data.list, keyValue, data.comparator); if (idx < 0) return null; // nothing found keyValue = (KeyValue) data.list.get(idx); return keyValue.getValue(); } else { if (meta.isUsingIntegerPair()) { Long value = data.longIndex.get(keyMeta.getInteger(keyData, 0)); if (value == null) return null; return new Object[] { value, }; } else { try { byte[] value = data.hashIndex.get(RowMeta.extractData(keyMeta, keyData)); if (value == null) return null; return RowMeta.getRow(data.valueMeta, value); } catch (Exception e) { logError("Oops", e); throw new RuntimeException(e); } } } } else { return (Object[]) data.look.get(new RowMetaAndData(keyMeta, keyData)); } }
@Test public void testQuoteReservedWords() { DatabaseMeta databaseMeta = mock(DatabaseMeta.class); doCallRealMethod().when(databaseMeta).quoteReservedWords(any(RowMetaInterface.class)); doCallRealMethod().when(databaseMeta).quoteField(anyString()); doCallRealMethod().when(databaseMeta).setDatabaseInterface(any(DatabaseInterface.class)); doReturn("\"").when(databaseMeta).getStartQuote(); doReturn("\"").when(databaseMeta).getEndQuote(); final DatabaseInterface databaseInterface = mock(DatabaseInterface.class); doReturn(true).when(databaseInterface).isQuoteAllFields(); databaseMeta.setDatabaseInterface(databaseInterface); final RowMeta fields = new RowMeta(); for (int i = 0; i < 10; i++) { final ValueMeta valueMeta = new ValueMeta("test_" + i); fields.addValueMeta(valueMeta); } for (int i = 0; i < 10; i++) { databaseMeta.quoteReservedWords(fields); } for (int i = 0; i < 10; i++) { databaseMeta.quoteReservedWords(fields); final String name = fields.getValueMeta(i).getName(); // check valueMeta index in list assertTrue(name.contains("test_" + i)); // check valueMeta is found by quoted name assertNotNull(fields.searchValueMeta(name)); } }
@Test public void testHTTPResultDefaultRows() throws IOException { File localFileForUpload = getInputFile("existingFile1", ".tmp"); File tempFileForDownload = File.createTempFile("downloadedFile1", ".tmp"); localFileForUpload.deleteOnExit(); tempFileForDownload.deleteOnExit(); Object[] r = new Object[] { HTTP_SERVER_BASEURL + "/uploadFile", localFileForUpload.getCanonicalPath(), tempFileForDownload.getCanonicalPath() }; RowMeta rowMetaDefault = new RowMeta(); rowMetaDefault.addValueMeta(new ValueMetaString("URL")); rowMetaDefault.addValueMeta(new ValueMetaString("UPLOAD")); rowMetaDefault.addValueMeta(new ValueMetaString("DESTINATION")); List<RowMetaAndData> rows = new ArrayList<RowMetaAndData>(); rows.add(new RowMetaAndData(rowMetaDefault, r)); Result previousResult = new Result(); previousResult.setRows(rows); JobEntryHTTP http = new JobEntryHTTP(); http.setParentJob(new Job()); http.setRunForEveryRow(true); http.setAddFilenameToResult(false); http.execute(previousResult, 0); assertTrue(FileUtils.contentEquals(localFileForUpload, tempFileForDownload)); }
@Test public void testConditionResolution() throws Exception { RowMeta rowMeta = new RowMeta(); rowMeta.addValueMeta(new ValueMetaString("aString")); rowMeta.addValueMeta(new ValueMetaInteger("anInt")); rowMeta.addValueMeta(new ValueMetaDate("aDate")); String query = "SELECT * FROM " + DATA_SERVICE_NAME + " WHERE anInt = 2 AND aDate IN ('2014-12-05','2008-01-01')"; when(transMeta.getStepFields(DATA_SERVICE_STEP)).thenReturn(rowMeta); DataServiceExecutor executor = new DataServiceExecutor.Builder(new SQL(query), dataService, context) .serviceTrans(transMeta) .prepareExecution(false) .build(); Condition condition = executor.getSql().getWhereCondition().getCondition(); Calendar calendar = Calendar.getInstance(); calendar.clear(); calendar.set(2014, Calendar.DECEMBER, 5); assertThat( condition.evaluate(rowMeta, new Object[] {"value", 2L, calendar.getTime()}), is(true)); assertThat(condition.evaluate(rowMeta, new Object[] {"value", 2L, new Date()}), is(false)); }
@Test public void testReturnDigitsOnly() throws KettleException { RowMeta inputRowMeta = new RowMeta(); ValueMetaString nameMeta = new ValueMetaString("Name"); inputRowMeta.addValueMeta(nameMeta); ValueMetaString valueMeta = new ValueMetaString("Value"); inputRowMeta.addValueMeta(valueMeta); RowSet inputRowSet = smh.getMockInputRowSet(new Object[][] {{"name1", "qwe123asd456zxc"}, {"name2", null}}); inputRowSet.setRowMeta(inputRowMeta); Calculator calculator = new Calculator(smh.stepMeta, smh.stepDataInterface, 0, smh.transMeta, smh.trans); calculator.getInputRowSets().add(inputRowSet); calculator.setInputRowMeta(inputRowMeta); calculator.init(smh.initStepMetaInterface, smh.initStepDataInterface); CalculatorMeta meta = new CalculatorMeta(); meta.setCalculation( new CalculatorMetaFunction[] { new CalculatorMetaFunction( "digits", CalculatorMetaFunction.CALC_GET_ONLY_DIGITS, "Value", null, null, ValueMetaInterface.TYPE_STRING, 0, 0, false, "", "", "", "") }); // Verify output try { calculator.addRowListener( new RowAdapter() { @Override public void rowWrittenEvent(RowMetaInterface rowMeta, Object[] row) throws KettleStepException { assertEquals("123456", row[2]); } }); calculator.processRow(meta, new CalculatorData()); } catch (KettleException ke) { ke.printStackTrace(); fail(); } }
private void addToCache( RowMetaInterface keyMeta, Object[] keyData, RowMetaInterface valueMeta, Object[] valueData) throws KettleValueException { if (meta.isMemoryPreservationActive()) { if (meta.isUsingSortedList()) { KeyValue keyValue = new KeyValue(keyData, valueData); int idx = Collections.binarySearch(data.list, keyValue, data.comparator); if (idx < 0) { int index = -idx - 1; // this is the insertion point data.list.add(index, keyValue); // insert to keep sorted. } else { data.list.set(idx, keyValue); // Overwrite to simulate Hashtable behaviour } } else { if (meta.isUsingIntegerPair()) { if (!data.metadataVerifiedIntegerPair) { data.metadataVerifiedIntegerPair = true; if (keyMeta.size() != 1 || valueMeta.size() != 1 || !keyMeta.getValueMeta(0).isInteger() || !valueMeta.getValueMeta(0).isInteger()) { throw new KettleValueException( BaseMessages.getString( PKG, "StreamLookup.Exception.CanNotUseIntegerPairAlgorithm")); } } Long key = keyMeta.getInteger(keyData, 0); Long value = valueMeta.getInteger(valueData, 0); data.longIndex.put(key, value); } else { if (data.hashIndex == null) { data.hashIndex = new ByteArrayHashIndex(keyMeta); } data.hashIndex.put( RowMeta.extractData(keyMeta, keyData), RowMeta.extractData(valueMeta, valueData)); } } } else { // We can't just put Object[] in the map // The compare function is not in it. // We need to wrap in and use that. // Let's use RowMetaAndData for this one. // data.look.put(new RowMetaAndData(keyMeta, keyData), valueData); } }
@Test public void calculatorShouldClearDataInstance() throws Exception { RowMeta inputRowMeta = new RowMeta(); ValueMetaInteger valueMeta = new ValueMetaInteger("Value"); inputRowMeta.addValueMeta(valueMeta); RowSet inputRowSet = smh.getMockInputRowSet(new Object[] {-1L}); inputRowSet.setRowMeta(inputRowMeta); Calculator calculator = new Calculator(smh.stepMeta, smh.stepDataInterface, 0, smh.transMeta, smh.trans); calculator.getInputRowSets().add(inputRowSet); calculator.setInputRowMeta(inputRowMeta); calculator.init(smh.initStepMetaInterface, smh.initStepDataInterface); CalculatorMeta meta = new CalculatorMeta(); meta.setCalculation( new CalculatorMetaFunction[] { new CalculatorMetaFunction( "test", CalculatorMetaFunction.CALC_ABS, "Value", null, null, ValueMetaInterface.TYPE_STRING, 0, 0, false, "", "", "", "") }); CalculatorData data = new CalculatorData(); data = spy(data); calculator.processRow(meta, data); verify(data).getValueMetaFor(eq(valueMeta.getType()), anyString()); calculator.processRow(meta, data); verify(data).clearValuesMetaMapping(); }
@Test public void testWithLazyConversion() throws Exception { RowMeta rowMeta = new RowMeta(); ValueMetaInterface vm = new ValueMetaString("aBinaryStoredString"); vm.setStorageType(ValueMetaInterface.STORAGE_TYPE_BINARY_STRING); vm.setStorageMetadata(new ValueMetaString()); rowMeta.addValueMeta(vm); String query = "SELECT * FROM " + DATA_SERVICE_NAME + " WHERE aBinaryStoredString = 'value'"; when(transMeta.getStepFields(DATA_SERVICE_STEP)).thenReturn(rowMeta); DataServiceExecutor executor = new DataServiceExecutor.Builder(new SQL(query), dataService, context) .serviceTrans(new Trans(transMeta)) .prepareExecution(false) .build(); executor .getSql() .getWhereCondition() .getCondition() .evaluate(rowMeta, new Object[] {"value".getBytes()}); }
private void loadAllTableDataIntoTheCache() throws KettleException { DatabaseMeta dbMeta = meta.getDatabaseMeta(); try { // We only want to get the used table fields... // String sql = "SELECT "; for (int i = 0; i < meta.getStreamKeyField1().length; i++) { if (i > 0) { sql += ", "; } sql += dbMeta.quoteField(meta.getTableKeyField()[i]); } // Also grab the return field... // for (int i = 0; i < meta.getReturnValueField().length; i++) { sql += ", " + dbMeta.quoteField(meta.getReturnValueField()[i]); } // The schema/table // sql += " FROM " + dbMeta.getQuotedSchemaTableCombination( environmentSubstitute(meta.getSchemaName()), environmentSubstitute(meta.getTablename())); // order by? if (meta.getOrderByClause() != null && meta.getOrderByClause().length() != 0) { sql += " ORDER BY " + meta.getOrderByClause(); } // Now that we have the SQL constructed, let's store the rows... // List<Object[]> rows = data.db.getRows(sql, 0); if (rows != null && rows.size() > 0) { RowMetaInterface returnRowMeta = data.db.getReturnRowMeta(); // Copy the data into 2 parts: key and value... // for (Object[] row : rows) { int index = 0; RowMeta keyMeta = new RowMeta(); Object[] keyData = new Object[meta.getStreamKeyField1().length]; for (int i = 0; i < meta.getStreamKeyField1().length; i++) { keyData[i] = row[index]; keyMeta.addValueMeta(returnRowMeta.getValueMeta(index++)); } // RowMeta valueMeta = new RowMeta(); Object[] valueData = new Object[data.returnMeta.size()]; for (int i = 0; i < data.returnMeta.size(); i++) { valueData[i] = row[index++]; // valueMeta.addValueMeta(returnRowMeta.getValueMeta(index++)); } // Store the data... // storeRowInCache(keyMeta, keyData, valueData); incrementLinesInput(); } } } catch (Exception e) { throw new KettleException(e); } }
public ResultSet getColumns( String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { log.debug( "catalog:" + catalog + " , schemaPattern:" + schemaPattern + " , tableNamePattern:" + tableNamePattern + " ,columnNamePattern:" + columnNamePattern); List<RowMetaAndData> rowAndDatas = new ArrayList<RowMetaAndData>(); // if USE_TRANSNAME_AS_SCHEMA is true, then we use the filename or // transformation name as the schema if (!isDir) { log.debug(helper.getRowMeta(tableNamePattern)); RowMeta rm = helper.getRowMeta(tableNamePattern); ColInfo[] colInfo = KettleHelper.convert(rm); String[] columns = rm.getFieldNames(); for (int i = 0; columns != null && i < columns.length; i++) { RowMetaAndData rd = new RowMetaAndData(); rd.addValue("TABLE_CAT", ValueMetaInterface.TYPE_STRING, catalog); rd.addValue("TABLE_SCHEM", ValueMetaInterface.TYPE_STRING, schemaPattern); rd.addValue("TABLE_NAME", ValueMetaInterface.TYPE_STRING, tableNamePattern); rd.addValue("COLUMN_NAME", ValueMetaInterface.TYPE_STRING, columns[i]); rd.addValue("DATA_TYPE", ValueMetaInterface.TYPE_INTEGER, colInfo[i].jdbcType); rd.addValue("TYPE_NAME", ValueMetaInterface.TYPE_STRING, ""); rd.addValue("COLUMN_SIZE", ValueMetaInterface.TYPE_INTEGER, columns.length); rd.addValue("BUFFER_LENGTH", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("DECIMAL_DIGITS", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("NUM_PREC_RADIX", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("NULLABLE", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("REMARKS", ValueMetaInterface.TYPE_STRING, ""); rd.addValue("COLUMN_DEF", ValueMetaInterface.TYPE_STRING, ""); rd.addValue("SQL_DATA_TYPE", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("SQL_DATETIME_SUB", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("CHAR_OCTET_LENGTH", ValueMetaInterface.TYPE_INTEGER, "1"); rd.addValue("ORDINAL_POSITION", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("IS_NULLABLE", ValueMetaInterface.TYPE_STRING, "0"); rd.addValue("SCOPE_CATALOG", ValueMetaInterface.TYPE_STRING, "0"); rd.addValue("SCOPE_SCHEMA", ValueMetaInterface.TYPE_STRING, "0"); rd.addValue("SCOPE_TABLE", ValueMetaInterface.TYPE_STRING, "0"); rd.addValue("SOURCE_DATA_TYPE", ValueMetaInterface.TYPE_INTEGER, "1"); rowAndDatas.add(rd); } KettleJDBCResultSet rs = new KettleJDBCResultSet(null, rowAndDatas, "*"); return rs; } // log.debug("getRowMeta:" + helper.getRowMeta(tableNamePattern)); RowMeta rm = helper.getRowMeta(tableNamePattern); ColInfo[] colInfo = KettleHelper.convert(rm); String[] columns = rm.getFieldNames(); for (int i = 0; columns != null && i < columns.length; i++) { String name = columns[i]; RowMetaAndData rd = new RowMetaAndData(); rd.addValue("TABLE_CAT", ValueMetaInterface.TYPE_STRING, catalog); rd.addValue("TABLE_SCHEM", ValueMetaInterface.TYPE_STRING, schemaPattern); rd.addValue("TABLE_NAME", ValueMetaInterface.TYPE_STRING, tableNamePattern); rd.addValue("COLUMN_NAME", ValueMetaInterface.TYPE_STRING, name); rd.addValue("DATA_TYPE", ValueMetaInterface.TYPE_INTEGER, colInfo[i].getJdbcType()); rd.addValue("TYPE_NAME", ValueMetaInterface.TYPE_STRING, ""); rd.addValue("COLUMN_SIZE", ValueMetaInterface.TYPE_INTEGER, columns.length); rd.addValue("BUFFER_LENGTH", ValueMetaInterface.TYPE_INTEGER, name); rd.addValue("DECIMAL_DIGITS", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("NUM_PREC_RADIX", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("NULLABLE", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("REMARKS", ValueMetaInterface.TYPE_STRING, name); rd.addValue("COLUMN_DEF", ValueMetaInterface.TYPE_STRING, name); rd.addValue("SQL_DATA_TYPE", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("SQL_DATETIME_SUB", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("CHAR_OCTET_LENGTH", ValueMetaInterface.TYPE_INTEGER, "1"); rd.addValue("ORDINAL_POSITION", ValueMetaInterface.TYPE_INTEGER, "20"); rd.addValue("IS_NULLABLE", ValueMetaInterface.TYPE_STRING, "0"); rd.addValue("SCOPE_CATALOG", ValueMetaInterface.TYPE_STRING, "0"); rd.addValue("SCOPE_SCHEMA", ValueMetaInterface.TYPE_STRING, "0"); rd.addValue("SCOPE_TABLE", ValueMetaInterface.TYPE_STRING, "0"); rd.addValue("SOURCE_DATA_TYPE", ValueMetaInterface.TYPE_INTEGER, "1"); rowAndDatas.add(rd); } KettleJDBCResultSet rs = new KettleJDBCResultSet(null, rowAndDatas, "*"); return rs; }
public void assertRoundGeneral( final Object expectedResult, final int calcFunction, final Number value, final Long precision, final Long roundingMode, final int valueDataType, final int functionDataType) throws KettleException { final String msg = getKettleTypeName(valueDataType) + "->" + getKettleTypeName(functionDataType) + " "; final RowMeta inputRowMeta = new RowMeta(); final List<Object> inputValues = new ArrayList<Object>(3); final String fieldValue = "Value"; final ValueMetaInterface valueMeta; switch (valueDataType) { case ValueMetaInterface.TYPE_BIGNUMBER: valueMeta = new ValueMetaBigNumber(fieldValue); break; case ValueMetaInterface.TYPE_NUMBER: valueMeta = new ValueMetaNumber(fieldValue); break; case ValueMetaInterface.TYPE_INTEGER: valueMeta = new ValueMetaInteger(fieldValue); break; default: throw new IllegalArgumentException( msg + "Unexpected value dataType: " + value.getClass().getName() + ". Long, Double or BigDecimal expected."); } inputRowMeta.addValueMeta(valueMeta); inputValues.add(value); final String fieldPrecision; final ValueMetaInteger precisionMeta; if (precision == null) { fieldPrecision = null; precisionMeta = null; } else { fieldPrecision = "Precision"; precisionMeta = new ValueMetaInteger(fieldPrecision); inputRowMeta.addValueMeta(precisionMeta); inputValues.add(precision); } final String fieldRoundingMode; final ValueMetaInteger roundingModeMeta; if (roundingMode == null) { fieldRoundingMode = null; roundingModeMeta = null; } else { fieldRoundingMode = "RoundingMode"; roundingModeMeta = new ValueMetaInteger(fieldRoundingMode); inputRowMeta.addValueMeta(roundingModeMeta); inputValues.add(roundingMode); } RowSet inputRowSet = smh.getMockInputRowSet(inputValues.toArray()); inputRowSet.setRowMeta(inputRowMeta); final String fieldA = inputRowMeta.size() > 0 ? inputRowMeta.getValueMetaList().get(0).getName() : null; final String fieldB = inputRowMeta.size() > 1 ? inputRowMeta.getValueMetaList().get(1).getName() : null; final String fieldC = inputRowMeta.size() > 2 ? inputRowMeta.getValueMetaList().get(2).getName() : null; final int resultDataType = functionDataType; final String fieldResult = "test"; final int expectedResultRowSize = inputRowMeta.size() + 1; Calculator calculator = new Calculator(smh.stepMeta, smh.stepDataInterface, 0, smh.transMeta, smh.trans); calculator.getInputRowSets().add(inputRowSet); calculator.setInputRowMeta(inputRowMeta); calculator.init(smh.initStepMetaInterface, smh.initStepDataInterface); CalculatorMeta meta = new CalculatorMeta(); meta.setCalculation( new CalculatorMetaFunction[] { new CalculatorMetaFunction( fieldResult, calcFunction, fieldA, fieldB, fieldC, resultDataType, 2, 0, false, "", "", "", "") }); // Verify output try { calculator.addRowListener( new RowAdapter() { @Override public void rowWrittenEvent(RowMetaInterface rowMeta, Object[] row) throws KettleStepException { assertEquals(msg + " resultRowSize", expectedResultRowSize, rowMeta.size()); final int fieldResultIndex = rowMeta.size() - 1; assertEquals( msg + " fieldResult", fieldResult, rowMeta.getValueMeta(fieldResultIndex).getName()); assertEquals(msg, expectedResult, row[fieldResultIndex]); } }); calculator.processRow(meta, new CalculatorData()); } catch (KettleException ke) { ke.printStackTrace(); fail(msg + ke.getMessage()); } }
private ArrayList<Object[]> writeToTable(RowMetaInterface rowMeta, ArrayList<Object[]> rows) throws KettleException { if (rows.isEmpty()) // Stop: last line or error encountered { if (log.isDetailed()) logDetailed("Last line inserted: stop"); return null; } PreparedStatement insertStatement = null; ArrayList<Object[]> insertRowsData = new ArrayList<Object[]>(); ArrayList<Object[]> outputRowsData = rows; String tableName = null; boolean sendToErrorRow = false; String errorMessage = null; boolean rowIsSafe = false; int[] updateCounts = null; List<Exception> exceptionsList = null; boolean batchProblem = false; for (Object[] row : rows) { if (meta.isTableNameInField()) { // Cache the position of the table name field if (data.indexOfTableNameField < 0) { String realTablename = environmentSubstitute(meta.getTableNameField()); data.indexOfTableNameField = rowMeta.indexOfValue(realTablename); if (data.indexOfTableNameField < 0) { String message = "Unable to find table name field [" + realTablename + "] in input row"; logError(message); throw new KettleStepException(message); } if (!meta.isTableNameInTable()) { data.insertRowMeta.removeValueMeta(data.indexOfTableNameField); } } tableName = rowMeta.getString(rows.get(0), data.indexOfTableNameField); if (!meta.isTableNameInTable()) { // If the name of the table should not be inserted itself, // remove the table name // from the input row data as well. This forcibly creates a // copy of r insertRowsData.add( RowDataUtil.removeItem(rowMeta.cloneRow(row), data.indexOfTableNameField)); } else { insertRowsData.add(row); } } else if (meta.isPartitioningEnabled() && (meta.isPartitioningDaily() || meta.isPartitioningMonthly()) && (meta.getPartitioningField() != null && meta.getPartitioningField().length() > 0)) { // Initialize some stuff! if (data.indexOfPartitioningField < 0) { data.indexOfPartitioningField = rowMeta.indexOfValue(environmentSubstitute(meta.getPartitioningField())); if (data.indexOfPartitioningField < 0) { throw new KettleStepException( "Unable to find field [" + meta.getPartitioningField() + "] in the input row!"); } if (meta.isPartitioningDaily()) { data.dateFormater = new SimpleDateFormat("yyyyMMdd"); } else { data.dateFormater = new SimpleDateFormat("yyyyMM"); } } ValueMetaInterface partitioningValue = rowMeta.getValueMeta(data.indexOfPartitioningField); if (!partitioningValue.isDate() || row[data.indexOfPartitioningField] == null) { throw new KettleStepException( "Sorry, the partitioning field needs to contain a data value and can't be empty!"); } Object partitioningValueData = rowMeta.getDate(row, data.indexOfPartitioningField); tableName = environmentSubstitute(meta.getTablename()) + "_" + data.dateFormater.format((Date) partitioningValueData); insertRowsData.add(row); } else { tableName = data.tableName; insertRowsData.add(row); } if (Const.isEmpty(tableName)) { throw new KettleStepException("The tablename is not defined (empty)"); } } if (!data.preparedStatements.containsKey(tableName)) { data.preparedStatements.put(tableName, new Hashtable<Integer, PreparedStatement>()); } insertStatement = (PreparedStatement) data.preparedStatements.get(tableName).get(rows.size()); if (insertStatement == null) { String sql = getInsertStatement( environmentSubstitute(meta.getSchemaName()), tableName, data.insertRowMeta, rows.size()); if (log.isDetailed()) logDetailed("Prepared statement : " + sql); insertStatement = data.db.prepareSQL(sql); if (!data.preparedStatements.containsKey(tableName)) { data.preparedStatements.put(tableName, new Hashtable<Integer, PreparedStatement>()); } data.preparedStatements.get(tableName).put(rows.size(), insertStatement); } try { // For PG & GP, we add a savepoint before the row. // Then revert to the savepoint afterwards... (not a transaction, so // hopefully still fast) // if (data.specialErrorHandling) { data.savepoint = data.db.setSavepoint(); } RowMeta insertRowMeta = new RowMeta(); for (int i = 0; i < rows.size(); i++) { for (int j = 0; j < data.valuenrs.length; j++) { insertRowMeta.addValueMeta(data.insertRowMeta.getValueMeta(j)); } } data.db.setValues(insertRowMeta, toArray(insertRowsData), insertStatement); data.db.insertRow(insertStatement, data.batchMode, false); // false: // no // commit, // it is // handled // in // this // step // different // Get a commit counter per prepared statement to keep track of // separate tables, etc. // Integer commitCounter = data.commitCounterMap.get(tableName); if (commitCounter == null) { commitCounter = Integer.valueOf(1); } else { commitCounter++; } data.commitCounterMap.put(tableName, Integer.valueOf(commitCounter.intValue())); // Release the savepoint if needed // if (data.specialErrorHandling) { if (data.releaseSavepoint) { data.db.releaseSavepoint(data.savepoint); } } // Perform a commit if needed // if ((data.commitSize > 0) && ((commitCounter % data.commitSize) == 0)) { if (data.batchMode) { try { insertStatement.executeBatch(); data.db.commit(); insertStatement.clearBatch(); } catch (BatchUpdateException ex) { KettleDatabaseBatchException kdbe = new KettleDatabaseBatchException("Error updating batch", ex); kdbe.setUpdateCounts(ex.getUpdateCounts()); List<Exception> exceptions = new ArrayList<Exception>(); // 'seed' the loop with the root exception SQLException nextException = ex; do { exceptions.add(nextException); // while current exception has next exception, add // to list } while ((nextException = nextException.getNextException()) != null); kdbe.setExceptionsList(exceptions); throw kdbe; } catch (SQLException ex) { throw new KettleDatabaseException("Error inserting row", ex); } catch (Exception ex) { throw new KettleDatabaseException("Unexpected error inserting row", ex); } } else { // insertRow normal commit data.db.commit(); } // Clear the batch/commit counter... // data.commitCounterMap.put(tableName, Integer.valueOf(0)); rowIsSafe = true; } else { rowIsSafe = false; } } catch (KettleDatabaseBatchException be) { errorMessage = be.toString(); batchProblem = true; sendToErrorRow = true; updateCounts = be.getUpdateCounts(); exceptionsList = be.getExceptionsList(); if (getStepMeta().isDoingErrorHandling()) { data.db.clearBatch(insertStatement); data.db.commit(true); } else { data.db.clearBatch(insertStatement); data.db.rollback(); StringBuffer msg = new StringBuffer("Error batch inserting rows into table [" + tableName + "]."); msg.append(Const.CR); msg.append("Errors encountered (first 10):").append(Const.CR); for (int x = 0; x < be.getExceptionsList().size() && x < 10; x++) { Exception exception = be.getExceptionsList().get(x); if (exception.getMessage() != null) msg.append(exception.getMessage()).append(Const.CR); } throw new KettleException(msg.toString(), be); } } catch (KettleDatabaseException dbe) { if (getStepMeta().isDoingErrorHandling()) { if (data.specialErrorHandling) { data.db.rollback(data.savepoint); if (data.releaseSavepoint) { data.db.releaseSavepoint(data.savepoint); } // data.db.commit(true); // force a commit on the connection // too. } sendToErrorRow = true; errorMessage = dbe.toString(); } else { if (meta.ignoreErrors()) { if (data.warnings < 20) { if (log.isBasic()) logBasic("WARNING: Couldn't insert row into table." + Const.CR + dbe.getMessage()); } else if (data.warnings == 20) { if (log.isBasic()) logBasic( "FINAL WARNING (no more then 20 displayed): Couldn't insert row into table: " + Const.CR + dbe.getMessage()); } data.warnings++; } else { setErrors(getErrors() + 1); data.db.rollback(); throw new KettleException("Error inserting row into table [" + tableName + "]", dbe); } } } if (data.batchMode) { if (sendToErrorRow) { if (batchProblem) { for (Object[] row : outputRowsData) { data.batchBuffer.add(row); } outputRowsData = null; processBatchException(errorMessage, updateCounts, exceptionsList); } else { // Simply add this row to the error row for (Object[] row : outputRowsData) { putError(rowMeta, row, 1L, errorMessage, null, "TOP001"); } outputRowsData = null; } } else { for (Object[] row : outputRowsData) { data.batchBuffer.add(row); } outputRowsData = null; if (rowIsSafe) // A commit was done and the rows are all safe // (no error) { for (int i = 0; i < data.batchBuffer.size(); i++) { Object[] row = (Object[]) data.batchBuffer.get(i); putRow(data.outputRowMeta, row); incrementLinesOutput(); } // Clear the buffer data.batchBuffer.clear(); } } } else { if (sendToErrorRow) { for (Object[] row : outputRowsData) { putError(rowMeta, row, 1L, errorMessage, null, "TOP001"); } outputRowsData = null; } } return outputRowsData; }
protected static RowMetaInterface createRowMeta(ValueMetaInterface... valueMetas) { RowMeta rowMeta = new RowMeta(); rowMeta.setValueMetaList(Arrays.asList(valueMetas)); return rowMeta; }