Пример #1
0
 /** Creates an array of {@link RexLocalRef} objects, one for each field of a given rowtype. */
 public static RexLocalRef[] toLocalRefs(RelDataType rowType) {
   final RelDataTypeField[] fields = rowType.getFields();
   final RexLocalRef[] refs = new RexLocalRef[fields.length];
   for (int i = 0; i < refs.length; i++) {
     refs[i] = new RexLocalRef(i, fields[i].getType());
   }
   return refs;
 }
Пример #2
0
 /**
  * Creates an array of {@link RexInputRef} objects, one for each field of a given rowtype,
  * according to a permutation.
  *
  * @param args Permutation
  * @param rowType Input row type
  * @return Array of input refs
  */
 public static RexInputRef[] toInputRefs(int[] args, RelDataType rowType) {
   final RelDataTypeField[] fields = rowType.getFields();
   final RexInputRef[] rexNodes = new RexInputRef[args.length];
   for (int i = 0; i < args.length; i++) {
     int fieldOrdinal = args[i];
     rexNodes[i] = new RexInputRef(fieldOrdinal, fields[fieldOrdinal].getType());
   }
   return rexNodes;
 }
  /**
   * Creates projection list for scan. If the projection contains expressions, then the input
   * references from those expressions are extracted and that list of references becomes the
   * projection list.
   *
   * @param origScan row scan underneath the project
   * @param projRel ProjectRel that we will be creating the projection for
   * @param projectedColumns returns a list of the projected column ordinals, if it is possible to
   *     project
   * @param preserveExprCondition condition that identifies special expressions that should be
   *     preserved in the projection
   * @param defaultExpr expression to be used in the projection if no fields or special columns are
   *     selected
   * @param newProjList returns a new projection RelNode corresponding to a projection that now
   *     references a rowscan that is projecting the input references that were extracted from the
   *     original projection expressions; if the original expression didn't contain expressions,
   *     then this list is returned empty
   * @return true if columns in projection list from the scan need to be renamed
   */
  public boolean createProjectionList(
      FennelRel origScan,
      ProjectRel projRel,
      List<Integer> projectedColumns,
      PushProjector.ExprCondition preserveExprCondition,
      RexNode defaultExpr,
      List<ProjectRel> newProjList) {
    // REVIEW:  what about AnonFields?
    int n = projRel.getChildExps().length;
    RelDataType rowType = origScan.getRowType();
    RelDataType projType = projRel.getRowType();
    RelDataTypeField[] projFields = projType.getFields();
    List<Integer> tempProjList = new ArrayList<Integer>();
    boolean needRename = false;
    for (int i = 0; i < n; ++i) {
      RexNode exp = projRel.getChildExps()[i];
      List<String> origFieldName = new ArrayList<String>();
      Integer projIndex = mapProjCol(exp, origFieldName, rowType);
      if (projIndex == null) {
        // there are expressions in the projection; we need to extract
        // all input references and any special expressions from the
        // projection
        PushProjector pushProject =
            new PushProjector(projRel, null, origScan, preserveExprCondition);
        ProjectRel newProject = pushProject.convertProject(defaultExpr);
        if (newProject == null) {
          // can't do any further projection
          return false;
        }
        newProjList.add(newProject);

        // using the input references we just extracted, it should now
        // be possible to create a projection for the row scan
        needRename =
            createProjectionList(
                origScan,
                (ProjectRel) newProject.getChild(),
                projectedColumns,
                preserveExprCondition,
                defaultExpr,
                newProjList);
        assert (projectedColumns.size() > 0);
        return needRename;
      }
      String projFieldName = projFields[i].getName();
      if (!projFieldName.equals(origFieldName.get(0))) {
        needRename = true;
      }
      tempProjList.add(projIndex);
    }

    // now that we've determined it is possible to project, add the
    // ordinals to the return list
    projectedColumns.addAll(tempProjList);
    return needRename;
  }
Пример #4
0
 /**
  * Generates a cast from one row type to another
  *
  * @param rexBuilder RexBuilder to use for constructing casts
  * @param lhsRowType target row type
  * @param rhsRowType source row type; fields must be 1-to-1 with lhsRowType, in same order
  * @return cast expressions
  */
 public static RexNode[] generateCastExpressions(
     RexBuilder rexBuilder, RelDataType lhsRowType, RelDataType rhsRowType) {
   int n = rhsRowType.getFieldCount();
   assert n == lhsRowType.getFieldCount()
       : "field count: lhs [" + lhsRowType + "] rhs [" + rhsRowType + "]";
   RexNode[] rhsExps = new RexNode[n];
   for (int i = 0; i < n; ++i) {
     rhsExps[i] = rexBuilder.makeInputRef(rhsRowType.getFields()[i].getType(), i);
   }
   return generateCastExpressions(rexBuilder, lhsRowType, rhsExps);
 }
Пример #5
0
 /**
  * Creates an expression which references the <i> fieldOrdinal</i><sup>th</sup> field of the
  * <i>ordinal</i><sup>th</sup> input.
  *
  * <p>(We can potentially optimize the generation process, so we can access field values without
  * actually instantiating the row.)
  */
 public Expression translateInputField(JavaRel rel, int ordinal, int fieldOrdinal) {
   assert ordinal >= 0;
   assert ordinal < rel.getInputs().size();
   assert fieldOrdinal >= 0;
   assert fieldOrdinal < rel.getInput(ordinal).getRowType().getFieldList().size();
   RelDataType rowType = rel.getRowType();
   final RelDataTypeField[] fields = rowType.getFields();
   final int fieldIndex = computeFieldOffset(rel, ordinal) + fieldOrdinal;
   assert fieldIndex >= 0;
   assert fieldIndex < fields.length;
   final RexNode expr = rexBuilder.makeInputRef(fields[fieldIndex].getType(), fieldIndex);
   return translate(rel, expr);
 }
Пример #6
0
 /**
  * Returns whether the type of an array of expressions is compatible with a struct type.
  *
  * @param exprs Array of expressions
  * @param type Type
  * @param fail Whether to fail if there is a mismatch
  * @return Whether every expression has the same type as the corresponding member of the struct
  *     type
  * @see RelOptUtil#eq(String, RelDataType, String, RelDataType, boolean)
  */
 public static boolean compatibleTypes(RexNode[] exprs, RelDataType type, boolean fail) {
   final RelDataTypeField[] fields = type.getFields();
   if (exprs.length != fields.length) {
     assert !fail : "rowtype mismatches expressions";
     return false;
   }
   for (int i = 0; i < fields.length; i++) {
     final RelDataType exprType = exprs[i].getType();
     final RelDataType fieldType = fields[i].getType();
     if (!RelOptUtil.eq("type1", exprType, "type2", fieldType, fail)) {
       return false;
     }
   }
   return true;
 }
Пример #7
0
 /**
  * Generates a cast for a row type.
  *
  * @param rexBuilder RexBuilder to use for constructing casts
  * @param lhsRowType target row type
  * @param rhsExps expressions to be cast
  * @return cast expressions
  */
 public static RexNode[] generateCastExpressions(
     RexBuilder rexBuilder, RelDataType lhsRowType, RexNode[] rhsExps) {
   RelDataTypeField[] lhsFields = lhsRowType.getFields();
   final int fieldCount = lhsFields.length;
   RexNode[] castExps = new RexNode[fieldCount];
   assert fieldCount == rhsExps.length;
   for (int i = 0; i < fieldCount; ++i) {
     RelDataTypeField lhsField = lhsFields[i];
     RelDataType lhsType = lhsField.getType();
     RelDataType rhsType = rhsExps[i].getType();
     if (lhsType.equals(rhsType)) {
       castExps[i] = rhsExps[i];
     } else {
       castExps[i] = rexBuilder.makeCast(lhsType, rhsExps[i]);
     }
   }
   return castExps;
 }
Пример #8
0
 /**
  * Returns whether the leading edge of a given array of expressions is wholly {@link RexInputRef}
  * objects with types corresponding to the underlying datatype.
  */
 public static boolean containIdentity(RexNode[] exprs, RelDataType rowType, boolean fail) {
   final RelDataTypeField[] fields = rowType.getFields();
   if (exprs.length < fields.length) {
     assert !fail : "exprs/rowType length mismatch";
     return false;
   }
   for (int i = 0; i < fields.length; i++) {
     if (!(exprs[i] instanceof RexInputRef)) {
       assert !fail : "expr[" + i + "] is not a RexInputRef";
       return false;
     }
     RexInputRef inputRef = (RexInputRef) exprs[i];
     if (inputRef.getIndex() != i) {
       assert !fail : "expr[" + i + "] has ordinal " + inputRef.getIndex();
       return false;
     }
     if (!RelOptUtil.eq("type1", exprs[i].getType(), "type2", fields[i].getType(), fail)) {
       return false;
     }
   }
   return true;
 }
 protected Integer mapFieldRef(RexNode exp, List<String> origFieldName, RelDataType rowType) {
   RexInputRef fieldAccess = (RexInputRef) exp;
   origFieldName.add(rowType.getFields()[fieldAccess.getIndex()].getName());
   return fieldAccess.getIndex();
 }
Пример #10
0
  /**
   * Generates code for a Java expression satisfying the {@link org.eigenbase.runtime.TupleIter}
   * interface. The generated code allocates a {@link org.eigenbase.runtime.CalcTupleIter} with a
   * dynamic {@link org.eigenbase.runtime.TupleIter#fetchNext()} method. If the "abort on error"
   * flag is false, or an error handling tag is specified, then fetchNext is written to handle row
   * errors.
   *
   * <p>Row errors are handled by wrapping expressions that can fail with a try/catch block. A
   * caught RuntimeException is then published to an "connection variable." In the event that errors
   * can overflow, an "error buffering" flag allows them to be posted again on the next iteration of
   * fetchNext.
   *
   * @param implementor an object that implements relations as Java code
   * @param rel the relation to be implemented
   * @param childExp the implemented child of the relation
   * @param varInputRow the Java variable to use for the input row
   * @param inputRowType the rel data type of the input row
   * @param outputRowType the rel data type of the output row
   * @param program the rex program to implemented by the relation
   * @param tag an error handling tag
   * @return a Java expression satisfying the TupleIter interface
   */
  public static Expression implementAbstractTupleIter(
      JavaRelImplementor implementor,
      JavaRel rel,
      Expression childExp,
      Variable varInputRow,
      final RelDataType inputRowType,
      final RelDataType outputRowType,
      RexProgram program,
      String tag) {
    MemberDeclarationList memberList = new MemberDeclarationList();

    // Perform error recovery if continuing on errors or if
    // an error handling tag has been specified
    boolean errorRecovery = !abortOnError || (tag != null);

    // Error buffering should not be enabled unless error recovery is
    assert !errorBuffering || errorRecovery;

    // Allow backwards compatibility until all Farrago extensions are
    // satisfied with the new error handling semantics. The new semantics
    // include:
    //   (1) cast input object to input row object outside of try block,
    //         should be fine, at least for base Farrago
    //   (2) maintain a columnIndex counter to better locate of error,
    //         at the cost of a few cycles
    //   (3) publish errors to the runtime context. FarragoRuntimeContext
    //         now supports this API
    boolean backwardsCompatible = true;
    if (tag != null) {
      backwardsCompatible = false;
    }

    RelDataTypeFactory typeFactory = implementor.getTypeFactory();
    OJClass outputRowClass = OJUtil.typeToOJClass(outputRowType, typeFactory);
    OJClass inputRowClass = OJUtil.typeToOJClass(inputRowType, typeFactory);

    Variable varOutputRow = implementor.newVariable();

    FieldDeclaration inputRowVarDecl =
        new FieldDeclaration(
            new ModifierList(ModifierList.PRIVATE),
            TypeName.forOJClass(inputRowClass),
            varInputRow.toString(),
            null);

    FieldDeclaration outputRowVarDecl =
        new FieldDeclaration(
            new ModifierList(ModifierList.PRIVATE),
            TypeName.forOJClass(outputRowClass),
            varOutputRow.toString(),
            new AllocationExpression(outputRowClass, new ExpressionList()));

    // The method body for fetchNext, a main target of code generation
    StatementList nextMethodBody = new StatementList();

    // First, post an error if it overflowed the previous time
    //     if (pendingError) {
    //         rc = handleRowError(...);
    //         if (rc instanceof NoDataReason) {
    //             return rc;
    //         }
    //         pendingError = false;
    //     }
    if (errorBuffering) {
      // add to next method body...
    }

    // Most of fetchNext falls within a while() block. The while block
    // allows us to try multiple input rows against a filter condition
    // before returning a single row.
    //     while (true) {
    //         Object varInputObj = inputIterator.fetchNext();
    //         if (varInputObj instanceof TupleIter.NoDataReason) {
    //             return varInputObj;
    //         }
    //         varInputRow = (InputRowClass) varInputObj;
    //         int columnIndex = 0;
    //         [calculation statements]
    //     }
    StatementList whileBody = new StatementList();

    Variable varInputObj = implementor.newVariable();

    whileBody.add(
        new VariableDeclaration(
            OJUtil.typeNameForClass(Object.class),
            varInputObj.toString(),
            new MethodCall(new FieldAccess("inputIterator"), "fetchNext", new ExpressionList())));

    StatementList ifNoDataReasonBody = new StatementList();

    whileBody.add(
        new IfStatement(
            new InstanceofExpression(
                varInputObj, OJUtil.typeNameForClass(TupleIter.NoDataReason.class)),
            ifNoDataReasonBody));

    ifNoDataReasonBody.add(new ReturnStatement(varInputObj));

    // Push up the row declaration for new error handling so that the
    // input row is available to the error handler
    if (!backwardsCompatible) {
      whileBody.add(assignInputRow(inputRowClass, varInputRow, varInputObj));
    }

    Variable varColumnIndex = null;
    if (errorRecovery && !backwardsCompatible) {
      // NOTE jvs 7-Oct-2006:  Declare varColumnIndex as a member
      // (rather than a local) in case in the future we want
      // to decompose complex expressions into helper methods.
      varColumnIndex = implementor.newVariable();
      FieldDeclaration varColumnIndexDecl =
          new FieldDeclaration(
              new ModifierList(ModifierList.PRIVATE),
              OJUtil.typeNameForClass(int.class),
              varColumnIndex.toString(),
              null);
      memberList.add(varColumnIndexDecl);
      whileBody.add(
          new ExpressionStatement(
              new AssignmentExpression(
                  varColumnIndex, AssignmentExpression.EQUALS, Literal.makeLiteral(0))));
    }

    // Calculator (projection, filtering) statements are later appended
    // to calcStmts. Typically, this target will be the while list itself.
    StatementList calcStmts;
    if (!errorRecovery) {
      calcStmts = whileBody;
    } else {
      // For error recovery, we wrap the calc statements
      // (e.g., everything but the code that reads rows from the
      // inputIterator) in a try/catch that publishes exceptions.

      calcStmts = new StatementList();

      // try { /* calcStmts */ }
      // catch(RuntimeException ex) {
      //     Object rc = connection.handleRowError(...);
      //     [buffer error if necessary]
      // }
      StatementList catchStmts = new StatementList();

      if (backwardsCompatible) {
        catchStmts.add(
            new ExpressionStatement(
                new MethodCall(
                    new MethodCall(
                        OJUtil.typeNameForClass(EigenbaseTrace.class), "getStatementTracer", null),
                    "log",
                    new ExpressionList(
                        new FieldAccess(OJUtil.typeNameForClass(Level.class), "WARNING"),
                        Literal.makeLiteral("java calc exception"),
                        new FieldAccess("ex")))));
      } else {
        Variable varRc = implementor.newVariable();
        ExpressionList handleRowErrorArgs =
            new ExpressionList(varInputRow, new FieldAccess("ex"), varColumnIndex);
        handleRowErrorArgs.add(Literal.makeLiteral(tag));
        catchStmts.add(
            new VariableDeclaration(
                OJUtil.typeNameForClass(Object.class),
                varRc.toString(),
                new MethodCall(
                    implementor.getConnectionVariable(), "handleRowError", handleRowErrorArgs)));

        // Buffer an error if it overflowed
        //     if (rc instanceof NoDataReason) {
        //         pendingError = true;
        //         [save error state]
        //         return rc;
        //     }
        if (errorBuffering) {
          // add to catch statements...
        }
      }

      CatchList catchList =
          new CatchList(
              new CatchBlock(
                  new Parameter(OJUtil.typeNameForClass(RuntimeException.class), "ex"),
                  catchStmts));

      TryStatement tryStmt = new TryStatement(calcStmts, catchList);

      whileBody.add(tryStmt);
    }

    if (backwardsCompatible) {
      calcStmts.add(assignInputRow(inputRowClass, varInputRow, varInputObj));
    }

    StatementList condBody;
    RexToOJTranslator translator = implementor.newStmtTranslator(rel, calcStmts, memberList);
    try {
      translator.pushProgram(program);
      if (program.getCondition() != null) {
        // TODO jvs 8-Oct-2006:  move condition to its own
        // method if big, as below for project exprs.
        condBody = new StatementList();
        RexNode rexIsTrue =
            rel.getCluster()
                .getRexBuilder()
                .makeCall(SqlStdOperatorTable.isTrueOperator, program.getCondition());
        Expression conditionExp = translator.translateRexNode(rexIsTrue);
        calcStmts.add(new IfStatement(conditionExp, condBody));
      } else {
        condBody = calcStmts;
      }

      RelDataTypeField[] fields = outputRowType.getFields();
      final List<RexLocalRef> projectRefList = program.getProjectList();
      int i = -1;
      for (RexLocalRef rhs : projectRefList) {

        // NOTE jvs 14-Sept-2006:  Put complicated project expressions
        // into their own method, otherwise a big select list can easily
        // blow the 64K Java limit on method bytecode size.  Make
        // methods private final in the hopes that they will get inlined
        // JIT.  For now we decide "complicated" based on the size of
        // the generated Java parse tree. A big enough select list of
        // simple expressions could still blow the limit, so we may need
        // to group them together, sub-divide, etc.

        StatementList projMethodBody = new StatementList();

        if (errorRecovery && !backwardsCompatible) {
          projMethodBody.add(
              new ExpressionStatement(
                  new UnaryExpression(varColumnIndex, UnaryExpression.POST_INCREMENT)));
        }
        ++i;

        RexToOJTranslator projTranslator = translator.push(projMethodBody);
        String javaFieldName = Util.toJavaId(fields[i].getName(), i);
        Expression lhs = new FieldAccess(varOutputRow, javaFieldName);
        projTranslator.translateAssignment(fields[i], lhs, rhs);

        int complexity = OJUtil.countParseTreeNodes(projMethodBody);

        // REVIEW: HCP 5/18/2011
        // The projMethod should be checked
        // for causing possible compiler errors caused by the use of
        // variables declared in other projMethods.  Also the
        // local declaration of variabled used by other proj methods
        // should also be checked.

        // Fixing for backswing integration 14270
        // TODO: check if abstracting this method body will cause
        // a compiler error
        if (true) {
          // No method needed; just append.
          condBody.addAll(projMethodBody);
          continue;
        }

        // Need a separate method.

        String projMethodName = "calc_" + varOutputRow.toString() + "_f_" + i;
        MemberDeclaration projMethodDecl =
            new MethodDeclaration(
                new ModifierList(ModifierList.PRIVATE | ModifierList.FINAL),
                TypeName.forOJClass(OJSystem.VOID),
                projMethodName,
                new ParameterList(),
                null,
                projMethodBody);
        memberList.add(projMethodDecl);
        condBody.add(new ExpressionStatement(new MethodCall(projMethodName, new ExpressionList())));
      }
    } finally {
      translator.popProgram(program);
    }

    condBody.add(new ReturnStatement(varOutputRow));

    WhileStatement whileStmt = new WhileStatement(Literal.makeLiteral(true), whileBody);

    nextMethodBody.add(whileStmt);

    MemberDeclaration fetchNextMethodDecl =
        new MethodDeclaration(
            new ModifierList(ModifierList.PUBLIC),
            OJUtil.typeNameForClass(Object.class),
            "fetchNext",
            new ParameterList(),
            null,
            nextMethodBody);

    // The restart() method should reset variables used to buffer errors
    //     pendingError = false
    if (errorBuffering) {
      // declare refinement of restart() and add to member list...
    }

    memberList.add(inputRowVarDecl);
    memberList.add(outputRowVarDecl);
    memberList.add(fetchNextMethodDecl);
    Expression newTupleIterExp =
        new AllocationExpression(
            OJUtil.typeNameForClass(CalcTupleIter.class), new ExpressionList(childExp), memberList);

    return newTupleIterExp;
  }