/**
   * Bind the tables in this DML statement.
   *
   * @param dataDictionary The data dictionary to use to look up the tables
   * @exception StandardException Thrown on error
   */
  protected void bindTables(DataDictionary dataDictionary) throws StandardException {
    /* Bind the tables in the resultSet
     * (DMLStatementNode is above all ResultSetNodes, so table numbering
     * will begin at 0.)
     * In case of referential action on delete , the table numbers can be
     * > 0 because the nodes are create for dependent tables also in the
     * the same context.
     */

    resultSet =
        resultSet.bindNonVTITables(
            dataDictionary,
            (FromList)
                getNodeFactory()
                    .getNode(
                        C_NodeTypes.FROM_LIST,
                        getNodeFactory().doJoinOrderOptimization(),
                        getContextManager()));
    resultSet =
        resultSet.bindVTITables(
            (FromList)
                getNodeFactory()
                    .getNode(
                        C_NodeTypes.FROM_LIST,
                        getNodeFactory().doJoinOrderOptimization(),
                        getContextManager()));
  }
  /**
   * Extract out and return the subquery, with a PRN on top. (See FromSubquery.preprocess() for more
   * details.)
   *
   * @param numTables The number of tables in the DML Statement
   * @return ResultSetNode at top of extracted tree.
   * @exception StandardException Thrown on error
   */
  public ResultSetNode extractSubquery(int numTables) throws StandardException {
    JBitSet newJBS;
    ResultSetNode newPRN;

    newPRN =
        (ResultSetNode)
            getNodeFactory()
                .getNode(
                    C_NodeTypes.PROJECT_RESTRICT_NODE,
                    subquery, /* Child ResultSet */
                    resultColumns, /* Projection */
                    null, /* Restriction */
                    null, /* Restriction as PredicateList */
                    null, /* Subquerys in Projection */
                    null, /* Subquerys in Restriction */
                    tableProperties,
                    getContextManager());

    /* Set up the PRN's referencedTableMap */
    newJBS = new JBitSet(numTables);
    newJBS.set(tableNumber);
    newPRN.setReferencedTableMap(newJBS);
    ((FromTable) newPRN).setTableNumber(tableNumber);

    return newPRN;
  }
  /**
   * Flatten this FSqry into the outer query block. The steps in flattening are: o Mark all
   * ResultColumns as redundant, so that they are "skipped over" at generate(). o Append the
   * wherePredicates to the outer list. o Return the fromList so that the caller will merge the 2
   * lists RESOLVE - FSqrys with subqueries are currently not flattenable. Some of them can be
   * flattened, however. We need to merge the subquery list when we relax this restriction.
   *
   * <p>NOTE: This method returns NULL when flattening RowResultSetNodes (the node for a VALUES
   * clause). The reason is that no reference is left to the RowResultSetNode after flattening is
   * done - the expressions point directly to the ValueNodes in the RowResultSetNode's
   * ResultColumnList.
   *
   * @param rcl The RCL from the outer query
   * @param outerPList PredicateList to append wherePredicates to.
   * @param sql The SubqueryList from the outer query
   * @param gbl The group by list, if any
   * @param havingClause The HAVING clause, if any
   * @return FromList The fromList from the underlying SelectNode.
   * @exception StandardException Thrown on error
   */
  public FromList flatten(
      ResultColumnList rcl,
      PredicateList outerPList,
      SubqueryList sql,
      GroupByList gbl,
      ValueNode havingClause)
      throws StandardException {
    FromList fromList = null;
    SelectNode selectNode;

    resultColumns.setRedundant();

    subquery.getResultColumns().setRedundant();

    /*
     ** RESOLVE: Each type of result set should know how to remap itself.
     */
    if (subquery instanceof SelectNode) {
      selectNode = (SelectNode) subquery;
      fromList = selectNode.getFromList();

      // selectNode.getResultColumns().setRedundant();

      if (selectNode.getWherePredicates().size() > 0) {
        outerPList.destructiveAppend(selectNode.getWherePredicates());
      }

      if (selectNode.getWhereSubquerys().size() > 0) {
        sql.destructiveAppend(selectNode.getWhereSubquerys());
      }
    } else if (!(subquery instanceof RowResultSetNode)) {
      if (SanityManager.DEBUG) {
        SanityManager.THROWASSERT(
            "subquery expected to be either a SelectNode or a RowResultSetNode, but is a "
                + subquery.getClass().getName());
      }
    }

    /* Remap all ColumnReferences from the outer query to this node.
     * (We replace those ColumnReferences with clones of the matching
     * expression in the SELECT's RCL.
     */
    rcl.remapColumnReferencesToExpressions();
    outerPList.remapColumnReferencesToExpressions();
    if (gbl != null) {
      gbl.remapColumnReferencesToExpressions();
    }

    if (havingClause != null) {
      havingClause.remapColumnReferencesToExpressions();
    }

    return fromList;
  }
  /**
   * Prints the sub-nodes of this object. See QueryTreeNode.java for how tree printing is supposed
   * to work.
   *
   * @param depth The depth of this node in the tree
   */
  public void printSubNodes(int depth) {
    if (SanityManager.DEBUG) {
      super.printSubNodes(depth);

      if (subquery != null) {
        printLabel(depth, "subquery: ");
        subquery.treePrint(depth + 1);
      }

      if (orderByList != null) {
        printLabel(depth, "orderByList: ");
        orderByList.treePrint(depth + 1);
      }

      if (offset != null) {
        printLabel(depth, "offset: ");
        offset.treePrint(depth + 1);
      }

      if (fetchFirst != null) {
        printLabel(depth, "fetchFirst: ");
        fetchFirst.treePrint(depth + 1);
      }
    }
  }
  private ResultSetNode wrapRowCountNode(
      ResultSetNode resultSet, ValueNode offset, ValueNode fetchFirst) throws StandardException {

    ResultSetNode topRS = resultSet;
    ResultColumnList selectRCs = topRS.getResultColumns().copyListAndObjects();
    selectRCs.genVirtualColumnNodes(topRS, topRS.getResultColumns());

    return (RowCountNode)
        getNodeFactory()
            .getNode(
                C_NodeTypes.ROW_COUNT_NODE,
                topRS,
                selectRCs,
                offset,
                fetchFirst,
                getContextManager());
  }
 /**
  * Prints the sub-nodes of this object. See QueryTreeNode.java for how tree printing is supposed
  * to work.
  *
  * @param depth The depth of this node in the tree
  */
 public void printSubNodes(int depth) {
   if (SanityManager.DEBUG) {
     super.printSubNodes(depth);
     if (resultSet != null) {
       printLabel(depth, "resultSet: ");
       resultSet.treePrint(depth + 1);
     }
   }
 }
  /**
   * Bind this subquery that appears in the FROM list.
   *
   * @param dataDictionary The DataDictionary to use for binding
   * @param fromListParam FromList to use/append to.
   * @return ResultSetNode The bound FromSubquery.
   * @exception StandardException Thrown on error
   */
  public ResultSetNode bindNonVTITables(DataDictionary dataDictionary, FromList fromListParam)
      throws StandardException {
    /* Assign the tableNumber */
    if (tableNumber == -1) // allow re-bind, in which case use old number
    tableNumber = getCompilerContext().getNextTableNumber();

    subquery = subquery.bindNonVTITables(dataDictionary, fromListParam);

    return this;
  }
  /**
   * Add any new ResultSetNodes that are necessary to the tree. We wait until after optimization to
   * do this in order to make it easier on the optimizer.
   *
   * @return (Potentially new) head of the ResultSetNode tree.
   * @exception StandardException Thrown on error
   */
  private ResultSetNode addNewNodes() throws StandardException {
    /* Only call addNewNodes() once */
    if (addNewNodesCalled) {
      return this;
    }

    addNewNodesCalled = true;

    ResultSetNode treeTop = this;

    if (orderByList != null) {
      // Generate an order by node on top of the intersect/except
      treeTop =
          (ResultSetNode)
              getNodeFactory()
                  .getNode(
                      C_NodeTypes.ORDER_BY_NODE,
                      treeTop,
                      orderByList,
                      tableProperties,
                      getContextManager());
    }

    if (offset != null || fetchFirst != null) {
      ResultColumnList newRcl = treeTop.getResultColumns().copyListAndObjects();
      newRcl.genVirtualColumnNodes(treeTop, treeTop.getResultColumns());

      treeTop =
          (ResultSetNode)
              getNodeFactory()
                  .getNode(
                      C_NodeTypes.ROW_COUNT_NODE,
                      treeTop,
                      newRcl,
                      offset,
                      fetchFirst,
                      Boolean.valueOf(hasJDBClimitClause),
                      getContextManager());
    }

    return treeTop;
  } // end of addNewNodes
  /**
   * Accept a visitor, and call v.visit() on child nodes as necessary.
   *
   * @param v the visitor
   * @exception StandardException on error
   */
  public Visitable accept(Visitor v) throws StandardException {
    if (v.skipChildren(this)) {
      return v.visit(this);
    }

    if (resultSet != null && !v.stopTraversal()) {
      resultSet = (ResultSetNode) resultSet.accept(v);
    }

    return this;
  }
Esempio n. 10
0
  /** @see QueryTreeNode#acceptChildren */
  void acceptChildren(Visitor v) throws StandardException {
    super.acceptChildren(v);

    subquery.accept(v);

    if (orderByList != null) {
      orderByList.accept(v);
    }

    if (offset != null) {
      offset.accept(v);
    }

    if (fetchFirst != null) {
      fetchFirst.accept(v);
    }
  }
  /**
   * Bind the expressions in the underlying ResultSets with tables.
   *
   * @exception StandardException Thrown on error
   */
  protected void bindExpressionsWithTables() throws StandardException {
    FromList fromList =
        (FromList)
            getNodeFactory()
                .getNode(
                    C_NodeTypes.FROM_LIST,
                    getNodeFactory().doJoinOrderOptimization(),
                    getContextManager());

    /* Bind the expressions under the resultSet */
    resultSet.bindExpressionsWithTables(fromList);

    /* Verify that all underlying ResultSets reclaimed their FromList */
    if (SanityManager.DEBUG)
      SanityManager.ASSERT(
          fromList.size() == 0,
          "fromList.size() is expected to be 0, not "
              + fromList.size()
              + " on return from RS.bindExpressions()");
  }
 private void pushOrderingDown(ResultSetNode rsn) throws StandardException {
   ContextManager cm = getContextManager();
   NodeFactory nf = getNodeFactory();
   OrderByList orderByList = (OrderByList) nf.getNode(C_NodeTypes.ORDER_BY_LIST, cm);
   for (int i = 0; i < intermediateOrderByColumns.length; i++) {
     OrderByColumn orderByColumn =
         (OrderByColumn)
             nf.getNode(
                 C_NodeTypes.ORDER_BY_COLUMN,
                 nf.getNode(
                     C_NodeTypes.INT_CONSTANT_NODE,
                     ReuseFactory.getInteger(intermediateOrderByColumns[i] + 1),
                     cm),
                 cm);
     if (intermediateOrderByDirection[i] < 0) orderByColumn.setDescending();
     if (intermediateOrderByNullsLow[i]) orderByColumn.setNullsOrderedLow();
     orderByList.addOrderByColumn(orderByColumn);
   }
   orderByList.bindOrderByColumns(rsn);
   rsn.pushOrderByList(orderByList);
 } // end of pushOrderingDown
  /**
   * Bind this CreateTableNode. This means doing any static error checking that can be done before
   * actually creating the base table or declaring the global temporary table. For eg, verifying
   * that the TableElementList does not contain any duplicate column names.
   *
   * @exception StandardException Thrown on error
   */
  public void bindStatement() throws StandardException {
    DataDictionary dataDictionary = getDataDictionary();
    int numPrimaryKeys = 0;
    int numCheckConstraints = 0;
    int numReferenceConstraints = 0;
    int numUniqueConstraints = 0;
    int numGenerationClauses = 0;

    SchemaDescriptor sd =
        getSchemaDescriptor(tableType != TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE, true);

    if (queryExpression != null) {
      FromList fromList =
          (FromList)
              getNodeFactory()
                  .getNode(
                      C_NodeTypes.FROM_LIST,
                      getNodeFactory().doJoinOrderOptimization(),
                      getContextManager());

      CompilerContext cc = getCompilerContext();
      ProviderList prevAPL = cc.getCurrentAuxiliaryProviderList();
      ProviderList apl = new ProviderList();

      try {
        cc.setCurrentAuxiliaryProviderList(apl);
        cc.pushCurrentPrivType(Authorizer.SELECT_PRIV);

        /* Bind the tables in the queryExpression */
        queryExpression = queryExpression.bindNonVTITables(dataDictionary, fromList);
        queryExpression = queryExpression.bindVTITables(fromList);

        /* Bind the expressions under the resultSet */
        queryExpression.bindExpressions(fromList);

        /* Bind the query expression */
        queryExpression.bindResultColumns(fromList);

        /* Reject any untyped nulls in the RCL */
        /* e.g. CREATE TABLE t1 (x) AS VALUES NULL WITH NO DATA */
        queryExpression.bindUntypedNullsToResultColumns(null);
      } finally {
        cc.popCurrentPrivType();
        cc.setCurrentAuxiliaryProviderList(prevAPL);
      }

      /* If there is an RCL for the table definition then copy the
       * names to the queryExpression's RCL after verifying that
       * they both have the same size.
       */
      ResultColumnList qeRCL = queryExpression.getResultColumns();

      if (resultColumns != null) {
        if (resultColumns.size() != qeRCL.visibleSize()) {
          throw StandardException.newException(
              SQLState.LANG_TABLE_DEFINITION_R_C_L_MISMATCH, getFullName());
        }
        qeRCL.copyResultColumnNames(resultColumns);
      }

      int schemaCollationType = sd.getCollationType();

      /* Create table element list from columns in query expression */
      tableElementList = new TableElementList();

      for (int index = 0; index < qeRCL.size(); index++) {
        ResultColumn rc = (ResultColumn) qeRCL.elementAt(index);
        if (rc.isGenerated()) {
          continue;
        }
        /* Raise error if column name is system generated. */
        if (rc.isNameGenerated()) {
          throw StandardException.newException(SQLState.LANG_TABLE_REQUIRES_COLUMN_NAMES);
        }

        DataTypeDescriptor dtd = rc.getExpression().getTypeServices();
        if ((dtd != null) && !dtd.isUserCreatableType()) {
          throw StandardException.newException(
              SQLState.LANG_INVALID_COLUMN_TYPE_CREATE_TABLE,
              dtd.getFullSQLTypeName(),
              rc.getName());
        }
        // DERBY-2879  CREATE TABLE AS <subquery> does not maintain the
        // collation for character types.
        // eg for a territory based collation database
        // create table t as select tablename from sys.systables with no data;
        // Derby at this point does not support for a table's character
        // columns to have a collation different from it's schema's
        // collation. Which means that in a territory based database,
        // the query above will cause table t's character columns to
        // have collation of UCS_BASIC but the containing schema of t
        // has collation of territory based. This is not supported and
        // hence we will throw an exception below for the query above in
        // a territory based database.
        if (dtd.getTypeId().isStringTypeId() && dtd.getCollationType() != schemaCollationType) {
          throw StandardException.newException(
              SQLState.LANG_CAN_NOT_CREATE_TABLE,
              dtd.getCollationName(),
              DataTypeDescriptor.getCollationName(schemaCollationType));
        }

        ColumnDefinitionNode column =
            (ColumnDefinitionNode)
                getNodeFactory()
                    .getNode(
                        C_NodeTypes.COLUMN_DEFINITION_NODE,
                        rc.getName(),
                        null,
                        rc.getType(),
                        null,
                        getContextManager());
        tableElementList.addTableElement(column);
      }
    } else {
      // Set the collation type and collation derivation of all the
      // character type columns. Their collation type will be same as the
      // collation of the schema they belong to. Their collation
      // derivation will be "implicit".
      // Earlier we did this in makeConstantAction but that is little too
      // late (DERBY-2955)
      // eg
      // CREATE TABLE STAFF9 (EMPNAME CHAR(20),
      //  CONSTRAINT STAFF9_EMPNAME CHECK (EMPNAME NOT LIKE 'T%'))
      // For the query above, when run in a territory based db, we need
      // to have the correct collation set in bind phase of create table
      // so that when LIKE is handled in LikeEscapeOperatorNode, we have
      // the correct collation set for EMPNAME otherwise it will throw an
      // exception for 'T%' having collation of territory based and
      // EMPNAME having the default collation of UCS_BASIC
      tableElementList.setCollationTypesOnCharacterStringColumns(
          getSchemaDescriptor(tableType != TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE, true));
    }

    tableElementList.validate(this, dataDictionary, (TableDescriptor) null);

    /* Only 1012 columns allowed per table */
    if (tableElementList.countNumberOfColumns() > Limits.DB2_MAX_COLUMNS_IN_TABLE) {
      throw StandardException.newException(
          SQLState.LANG_TOO_MANY_COLUMNS_IN_TABLE_OR_VIEW,
          String.valueOf(tableElementList.countNumberOfColumns()),
          getRelativeName(),
          String.valueOf(Limits.DB2_MAX_COLUMNS_IN_TABLE));
    }

    numPrimaryKeys = tableElementList.countConstraints(DataDictionary.PRIMARYKEY_CONSTRAINT);

    /* Only 1 primary key allowed per table */
    if (numPrimaryKeys > 1) {
      throw StandardException.newException(
          SQLState.LANG_TOO_MANY_PRIMARY_KEY_CONSTRAINTS, getRelativeName());
    }

    /* Check the validity of all check constraints */
    numCheckConstraints = tableElementList.countConstraints(DataDictionary.CHECK_CONSTRAINT);

    numReferenceConstraints =
        tableElementList.countConstraints(DataDictionary.FOREIGNKEY_CONSTRAINT);

    numUniqueConstraints = tableElementList.countConstraints(DataDictionary.UNIQUE_CONSTRAINT);

    numGenerationClauses = tableElementList.countGenerationClauses();

    // temp tables can't have primary key or check or foreign key or unique constraints defined on
    // them
    if ((tableType == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE)
        && (numPrimaryKeys > 0
            || numCheckConstraints > 0
            || numReferenceConstraints > 0
            || numUniqueConstraints > 0))
      throw StandardException.newException(
          SQLState.LANG_NOT_ALLOWED_FOR_DECLARED_GLOBAL_TEMP_TABLE);

    // each of these constraints have a backing index in the back. We need to make sure that a table
    // never has more
    // more than 32767 indexes on it and that is why this check.
    if ((numPrimaryKeys + numReferenceConstraints + numUniqueConstraints)
        > Limits.DB2_MAX_INDEXES_ON_TABLE) {
      throw StandardException.newException(
          SQLState.LANG_TOO_MANY_INDEXES_ON_TABLE,
          String.valueOf(numPrimaryKeys + numReferenceConstraints + numUniqueConstraints),
          getRelativeName(),
          String.valueOf(Limits.DB2_MAX_INDEXES_ON_TABLE));
    }

    if ((numCheckConstraints > 0) || (numGenerationClauses > 0) || (numReferenceConstraints > 0)) {
      /* In order to check the validity of the check constraints and
       * generation clauses
       * we must goober up a FromList containing a single table,
       * the table being created, with an RCL containing the
       * new columns and their types.  This will allow us to
       * bind the constraint definition trees against that
       * FromList.  When doing this, we verify that there are
       * no nodes which can return non-deterministic results.
       */
      FromList fromList = makeFromList(null, tableElementList, true);
      FormatableBitSet generatedColumns = new FormatableBitSet();

      /* Now that we've finally goobered stuff up, bind and validate
       * the check constraints and generation clauses.
       */
      if (numGenerationClauses > 0) {
        tableElementList.bindAndValidateGenerationClauses(sd, fromList, generatedColumns, null);
      }
      if (numCheckConstraints > 0) {
        tableElementList.bindAndValidateCheckConstraints(fromList);
      }
      if (numReferenceConstraints > 0) {
        tableElementList.validateForeignKeysOnGenerationClauses(fromList, generatedColumns);
      }
    }

    if (numPrimaryKeys > 0) {
      tableElementList.validatePrimaryKeyNullability();
    }
  }
Esempio n. 14
0
 /**
  * Check for (and reject) ? parameters directly under the ResultColumns. This is done for SELECT
  * statements. For FromSubquery, we simply pass the check through to the subquery.
  *
  * @exception StandardException Thrown if a ? parameter found directly under a ResultColumn
  */
 public void rejectParameters() throws StandardException {
   subquery.rejectParameters();
 }
Esempio n. 15
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);
    }
  }
  /**
   * Make a ResultDescription for use in a PreparedStatement.
   *
   * <p>ResultDescriptions are visible to JDBC only for cursor statements. For other types of
   * statements, they are only used internally to get descriptions of the base tables being
   * affected. For example, for an INSERT statement, the ResultDescription describes the rows in the
   * table being inserted into, which is useful when the values being inserted are of a different
   * type or length than the columns in the base table.
   *
   * @return A ResultDescription for this DML statement
   */
  public ResultDescription makeResultDescription() {
    ResultColumnDescriptor[] colDescs = resultSet.makeResultDescriptors();
    String statementType = statementToString();

    return getExecutionFactory().getResultDescription(colDescs, statementType);
  }
Esempio n. 17
0
  /**
   * Preprocess a ResultSetNode - this currently means: o Generating a referenced table map for each
   * ResultSetNode. o Putting the WHERE and HAVING clauses in conjunctive normal form (CNF). o
   * Converting the WHERE and HAVING clauses into PredicateLists and classifying them. o Ensuring
   * that a ProjectRestrictNode is generated on top of every FromBaseTable and generated in place of
   * every FromSubquery. o Pushing single table predicates down to the new ProjectRestrictNodes.
   *
   * @param numTables The number of tables in the DML Statement
   * @param gbl The group by list, if any
   * @param fromList The from list, if any
   * @return ResultSetNode at top of preprocessed tree.
   * @exception StandardException Thrown on error
   */
  public ResultSetNode preprocess(int numTables, GroupByList gbl, FromList fromList)
      throws StandardException {
    // Push the order by list down to the ResultSet
    if (orderByList != null) {
      // If we have more than 1 ORDERBY columns, we may be able to
      // remove duplicate columns, e.g., "ORDER BY 1, 1, 2".
      if (orderByList.size() > 1) {
        orderByList.removeDupColumns();
      }

      subquery.pushOrderByList(orderByList);
      orderByList = null;
    }

    subquery.pushOffsetFetchFirst(offset, fetchFirst, hasJDBClimitClause);

    /* We want to chop out the FromSubquery from the tree and replace it
     * with a ProjectRestrictNode.  One complication is that there may be
     * ColumnReferences above us which point to the FromSubquery's RCL.
     * What we want to return is a tree with a PRN with the
     * FromSubquery's RCL on top.  (In addition, we don't want to be
     * introducing any redundant ProjectRestrictNodes.)
     * Another complication is that we want to be able to only push
     * projections and restrictions down to this ProjectRestrict, but
     * we want to be able to push them through as well.
     * So, we:
     *		o call subquery.preprocess() which returns a tree with
     *		  a SelectNode or a RowResultSetNode on top.
     *		o If the FSqry is flattenable(), then we return (so that the
     *		  caller can then call flatten()), otherwise we:
     *		o generate a PRN, whose RCL is the FSqry's RCL, on top of the result.
     *		o create a referencedTableMap for the PRN which represents
     *		  the FSqry's tableNumber, since ColumnReferences in the outer
     *		  query block would be referring to that one.
     *		  (This will allow us to push restrictions down to the PRN.)
     */

    subquery = subquery.preprocess(numTables, gbl, fromList);

    /* Return if the FSqry is flattenable()
     * NOTE: We can't flatten a FromSubquery if there is a group by list
     * because the group by list must be ColumnReferences.  For:
     *	select c1 from v1 group by c1,
     *	where v1 is select 1 from t1
     * The expression under the last redundant ResultColumn is an IntConstantNode,
     * not a ColumnReference.
     * We also do not flatten a subquery if tableProperties is non-null,
     * as the user is specifying 1 or more properties for the derived table,
     * which could potentially be lost on the flattening.
     * RESOLVE - this is too restrictive.
     */
    if ((gbl == null || gbl.size() == 0)
        && tableProperties == null
        && subquery.flattenableInFromSubquery(fromList)) {
      /* Set our table map to the subquery's table map. */
      setReferencedTableMap(subquery.getReferencedTableMap());
      return this;
    }

    return extractSubquery(numTables);
  }
  /**
   * 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());
      }
    }
  }
Esempio n. 19
0
 /**
  * Search to see if a query references the specifed table name.
  *
  * @param name Table name (String) to search for.
  * @param baseTable Whether or not name is for a base table
  * @return true if found, else false
  * @exception StandardException Thrown on error
  */
 public boolean referencesTarget(String name, boolean baseTable) throws StandardException {
   return subquery.referencesTarget(name, baseTable);
 }
Esempio n. 20
0
 /**
  * Return true if the node references SESSION schema tables (temporary or permanent)
  *
  * @return true if references SESSION schema tables, else false
  * @exception StandardException Thrown on error
  */
 public boolean referencesSessionSchema() throws StandardException {
   return subquery.referencesSessionSchema();
 }
Esempio n. 21
0
 /**
  * Bind any untyped null nodes to the types in the given ResultColumnList.
  *
  * @param bindingRCL The ResultColumnList with the types to bind to.
  * @exception StandardException Thrown on error
  */
 public void bindUntypedNullsToResultColumns(ResultColumnList bindingRCL)
     throws StandardException {
   subquery.bindUntypedNullsToResultColumns(bindingRCL);
 }
Esempio n. 22
0
  /**
   * Bind this subquery that appears in the FROM list.
   *
   * @param fromListParam FromList to use/append to.
   * @return ResultSetNode The bound FromSubquery.
   * @exception StandardException Thrown on error
   */
  public ResultSetNode bindVTITables(FromList fromListParam) throws StandardException {
    subquery = subquery.bindVTITables(fromListParam);

    return this;
  }
Esempio n. 23
0
 /**
  * Decrement (query block) level (0-based) for this FromTable. This is useful when flattening a
  * subquery.
  *
  * @param decrement The amount to decrement by.
  */
 void decrementLevel(int decrement) {
   super.decrementLevel(decrement);
   subquery.decrementLevel(decrement);
 }