📄 columnreference.java
字号:
public void setTableNameNode(TableName tableName) { this.tableName = tableName; } /** * Get the column number for this ColumnReference. * * @return int The column number for this ColumnReference */ public int getColumnNumber() { return columnNumber; } /** * Set the column number for this ColumnReference. This is * used when scoping predicates for pushdown. * * @param colNum The new column number. */ public void setColumnNumber(int colNum) { this.columnNumber = colNum; } /** * Get the source this columnReference * * @return The source of this columnReference */ public ResultColumn getSource() { return source; } /** * Set the source this columnReference * * @param source The source of this columnReference * * @return None. */ public void setSource(ResultColumn source) { this.source = source; } /** * Do the 1st step in putting an expression into conjunctive normal * form. This step ensures that the top level of the expression is * a chain of AndNodes. * * @return The modified expression * * @exception StandardException Thrown on error */ public ValueNode putAndsOnTop() throws StandardException { BinaryComparisonOperatorNode equalsNode; BooleanConstantNode trueNode; NodeFactory nodeFactory = getNodeFactory(); ValueNode andNode; trueNode = (BooleanConstantNode) nodeFactory.getNode( C_NodeTypes.BOOLEAN_CONSTANT_NODE, Boolean.TRUE, getContextManager()); equalsNode = (BinaryComparisonOperatorNode) nodeFactory.getNode( C_NodeTypes.BINARY_EQUALS_OPERATOR_NODE, this, trueNode, getContextManager()); /* Set type info for the operator node */ equalsNode.bindComparisonOperator(); andNode = (ValueNode) nodeFactory.getNode( C_NodeTypes.AND_NODE, equalsNode, trueNode, getContextManager()); ((AndNode) andNode).postBindFixup(); return andNode; } /** * Categorize this predicate. Initially, this means * building a bit map of the referenced tables for each predicate. * If the source of this ColumnReference (at the next underlying level) * is not a ColumnReference or a VirtualColumnNode then this predicate * will not be pushed down. * * For example, in: * select * from (select 1 from s) a (x) where x = 1 * we will not push down x = 1. * NOTE: It would be easy to handle the case of a constant, but if the * inner SELECT returns an arbitrary expression, then we would have to copy * that tree into the pushed predicate, and that tree could contain * subqueries and method calls. * * Also, don't allow a predicate to be pushed down if it contains a * ColumnReference that replaces an aggregate. This can happen if * the aggregate is in the HAVING clause. In this case, we would be * pushing the predicate into the SelectNode that evaluates the aggregate, * which doesn't make sense, since the having clause is supposed to be * applied to the result of the SelectNode. * * RESOLVE - revisit this issue once we have views. * * @param referencedTabs JBitSet with bit map of referenced FromTables * @param simplePredsOnly Whether or not to consider method * calls, field references and conditional nodes * when building bit map * * @return boolean Whether or not source.expression is a ColumnReference * or a VirtualColumnNode or a ConstantNode. */ public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly) { if (SanityManager.DEBUG) SanityManager.ASSERT(tableNumber >= 0, "tableNumber is expected to be non-negative"); referencedTabs.set(tableNumber); return ( ! replacesAggregate ) && ( (source.getExpression() instanceof ColumnReference) || (source.getExpression() instanceof VirtualColumnNode) || (source.getExpression() instanceof ConstantNode)); } /** * Remap all of the ColumnReferences in this expression tree * to point to the ResultColumn that is 1 level under their * current source ResultColumn. * This is useful for pushing down single table predicates. * * RESOLVE: Once we start pushing join clauses, we will need to walk the * ResultColumn/VirtualColumnNode chain for them to remap the references. * * @return None. */ public void remapColumnReferences() { ValueNode expression = source.getExpression(); if (SanityManager.DEBUG) { // SanityManager.ASSERT(origSource == null, // "Trying to remap ColumnReference twice without unremapping it."); } if ( ! ( (expression instanceof VirtualColumnNode) || (expression instanceof ColumnReference) ) ) { return; } /* Find the matching ResultColumn */ origSource = source; source = getSourceResultColumn(); origName = columnName; columnName = source.getName(); origColumnNumber = columnNumber; columnNumber = source.getColumnPosition(); origTableNumber = tableNumber; if (source.getExpression() instanceof ColumnReference) { ColumnReference cr = (ColumnReference) source.getExpression(); tableNumber = cr.getTableNumber(); if (SanityManager.DEBUG) { // if dummy cr generated to replace aggregate, it may not have table number // because underneath can be more than 1 table. if (tableNumber == -1 && ! cr.getGeneratedToReplaceAggregate()) { SanityManager.THROWASSERT( "tableNumber not expected to be -1, origName = " + origName); } } } } public void unRemapColumnReferences() { if (origSource == null) return; if (SanityManager.DEBUG) { // SanityManager.ASSERT(origSource != null, // "Trying to unremap a ColumnReference that was not remapped."); } source = origSource; origSource = null; columnName = origName; origName = null; tableNumber = origTableNumber; columnNumber = origColumnNumber; } /** * Returns true if this ColumnReference has been remapped; false * otherwise. * * @return Whether or not this ColumnReference has been remapped. */ protected boolean hasBeenRemapped() { return (origSource != null); } /* * Get the ResultColumn that the source points to. This is useful for * getting what the source will be after this ColumnReference is remapped. */ public ResultColumn getSourceResultColumn() { ValueNode expression = source.getExpression(); /* Find the matching ResultColumn */ if (expression instanceof VirtualColumnNode) { return ((VirtualColumnNode) expression).getSourceResultColumn(); } else { /* RESOLVE - If expression is a ColumnReference, then we are hitting * the top of a query block (derived table or view.) * In order to be able to push the expression down into the next * query block, it looks like we should reset the contents of the * current ColumnReference to be the same as expression. (This probably * only means names and tableNumber.) We would then "rebind" the top * level predicate somewhere up the call stack and see if we could push * the predicate through. */ return ((ColumnReference) expression).getSourceResultColumn(); } } /** * Remap all ColumnReferences in this tree to be clones of the * underlying expression. * * @return ValueNode The remapped expression tree. * * @exception StandardException Thrown on error */ public ValueNode remapColumnReferencesToExpressions() throws StandardException { ResultColumn rc; ResultColumn sourceRC = source; /* Nothing to do if we are not pointing to a redundant RC */ if (! source.isRedundant()) { return this; } /* Find the last redundant RC in the chain. We * want to clone its expression. */ for (rc = source; rc != null && rc.isRedundant(); ) { ResultColumn nextRC = null; ValueNode expression = rc.getExpression(); /* Find the matching ResultColumn */ if (expression instanceof VirtualColumnNode) { nextRC = ((VirtualColumnNode) expression).getSourceResultColumn(); } else if (expression instanceof ColumnReference) { nextRC = ((ColumnReference) expression).getSourceResultColumn(); } else { nextRC = null; } if (nextRC != null && nextRC.isRedundant()) { sourceRC = nextRC; } rc = nextRC; } if (SanityManager.DEBUG) { if (sourceRC == null) { SanityManager.THROWASSERT( "sourceRC is expected to be non-null for " + columnName); } if ( ! sourceRC.isRedundant()) { SanityManager.THROWASSERT( "sourceRC is expected to be redundant for " + columnName); } } /* If last expression is a VCN, then we can't clone it. * Instead, we just reset our source to point to the * source of the VCN, those chopping out the layers. * Otherwise, we return a clone of the underlying expression. */ if (sourceRC.getExpression() instanceof VirtualColumnNode) { VirtualColumnNode vcn = (VirtualColumnNode) (sourceRC.getExpression()); ResultSetNode rsn = vcn.getSourceResultSet(); if (rsn instanceof FromTable) { tableNumber = ((FromTable) rsn).getTableNumber(); if (SanityManager.DEBUG) { SanityManager.ASSERT(tableNumber != -1, "tableNumber not expected to be -1"); } } else { if (SanityManager.DEBUG) { SanityManager.THROWASSERT("rsn expected to be a FromTable, but is a " + rsn.getClass().getName()); } } source = ((VirtualColumnNode) sourceRC.getExpression()). getSourceResultColumn(); return this; } else { return sourceRC.getExpression().getClone(); } } /** * Update the table map to reflect the source * of this CR. * * @param refs The table map. * * @return Nothing. */ void getTablesReferenced(JBitSet refs) { if (refs.size() < tableNumber) refs.grow(tableNumber); if (tableNumber != -1) // it may not be set if replacesAggregate is true refs.set(tableNumber); } /** * Return whether or not this expression tree is cloneable. * * @return boolean Whether or not this expression tree is cloneable. */ public boolean isCloneable() { return true; } /** @see ValueNode#constantExpression */ public boolean constantExpression(PredicateList whereClause) { return whereClause.constantColumn(this); } /** * ColumnReference's are to the current row in the system. * This lets us generate * a faster get that simply returns the column from the * current row, rather than getting the value out and * returning that, only to have the caller (in the situations * needed) stuffing it back into a new column holder object. * We will assume the general generate() path is for getting * the value out, and use generateColumn() when we want to * keep the column wrapped. * * @exception StandardException Thrown on error */ public void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException { int sourceResultSetNumber = source.getResultSetNumber(); //PUSHCOMPILE /* Reuse generated code, where possible */ /* ** If the source is redundant, return the generation of its source. ** Most redundant nodes will be flattened out by this point, but ** in at least one case (elimination of redundant ProjectRestricts ** during generation) we don't do this. */ if (source.isRedundant()) { source.generateExpression(acb, mb); return; } if (SanityManager.DEBUG) { if (sourceResultSetNumber < 0) { SanityManager.THROWASSERT("sourceResultSetNumber expected to be >= 0 for " + getTableName() + "." + getColumnName()); } } /* The ColumnReference is from an immediately underlying ResultSet. * The Row for that ResultSet is Activation.row[sourceResultSetNumber], * where sourceResultSetNumber is the resultSetNumber for that ResultSet. * * The generated java is the expression: * (<interface>) this.row[sourceResultSetNumber].getColumn(#columnId); * * where <interface> is the appropriate Datatype protocol interface * for the type of the column. */ acb.pushColumnReference(mb, sourceResultSetNumber, source.getVirtualColumnId()); mb.cast(getTypeCompiler().interfaceName()); /* Remember generated code for possible resuse */ } /** * Get the user-supplied schema name of this column. This will be null * if the user did not supply a name (for example, select t.a from t). * Another example for null return value (for example, select b.a from t as b). * But for following query select app.t.a from t, this will return APP * Code generation of aggregate functions relies on this method * * @return The user-supplied schema name of this column. Null if no user- * supplied name. */ public String getSchemaName() { return ( ( tableName != null) ? tableName.getSchemaName() : null ); } /** * 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 expressions) * * @return The variant type for the underlying expression. */ protected int getOrderableVariantType() { // ColumnReferences are invariant for the life of the scan return Qualifier.SCAN_INVARIANT; } /** * Return whether or not the source of this ColumnReference is itself a ColumnReference. * * @return Whether or not the source of this ColumnReference is itself a ColumnReference. */ boolean pointsToColumnReference() { return (source.getExpression() instanceof ColumnReference); } /** * Get the DataTypeServices from this Node. * * @return The DataTypeServices from this Node. This * may be null if the node isn't bound yet. */ public DataTypeDescriptor getTypeServices() { DataTypeDescriptor dtd = super.getTypeServices(); if( dtd == null && source != null) { dtd = source.getTypeServices(); if( dtd != null) setType( dtd); } return dtd; } // end of getTypeServices /** * Determine whether or not this ColumnReference's source comes * from a FromBaseTable (as opposed to some other ResultSetNode). * We figure this out by walking the ResultColumn/VirtualColumnNode * chain until we get to last VirtualColumnNode in the chain * (if there is one), and then seeing what that VCN's source * result set is. If there are no VCNs then we check to see * if the source is pointing to a BaseColumnNode. * * This is useful when scoping predicates for pushing; we * need to know if the predicate's column references are pointing * directly to base tables so that we can set the scoped references' * column numbers correctly. */ protected boolean pointsToBaseTable() throws StandardException { ResultColumn rc = getSource(); if (rc == null) { // this can happen if column reference is pointing to a column // that is not from a base table. For example, if we have a // VALUES clause like // // (values (1, 2), (3, 4)) V1 (i, j) // // and then a column reference to VI.i, the column reference // won't have a source. return false; } // Walk the VirtualColumnNode->ResultColumn chain. VirtualColumnNode vcn = null; ValueNode rcExpr = rc.getExpression(); while (rcExpr instanceof VirtualColumnNode) { vcn = (VirtualColumnNode)rcExpr; rc = vcn.getSourceColumn(); rcExpr = rc.getExpression(); } // If we've reached the bottom of the chain then see if // the VCN is pointing to a FromBaseTable. if (vcn != null) return (vcn.getSourceResultSet() instanceof FromBaseTable); // Else check our source's expression. return (rc.getExpression() instanceof BaseColumnNode); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -