Пример #1
0
  public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException {
    if (data.linesWritten >= meta.getDataLines().size()) // no more rows to be written
    {
      setOutputDone();
      return false;
    }

    if (first) {
      // The output meta is the original input meta + the
      // additional constant fields.

      first = false;
      data.linesWritten = 0;

      data.outputRowMeta = new RowMeta();
      meta.getFields(data.outputRowMeta, getStepname(), null, null, this);

      // Use these metadata values to convert data...
      //
      data.convertMeta = data.outputRowMeta.clone();
      for (ValueMetaInterface valueMeta : data.convertMeta.getValueMetaList()) {
        valueMeta.setType(ValueMetaInterface.TYPE_STRING);
      }
    }

    Object[] outputRowData = RowDataUtil.allocateRowData(data.outputRowMeta.size());
    List<String> outputLine = meta.getDataLines().get(data.linesWritten);

    for (int i = 0; i < data.outputRowMeta.size(); i++) {
      ValueMetaInterface valueMeta = data.outputRowMeta.getValueMeta(i);
      ValueMetaInterface convertMeta = data.convertMeta.getValueMeta(i);
      String valueData = outputLine.get(i);

      outputRowData[i] = valueMeta.convertDataFromString(valueData, convertMeta, null, null, 0);
    }

    putRow(data.outputRowMeta, outputRowData);
    data.linesWritten++;

    if (log.isRowLevel()) {
      log.logRowlevel(
          toString(),
          BaseMessages.getString(
              PKG,
              "DataGrid.Log.Wrote.Row",
              Long.toString(getLinesWritten()),
              data.outputRowMeta.getString(outputRowData)));
    }

    if (checkFeedback(getLinesWritten())) {
      if (log.isBasic())
        logBasic(
            BaseMessages.getString(PKG, "DataGrid.Log.LineNr", Long.toString(getLinesWritten())));
    }

    return true;
  }
  public static final RowMetaAndData buildRow(
      RowGeneratorMeta meta, List<CheckResultInterface> remarks, String origin) {
    RowMetaInterface rowMeta = new RowMeta();
    Object[] rowData = RowDataUtil.allocateRowData(meta.getFieldName().length);

    for (int i = 0; i < meta.getFieldName().length; i++) {
      int valtype = ValueMeta.getType(meta.getFieldType()[i]);
      if (meta.getFieldName()[i] != null) {
        ValueMetaInterface valueMeta =
            new ValueMeta(meta.getFieldName()[i], valtype); // build a value!
        valueMeta.setLength(meta.getFieldLength()[i]);
        valueMeta.setPrecision(meta.getFieldPrecision()[i]);
        valueMeta.setConversionMask(meta.getFieldFormat()[i]);
        valueMeta.setGroupingSymbol(meta.getGroup()[i]);
        valueMeta.setDecimalSymbol(meta.getDecimal()[i]);
        valueMeta.setOrigin(origin);

        ValueMetaInterface stringMeta = valueMeta.clone();
        stringMeta.setType(ValueMetaInterface.TYPE_STRING);

        String stringValue = meta.getValue()[i];

        // If the value is empty: consider it to be NULL.
        if (Const.isEmpty(stringValue)) {
          rowData[i] = null;

          if (valueMeta.getType() == ValueMetaInterface.TYPE_NONE) {
            String message =
                BaseMessages.getString(
                    PKG,
                    "RowGenerator.CheckResult.SpecifyTypeError",
                    valueMeta.getName(),
                    stringValue);
            remarks.add(new CheckResult(CheckResultInterface.TYPE_RESULT_ERROR, message, null));
          }
        } else {
          // Convert the data from String to the specified type ...
          //
          try {
            rowData[i] = valueMeta.convertData(stringMeta, stringValue);
          } catch (KettleValueException e) {
            switch (valueMeta.getType()) {
              case ValueMetaInterface.TYPE_NUMBER:
                {
                  String message =
                      BaseMessages.getString(
                          PKG,
                          "RowGenerator.BuildRow.Error.Parsing.Number",
                          valueMeta.getName(),
                          stringValue,
                          e.toString());
                  remarks.add(
                      new CheckResult(CheckResultInterface.TYPE_RESULT_ERROR, message, null));
                }
                break;
              case ValueMetaInterface.TYPE_DATE:
                {
                  String message =
                      BaseMessages.getString(
                          PKG,
                          "RowGenerator.BuildRow.Error.Parsing.Date",
                          valueMeta.getName(),
                          stringValue,
                          e.toString());
                  remarks.add(
                      new CheckResult(CheckResultInterface.TYPE_RESULT_ERROR, message, null));
                }
                break;
              case ValueMetaInterface.TYPE_INTEGER:
                {
                  String message =
                      BaseMessages.getString(
                          PKG,
                          "RowGenerator.BuildRow.Error.Parsing.Integer",
                          valueMeta.getName(),
                          stringValue,
                          e.toString());
                  remarks.add(
                      new CheckResult(CheckResultInterface.TYPE_RESULT_ERROR, message, null));
                }
                break;
              case ValueMetaInterface.TYPE_BIGNUMBER:
                {
                  String message =
                      BaseMessages.getString(
                          PKG,
                          "RowGenerator.BuildRow.Error.Parsing.BigNumber",
                          valueMeta.getName(),
                          stringValue,
                          e.toString());
                  remarks.add(
                      new CheckResult(CheckResultInterface.TYPE_RESULT_ERROR, message, null));
                }
                break;
              default:
                // Boolean and binary don't throw errors normally, so it's probably an unspecified
                // error problem...
                {
                  String message =
                      BaseMessages.getString(
                          PKG,
                          "RowGenerator.CheckResult.SpecifyTypeError",
                          valueMeta.getName(),
                          stringValue);
                  remarks.add(
                      new CheckResult(CheckResultInterface.TYPE_RESULT_ERROR, message, null));
                }
                break;
            }
          }
        }
        // Now add value to the row!
        // This is in fact a copy from the fields row, but now with data.
        rowMeta.addValueMeta(valueMeta);
      }
    }

    return new RowMetaAndData(rowMeta, rowData);
  }
  public void getFields(
      RowMetaInterface rowMeta,
      String origin,
      RowMetaInterface[] info,
      StepMeta nextStep,
      VariableSpace space)
      throws KettleStepException {
    rowMeta.clear(); // Start with a clean slate, eats the input

    for (int i = 0; i < inputFields.length; i++) {
      TextFileInputField field = inputFields[i];

      ValueMetaInterface valueMeta = new ValueMeta(field.getName(), field.getType());
      valueMeta.setConversionMask(field.getFormat());
      valueMeta.setLength(field.getLength());
      valueMeta.setPrecision(field.getPrecision());
      valueMeta.setConversionMask(field.getFormat());
      valueMeta.setDecimalSymbol(field.getDecimalSymbol());
      valueMeta.setGroupingSymbol(field.getGroupSymbol());
      valueMeta.setCurrencySymbol(field.getCurrencySymbol());
      valueMeta.setTrimType(field.getTrimType());
      if (lazyConversionActive)
        valueMeta.setStorageType(ValueMetaInterface.STORAGE_TYPE_BINARY_STRING);
      valueMeta.setStringEncoding(space.environmentSubstitute(encoding));

      // In case we want to convert Strings...
      // Using a copy of the valueMeta object means that the inner and outer representation format
      // is the same.
      // Preview will show the data the same way as we read it.
      // This layout is then taken further down the road by the metadata through the transformation.
      //
      ValueMetaInterface storageMetadata = valueMeta.clone();
      storageMetadata.setType(ValueMetaInterface.TYPE_STRING);
      storageMetadata.setStorageType(ValueMetaInterface.STORAGE_TYPE_NORMAL);
      storageMetadata.setLength(
          -1, -1); // we don't really know the lengths of the strings read in advance.
      valueMeta.setStorageMetadata(storageMetadata);

      valueMeta.setOrigin(origin);

      rowMeta.addValueMeta(valueMeta);
    }

    if (!Const.isEmpty(filenameField) && includingFilename) {
      ValueMetaInterface filenameMeta =
          new ValueMeta(filenameField, ValueMetaInterface.TYPE_STRING);
      filenameMeta.setOrigin(origin);
      if (lazyConversionActive) {
        filenameMeta.setStorageType(ValueMetaInterface.STORAGE_TYPE_BINARY_STRING);
        filenameMeta.setStorageMetadata(
            new ValueMeta(filenameField, ValueMetaInterface.TYPE_STRING));
      }
      rowMeta.addValueMeta(filenameMeta);
    }

    if (!Const.isEmpty(rowNumField)) {
      ValueMetaInterface rowNumMeta = new ValueMeta(rowNumField, ValueMetaInterface.TYPE_INTEGER);
      rowNumMeta.setLength(10);
      rowNumMeta.setOrigin(origin);
      rowMeta.addValueMeta(rowNumMeta);
    }
  }
  public void getFields(
      RowMetaInterface row,
      String origin,
      RowMetaInterface[] info,
      StepMeta nextStep,
      VariableSpace space)
      throws KettleStepException {
    // Row should normally be empty when we get here.
    // That is because there is no previous step to this mapping input step from the viewpoint of
    // this single sub-transformation.
    // From the viewpoint of the transformation that executes the mapping, it's important to know
    // what comes out at the exit points.
    // For that reason we need to re-order etc, based on the input specification...
    //
    if (inputRowMeta != null && !inputRowMeta.isEmpty()) {
      // this gets set only in the parent transformation...
      // It includes all the renames that needed to be done
      //
      if (selectingAndSortingUnspecifiedFields) {

        // First rename any fields...
        if (valueRenames != null) {
          for (MappingValueRename valueRename : valueRenames) {
            ValueMetaInterface valueMeta =
                inputRowMeta.searchValueMeta(valueRename.getSourceValueName());
            if (valueMeta == null) {
              throw new KettleStepException(
                  BaseMessages.getString(
                      PKG,
                      "MappingInput.Exception.UnableToFindMappedValue",
                      valueRename.getSourceValueName()));
            }
            valueMeta.setName(valueRename.getTargetValueName());
          }
        }

        // Select the specified fields from the input, re-order everything and put the other fields
        // at the back, sorted...
        //
        RowMetaInterface newRow = new RowMeta();

        for (int i = 0; i < fieldName.length; i++) {
          int index = inputRowMeta.indexOfValue(fieldName[i]);
          if (index < 0) {
            throw new KettleStepException(
                BaseMessages.getString(
                    PKG, "MappingInputMeta.Exception.UnknownField", fieldName[i]));
          }

          newRow.addValueMeta(inputRowMeta.getValueMeta(index));
        }

        // Now get the unspecified fields.
        // Sort the fields
        // Add them after the specified fields...
        //
        List<String> extra = new ArrayList<String>();
        for (int i = 0; i < inputRowMeta.size(); i++) {
          String fieldName = inputRowMeta.getValueMeta(i).getName();
          if (newRow.indexOfValue(fieldName) < 0) {
            extra.add(fieldName);
          }
        }
        Collections.sort(extra);
        for (String fieldName : extra) {
          ValueMetaInterface extraValue = inputRowMeta.searchValueMeta(fieldName);
          newRow.addValueMeta(extraValue);
        }

        // now merge the new row...
        // This is basically the input row meta data with the fields re-ordered.
        //
        row.mergeRowMeta(newRow);
      } else {
        row.mergeRowMeta(inputRowMeta);

        // Validate the existence of all the specified fields...
        //
        if (!row.isEmpty()) {
          for (int i = 0; i < fieldName.length; i++) {
            if (row.indexOfValue(fieldName[i]) < 0) {
              throw new KettleStepException(
                  BaseMessages.getString(
                      PKG, "MappingInputMeta.Exception.UnknownField", fieldName[i]));
            }
          }
        }
      }
    } else {
      // We'll have to work with the statically provided information
      for (int i = 0; i < fieldName.length; i++) {
        if (!Const.isEmpty(fieldName[i])) {
          ValueMetaInterface v = new ValueMeta(fieldName[i], fieldType[i]);
          if (v.getType() == ValueMetaInterface.TYPE_NONE)
            v.setType(ValueMetaInterface.TYPE_STRING);
          v.setLength(fieldLength[i]);
          v.setPrecision(fieldPrecision[i]);
          v.setOrigin(origin);
          row.addValueMeta(v);
        }
      }
    }
  }
  private ValueMetaInterface getValueMeta(CalculatorMetaFunction fn, String origin) {
    ValueMetaInterface v = new ValueMeta(fn.getFieldName(), fn.getValueType());
    v.setLength(fn.getValueLength());
    v.setPrecision(fn.getValuePrecision());
    v.setOrigin(origin);
    v.setComments(fn.getCalcTypeDesc());
    v.setConversionMask(fn.getConversionMask());
    v.setDecimalSymbol(fn.getDecimalSymbol());
    v.setGroupingSymbol(fn.getGroupingSymbol());
    v.setCurrencySymbol(fn.getCurrencySymbol());

    // What if the user didn't specify a data type?
    // In that case we look for the default data type
    //
    if (fn.getValueType() == ValueMetaInterface.TYPE_NONE) {
      int defaultResultType = ValueMetaInterface.TYPE_NONE;

      switch (fn.getCalcType()) {
        case CalculatorMetaFunction.CALC_NONE:
          break;
        case CalculatorMetaFunction.CALC_ADD: // A + B
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_SUBTRACT: // A - B
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_MULTIPLY: // A * B
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_DIVIDE: // A / B
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_SQUARE: // A * A
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_SQUARE_ROOT: // SQRT( A )
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_PERCENT_1: // 100 * A / B
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_PERCENT_2: // A - ( A * B / 100 )
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_PERCENT_3: // A + ( A * B / 100 )
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_COMBINATION_1: // A + B * C
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_COMBINATION_2: // SQRT( A*A + B*B )
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_ROUND_1: // ROUND( A )
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction.CALC_ROUND_2: //  ROUND( A , B )
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_CONSTANT: // Set field to constant value...
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_NVL: // Replace null values with another value
          break;
        case CalculatorMetaFunction.CALC_ADD_DAYS: // Add B days to date field A
          defaultResultType = ValueMetaInterface.TYPE_DATE;
          break;
        case CalculatorMetaFunction.CALC_YEAR_OF_DATE: // What is the year (Integer) of a date?
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction.CALC_MONTH_OF_DATE: // What is the month (Integer) of a date?
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction
            .CALC_DAY_OF_YEAR: // What is the day of year (Integer) of a date?
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction
            .CALC_DAY_OF_MONTH: // What is the day of month (Integer) of a date?
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction
            .CALC_DAY_OF_WEEK: // What is the day of week (Integer) of a date?
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction
            .CALC_WEEK_OF_YEAR: // What is the week of year (Integer) of a date?
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction
            .CALC_WEEK_OF_YEAR_ISO8601: // What is the week of year (Integer) of a date ISO8601
          // style?
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction
            .CALC_YEAR_OF_DATE_ISO8601: // What is the year (Integer) of a date ISO8601 style?
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction.CALC_BYTE_TO_HEX_ENCODE: // Byte to Hex encode string field A
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_HEX_TO_BYTE_DECODE: // Hex to Byte decode string field A
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_CHAR_TO_HEX_ENCODE: // Char to Hex encode string field A
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_HEX_TO_CHAR_DECODE: // Hex to Char decode string field A
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_CRC32: // CRC32 of a file A
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction.CALC_ADLER32: // ADLER32 of a file A
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction.CALC_MD5: // MD5 of a file A
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_SHA1: // SHA1 of a file Al
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction
            .CALC_LEVENSHTEIN_DISTANCE: // LEVENSHTEIN_DISTANCE of string A and string B
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction.CALC_METAPHONE: // METAPHONE of string A
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_DOUBLE_METAPHONE: // Double METAPHONE of string A
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_ABS: // ABS( A )
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction.CALC_REMOVE_TIME_FROM_DATE: // Remove time from field A
          defaultResultType = ValueMetaInterface.TYPE_DATE;
          break;
        case CalculatorMetaFunction.CALC_DATE_DIFF: // DateA - DateB
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction.CALC_ADD3: // A + B +C
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_INITCAP: // InitCap(A)
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_UPPER_CASE: // UpperCase(A)
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_LOWER_CASE: // LowerCase(A)
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_MASK_XML: // MaskXML(A)
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_USE_CDATA: // CDATA(A)
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_REMOVE_CR: // REMOVE CR FROM string A
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_REMOVE_LF: // REMOVE LF FROM string A
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_REMOVE_CRLF: // REMOVE CRLF FROM string A
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_REMOVE_TAB: // REMOVE TAB FROM string A
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_GET_ONLY_DIGITS: // GET ONLY DIGITS FROM string A
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction.CALC_REMOVE_DIGITS: // REMOVE DIGITS FROM string A
          defaultResultType = ValueMetaInterface.TYPE_STRING;
          break;
        case CalculatorMetaFunction.CALC_STRING_LEN: // LENGTH OF string A
          defaultResultType = ValueMetaInterface.TYPE_INTEGER;
          break;
        case CalculatorMetaFunction.CALC_LOAD_FILE_CONTENT_BINARY: // LOAD FILE CONTENT IN BLOB
          defaultResultType = ValueMetaInterface.TYPE_BINARY;
          break;
        case CalculatorMetaFunction.CALC_ADD_TIME_TO_DATE: // ADD TIME TO A DATE
          defaultResultType = ValueMetaInterface.TYPE_DATE;
          break;
        case CalculatorMetaFunction.CALC_GEOM_UNION: // Calculate geometry union
          defaultResultType = ValueMetaInterface.TYPE_GEOMETRY;
          break;
        case CalculatorMetaFunction.CALC_GEOM_INTERSECTION: // Calculate geometry intersection
          defaultResultType = ValueMetaInterface.TYPE_GEOMETRY;
          break;
        case CalculatorMetaFunction.CALC_GEOM_DIFFERENCE: // Calculate geometry difference
          defaultResultType = ValueMetaInterface.TYPE_GEOMETRY;
          break;
        case CalculatorMetaFunction
            .CALC_GEOM_SYMETRIC_DIFFERENCE: // Calculate geometry symetric difference
          defaultResultType = ValueMetaInterface.TYPE_GEOMETRY;
          break;
        case CalculatorMetaFunction.CALC_GEOM_AREA: // Calculate area
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_GEOM_LENGTH: // Calculate length
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        case CalculatorMetaFunction.CALC_GEOM_CENTROID: // Calculate centroid
          defaultResultType = ValueMetaInterface.TYPE_GEOMETRY;
          break;
        case CalculatorMetaFunction.CALC_GEOM_POINT_ON_SURFACE: // Calculate random point on surface
          defaultResultType = ValueMetaInterface.TYPE_GEOMETRY;
          break;
        case CalculatorMetaFunction.CALC_GEOM_REVERSE: // Reverse geometry
          defaultResultType = ValueMetaInterface.TYPE_GEOMETRY;
          break;
        case CalculatorMetaFunction.CALC_GEOM_BOUNDARY: // Calculate geometry boundary
          defaultResultType = ValueMetaInterface.TYPE_GEOMETRY;
          break;
        case CalculatorMetaFunction.CALC_GEOM_ENVELOPE: // Calculate geometry envelope
          defaultResultType = ValueMetaInterface.TYPE_GEOMETRY;
          break;
        case CalculatorMetaFunction.CALC_GEOM_CONVEX_HULL: // Calculate geometry convex hull
          defaultResultType = ValueMetaInterface.TYPE_GEOMETRY;
          break;
        case CalculatorMetaFunction.CALC_GEOM_BUFFER: // Calculate geometry buffer
          defaultResultType = ValueMetaInterface.TYPE_GEOMETRY;
          break;
        case CalculatorMetaFunction.CALC_GEOM_DISTANCE: // Calculate distance between geometries
          defaultResultType = ValueMetaInterface.TYPE_NUMBER;
          break;
        default:
          break;
      }

      v.setType(defaultResultType);
    }

    return v;
  }
  public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException {
    meta = (DatabaseLookupMeta) smi;
    data = (DatabaseLookupData) sdi;

    boolean sendToErrorRow = false;
    String errorMessage = null;

    Object[] r = getRow(); // Get row from input rowset & set row busy!
    if (r == null) // no more input to be expected...
    {
      setOutputDone();
      return false;
    }

    if (first) {
      first = false;

      // create the output metadata
      data.outputRowMeta = getInputRowMeta().clone();
      meta.getFields(data.outputRowMeta, getStepname(), null, null, this);

      if (meta.isCached()) {
        if (meta.getCacheSize() > 0) {
          data.look = new Hashtable<RowMetaAndData, TimedRow>((int) (meta.getCacheSize() * 1.5));
        } else {
          data.look = new Hashtable<RowMetaAndData, TimedRow>();
        }
      }

      data.db.setLookup(
          environmentSubstitute(meta.getSchemaName()),
          environmentSubstitute(meta.getTablename()),
          meta.getTableKeyField(),
          meta.getKeyCondition(),
          meta.getReturnValueField(),
          meta.getReturnValueNewName(),
          meta.getOrderByClause(),
          meta.isFailingOnMultipleResults());

      // lookup the values!
      if (log.isDetailed())
        logDetailed(
            BaseMessages.getString(PKG, "DatabaseLookup.Log.CheckingRow")
                + getInputRowMeta().getString(r)); // $NON-NLS-1$

      data.keynrs = new int[meta.getStreamKeyField1().length];
      data.keynrs2 = new int[meta.getStreamKeyField1().length];

      for (int i = 0; i < meta.getStreamKeyField1().length; i++) {
        data.keynrs[i] = getInputRowMeta().indexOfValue(meta.getStreamKeyField1()[i]);
        if (data.keynrs[i] < 0
            && // couldn't find field!
            !"IS NULL".equalsIgnoreCase(meta.getKeyCondition()[i])
            && // No field needed! //$NON-NLS-1$
            !"IS NOT NULL"
                .equalsIgnoreCase(meta.getKeyCondition()[i]) // No field needed! //$NON-NLS-1$
        ) {
          throw new KettleStepException(
              BaseMessages.getString(PKG, "DatabaseLookup.ERROR0001.FieldRequired1.Exception")
                  + meta.getStreamKeyField1()[i]
                  + BaseMessages.getString(
                      PKG,
                      "DatabaseLookup.ERROR0001.FieldRequired2.Exception")); //$NON-NLS-1$
                                                                             // //$NON-NLS-2$
        }
        data.keynrs2[i] = getInputRowMeta().indexOfValue(meta.getStreamKeyField2()[i]);
        if (data.keynrs2[i] < 0
            && // couldn't find field!
            "BETWEEN".equalsIgnoreCase(meta.getKeyCondition()[i]) // 2 fields needed! //$NON-NLS-1$
        ) {
          throw new KettleStepException(
              BaseMessages.getString(PKG, "DatabaseLookup.ERROR0001.FieldRequired3.Exception")
                  + meta.getStreamKeyField2()[i]
                  + BaseMessages.getString(
                      PKG,
                      "DatabaseLookup.ERROR0001.FieldRequired4.Exception")); //$NON-NLS-1$
                                                                             // //$NON-NLS-2$
        }
        if (log.isDebug())
          logDebug(
              BaseMessages.getString(PKG, "DatabaseLookup.Log.FieldHasIndex1")
                  + meta.getStreamKeyField1()[i]
                  + BaseMessages.getString(PKG, "DatabaseLookup.Log.FieldHasIndex2")
                  + data.keynrs[i]); // $NON-NLS-1$ //$NON-NLS-2$
      }

      data.nullif = new Object[meta.getReturnValueField().length];

      for (int i = 0; i < meta.getReturnValueField().length; i++) {
        ValueMetaInterface stringMeta = new ValueMeta("string", ValueMetaInterface.TYPE_STRING);
        ValueMetaInterface returnMeta =
            data.outputRowMeta.getValueMeta(i + getInputRowMeta().size());

        if (!Const.isEmpty(meta.getReturnValueDefault()[i])) {
          data.nullif[i] = returnMeta.convertData(stringMeta, meta.getReturnValueDefault()[i]);
        } else {
          data.nullif[i] = null;
          ;
        }
      }

      // Determine the types...
      data.keytypes = new int[meta.getTableKeyField().length];
      String schemaTable =
          meta.getDatabaseMeta()
              .getQuotedSchemaTableCombination(
                  environmentSubstitute(meta.getSchemaName()),
                  environmentSubstitute(meta.getTablename()));
      RowMetaInterface fields = data.db.getTableFields(schemaTable);
      if (fields != null) {
        // Fill in the types...
        for (int i = 0; i < meta.getTableKeyField().length; i++) {
          ValueMetaInterface key = fields.searchValueMeta(meta.getTableKeyField()[i]);
          if (key != null) {
            data.keytypes[i] = key.getType();
          } else {
            throw new KettleStepException(
                BaseMessages.getString(PKG, "DatabaseLookup.ERROR0001.FieldRequired5.Exception")
                    + meta.getTableKeyField()[i]
                    + BaseMessages.getString(
                        PKG,
                        "DatabaseLookup.ERROR0001.FieldRequired6.Exception")); //$NON-NLS-1$
                                                                               // //$NON-NLS-2$
          }
        }
      } else {
        throw new KettleStepException(
            BaseMessages.getString(PKG, "DatabaseLookup.ERROR0002.UnableToDetermineFieldsOfTable")
                + schemaTable
                + "]"); //$NON-NLS-1$ //$NON-NLS-2$
      }

      // Count the number of values in the lookup as well as the metadata to send along with it.
      //
      data.lookupMeta = new RowMeta();

      for (int i = 0; i < meta.getStreamKeyField1().length; i++) {
        if (data.keynrs[i] >= 0) {
          ValueMetaInterface value = getInputRowMeta().getValueMeta(data.keynrs[i]).clone();

          // Try to convert type if needed in a clone, we don't want to
          // change the type in the original row

          value.setType(data.keytypes[i]);
          data.lookupMeta.addValueMeta(value);
        }
        if (data.keynrs2[i] >= 0) {
          ValueMetaInterface value = getInputRowMeta().getValueMeta(data.keynrs2[i]).clone();

          // Try to convert type if needed in a clone, we don't want to
          // change the type in the original row

          value.setType(data.keytypes[i]);
          data.lookupMeta.addValueMeta(value);
        }
      }

      // We also want to know the metadata of the return values beforehand (null handling)
      data.returnMeta = new RowMeta();

      for (int i = 0; i < meta.getReturnValueField().length; i++) {
        ValueMetaInterface v =
            data.outputRowMeta.getValueMeta(getInputRowMeta().size() + i).clone();
        data.returnMeta.addValueMeta(v);
      }

      // If the user selected to load all data into the cache at startup, that's what we do now...
      //
      if (meta.isCached() && meta.isLoadingAllDataInCache()) {
        loadAllTableDataIntoTheCache();
      }
    }

    if (log.isRowLevel())
      logRowlevel(
          BaseMessages.getString(PKG, "DatabaseLookup.Log.GotRowFromPreviousStep")
              + getInputRowMeta().getString(r)); // $NON-NLS-1$

    try {
      // add new lookup values to the row
      Object[] outputRow = lookupValues(getInputRowMeta(), r);

      if (outputRow != null) {
        // copy row to output rowset(s);
        putRow(data.outputRowMeta, outputRow);

        if (log.isRowLevel())
          logRowlevel(
              BaseMessages.getString(PKG, "DatabaseLookup.Log.WroteRowToNextStep")
                  + getInputRowMeta().getString(r)); // $NON-NLS-1$
        if (checkFeedback(getLinesRead())) logBasic("linenr " + getLinesRead()); // $NON-NLS-1$
      }
    } catch (KettleException e) {
      if (getStepMeta().isDoingErrorHandling()) {
        sendToErrorRow = true;
        errorMessage = e.toString();
      } else {
        logError(
            BaseMessages.getString(PKG, "DatabaseLookup.ERROR003.UnexpectedErrorDuringProcessing")
                + e.getMessage()); // $NON-NLS-1$
        setErrors(1);
        stopAll();
        setOutputDone(); // signal end to receiver(s)
        return false;
      }
      if (sendToErrorRow) {
        // Simply add this row to the error row
        putError(getInputRowMeta(), r, 1, errorMessage, null, "DBLOOKUPD001");
      }
    }

    return true;
  }