예제 #1
0
 /**
  * @param expr
  * @param tables
  */
 void getTablesForExpression(AbstractExpression expr, HashSet<Table> tables) {
   List<TupleValueExpression> tves = ExpressionUtil.getTupleValueExpressions(expr);
   for (TupleValueExpression tupleExpr : tves) {
     String tableName = tupleExpr.getTableName();
     Table table = getTableFromDB(tableName);
     tables.add(table);
   }
 }
예제 #2
0
 /**
  * @param exprNode
  * @return
  */
 private static AbstractExpression parseSimpleColumnExpression(VoltXMLElement exprNode) {
   // This object is a place holder that gets filled in later based on the display column it
   // aliases.
   String alias = exprNode.attributes.get("alias");
   TupleValueExpression expr = new TupleValueExpression();
   expr.setColumnAlias(alias);
   return expr;
 }
예제 #3
0
 // Even though this function applies generally to expressions and tables
 // and not just to TVEs as such, it is somewhat TVE-related because TVEs
 // represent the points where expression trees depend on tables.
 public static boolean isOperandDependentOnTable(AbstractExpression expr, String tableAlias) {
   assert (tableAlias != null);
   for (TupleValueExpression tve : ExpressionUtil.getTupleValueExpressions(expr)) {
     if (tableAlias.equals(tve.getTableAlias())) {
       return true;
     }
   }
   return false;
 }
 @Override
 public Object clone() throws CloneNotSupportedException {
   TupleValueExpression clone = (TupleValueExpression) super.clone();
   clone.m_columnIndex = m_columnIndex;
   clone.m_tableName = m_tableName;
   clone.m_columnName = m_columnName;
   clone.m_columnAlias = m_columnAlias;
   return clone;
 }
예제 #5
0
 @Override
 public Object clone() {
   TupleValueExpression clone = (TupleValueExpression) super.clone();
   clone.m_columnIndex = m_columnIndex;
   clone.m_tableName = m_tableName;
   clone.m_columnName = m_columnName;
   clone.m_columnAlias = m_columnAlias;
   return clone;
 }
예제 #6
0
 // Even though this function applies generally to expressions and tables and not just to TVEs as
 // such,
 // this function is somewhat TVE-related because TVEs DO represent the points where expression
 // trees
 // depend on tables.
 public static boolean isOperandDependentOnTable(AbstractExpression expr, Table table) {
   for (TupleValueExpression tve : ExpressionUtil.getTupleValueExpressions(expr)) {
     // TODO: This clumsy testing of table names regardless of table aliases is
     // EXACTLY why we can't have nice things like self-joins.
     if (table.getTypeName().equals(tve.getTableName())) {
       return true;
     }
   }
   return false;
 }
예제 #7
0
  /**
   * @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;
  }
예제 #8
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]);
      }
    }
  }
예제 #9
0
  /**
   * Parse the scan_columns element out of the HSQL-generated XML. Fills scanColumns with a list of
   * the columns used in the plan, hashed by table name.
   *
   * @param columnsNode
   */
  void parseScanColumns(VoltXMLElement columnsNode) {
    scanColumns = new HashMap<String, ArrayList<SchemaColumn>>();

    for (VoltXMLElement child : columnsNode.children) {
      assert (child.name.equals("columnref"));
      AbstractExpression col_exp = parseExpressionTree(child);
      // TupleValueExpressions are always specifically typed,
      // so there is no need for expression type specialization, here.
      assert (col_exp != null);
      assert (col_exp instanceof TupleValueExpression);
      TupleValueExpression tve = (TupleValueExpression) col_exp;
      SchemaColumn col =
          new SchemaColumn(tve.getTableName(), tve.getColumnName(), tve.getColumnAlias(), col_exp);
      ArrayList<SchemaColumn> table_cols = null;
      if (!scanColumns.containsKey(col.getTableName())) {
        table_cols = new ArrayList<SchemaColumn>();
        scanColumns.put(col.getTableName(), table_cols);
      }
      table_cols = scanColumns.get(col.getTableName());
      table_cols.add(col);
    }
  }
예제 #10
0
 @Override
 public void processTVE(TupleValueExpression expr, String columnName) {
   expr.resolveForTable(m_table);
 }
예제 #11
0
  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);
  }
예제 #12
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);
    }
  }