Exemple #1
0
  // test that if scan columns are specified the output schema of
  // a scan node consists of those columns
  public void testOutputSchemaSomeScanColumns() {
    AbstractScanPlanNode dut = new SeqScanPlanNode();
    dut.setTargetTableName(TABLE1);

    int[] scan_col_indexes = {1, 3};
    ArrayList<SchemaColumn> scanColumns = new ArrayList<SchemaColumn>();
    for (int index : scan_col_indexes) {
      TupleValueExpression tve = new TupleValueExpression();
      tve.setTableName(TABLE1);
      tve.setColumnName(COLS[index]);
      tve.setColumnAlias(COLS[index]);
      tve.setValueType(COLTYPES[index]);
      tve.setValueSize(COLTYPES[index].getLengthInBytesForFixedTypes());
      SchemaColumn col = new SchemaColumn(TABLE1, COLS[index], COLS[index], tve);
      scanColumns.add(col);
    }
    dut.setScanColumns(scanColumns);

    // Should be able to do this safely and repeatably multiple times
    for (int i = 0; i < 3; i++) {
      dut.generateOutputSchema(m_voltdb.getDatabase());
      NodeSchema dut_schema = dut.getOutputSchema();
      System.out.println(dut_schema.toString());
      assertEquals(scan_col_indexes.length, dut_schema.size());
      for (int index : scan_col_indexes) {
        SchemaColumn col = dut_schema.find(TABLE1, COLS[index], "");
        assertNotNull(col);
        assertEquals(col.getExpression().getExpressionType(), ExpressionType.VALUE_TUPLE);
        assertEquals(col.getExpression().getValueType(), COLTYPES[index]);
      }
    }
  }
  /**
   * @param exprNode
   * @return
   */
  private static AbstractExpression parseColumnRefExpression(VoltXMLElement exprNode) {
    TupleValueExpression expr = new TupleValueExpression();

    String alias = exprNode.attributes.get("alias");
    String tableName = exprNode.attributes.get("table");
    String columnName = exprNode.attributes.get("column");

    expr.setColumnAlias(alias);
    expr.setColumnName(columnName);
    expr.setTableName(tableName);

    return expr;
  }
  void parseOrderColumn(VoltXMLElement orderByNode) {
    // make sure everything is kosher
    assert (orderByNode.name.equalsIgnoreCase("operation"));
    String operationType = orderByNode.attributes.get("type");
    assert (operationType != null);
    assert (operationType.equalsIgnoreCase("orderby"));

    // get desc/asc
    String desc = orderByNode.attributes.get("desc");
    boolean descending = (desc != null) && (desc.equalsIgnoreCase("true"));

    // get the columnref expression inside the orderby node
    VoltXMLElement child = orderByNode.children.get(0);
    assert (child != null);

    // create the orderby column
    ParsedColInfo order_col = new ParsedColInfo();
    order_col.orderBy = true;
    order_col.ascending = !descending;
    AbstractExpression order_exp = parseExpressionTree(child);

    // Cases:
    // inner child could be columnref, in which case it's just a normal
    // column.  Just make a ParsedColInfo object for it and the planner
    // will do the right thing later
    if (child.name.equals("columnref")) {
      order_col.columnName = child.attributes.get("column");
      order_col.tableName = child.attributes.get("table");
      String alias = child.attributes.get("alias");
      order_col.alias = alias;

      // The ORDER BY column MAY be identical to a simple display column, in which case,
      // tagging the actual display column as being also an order by column
      // helps later when trying to determine ORDER BY coverage (for determinism).
      if (order_exp instanceof TupleValueExpression) {
        ParsedColInfo orig_col = null;
        for (ParsedColInfo col : displayColumns) {
          if (col.expression.equals(order_exp)) {
            orig_col = col;
            break;
          }
        }
        if (orig_col != null) {
          orig_col.orderBy = true;
          orig_col.ascending = order_col.ascending;
        }
      }
    } else if (child.name.equals("operation")) {
      order_col.columnName = "";
      // I'm not sure anyone actually cares about this table name
      order_col.tableName = "VOLT_TEMP_TABLE";

      // If it's a simplecolumn operation.  This means that the alias that
      //    we have should refer to a column that we compute
      //    somewhere else (like an aggregate, mostly).
      //    Look up that column in the displayColumns list,
      //    and then create a new order by column with a magic TVE.
      // This case seems to be the result of cross-referencing a display column
      // by its position, as in "ORDER BY 2, 3". Otherwise the ORDER BY column
      // is a columnref as handled in the prior code block.
      if (order_exp instanceof TupleValueExpression) {
        String alias = child.attributes.get("alias");
        order_col.alias = alias;
        ParsedColInfo orig_col = null;
        for (ParsedColInfo col : displayColumns) {
          if (col.alias.equals(alias)) {
            orig_col = col;
            break;
          }
        }
        // We need the original column expression so we can extract
        // the value size and type for our TVE that refers back to it.
        // XXX: This check runs into problems for some cases where a display column expression gets
        // re-used in the ORDER BY.
        // I THINK one problem case was "select x, max(y) from t group by x order by max(y);" --paul
        if (orig_col == null) {
          throw new PlanningErrorException(
              "Unable to find source " + "column for simplecolumn: " + alias);
        }

        // Tagging the actual display column as being also an order by column
        // helps later when trying to determine ORDER BY coverage (for determinism).
        orig_col.orderBy = true;
        orig_col.ascending = order_col.ascending;

        assert (orig_col.tableName.equals("VOLT_TEMP_TABLE"));
        // Construct our fake TVE that will point back at the input
        // column.
        TupleValueExpression tve = (TupleValueExpression) order_exp;
        tve.setColumnAlias(alias);
        tve.setColumnName("");
        tve.setColumnIndex(-1);
        tve.setTableName("VOLT_TEMP_TABLE");
        tve.setValueSize(orig_col.expression.getValueSize());
        tve.setValueType(orig_col.expression.getValueType());
        if (orig_col.expression.hasAnySubexpressionOfClass(AggregateExpression.class)) {
          tve.setHasAggregate(true);
        }
      }
    } else if (child.name.equals("function") == false) {
      throw new RuntimeException("ORDER BY parsed with strange child node type: " + child.name);
    }
    if (order_exp instanceof ConstantValueExpression) {
      assert (order_exp.getValueType() != VoltType.NUMERIC);
    }
    ExpressionUtil.finalizeValueTypes(order_exp);
    order_col.expression = order_exp;
    orderColumns.add(order_col);
  }
Exemple #4
0
  // test that if someone provides their own inline projection
  // that the output schema of the scan node consists of the output
  // schema of the projection.  Updates will do this so that the
  // inlined projection fills the values of the output tuples correctly
  // before it attempts to update them
  public void testOutputSchemaOverriddenProjection() {
    AbstractScanPlanNode dut = new SeqScanPlanNode();
    dut.setTargetTableName(TABLE1);

    // Create an output schema like we might see for an inlined projection
    // generated for update.  We'll have 4 output columns, the first will
    // be the tuple address, the second one a parameter expression, next
    // will be a constant, and the other will be a more complex expression
    // that uses some TVEs.
    NodeSchema proj_schema = new NodeSchema();
    String[] cols = new String[4];

    TupleAddressExpression col1_exp = new TupleAddressExpression();
    proj_schema.addColumn(new SchemaColumn("", "tuple_address", "tuple_address", col1_exp));
    cols[0] = "tuple_address";

    // update column 1 with a parameter value
    ParameterValueExpression col2_exp = new ParameterValueExpression();
    col2_exp.setParameterIndex(0);
    col2_exp.setValueType(COLTYPES[1]);
    col2_exp.setValueSize(COLTYPES[1].getLengthInBytesForFixedTypes());
    // XXX I'm not sure what to do with the name for the updated column yet.
    // I think it should be an alias and not the original table name/col name
    proj_schema.addColumn(new SchemaColumn(TABLE1, COLS[1], COLS[1], col2_exp));
    cols[1] = COLS[1];

    // Update column 3 with a constant value
    ConstantValueExpression col3_exp = new ConstantValueExpression();
    col3_exp.setValueType(COLTYPES[3]);
    col3_exp.setValueSize(COLTYPES[3].getLengthInBytesForFixedTypes());
    col3_exp.setValue("3.14159");
    proj_schema.addColumn(new SchemaColumn(TABLE1, COLS[3], COLS[3], col3_exp));
    cols[2] = COLS[3];

    // update column 4 with a sum of columns 0 and 2
    OperatorExpression col4_exp = new OperatorExpression();
    col4_exp.setValueType(COLTYPES[4]);
    col4_exp.setValueSize(COLTYPES[4].getLengthInBytesForFixedTypes());
    col4_exp.setExpressionType(ExpressionType.OPERATOR_PLUS);
    TupleValueExpression left = new TupleValueExpression();
    left.setTableName(TABLE1);
    left.setColumnName(COLS[0]);
    left.setColumnAlias(COLS[0]);
    left.setValueType(COLTYPES[0]);
    left.setValueSize(COLTYPES[0].getLengthInBytesForFixedTypes());
    TupleValueExpression right = new TupleValueExpression();
    right.setTableName(TABLE1);
    right.setColumnName(COLS[2]);
    right.setColumnAlias(COLS[2]);
    right.setValueType(COLTYPES[2]);
    right.setValueSize(COLTYPES[2].getLengthInBytesForFixedTypes());
    col4_exp.setLeft(left);
    col4_exp.setRight(right);
    proj_schema.addColumn(new SchemaColumn(TABLE1, COLS[4], "C1", col4_exp));
    cols[3] = COLS[4];

    ProjectionPlanNode proj_node = new ProjectionPlanNode();
    proj_node.setOutputSchema(proj_schema);
    dut.addInlinePlanNode(proj_node);

    System.out.println("ProjSchema: " + proj_schema.toString());

    dut.generateOutputSchema(m_voltdb.getDatabase());
    NodeSchema dut_schema = dut.getOutputSchema();
    System.out.println(dut_schema.toString());
    for (int i = 0; i < cols.length; i++) {
      SchemaColumn col = null;
      if (i == 0) {
        col = dut_schema.find("", cols[i], cols[i]);
      } else {
        col = dut_schema.find(TABLE1, cols[i], cols[i]);
      }
      assertNotNull(col);
      assertEquals(col.getExpression().getExpressionType(), ExpressionType.VALUE_TUPLE);
    }
  }