/**
   * This overload variant of optimizeStatement is used by subclass CursorNode (as well as a minion
   * for the no-arg variant).
   *
   * @param offset Any OFFSET row count, or null
   * @param fetchFirst Any FETCH FIRST row count or null
   * @exception StandardException Thrown on error
   * @see DMLStatementNode#optimizeStatement()
   */
  protected void optimizeStatement(ValueNode offset, ValueNode fetchFirst)
      throws StandardException {
    resultSet = resultSet.preprocess(getCompilerContext().getNumTables(), null, (FromList) null);
    resultSet = resultSet.optimize(getDataDictionary(), null, 1.0d);

    resultSet = resultSet.modifyAccessPaths();

    // Any OFFSET/FETCH FIRST narrowing must be done *after* any rewrite of
    // the query tree (if not, underlying GROUP BY fails), but *before* the
    // final scroll insensitive result node set is added - that one needs
    // to sit on top - so now is the time.
    //
    // This example statement fails if we wrap *before* the optimization
    // above:
    //     select max(a) from t1 group by b fetch first row only
    //
    // A java.sql.ResultSet#previous on a scrollable result set will fail
    // if we don't wrap *after* the ScrollInsensitiveResultSetNode below.
    //
    // We need only wrap the RowCountNode set if at least one of the
    // clauses is present.

    if (offset != null || fetchFirst != null) {
      resultSet = wrapRowCountNode(resultSet, offset, fetchFirst);
    }

    /* If this is a cursor, then we
     * need to generate a new ResultSetNode to enable the scrolling
     * on top of the tree before modifying the access paths.
     */
    if (this instanceof CursorNode) {
      ResultColumnList siRCList;
      ResultColumnList childRCList;
      ResultSetNode siChild = resultSet;

      /* We get a shallow copy of the ResultColumnList and its
       * ResultColumns.  (Copy maintains ResultColumn.expression for now.)
       */
      siRCList = resultSet.getResultColumns();
      childRCList = siRCList.copyListAndObjects();
      resultSet.setResultColumns(childRCList);

      /* Replace ResultColumn.expression with new VirtualColumnNodes
       * in the ScrollInsensitiveResultSetNode's ResultColumnList.  (VirtualColumnNodes include
       * pointers to source ResultSetNode, this, and source ResultColumn.)
       */
      siRCList.genVirtualColumnNodes(resultSet, childRCList);

      /* Finally, we create the new ScrollInsensitiveResultSetNode */
      resultSet =
          (ResultSetNode)
              getNodeFactory()
                  .getNode(
                      C_NodeTypes.SCROLL_INSENSITIVE_RESULT_SET_NODE,
                      resultSet,
                      siRCList,
                      null,
                      getContextManager());
      // Propagate the referenced table map if it's already been created
      if (siChild.getReferencedTableMap() != null) {
        resultSet.setReferencedTableMap((JBitSet) siChild.getReferencedTableMap().clone());
      }
    }
  }
Exemplo n.º 2
0
  /**
   * Bind the expressions in this FromSubquery. This means binding the sub-expressions, as well as
   * figuring out what the return type is for each expression.
   *
   * @exception StandardException Thrown on error
   */
  public void bindExpressions(FromList fromListParam) throws StandardException {
    FromList emptyFromList =
        (FromList)
            getNodeFactory()
                .getNode(
                    C_NodeTypes.FROM_LIST,
                    getNodeFactory().doJoinOrderOptimization(),
                    getContextManager());
    ResultColumnList derivedRCL = resultColumns;
    ResultColumnList subqueryRCL;
    FromList nestedFromList;

    /* From subqueries cannot be correlated, so we pass an empty FromList
     * to subquery.bindExpressions() and .bindResultColumns()
     */
    if (orderByList != null) {
      orderByList.pullUpOrderByColumns(subquery);
    }

    nestedFromList = emptyFromList;

    CompilerContext compilerContext = getCompilerContext();

    if (origCompilationSchema != null) {
      // View expansion needs the definition time schema
      compilerContext.pushCompilationSchema(origCompilationSchema);
    }

    try {
      subquery.bindExpressions(nestedFromList);
      subquery.bindResultColumns(nestedFromList);
    } finally {
      if (origCompilationSchema != null) {
        compilerContext.popCompilationSchema();
      }
    }

    if (orderByList != null) {
      orderByList.bindOrderByColumns(subquery);
    }

    bindOffsetFetch(offset, fetchFirst);

    /* NOTE: If the size of the derived column list is less than
     * the size of the subquery's RCL and the derived column list is marked
     * for allowing a size mismatch, then we have a select * view
     * on top of a table that has had columns added to it via alter table.
     * In this case, we trim out the columns that have been added to
     * the table since the view was created.
     */
    subqueryRCL = subquery.getResultColumns();
    if (resultColumns != null
        && resultColumns.getCountMismatchAllowed()
        && resultColumns.size() < subqueryRCL.size()) {
      for (int index = subqueryRCL.size() - 1; index >= resultColumns.size(); index--) {
        subqueryRCL.removeElementAt(index);
      }
    }

    /*
     * Create RCL based on subquery, adding a level of VCNs.
     */
    ResultColumnList newRcl = subqueryRCL.copyListAndObjects();
    newRcl.genVirtualColumnNodes(subquery, subquery.getResultColumns());
    resultColumns = newRcl;

    /* Propagate the name info from the derived column list */
    if (derivedRCL != null) {
      resultColumns.propagateDCLInfo(derivedRCL, correlationName);
    }
  }