public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException { meta = (FormulaMeta) smi; data = (FormulaData) sdi; Object[] r = getRow(); // get row, set busy! if (r == null) { // no more input to be expected... setOutputDone(); return false; } if (first) { first = false; data.outputRowMeta = getInputRowMeta().clone(); meta.getFields(data.outputRowMeta, getStepname(), null, null, this, repository, metaStore); // Create the context data.context = new RowForumulaContext(data.outputRowMeta); data.parser = new FormulaParser(); // Calculate replace indexes... // data.replaceIndex = new int[meta.getFormula().length]; for (int i = 0; i < meta.getFormula().length; i++) { FormulaMetaFunction fn = meta.getFormula()[i]; if (!Const.isEmpty(fn.getReplaceField())) { data.replaceIndex[i] = getInputRowMeta().indexOfValue(fn.getReplaceField()); if (data.replaceIndex[i] < 0) { throw new KettleException( "Unknown field specified to replace with a formula result: [" + fn.getReplaceField() + "]"); } } else { data.replaceIndex[i] = -1; } } } if (log.isRowLevel()) { logRowlevel("Read row #" + getLinesRead() + " : " + r); } Object[] outputRowData = calcFields(getInputRowMeta(), r); putRow(data.outputRowMeta, outputRowData); // copy row to possible alternate rowset(s). if (log.isRowLevel()) { logRowlevel("Wrote row #" + getLinesWritten() + " : " + r); } if (checkFeedback(getLinesRead())) { logBasic("Linenr " + getLinesRead()); } return true; }
public boolean init(StepMetaInterface smi, StepDataInterface sdi) { meta = (FormulaMeta) smi; data = (FormulaData) sdi; if (super.init(smi, sdi)) { // Add init code here. // Return data type discovery is expensive, let's discover them one time only. // data.returnType = new int[meta.getFormula().length]; for (int i = 0; i < meta.getFormula().length; i++) { data.returnType[i] = -1; } return true; } return false; }
private Object[] calcFields(RowMetaInterface rowMeta, Object[] r) throws KettleValueException { try { Object[] outputRowData = RowDataUtil.createResizedCopy(r, data.outputRowMeta.size()); int tempIndex = rowMeta.size(); // Assign this tempRowData to the formula context // data.context.setRowData(outputRowData); // Initialize parsers etc. Only do it once. // if (data.formulas == null) { // Create a set of LValues to put the parsed results in... data.formulas = new org.pentaho.reporting.libraries.formula.Formula[meta.getFormula().length]; for (int i = 0; i < meta.getFormula().length; i++) { FormulaMetaFunction fn = meta.getFormula()[i]; if (!Const.isEmpty(fn.getFieldName())) { data.formulas[i] = data.createFormula(meta.getFormula()[i].getFormula()); } else { throw new KettleException( "Unable to find field name for formula [" + Const.NVL(fn.getFormula(), "") + "]"); } } } for (int i = 0; i < meta.getFormula().length; i++) { FormulaMetaFunction fn = meta.getFormula()[i]; if (!Const.isEmpty(fn.getFieldName())) { if (data.formulas[i] == null) { data.formulas[i] = data.createFormula(meta.getFormula()[i].getFormula()); } // this is main part of all this step: calculate formula Object formulaResult = data.formulas[i].evaluate(); if (formulaResult instanceof LibFormulaErrorValue) { // inspect why it is happens to get clear error message. throw new KettleException( "Error calculate formula. Formula " + fn.getFormula() + " output field: " + fn.getFieldName() + ", error is: " + formulaResult.toString()); } // Calculate the return type on the first row... // for most cases we can try to convert data on a fly. if (data.returnType[i] < 0) { if (formulaResult instanceof String) { data.returnType[i] = FormulaData.RETURN_TYPE_STRING; fn.setNeedDataConversion(fn.getValueType() != ValueMetaInterface.TYPE_STRING); } else if (formulaResult instanceof Integer) { data.returnType[i] = FormulaData.RETURN_TYPE_INTEGER; fn.setNeedDataConversion(fn.getValueType() != ValueMetaInterface.TYPE_INTEGER); } else if (formulaResult instanceof Long) { data.returnType[i] = FormulaData.RETURN_TYPE_LONG; fn.setNeedDataConversion(fn.getValueType() != ValueMetaInterface.TYPE_INTEGER); } else if (formulaResult instanceof Date) { data.returnType[i] = FormulaData.RETURN_TYPE_DATE; fn.setNeedDataConversion(fn.getValueType() != ValueMetaInterface.TYPE_DATE); } else if (formulaResult instanceof BigDecimal) { data.returnType[i] = FormulaData.RETURN_TYPE_BIGDECIMAL; fn.setNeedDataConversion(fn.getValueType() != ValueMetaInterface.TYPE_BIGNUMBER); } else if (formulaResult instanceof Number) { data.returnType[i] = FormulaData.RETURN_TYPE_NUMBER; fn.setNeedDataConversion(fn.getValueType() != ValueMetaInterface.TYPE_NUMBER); // this types we will not make attempt to auto-convert } else if (formulaResult instanceof byte[]) { data.returnType[i] = FormulaData.RETURN_TYPE_BYTE_ARRAY; if (fn.getValueType() != ValueMetaInterface.TYPE_BINARY) { throw new KettleValueException( "Please specify a Binary type for field [" + fn.getFieldName() + "] as a result of formula [" + fn.getFormula() + "]"); } } else if (formulaResult instanceof Boolean) { data.returnType[i] = FormulaData.RETURN_TYPE_BOOLEAN; if (fn.getValueType() != ValueMetaInterface.TYPE_BOOLEAN) { throw new KettleValueException( "Please specify a Boolean type for field [" + fn.getFieldName() + "] as a result of formula [" + fn.getFormula() + "]"); } } else { data.returnType[i] = FormulaData.RETURN_TYPE_STRING; } } int realIndex = (data.replaceIndex[i] < 0) ? tempIndex++ : data.replaceIndex[i]; outputRowData[realIndex] = getReturnValue(formulaResult, data.returnType[i], realIndex, fn); } } return outputRowData; } catch (Throwable e) { throw new KettleValueException(e); } }