📄 resultcolumnlist.java
字号:
} } } /** * Walk the list and adjust the virtualColumnIds in the ResultColumns * by the specified amount. If ResultColumn.expression is a VirtualColumnNode, * then we adjust the columnId there as well. * * @param increment The size of the increment. * * @return None. */ public void adjustVirtualColumnIds(int adjust) { int size = size(); for (int index = 0; index < size; index++) { ResultColumn resultColumn = (ResultColumn) elementAt(index); resultColumn.adjustVirtualColumnId(adjust); if (SanityManager.DEBUG) { if ( ! (resultColumn.getExpression() instanceof VirtualColumnNode)) { SanityManager.THROWASSERT( "resultColumn.getExpression() is expected to be " + "instanceof VirtualColumnNode" + " not " + resultColumn.getExpression().getClass().getName()); } } ((VirtualColumnNode) resultColumn.getExpression()).columnId += adjust; } } /** * Project out any unreferenced ResultColumns from the list and * reset the virtual column ids in the referenced ResultColumns. * If all ResultColumns are projected out, then the list is not empty. * * @return None. * * @exception StandardException Thrown on error */ public void doProjection() throws StandardException { int numDeleted = 0; int size = size(); ResultColumnList deletedRCL = new ResultColumnList(); for (int index = 0; index < size; index++) { ResultColumn resultColumn = (ResultColumn) elementAt(index); /* RC's for FromBaseTables are marked as referenced during binding. * For other nodes, namely JoinNodes, we need to go 1 level * down the RC/VCN chain to see if the RC is referenced. This is * because we propagate the referencing info from the bottom up. */ if ((! resultColumn.isReferenced()) && (resultColumn.getExpression() instanceof VirtualColumnNode) && !(((VirtualColumnNode) resultColumn.getExpression()).getSourceColumn().isReferenced())) { // Remember the RC to delete when done deletedRCL.addElement(resultColumn); /* Remember how many we have deleted and decrement the * VirtualColumnIds for all nodes which appear after us * in the list. */ numDeleted++; } else { /* Decrement the VirtualColumnId for each node in the list * after the 1st deleted one. */ if (numDeleted >= 1) resultColumn.adjustVirtualColumnId( - numDeleted); /* Make sure that the RC is marked as referenced! */ resultColumn.setReferenced(); } } // Go back and delete the RCs to be delete from the list for (int index = 0; index < deletedRCL.size(); index++) { removeElement((ResultColumn) deletedRCL.elementAt(index)); } } /** * Check the uniqueness of the column names within a column list. * * @param errForGenCols Raise an error for any generated column names. * * @return String The first duplicate column name, if any. */ public String verifyUniqueNames(boolean errForGenCols) throws StandardException { int size = size(); Hashtable ht = new Hashtable(size + 2, (float) .999); ResultColumn rc; for (int index = 0; index < size; index++) { rc = (ResultColumn) elementAt(index); if (errForGenCols && rc.isNameGenerated()) throw StandardException.newException(SQLState.LANG_DB2_VIEW_REQUIRES_COLUMN_NAMES); /* Verify that this column's name is unique within the list */ String colName = ((ResultColumn) elementAt(index)).getName(); Object object = ht.put(colName, colName); if (object != null && ((String) object).equals(colName)) { return colName; } } /* No duplicate column names */ return null; } /** * Validate the derived column list (DCL) and propagate the info * from the list to the final ResultColumnList. * * @param derivedRCL The derived column list * @param tableName The table name for the FromTable * * @return None. * * @exception StandardException Thrown on error */ public void propagateDCLInfo(ResultColumnList derivedRCL, String tableName) throws StandardException { String duplicateColName; /* Do both lists, if supplied by user, have the same degree? */ if (derivedRCL.size() != size() && ! derivedRCL.getCountMismatchAllowed()) { throw StandardException.newException(SQLState.LANG_DERIVED_COLUMN_LIST_MISMATCH, tableName); } /* Check the uniqueness of the column names within the derived list */ duplicateColName = derivedRCL.verifyUniqueNames(false); if (duplicateColName != null) { throw StandardException.newException(SQLState.LANG_DUPLICATE_COLUMN_NAME_DERIVED, duplicateColName); } /* We can finally copy the derived names into the final list */ copyResultColumnNames(derivedRCL); } /** * Look for and reject ? parameters under ResultColumns. This is done for * SELECT statements. * * @return Nothing * * @exception StandardException Thrown if a ? parameter found directly * under a ResultColumn */ void rejectParameters() throws StandardException { int size = size(); for (int index = 0; index < size; index++) { ResultColumn rc = (ResultColumn) elementAt(index); rc.rejectParameter(); } } /** * Check for (and reject) XML values directly under the ResultColumns. * This is done for SELECT/VALUES statements. We reject values * in this case because JDBC does not define an XML type/binding * and thus there's no standard way to pass such a type back * to a JDBC application. * * Note that we DO allow an XML column in a top-level RCL * IF that column was added to the RCL by _us_ instead of * by the user. For example, if we have a table: * * create table t1 (i int, x xml) * * and the user query is: * * select i from t1 order by x * * the "x" column will be added (internally) to the RCL * as part of ORDER BY processing--and so we need to * allow that XML column to be bound without throwing * an error. If, as in this case, the XML column reference * is invalid (we can't use ORDER BY on an XML column because * XML values aren't ordered), a more appropriate error * message should be returned to the user in later processing. * If we didn't allow for this, the user would get an * error saying that XML columns are not valid as part * of the result set--but as far as s/he knows, there * isn't such a column: only "i" is supposed to be returned * (the RC for "x" was added to the RCL by _us_ as part of * ORDER BY processing). * * ASSUMPTION: Any RCs that are generated internally and * added to this RCL (before this RCL is bound) are added * at the _end_ of the list. If that's true, then any * RC with an index greater than the size of the initial * (user-specified) list must have been added internally * and will not be returned to the user. * * @return Nothing * * @exception StandardException Thrown if an XML value found * directly under a ResultColumn */ void rejectXMLValues() throws StandardException { int sz = size(); ResultColumn rc = null; for (int i = 1; i <= sz; i++) { if (i > initialListSize) // this RC was generated internally and will not // be returned to the user, so don't throw error. continue; rc = getResultColumn(i); if ((rc != null) && (rc.getType() != null) && rc.getType().getTypeId().isXMLTypeId()) { // Disallow it. throw StandardException.newException( SQLState.LANG_ATTEMPT_TO_SELECT_XML); } } } /** * Set the resultSetNumber in all of the ResultColumns. * * @param resultSetNumber The resultSetNumber * * @return Nothing. */ public void setResultSetNumber(int resultSetNumber) { int size = size(); for (int index = 0; index < size; index++) { ((ResultColumn) elementAt(index)).setResultSetNumber(resultSetNumber); } } /** * Mark all of the ResultColumns as redundant. * Useful when chopping a ResultSetNode out of a tree when there are * still references to its RCL. * * @return Nothing. */ public void setRedundant() { int size = size(); for (int index = 0; index < size; index++) { ((ResultColumn) elementAt(index)).setRedundant(); } } /** * Verify that all of the columns in the SET clause of a positioned update * appear in the cursor's FOR UPDATE OF list. * * @param ucl The cursor's FOR UPDATE OF list. (May be null.) * @param cursorName The cursor's name. * * @return Nothing. * * @exception StandardException Thrown on error */ public void checkColumnUpdateability(String[] ucl, String cursorName) throws StandardException { int size = size(); for (int index = 0; index < size; index++) { ResultColumn resultColumn = (ResultColumn) elementAt(index); if (resultColumn.updated() && ! resultColumn.foundInList(ucl)) { throw StandardException.newException(SQLState.LANG_COLUMN_NOT_UPDATABLE_IN_CURSOR, resultColumn.getName(), cursorName); } } } /** * Set up the result expressions for a UNION, INTERSECT, or EXCEPT: * o Verify union type compatiblity * o Get dominant type for result (type + max length + nullability) * o Create a new ColumnReference with dominant type and name of from this * RCL and make that the new expression. * o Set the type info for in the ResultColumn to the dominant type * * NOTE - We are assuming that caller has generated a new RCL for the UNION * with the same names as the left side's RCL and copies of the expressions. * * @param otherRCL RCL from other side of the UNION. * @param tableNumber The tableNumber for the UNION. * @param level The nesting level for the UNION. * @param operatorName "UNION", "INTERSECT", or "EXCEPT" * * @return Nothing. * * @exception StandardException Thrown on error */ public void setUnionResultExpression(ResultColumnList otherRCL, int tableNumber, int level, String operatorName) throws StandardException { TableName dummyTN; if (SanityManager.DEBUG) { if (size() != otherRCL.size()) { SanityManager.THROWASSERT( "size() = (" + size() + ") is expected to equal otherRCL.size (" + otherRCL.size() + ")"); } } /* Make a dummy TableName to be shared by all new CRs */ dummyTN = (TableName) getNodeFactory().getNode( C_NodeTypes.TABLE_NAME, null, null, getContextManager()); ContextManager cm = getContextManager(); int size = size(); for (int index = 0; index < size; index++) { boolean nullableResult; ColumnReference newCR; ResultColumn thisRC = (ResultColumn) elementAt(index); ResultColumn otherRC = (ResultColumn) otherRCL.elementAt(index); ValueNode thisExpr = thisRC.getExpression(); ValueNode otherExpr = otherRC.getExpression(); // If there is one row that is not 'autoincrement', the Union should // not be 'autoincrement'. if (!otherRC.isAutoincrementGenerated() && thisRC.isAutoincrementGenerated()) { thisRC.resetAutoincrementGenerated(); } /* ** If there are ? parameters in the ResultColumnList of a row ** in a table constructor, their types will not be set. Just skip ** these - their types will be set later. Each ? parameter will ** get the type of the first non-? in its column, so it can't ** affect the final dominant type. It's possible that all the ** rows for a particular column will have ? parameters - this is ** an error condition that will be caught later. */ TypeId thisTypeId = thisExpr.getTypeId(); if (thisTypeId == null) continue; TypeId otherTypeId = otherExpr.getTypeId(); if (otherTypeId == null) continue; /* ** Check type compatability. We want to make sure that ** the types are assignable in either direction ** and they are comparable. */ ClassFactory cf = getClassFactory(); if ( !thisExpr.getTypeCompiler().storable(otherTypeId, cf) && !otherExpr.getTypeCompiler().storable(thisTypeId, cf)) { throw StandardException.newException(SQLState.LANG_NOT_UNION_COMPATIBLE, thisTypeId.getSQLTypeName(), otherTypeId.getSQLTypeName(), operatorName); } DataTypeDescriptor resultType = thisExpr.getTypeServices().getDominantType( otherExpr.getTypeServices(), cf); newCR = (ColumnReference) getNodeFactory().getNode( C_NodeTypes.COLUMN_REFERENCE, thisRC.getName(), dummyTN, getContextManager()); newCR.setType(resultType); /* Set the tableNumber and nesting levels in newCR. * If thisExpr is not a CR, then newCR cannot be * correlated, hence source and nesting levels are * the same. */ if (thisExpr instanceof ColumnReference) { newCR.copyFields((ColumnReference) thisExpr); } else { newCR.setNestingLevel(level); newCR.setSourceLevel(level); } newCR.setTableNumber(tableNumber); thisRC.setExpression(newCR); thisRC.setType( thisRC.getTypeServices().getDominantType( otherRC.getTypeServices(), cf)); /* DB2 requires both sides of union to have same name for the result to * have that name. Otherwise,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -