/** Check the 2 lists comparing the rows in order. If they are not the same fail the test. */ public void checkRows(List<RowMetaAndData> rows1, List<RowMetaAndData> rows2) { int idx = 1; if (rows1.size() != rows2.size()) { fail("Number of rows is not the same: " + rows1.size() + " and " + rows2.size()); } Iterator<RowMetaAndData> it1 = rows1.iterator(); Iterator<RowMetaAndData> it2 = rows2.iterator(); while (it1.hasNext() && it2.hasNext()) { RowMetaAndData rm1 = it1.next(); RowMetaAndData rm2 = it2.next(); Object[] r1 = rm1.getData(); Object[] r2 = rm2.getData(); if (rm1.size() != rm2.size()) { fail("row nr " + idx + " is not equal"); } int fields[] = new int[rm1.size()]; for (int ydx = 0; ydx < rm1.size(); ydx++) { fields[ydx] = ydx; } try { if (rm1.getRowMeta().compare(r1, r2, fields) != 0) { fail("row nr " + idx + " is not equal"); } } catch (KettleValueException e) { fail("row nr " + idx + " is not equal"); } idx++; } }
public boolean init(StepMetaInterface smi, StepDataInterface sdi) { meta = (RowGeneratorMeta) smi; data = (RowGeneratorData) sdi; if (super.init(smi, sdi)) { // Determine the number of rows to generate... data.rowLimit = Const.toLong(environmentSubstitute(meta.getRowLimit()), -1L); data.rowsWritten = 0L; if (data.rowLimit < 0L) // Unable to parse { logError(BaseMessages.getString(PKG, "RowGenerator.Wrong.RowLimit.Number")); return false; // fail } // Create a row (constants) with all the values in it... List<CheckResultInterface> remarks = new ArrayList<CheckResultInterface>(); // stores the errors... RowMetaAndData outputRow = buildRow(meta, remarks, getStepname()); if (!remarks.isEmpty()) { for (int i = 0; i < remarks.size(); i++) { CheckResult cr = (CheckResult) remarks.get(i); logError(cr.getText()); } return false; } data.outputRowData = outputRow.getData(); data.outputRowMeta = outputRow.getRowMeta(); return true; } return false; }
/** Test case for injector step... also a show case on how to use injector. */ public void testInjector() throws Exception { KettleEnvironment.init(); // // Create a new transformation... // TransMeta transMeta = new TransMeta(); transMeta.setName("injectortest"); PluginRegistry registry = PluginRegistry.getInstance(); // // create an injector step... // String injectorStepname = "injector step"; InjectorMeta im = new InjectorMeta(); // Set the information of the injector. String injectorPid = registry.getPluginId(StepPluginType.class, im); StepMeta injectorStep = new StepMeta(injectorPid, injectorStepname, (StepMetaInterface) im); transMeta.addStep(injectorStep); // // Create a dummy step // String dummyStepname = "dummy step"; DummyTransMeta dm = new DummyTransMeta(); String dummyPid = registry.getPluginId(StepPluginType.class, dm); StepMeta dummyStep = new StepMeta(dummyPid, dummyStepname, (StepMetaInterface) dm); transMeta.addStep(dummyStep); TransHopMeta hi = new TransHopMeta(injectorStep, dummyStep); transMeta.addTransHop(hi); // Now execute the transformation... Trans trans = new Trans(transMeta); trans.prepareExecution(null); StepInterface si = trans.getStepInterface(dummyStepname, 0); RowStepCollector rc = new RowStepCollector(); si.addRowListener(rc); RowProducer rp = trans.addRowProducer(injectorStepname, 0); trans.startThreads(); // add rows List<RowMetaAndData> inputList = createData(); for (RowMetaAndData rm : inputList) { rp.putRow(rm.getRowMeta(), rm.getData()); } rp.finished(); trans.waitUntilFinished(); List<RowMetaAndData> resultRows = rc.getRowsWritten(); checkRows(resultRows, inputList); }
/** * Check the 2 lists comparing the rows in order. If they are not the same fail the test. * * @param rows1 set 1 of rows to compare * @param rows2 set 2 of rows to compare * @param fileNameColumn Number of the column containing the filename. This is only checked for * being non-null (some systems maybe canonize names differently than we input). */ public static void checkRows( List<RowMetaAndData> rows1, List<RowMetaAndData> rows2, int fileNameColumn) throws TestFailedException { int idx = 1; if (rows1.size() != rows2.size()) { throw new TestFailedException( "Number of rows is not the same: " + rows1.size() + " and " + rows2.size()); } Iterator<RowMetaAndData> itrRows1 = rows1.iterator(); Iterator<RowMetaAndData> itrRows2 = rows2.iterator(); while (itrRows1.hasNext() && itrRows2.hasNext()) { RowMetaAndData rowMetaAndData1 = itrRows1.next(); RowMetaAndData rowMetaAndData2 = itrRows2.next(); RowMetaInterface rowMetaInterface1 = rowMetaAndData1.getRowMeta(); Object[] rowObject1 = rowMetaAndData1.getData(); Object[] rowObject2 = rowMetaAndData2.getData(); if (rowMetaAndData1.size() != rowMetaAndData2.size()) { throw new TestFailedException("row number " + idx + " is not equal"); } int[] fields = new int[rowMetaInterface1.size()]; for (int ydx = 0; ydx < rowMetaInterface1.size(); ydx++) { fields[ydx] = ydx; } try { if (fileNameColumn >= 0) { rowObject1[fileNameColumn] = rowObject2[fileNameColumn]; } if (rowMetaAndData1.getRowMeta().compare(rowObject1, rowObject2, fields) != 0) { throw new ComparisonFailure( "row nr " + idx + " is not equal", rowMetaInterface1.getString(rowObject1), rowMetaInterface1.getString(rowObject2)); } } catch (KettleValueException e) { throw new TestFailedException("row nr " + idx + " is not equal"); } idx++; } }
public synchronized int getNrStepAttributes(ObjectId id_step) throws KettleException { int retval = 0; RowMetaAndData par = repository.connectionDelegate.getParameterMetaData(id_step); String sql = "SELECT COUNT(*) FROM " + quoteTable(KettleDatabaseRepository.TABLE_R_STEP_ATTRIBUTE) + " WHERE " + quote(KettleDatabaseRepository.FIELD_STEP_ATTRIBUTE_ID_STEP) + " = ? "; RowMetaAndData r = repository.connectionDelegate.getOneRow(sql, par.getRowMeta(), par.getData()); if (r != null) { retval = (int) r.getInteger(0, 0L); } return retval; }
public synchronized int getNrDatabases(ObjectId id_transformation) throws KettleException { int retval = 0; RowMetaAndData transIdRow = repository.connectionDelegate.getParameterMetaData(id_transformation); String sql = "SELECT COUNT(*) FROM " + quoteTable(KettleDatabaseRepository.TABLE_R_STEP_DATABASE) + " WHERE " + quote(KettleDatabaseRepository.FIELD_STEP_DATABASE_ID_TRANSFORMATION) + " = ? "; RowMetaAndData r = repository.connectionDelegate.getOneRow(sql, transIdRow.getRowMeta(), transIdRow.getData()); if (r != null) { retval = (int) r.getInteger(0, 0L); } return retval; }
private Object[] getRowFromCache(RowMetaInterface lookupMeta, Object[] lookupRow) throws KettleException { if (data.allEquals) { // only do the hashtable lookup when all equals otherwise conditions >, <, <> will give wrong // results TimedRow timedRow = data.look.get(new RowMetaAndData(data.lookupMeta, lookupRow)); if (timedRow != null) { return timedRow.getRow(); } } else { // special handling of conditions <,>, <> etc. if (!data.hasDBCondition) { // e.g. LIKE not handled by this routine, yet // TODO: find an alternative way to look up the data based on the condition. // Not all conditions are "=" so we are going to have to evaluate row by row // A sorted list or index might be a good solution here... // Enumeration<RowMetaAndData> keys = data.look.keys(); while (keys.hasMoreElements()) { RowMetaAndData key = keys.nextElement(); // Now verify that the key is matching our conditions... // boolean match = true; int lookupIndex = 0; for (int i = 0; i < data.conditions.length && match; i++) { ValueMetaInterface cmpMeta = lookupMeta.getValueMeta(lookupIndex); Object cmpData = lookupRow[lookupIndex]; ValueMetaInterface keyMeta = key.getValueMeta(i); Object keyData = key.getData()[i]; switch (data.conditions[i]) { case DatabaseLookupMeta.CONDITION_EQ: match = (cmpMeta.compare(cmpData, keyMeta, keyData) == 0); break; case DatabaseLookupMeta.CONDITION_NE: match = (cmpMeta.compare(cmpData, keyMeta, keyData) != 0); break; case DatabaseLookupMeta.CONDITION_LT: match = (cmpMeta.compare(cmpData, keyMeta, keyData) > 0); break; case DatabaseLookupMeta.CONDITION_LE: match = (cmpMeta.compare(cmpData, keyMeta, keyData) >= 0); break; case DatabaseLookupMeta.CONDITION_GT: match = (cmpMeta.compare(cmpData, keyMeta, keyData) < 0); break; case DatabaseLookupMeta.CONDITION_GE: match = (cmpMeta.compare(cmpData, keyMeta, keyData) <= 0); break; case DatabaseLookupMeta.CONDITION_IS_NULL: match = keyMeta.isNull(keyData); break; case DatabaseLookupMeta.CONDITION_IS_NOT_NULL: match = !keyMeta.isNull(keyData); break; case DatabaseLookupMeta.CONDITION_BETWEEN: // Between key >= cmp && key <= cmp2 ValueMetaInterface cmpMeta2 = lookupMeta.getValueMeta(lookupIndex + 1); Object cmpData2 = lookupRow[lookupIndex + 1]; match = (keyMeta.compare(keyData, cmpMeta, cmpData) >= 0); if (match) { match = (keyMeta.compare(keyData, cmpMeta2, cmpData2) <= 0); } lookupIndex++; break; // TODO: add LIKE operator (think of changing the hasDBCondition logic then) default: match = false; data.hasDBCondition = true; // avoid looping in here the next time, also safety when a new condition // will be introduced break; } lookupIndex++; } if (match) { TimedRow timedRow = data.look.get(key); if (timedRow != null) { return timedRow.getRow(); } } } } } return null; }
/** Test case for janino step. */ public void testJaninoStep() throws Exception { KettleEnvironment.init(); // // Create a new transformation... // TransMeta transMeta = new TransMeta(); transMeta.setName("janino test"); PluginRegistry registry = PluginRegistry.getInstance(); // create an injector step... String injectorStepName = "injector step"; InjectorMeta im = new InjectorMeta(); // Set the information of the injector. String injectorPid = registry.getPluginId(StepPluginType.class, im); StepMeta injectorStep = new StepMeta(injectorPid, injectorStepName, im); transMeta.addStep(injectorStep); // // create a janino step... // String stepname = "janino"; JaninoMeta jm = new JaninoMeta(); // Set the information of the step String janinoPid = registry.getPluginId(StepPluginType.class, jm); StepMeta janinoStep = new StepMeta(janinoPid, stepname, jm); transMeta.addStep(janinoStep); jm.setDefault(); JaninoMetaFunction[] formulas = { new JaninoMetaFunction( "string", "(string==null)?null:\"string-value\"", ValueMeta.TYPE_STRING, -1, -1, "string"), new JaninoMetaFunction( "integer", "(integer==null)?null:new Long(42L)", ValueMeta.TYPE_INTEGER, -1, -1, "integer"), new JaninoMetaFunction( "number", "(number==null)?null:new Double(23.0)", ValueMeta.TYPE_NUMBER, -1, -1, "number"), new JaninoMetaFunction( "bigdecimal", "(bigdecimal==null)?null:new java.math.BigDecimal(11.0)", ValueMeta.TYPE_BIGNUMBER, -1, -1, "bigdecimal"), new JaninoMetaFunction( "date", "(date==null)?null:new java.util.Date(10000000)", ValueMeta.TYPE_DATE, -1, -1, "date"), new JaninoMetaFunction( "binary", "(binary==null)?null:new byte[]{1,2,3,4,5}", ValueMeta.TYPE_BINARY, -1, -1, "binary"), new JaninoMetaFunction( "bool", "(bool==null)?null:Boolean.TRUE", ValueMeta.TYPE_BOOLEAN, -1, -1, "bool"), }; jm.setFormula(formulas); transMeta.addTransHop(new TransHopMeta(injectorStep, janinoStep)); // // Create a dummy step // String dummyStepname = "dummy step"; DummyTransMeta dm = new DummyTransMeta(); String dummyPid = registry.getPluginId(StepPluginType.class, dm); StepMeta dummyStep = new StepMeta(dummyPid, dummyStepname, dm); transMeta.addStep(dummyStep); TransHopMeta hi = new TransHopMeta(janinoStep, dummyStep); transMeta.addTransHop(hi); // Now execute the transformation... Trans trans = new Trans(transMeta); trans.prepareExecution(null); StepInterface si = trans.getStepInterface(dummyStepname, 0); RowStepCollector rc = new RowStepCollector(); si.addRowListener(rc); RowProducer rp = trans.addRowProducer(injectorStepName, 0); trans.startThreads(); for (RowMetaAndData rm : createInputList()) { rp.putRow(rm.getRowMeta(), rm.getData()); } rp.finished(); trans.waitUntilFinished(); List<RowMetaAndData> checkList = createExpectedList(); List<RowMetaAndData> resultRows = rc.getRowsWritten(); checkRows(resultRows, checkList); }
protected Object[] writeToTable(RowMetaInterface rowMeta, Object[] r) throws KettleException { if (r == null) { // Stop: last line or error encountered if (log.isDetailed()) { logDetailed("Last line inserted: stop"); } return null; } PreparedStatement insertStatement = null; Object[] insertRowData; Object[] outputRowData = r; String tableName = null; boolean sendToErrorRow = false; String errorMessage = null; boolean rowIsSafe = false; int[] updateCounts = null; List<Exception> exceptionsList = null; boolean batchProblem = false; Object generatedKey = null; 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() && !meta.specifyFields()) { data.insertRowMeta.removeValueMeta(data.indexOfTableNameField); } } tableName = rowMeta.getString(r, data.indexOfTableNameField); if (!meta.isTableNameInTable() && !meta.specifyFields()) { // 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 // insertRowData = RowDataUtil.removeItem(rowMeta.cloneRow(r), data.indexOfTableNameField); } else { insertRowData = r; } } 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() || r[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(r, data.indexOfPartitioningField); tableName = environmentSubstitute(meta.getTableName()) + "_" + data.dateFormater.format((Date) partitioningValueData); insertRowData = r; } else { tableName = data.tableName; insertRowData = r; } if (meta.specifyFields()) { // // The values to insert are those in the fields sections // insertRowData = new Object[data.valuenrs.length]; for (int idx = 0; idx < data.valuenrs.length; idx++) { insertRowData[idx] = r[data.valuenrs[idx]]; } } if (Const.isEmpty(tableName)) { throw new KettleStepException("The tablename is not defined (empty)"); } insertStatement = data.preparedStatements.get(tableName); if (insertStatement == null) { String sql = data.db.getInsertStatement( environmentSubstitute(meta.getSchemaName()), tableName, data.insertRowMeta); if (log.isDetailed()) { logDetailed("Prepared statement : " + sql); } insertStatement = data.db.prepareSQL(sql, meta.isReturningGeneratedKeys()); data.preparedStatements.put(tableName, 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.useSafePoints) { data.savepoint = data.db.setSavepoint(); } data.db.setValues(data.insertRowMeta, insertRowData, insertStatement); data.db.insertRow( insertStatement, data.batchMode, false); // false: no commit, it is handled in this step // different if (isRowLevel()) { logRowlevel("Written row: " + data.insertRowMeta.getString(insertRowData)); } // 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.useSafePoints) { if (data.releaseSavepoint) { data.db.releaseSavepoint(data.savepoint); } } // Perform a commit if needed // if ((data.commitSize > 0) && ((commitCounter % data.commitSize) == 0)) { if (data.db.getUseBatchInsert(data.batchMode)) { try { insertStatement.executeBatch(); data.db.commit(); insertStatement.clearBatch(); } catch (SQLException ex) { throw Database.createKettleDatabaseBatchException("Error updating batch", 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; } // See if we need to get back the keys as well... if (meta.isReturningGeneratedKeys()) { RowMetaAndData extraKeys = data.db.getGeneratedKeys(insertStatement); if (extraKeys.getRowMeta().size() > 0) { // Send out the good word! // Only 1 key at the moment. (should be enough for now :-) generatedKey = extraKeys.getRowMeta().getInteger(extraKeys.getData(), 0); } else { // we have to throw something here, else we don't know what the // type is of the returned key(s) and we would violate our own rule // that a hop should always contain rows of the same type. throw new KettleStepException( "No generated keys while \"return generated keys\" is active!"); } } } 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(); StringBuilder msg = new StringBuilder("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 (isRowLevel()) { logRowlevel("Written row to error handling : " + getInputRowMeta().getString(r)); } if (data.useSafePoints) { 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: " + rowMeta.getString(r) + 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: " + rowMeta.getString(r) + Const.CR + dbe.getMessage()); } } data.warnings++; } else { setErrors(getErrors() + 1); data.db.rollback(); throw new KettleException( "Error inserting row into table [" + tableName + "] with values: " + rowMeta.getString(r), dbe); } } } // We need to add a key if (generatedKey != null) { outputRowData = RowDataUtil.addValueData(outputRowData, rowMeta.size(), generatedKey); } if (data.batchMode) { if (sendToErrorRow) { if (batchProblem) { data.batchBuffer.add(outputRowData); outputRowData = null; processBatchException(errorMessage, updateCounts, exceptionsList); } else { // Simply add this row to the error row putError(rowMeta, r, 1L, errorMessage, null, "TOP001"); outputRowData = null; } } else { data.batchBuffer.add(outputRowData); outputRowData = 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 = data.batchBuffer.get(i); putRow(data.outputRowMeta, row); incrementLinesOutput(); } // Clear the buffer data.batchBuffer.clear(); } } } else { if (sendToErrorRow) { putError(rowMeta, r, 1, errorMessage, null, "TOP001"); outputRowData = null; } } return outputRowData; }