Class ResultColumn

  • All Implemented Interfaces:
    java.lang.Comparable<ResultColumn>, Visitable, ResultColumnDescriptor
    Direct Known Subclasses:
    AllResultColumn

    class ResultColumn
    extends ValueNode
    implements ResultColumnDescriptor, java.lang.Comparable<ResultColumn>
    A ResultColumn represents a result column in a SELECT, INSERT, or UPDATE statement. In a SELECT statement, the result column just represents an expression in a row being returned to the client. For INSERT and UPDATE statements, the result column represents an column in a stored table. So, a ResultColumn has to be bound differently depending on the type of statement it appears in.

    The type of the ResultColumn can differ from its underlying expression, for example in certain joins the ResultColumn can be nullable even if its underlying column is not. In an INSERT or UPDATE the ResultColumn will represent the type of the column in the table, the type of the underlying expression will be the type of the source of the value to be insert or updated. The method columnTypeAndLengthMatch() can be used to detect when normalization is required between the expression and the type of ResultColumn. This class does not implement any type normalization (conversion), this is typically handled by a NormalizeResultSetNode.

    • Field Detail

      • _underlyingName

        private java.lang.String _underlyingName
      • _derivedColumnName

        private java.lang.String _derivedColumnName
      • _unqualifiedTableName

        private java.lang.String _unqualifiedTableName
      • _unqualifiedSourceTableName

        private java.lang.String _unqualifiedSourceTableName
      • _sourceSchemaName

        private java.lang.String _sourceSchemaName
      • _isGenerated

        private boolean _isGenerated
      • _isGeneratedForUnmatchedColumnInInsert

        private boolean _isGeneratedForUnmatchedColumnInInsert
      • _isGroupingColumn

        private boolean _isGroupingColumn
      • _isReferenced

        private boolean _isReferenced
      • _isRedundant

        private boolean _isRedundant
      • _isNameGenerated

        private boolean _isNameGenerated
      • _updated

        private boolean _updated
      • _updatableByCursor

        private boolean _updatableByCursor
      • defaultColumn

        private boolean defaultColumn
      • wasDefault

        private boolean wasDefault
      • rightOuterJoinUsingClause

        private boolean rightOuterJoinUsingClause
      • joinResultSet

        private JoinNode joinResultSet
      • _autoincrementGenerated

        private boolean _autoincrementGenerated
      • _autoincrement

        private boolean _autoincrement
      • resultSetNumber

        private int resultSetNumber
      • virtualColumnId

        private int virtualColumnId
    • Method Detail

      • setTypeExpressionAndDefault

        private void setTypeExpressionAndDefault​(ValueNode expression)
      • isRightOuterJoinUsingClause

        boolean isRightOuterJoinUsingClause()
        Returns TRUE if the ResultColumn is join column for a RIGHT OUTER JOIN with USING/NATURAL. More comments at the top of this class where rightOuterJoinUsingClause is defined.
      • setRightOuterJoinUsingClause

        void setRightOuterJoinUsingClause​(boolean value)
        Will be set to TRUE if this ResultColumn is join column for a RIGHT OUTER JOIN with USING/NATURAL. More comments at the top of this class where rightOuterJoinUsingClause is defined. 2 eg cases 1)select c from t1 right join t2 using (c) This case is talking about column c as in "select c" 2)select c from t1 right join t2 using (c) For "using(c)", a join predicate will be created as follows t1.c=t2.c This case is talking about column t2.c of the join predicate. This method gets called for Case 1) during the bind phase of ResultColumn(ResultColumn.bindExpression). This method gets called for Case 2) during the bind phase of JoinNode while we are going through the list of join columns for a NATURAL JOIN or user supplied list of join columns for USING clause(JoinNode.getMatchingColumn).
        Parameters:
        value - True/False
      • getJoinResultSet

        JoinNode getJoinResultSet()
        Returns a non-null value if the ResultColumn represents the join column which is part of the SELECT list of a RIGHT OUTER JOIN with USING/NATURAL. eg select c from t1 right join t2 using (c) The join column we are talking about is column c as in "select c" The return value of following method will show the association of this result column to the join resultset created for the RIGHT OUTER JOIN with USING/NATURAL. This information along with rightOuterJoinUsingClause will be used during the code generation time.
      • setJoinResultset

        void setJoinResultset​(JoinNode resultSet)
        This method gets called during the bind phase of a ResultColumn if it is determined that the ResultColumn represents the join column which is part of the SELECT list of a RIGHT OUTER JOIN with USING/NATURAL. eg select c from t1 right join t2 using (c) This case is talking about column c as in "select c"
        Parameters:
        resultSet - - The ResultColumn belongs to this JoinNode
      • isDefaultColumn

        boolean isDefaultColumn()
        Returns TRUE if the ResultColumn is standing in for a DEFAULT keyword in an insert/update statement.
      • setDefaultColumn

        void setDefaultColumn​(boolean value)
      • wasDefaultColumn

        boolean wasDefaultColumn()
        Returns TRUE if the ResultColumn used to stand in for a DEFAULT keyword in an insert/update statement.
      • setWasDefaultColumn

        void setWasDefaultColumn​(boolean value)
      • columnNameMatches

        boolean columnNameMatches​(java.lang.String columnName)
        Return TRUE if this result column matches the provided column name. This function is used by ORDER BY column resolution. For the ORDER BY clause, Derby will prefer to match on the column's alias (_derivedColumnName), but will also successfully match on the underlying column name. Thus the following statements are treated equally: select name from person order by name; select name as person_name from person order by name; select name as person_name from person order by person_name; See DERBY-2351 for more discussion.
      • getUnderlyingOrAliasName

        java.lang.String getUnderlyingOrAliasName()
        Get non-null column name. This method is called during the bind phase to see if we are dealing with ResultColumn in the SELECT list that belongs to a RIGHT OUTER JOIN(NATURAL OR USING)'s join column. For a query like following, we want to use column name x and not the alias x1 when looking in the JoinNode for join column SELECT x x1 FROM derby4631_t2 NATURAL RIGHT OUTER JOIN derby4631_t1; For a query like following, getSourceColumnName() will return null because we are dealing with a function for the column. For this case, "name" will return the alias name cx SELECT coalesce(derby4631_t2.x, derby4631_t1.x) cx FROM derby4631_t2 NATURAL RIGHT OUTER JOIN derby4631_t1; For a query like following, getSourceColumnName() and name will return null and hence need to use the generated name SELECT ''dummy="'|| TRIM(CHAR(x))|| '"' FROM (derby4631_t2 NATURAL RIGHT OUTER JOIN derby4631_t1);
      • isUpdatable

        boolean isUpdatable()
        Returns true if this column is updatable. This method is used for determining if updateRow and insertRow are allowed for this cursor (DERBY-1773). Since the updateRow and insertRow implementations dynamically build SQL statements on the fly, the critical issue here is whether we have a column that has been aliased, because if it has been aliased, the dynamic SQL generation logic won't be able to compute the proper true base column name when it needs to.
        Returns:
        true if this result column is updatable.
      • getSourceColumnName

        java.lang.String getSourceColumnName()
        Returns the underlying source column name, if this ResultColumn is a simple direct reference to a table column, or NULL otherwise.
      • getName

        public java.lang.String getName()
        The following methods implement the ResultColumnDescriptor interface. See the Language Module Interface for details.
        Specified by:
        getName in interface ResultColumnDescriptor
        Returns:
        A String containing the name of the column.
      • getSchemaName

        java.lang.String getSchemaName()
                                throws StandardException
        Description copied from class: ValueNode
        This returns the user-supplied schema name of the column. At this class level, it simply returns null. But, the subclasses of ValueNode will overwrite this method to return the user-supplied schema name. When the value node is in a result column of a select list, the user can request metadata information. The result column won't have a column descriptor, so we return some default information through the expression. This lets expressions that are simply columns return all of the info, and others use this supertype's default values.
        Overrides:
        getSchemaName in class ValueNode
        Returns:
        the default schema name for an expression -- null
        Throws:
        StandardException
      • getTableName

        java.lang.String getTableName()
        Description copied from class: ValueNode
        This returns the user-supplied table name of the column. At this class level, it simply returns null. But, the subclasses of ValueNode will overwrite this method to return the user-supplied table name. When the value node is in a result column of a select list, the user can request metadata information. The result column won't have a column descriptor, so we return some default information through the expression. This lets expressions that are simply columns return all of the info, and others use this supertype's default values.
        Overrides:
        getTableName in class ValueNode
        Returns:
        the default table name for an expression -- null
      • getSourceTableName

        public java.lang.String getSourceTableName()
        Description copied from interface: ResultColumnDescriptor
        Get the name of the underlying(base) table this column comes from, if any. Following example queries will all return T select a from t select b.a from t as b select t.a from t
        Specified by:
        getSourceTableName in interface ResultColumnDescriptor
        Returns:
        A String containing the name of the base table of the Column is in. If the column is not in a table (i.e. is a derived column), it returns NULL. The name of the Column's base table. If the column is not in a schema (i.e. is a derived column), it returns NULL.
        See Also:
        ResultColumnDescriptor.getSourceTableName()
      • getSourceSchemaName

        public java.lang.String getSourceSchemaName()
        Description copied from interface: ResultColumnDescriptor
        Get the name of the schema for the Column's base table, if any. Following example queries will all return APP (assuming user is in schema APP) select t.a from t select b.a from t as b select app.t.a from t
        Specified by:
        getSourceSchemaName in interface ResultColumnDescriptor
        Returns:
        The name of the schema of the Column's base table. If the column is not in a schema (i.e. is a derived column), it returns NULL.
        See Also:
        ResultColumnDescriptor.getSourceSchemaName()
      • clearTableName

        void clearTableName()
        Clear the table name for the underlying ColumnReference. See UpdateNode.scrubResultColumns() for full explaination.
      • getType

        public DataTypeDescriptor getType()
        Description copied from interface: ResultColumnDescriptor
        Returns a DataTypeDescriptor for the column. This DataTypeDescriptor will not represent an actual value, it will only represent the type that all values in the column will have.
        Specified by:
        getType in interface ResultColumnDescriptor
        Returns:
        A DataTypeDescriptor describing the type of the column.
      • getColumnPosition

        public int getColumnPosition()
        Description copied from interface: ResultColumnDescriptor
        Get the position of the Column. NOTE - position is 1-based.
        Specified by:
        getColumnPosition in interface ResultColumnDescriptor
        Returns:
        An int containing the position of the Column within the table.
      • setExpression

        void setExpression​(ValueNode expression)
        Set the expression in this ResultColumn. This is useful in those cases where you don't know the expression in advance, like for INSERT statements with column lists, where the column list and SELECT or VALUES clause are parsed separately, and then have to be hooked up.
        Parameters:
        expression - The expression to be set in this ResultColumn
      • getExpression

        ValueNode getExpression()
        Get the expression in this ResultColumn.
        Returns:
        ValueNode this.expression
      • setExpressionToNullNode

        void setExpressionToNullNode()
                              throws StandardException
        Set the expression to a null node of the correct type.
        Throws:
        StandardException - Thrown on error
      • setName

        void setName​(java.lang.String name)
        Set the name in this ResultColumn. This is useful when you don't know the name at the time you create the ResultColumn, for example, in an insert-select statement, where you want the names of the result columns to match the table being inserted into, not the table they came from.
        Parameters:
        name - The name to set in this ResultColumn
      • isNameGenerated

        boolean isNameGenerated()
        Is the name for this ResultColumn generated?
      • setNameGenerated

        void setNameGenerated​(boolean value)
        Set that this result column name is generated.
      • setResultSetNumber

        void setResultSetNumber​(int resultSetNumber)
        Set the resultSetNumber for this ResultColumn. This is the resultSetNumber for the ResultSet that we belong to. This is useful for generate() and necessary since we do not have a back pointer to the RSN.
        Parameters:
        resultSetNumber - The resultSetNumber.
      • getResultSetNumber

        public int getResultSetNumber()
        Get the resultSetNumber for this ResultColumn.
        Returns:
        int The resultSetNumber.
      • adjustVirtualColumnId

        void adjustVirtualColumnId​(int adjust)
        Adjust the virtualColumnId for this ResultColumn by the specified amount
        Parameters:
        adjust - The adjustment for the virtualColumnId
      • setVirtualColumnId

        void setVirtualColumnId​(int id)
        Set the virtualColumnId for this ResultColumn
        Parameters:
        id - The virtualColumnId for this ResultColumn
      • getVirtualColumnId

        int getVirtualColumnId()
        Get the virtualColumnId for this ResultColumn
        Returns:
        virtualColumnId for this ResultColumn
      • collapseVirtualColumnIdGap

        void collapseVirtualColumnIdGap​(int removedColumnId)
        Adjust this virtualColumnId to account for the removal of a column This routine is called when bind processing finds and removes duplicate columns in the result list which were pulled up due to their presence in the ORDER BY clause, but were later found to be duplicate. If this column is a virtual column, and if this column's virtual column id is greater than the column id which is being removed, then we must logically shift this column to the left by decrementing its virtual column id.
        Parameters:
        removedColumnId - id of the column being removed.
      • guaranteeColumnName

        void guaranteeColumnName()
                          throws StandardException
        Generate a unique (across the entire statement) column name for unnamed ResultColumns
        Throws:
        StandardException - Thrown on error
      • toString

        public java.lang.String toString()
        Convert this object to a String. See comments in QueryTreeNode.java for how this should be done for tree printing.
        Overrides:
        toString in class ValueNode
        Returns:
        This object as a String
      • printSubNodes

        void printSubNodes​(int depth)
        Prints the sub-nodes of this object. See QueryTreeNode.java for how tree printing is supposed to work.
        Overrides:
        printSubNodes in class QueryTreeNode
        Parameters:
        depth - The depth of this node in the tree
      • bindExpression

        ResultColumn bindExpression​(FromList fromList,
                                    SubqueryList subqueryList,
                                    java.util.List<AggregateNode> aggregates)
                             throws StandardException
        Bind this expression. This means binding the sub-expressions. In this case, we figure out what the result type of this result column is when we call one of the bindResultColumn*() methods. The reason is that there are different ways of binding the result columns depending on the statement type, and this is a standard interface that does not take the statement type as a parameter.
        Overrides:
        bindExpression in class ValueNode
        Parameters:
        fromList - The FROM list for the query this expression is in, for binding columns.
        subqueryList - The subquery list being built as we find SubqueryNodes
        aggregates - The aggregate list being built as we find AggregateNodes
        Returns:
        The new top of the expression tree.
        Throws:
        StandardException - Thrown on error
      • bindResultColumnByPosition

        void bindResultColumnByPosition​(TableDescriptor tableDescriptor,
                                        int columnId)
                                 throws StandardException
        Bind this result column by ordinal position and set the VirtualColumnId. This is useful for INSERT statements like "insert into t values (1, 2, 3)", where the user did not specify a column list. If a columnDescriptor is not found for a given position, then the user has specified more values than the # of columns in the table and an exception is thrown. NOTE: We must set the VirtualColumnId here because INSERT does not construct the ResultColumnList in the usual way.
        Parameters:
        tableDescriptor - The descriptor for the table being inserted into
        columnId - The ordinal position of the column in the table, starting at 1.
        Throws:
        StandardException - Thrown on error
      • bindResultColumnByName

        void bindResultColumnByName​(TableDescriptor tableDescriptor,
                                    int columnId)
                             throws StandardException
        Bind this result column by its name and set the VirtualColumnId. This is useful for update statements, and for INSERT statements like "insert into t (a, b, c) values (1, 2, 3)" where the user specified a column list. An exception is thrown when a columnDescriptor cannot be found for a given name. (There is no column with that name.) NOTE: We must set the VirtualColumnId here because INSERT does not construct the ResultColumnList in the usual way.
        Parameters:
        tableDescriptor - The descriptor for the table being updated or inserted into
        columnId - The ordinal position of the column in the table, starting at 1. (Used to set the VirtualColumnId.)
        Throws:
        StandardException - Thrown on error
      • setColumnDescriptor

        void setColumnDescriptor​(TableDescriptor tableDescriptor,
                                 ColumnDescriptor columnDescriptor)
                          throws StandardException
        Set the column descriptor for this result column. It also gets the data type services from the column descriptor and stores it in this result column: this is redundant, but we have to store the result type here for SELECT statements, and it is more orthogonal if the type can be found here regardless of what type of statement it is.
        Parameters:
        tableDescriptor - The TableDescriptor for the table being updated or inserted into. This parameter is used only for error reporting.
        columnDescriptor - The ColumnDescriptor to set in this ResultColumn.
        Throws:
        StandardException - tableNameMismatch
      • bindResultColumnToExpression

        void bindResultColumnToExpression()
                                   throws StandardException
        Bind the result column to the expression that lives under it. All this does is copy the datatype information to this node. This is useful for SELECT statements, where the result type of each column is the type of the column's expression.
        Throws:
        StandardException - Thrown on error
      • setSourceTableName

        void setSourceTableName​(java.lang.String t)
        Set the column source's table name
        Parameters:
        t - The source table name
      • setSourceSchemaName

        void setSourceSchemaName​(java.lang.String s)
        Set the column source's schema name
        Parameters:
        s - The source schema name
      • preprocess

        ResultColumn preprocess​(int numTables,
                                FromList outerFromList,
                                SubqueryList outerSubqueryList,
                                PredicateList outerPredicateList)
                         throws StandardException
        Preprocess an expression tree. We do a number of transformations here (including subqueries, IN lists, LIKE and BETWEEN) plus subquery flattening. NOTE: This is done before the outer ResultSetNode is preprocessed.
        Overrides:
        preprocess in class ValueNode
        Parameters:
        numTables - Number of tables in the DML Statement
        outerFromList - FromList from outer query block
        outerSubqueryList - SubqueryList from outer query block
        outerPredicateList - PredicateList from outer query block
        Returns:
        The modified expression
        Throws:
        StandardException - Thrown on error
      • checkStorableExpression

        void checkStorableExpression​(ResultColumn toStore)
                              throws StandardException
        This verifies that the expression is storable into the result column. It checks versus the given ResultColumn. This method should not be called until the result column and expression both have a valid type, i.e. after they are bound appropriately. Its use is for statements like insert, that need to verify if a given value can be stored into a column.
        Throws:
        StandardException - thrown if types not suitable.
      • checkStorableExpression

        void checkStorableExpression()
                              throws StandardException
        This verifies that the expression is storable into the result column. It checks versus the expression under this ResultColumn. This method should not be called until the result column and expression both have a valid type, i.e. after they are bound appropriately. Its use is for statements like update, that need to verify if a given value can be stored into a column.
        Throws:
        StandardException - thrown if types not suitable.
      • columnTypeAndLengthMatch

        boolean columnTypeAndLengthMatch()
                                  throws StandardException
        Check whether the column length and type of this result column match the expression under the columns. This is useful for INSERT and UPDATE statements. For SELECT statements this method should always return true. There is no need to call this for a DELETE statement.
        Returns:
        true means the column matches its expressions, false means it doesn't match.
        Throws:
        StandardException
      • isGenerated

        boolean isGenerated()
        Is this a generated column?
        Returns:
        Boolean - whether or not this column is a generated column.
      • isGeneratedForUnmatchedColumnInInsert

        boolean isGeneratedForUnmatchedColumnInInsert()
        Is this columm generated for an unmatched column in an insert?
        Returns:
        Boolean - whether or not this columm was generated for an unmatched column in an insert.
      • markGenerated

        void markGenerated()
        Mark this a columm as a generated column
      • markGeneratedForUnmatchedColumnInInsert

        void markGeneratedForUnmatchedColumnInInsert()
        Mark this a columm as generated for an unmatched column in an insert
      • isReferenced

        boolean isReferenced()
        Is this a referenced column?
        Returns:
        Boolean - whether or not this column is a referenced column.
      • setReferenced

        void setReferenced()
        Mark this column as a referenced column.
      • pullVirtualIsReferenced

        void pullVirtualIsReferenced()
        Mark this column as a referenced column if it is already marked as referenced or if any result column in its chain of virtual columns is marked as referenced.
      • setUnreferenced

        void setUnreferenced()
        Mark this column as an unreferenced column.
      • markAllRCsInChainReferenced

        void markAllRCsInChainReferenced()
        Mark this RC and all RCs in the underlying RC/VCN chain as referenced.
      • isRedundant

        boolean isRedundant()
        Is this a redundant ResultColumn?
        Returns:
        Boolean - whether or not this RC is redundant.
      • setRedundant

        void setRedundant()
        Mark this ResultColumn as redundant.
      • markAsGroupingColumn

        void markAsGroupingColumn()
        Mark this ResultColumn as a grouping column in the SELECT list
      • rejectParameter

        void rejectParameter()
                      throws StandardException
        Look for and reject ?/-?/+? parameter under this ResultColumn. This is called for SELECT statements.
        Throws:
        StandardException - Thrown if a ?/-?/+? parameter was found directly under this ResultColumn.
      • compareTo

        public int compareTo​(ResultColumn other)
        Specified by:
        compareTo in interface java.lang.Comparable<ResultColumn>
      • markUpdated

        void markUpdated()
        Mark this column as being updated by an update statement.
      • markUpdatableByCursor

        void markUpdatableByCursor()
        Mark this column as being updatable, so we can make sure it is in the "for update" list of a positioned update.
      • updated

        boolean updated()
        Tell whether this column is being updated.
        Returns:
        true means this column is being updated.
      • getMaximumColumnSize

        int getMaximumColumnSize()
        Get the maximum size of the column
        Returns:
        the max size
      • getTypeServices

        public DataTypeDescriptor getTypeServices()
        Description copied from class: ValueNode
        Get the DataTypeServices from this ValueNode.
        Overrides:
        getTypeServices in class ValueNode
        Returns:
        The DataTypeServices from this ValueNode. This may be null if the node isn't bound yet.
      • getOrderableVariantType

        protected int getOrderableVariantType()
                                       throws StandardException
        Return the variant type for the underlying expression. The variant type can be: VARIANT - variant within a scan (method calls and non-static field access) SCAN_INVARIANT - invariant within a scan (column references from outer tables) QUERY_INVARIANT - invariant within the life of a query CONSTANT - constant
        Overrides:
        getOrderableVariantType in class ValueNode
        Returns:
        The variant type for the underlying expression.
        Throws:
        StandardException - thrown on error
      • getTableColumnDescriptor

        ColumnDescriptor getTableColumnDescriptor()
        If this ResultColumn is bound to a column in a table get the column descriptor for the column in the table. Otherwise return null.
      • isAutoincrementGenerated

        boolean isAutoincrementGenerated()
        Returns true if this result column is a placeholder for a generated autoincrement value.
      • setAutoincrementGenerated

        void setAutoincrementGenerated()
      • resetAutoincrementGenerated

        void resetAutoincrementGenerated()
      • isAutoincrement

        public boolean isAutoincrement()
        Description copied from interface: ResultColumnDescriptor
        Tell us if the column is an autoincrement column or not.
        Specified by:
        isAutoincrement in interface ResultColumnDescriptor
        Returns:
        TRUE, if the column is a base column of a table and is an autoincrement column.
      • setAutoincrement

        void setAutoincrement()
      • isGroupingColumn

        public boolean isGroupingColumn()
      • getTableNameObject

        public TableName getTableNameObject()
      • getColumnDescriptor

        ColumnDescriptor getColumnDescriptor()
        Get the column descriptor
      • getBaseColumnNode

        BaseColumnNode getBaseColumnNode()
        Get the source BaseColumnNode for this result column. The BaseColumnNode cannot be found unless the ResultColumn is bound and is a simple reference to a column in a BaseFromTable.
        Returns:
        a BaseColumnNode, or null if a BaseColumnNode cannot be found
      • getTableNumber

        int getTableNumber()
                    throws StandardException
        Search the tree beneath this ResultColumn until we find the number of the table to which this RC points, and return that table number. If we can't determine which table this RC is for, then return -1. There are two places we can find the table number: 1) if our expression is a ColumnReference, then we can get the target table number from the ColumnReference and that's it; 2) if expression is a VirtualColumnNode, then if the VirtualColumnNode points to a FromBaseTable, we can get that FBT's table number; otherwise, we walk the VirtualColumnNode-ResultColumn chain and do a recursive search.
        Returns:
        The number of the table to which this ResultColumn points, or -1 if we can't determine that from where we are.
        Throws:
        StandardException
      • isEquivalent

        boolean isEquivalent​(ValueNode o)
                      throws StandardException
        Description copied from class: ValueNode
        Tests if this node is equivalent to the specified ValueNode. Two ValueNodes are considered equivalent if they will evaluate to the same value during query execution.

        This method provides basic expression matching facility for the derived class of ValueNode and it is used by the language layer to compare the node structural form of the two expressions for equivalence at bind phase.

        Note that it is not comparing the actual row values at runtime to produce a result; hence, when comparing SQL NULLs, they are considered to be equivalent and not unknown.

        One usage case of this method in this context is to compare the select column expression against the group by expression to check if they are equivalent. e.g.:

        SELECT c1+c2 FROM t1 GROUP BY c1+c2

        In general, node equivalence is determined by the derived class of ValueNode. But they generally abide to the rules below:

        • The two ValueNodes must be of the same node type to be considered equivalent. e.g.: CastNode vs. CastNode - equivalent (if their args also match), ColumnReference vs CastNode - not equivalent.
        • If node P contains other ValueNode(s) and so on, those node(s) must also be of the same node type to be considered equivalent.
        • If node P takes a parameter list, then the number of arguments and its arguments for the two nodes must also match to be considered equivalent. e.g.: CAST(c1 as INTEGER) vs CAST(c1 as SMALLINT), they are not equivalent.
        • When comparing SQL NULLs in this context, they are considered to be equivalent.
        • If this does not apply or it is determined that the two nodes are not equivalent then the derived class of this method should return false; otherwise, return true.
        Specified by:
        isEquivalent in class ValueNode
        Parameters:
        o - the node to compare this ValueNode against.
        Returns:
        true if the two nodes are equivalent, false otherwise.
        Throws:
        StandardException