📄 fromvti.java
字号:
getNodeFactory().doJoinOrderOptimization(), getContextManager()), (SubqueryList) getNodeFactory().getNode( C_NodeTypes.SUBQUERY_LIST, getContextManager()), (PredicateList) getNodeFactory().getNode( C_NodeTypes.PREDICATE_LIST, getContextManager())); /* Generate the referenced table map */ referencedTableMap = new JBitSet(numTables); referencedTableMap.set(tableNumber); newInvocation.categorize(referencedTableMap, false); // Create the dependency map dependencyMap = new JBitSet(numTables); for (int index = 0; index < numTables; index++) { if ((index != tableNumber) && referencedTableMap.get(index)) { dependencyMap.set(index); } } // Get a JBitSet of the outer tables represented in the parameter list correlationMap = new JBitSet(numTables); newInvocation.getCorrelationTables(correlationMap); return genProjectRestrict(numTables); } /** * Put a ProjectRestrictNode on top of each FromTable in the FromList. * ColumnReferences must continue to point to the same ResultColumn, so * that ResultColumn must percolate up to the new PRN. However, * that ResultColumn will point to a new expression, a VirtualColumnNode, * which points to the FromTable and the ResultColumn that is the source for * the ColumnReference. * (The new PRN will have the original of the ResultColumnList and * the ResultColumns from that list. The FromTable will get shallow copies * of the ResultColumnList and its ResultColumns. ResultColumn.expression * will remain at the FromTable, with the PRN getting a new * VirtualColumnNode for each ResultColumn.expression.) * We then project out the non-referenced columns. If there are no referenced * columns, then the PRN's ResultColumnList will consist of a single ResultColumn * whose expression is 1. * * @param numTables Number of tables in the DML Statement * * @return The generated ProjectRestrictNode atop the original FromTable. * * @exception StandardException Thrown on error */ protected ResultSetNode genProjectRestrict(int numTables) throws StandardException { ResultColumnList prRCList; /* We get a shallow copy of the ResultColumnList and its * ResultColumns. (Copy maintains ResultColumn.expression for now.) */ prRCList = resultColumns; resultColumns = resultColumns.copyListAndObjects(); /* Replace ResultColumn.expression with new VirtualColumnNodes * in the ProjectRestrictNode's ResultColumnList. (VirtualColumnNodes include * pointers to source ResultSetNode, this, and source ResultColumn.) * NOTE: We don't want to mark the underlying RCs as referenced, otherwise * we won't be able to project out any of them. */ prRCList.genVirtualColumnNodes(this, resultColumns, false); /* Project out any unreferenced columns. If there are no referenced * columns, generate and bind a single ResultColumn whose expression is 1. */ prRCList.doProjection(); /* Finally, we create the new ProjectRestrictNode */ return (ResultSetNode) getNodeFactory().getNode( C_NodeTypes.PROJECT_RESTRICT_NODE, this, prRCList, null, /* Restriction */ null, /* Restriction as PredicateList */ null, /* Project subquery list */ null, /* Restrict subquery list */ tableProperties, getContextManager() ); } /** * Return whether or not to materialize this ResultSet tree. * * @return Whether or not to materialize this ResultSet tree. * would return valid results. * * @exception StandardException Thrown on error */ public boolean performMaterialization(JBitSet outerTables) throws StandardException { /* We need to materialize the VTI iff: * o It is an inner table. * o The VTI can be materialized. * o The VTI cannot be instantiated multiple times. * o The join strategy does not do materialization. * RESOLVE - We don't have to materialize if all of the * outer tables are 1 row tables. */ return (outerTables.getFirstSetBit() != -1 && ! outerTables.hasSingleBitSet() && // Not the outer table (! getTrulyTheBestAccessPath(). getJoinStrategy(). doesMaterialization()) && // Join strategy does not do materialization isMaterializable() && // VTI can be materialized ! supportsMultipleInstantiations // VTI does not support multiple instantiations ); } /** * Generation on a FromVTI creates a wrapper around * the user's java.sql.ResultSet * * @param acb The ActivationClassBuilder for the class being built * @param mb The MethodBuilder for the execute() method to be built * * @return A compiled Expression that returns a ResultSet that * iterates through the user's java.sql.ResultSet. * * @exception StandardException Thrown on error */ public void generate(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException { /* NOTE: We need to remap any CRs within the parameters * so that we get their values from the right source * row. For example, if a CR is a join column, we need * to get the value from the source table and not the * join row since the join row hasn't been filled in yet. */ RemapCRsVisitor rcrv = new RemapCRsVisitor(true); newInvocation.accept(rcrv); /* Get the next ResultSet #, so that we can number this ResultSetNode, its * ResultColumnList and ResultSet. */ assignResultSetNumber(); acb.pushGetResultSetFactoryExpression(mb); int nargs = getScanArguments(acb, mb); mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getVTIResultSet", ClassName.NoPutResultSet, nargs); } private int getScanArguments(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException { int rclSize = resultColumns.size(); FormatableBitSet referencedCols = new FormatableBitSet(rclSize); int erdNumber = -1; int numSet = 0; // Get our final cost estimate. costEstimate = getFinalCostEstimate(); for (int index = 0; index < rclSize; index++) { ResultColumn rc = (ResultColumn) resultColumns.elementAt(index); if (rc.isReferenced()) { referencedCols.set(index); numSet++; } } // Only add referencedCols if not all columns are accessed if (numSet != numVTICols) { erdNumber = acb.addItem(referencedCols); } // compileTimeConstants can be null int ctcNumber = acb.addItem(compileTimeConstants); acb.pushThisAsActivation(mb); // arg 1 // get a function to allocate scan rows of the right shape and size resultColumns.generateHolder(acb, mb); // arg 2 // For a Version 2 VTI we never maintain the java.sql.PreparedStatement // from compile time to execute time. This would rquire the PreparedStatement // to be shareable across multiple connections, which is not the model for // java.sql.PreparedStatement. // For a Version 2 VTI we do pass onto the ResultSet the re-useability // of the java.sql.PreparedStatement at runtime. The java.sql.PreparedStatement // is re-uesable if // // o No ? or ColumnReferences in parameters boolean reuseablePs = version2 && (getNodesFromParameters(ParameterNode.class).size() == 0) && (getNodesFromParameters(ColumnReference.class).size() == 0); mb.push(resultSetNumber); // arg 3 // The generated method for the constructor generateConstructor(acb, mb, reuseablePs); // arg 4 // Pass in the class name mb.push(newInvocation.getJavaClassName()); // arg 5 if (restrictionList != null) { restrictionList.generateQualifiers(acb, mb, this, true); } else mb.pushNull(ClassName.Qualifier + "[][]"); // Pass in the erdNumber for the referenced column FormatableBitSet mb.push(erdNumber); // arg 6 // Whether or not this is a version 2 VTI mb.push(version2); mb.push(reuseablePs); mb.push(ctcNumber); // Whether or not this is a target VTI mb.push(isTarget); // isolation level of the scan (if specified) mb.push(getCompilerContext().getScanIsolationLevel()); // estimated row count mb.push(costEstimate.rowCount()); // estimated cost mb.push(costEstimate.getEstimatedCost()); // let the superclass deal with statement level argument closeMethodArgument(acb, mb); return 15; } private void generateConstructor(ActivationClassBuilder acb, MethodBuilder mb, boolean reuseablePs) throws StandardException { // this sets up the method and the static field. // generates: // java.sql.ResultSet userExprFun { } MethodBuilder userExprFun = acb.newGeneratedFun( version2 ? "java.sql.PreparedStatement" : "java.sql.ResultSet", Modifier.PUBLIC); userExprFun.addThrownException("java.lang.Exception"); // If it's a re-useable PreparedStatement then hold onto it. LocalField psHolder = reuseablePs ? acb.newFieldDeclaration(Modifier.PRIVATE, "java.sql.PreparedStatement") : null; if (reuseablePs) { userExprFun.getField(psHolder); userExprFun.conditionalIfNull(); } newInvocation.generateExpression(acb, userExprFun); if (reuseablePs) { userExprFun.putField(psHolder); userExprFun.startElseCode(); userExprFun.getField(psHolder); userExprFun.completeConditional(); } userExprFun.methodReturn(); // newInvocation knows it is returning its value; /* generates: * return <newInvocation.generate(acb)>; */ // we are done modifying userExprFun, complete it. userExprFun.complete(); // constructor is used in the final result set as an access of the new static // field holding a reference to this new method. // generates: // ActivationClass.userExprFun // which is the static field that "points" to the userExprFun // that evaluates the where clause. acb.pushMethodReference(mb, userExprFun); // now add in code to close the reusable PreparedStatement when // the activation is closed. if (reuseablePs) { MethodBuilder closeActivationMethod = acb.getCloseActivationMethod(); closeActivationMethod.getField(psHolder); closeActivationMethod.conditionalIfNull(); // do nothing closeActivationMethod.push(0); // work around for no support for real if statements closeActivationMethod.startElseCode(); closeActivationMethod.getField(psHolder); closeActivationMethod.callMethod(VMOpcode.INVOKEINTERFACE, "java.sql.Statement", "close", "void", 0); closeActivationMethod.push(0); closeActivationMethod.completeConditional(); closeActivationMethod.endStatement(); } } /** * 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 (! baseTable) && name.equals(newInvocation.getJavaClassName()); } /** * 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); } Visitable returnNode = super.accept(v); if (!v.stopTraversal()) { newInvocation = (NewInvocationNode) newInvocation.accept(v); } return returnNode; } /** * Check and see if we have a special trigger VTI. * If it cannot be bound (because we aren't actually * compiling or executing a trigger), then throw * an exception. * * @return null if not a special trigger vti, or the table * id if it is */ private UUID getSpecialTriggerVTITableName(LanguageConnectionContext lcc, String className) throws StandardException { if (className.equals(ClassName.TriggerNewTransitionRows) || className.equals(ClassName.TriggerOldTransitionRows)) { // if there isn't an active trigger being compiled, error if (lcc.getTriggerTable() != null) { return lcc.getTriggerTable().getUUID(); } else if (lcc.getTriggerExecutionContext() != null) { return lcc.getTriggerExecutionContext().getTargetTableId(); } else { throw StandardException.newException(SQLState.LANG_CANNOT_BIND_TRIGGER_V_T_I, className); } } return (UUID)null; } private ResultColumnList genResultColList(TableDescriptor td) throws StandardException { ResultColumnList rcList = null; ResultColumn resultColumn; ValueNode valueNode; ColumnDescriptor colDesc = null; TableName tableName = makeTableName(td.getSchemaName(), td.getName()); /* Add all of the columns in the table */ rcList = (ResultColumnList) getNodeFactory().getNode( C_NodeTypes.RESULT_COLUMN_LIST, getContextManager()); ColumnDescriptorList cdl = td.getColumnDescriptorList(); int cdlSize = cdl.size(); for (int index = 0; index < cdlSize; index++) { /* Build a ResultColumn/BaseColumnNode pair for the column */ colDesc = (ColumnDescriptor) cdl.elementAt(index); valueNode = (ValueNode) getNodeFactory().getNode( C_NodeTypes.BASE_COLUMN_NODE, colDesc.getColumnName(), exposedName, colDesc.getType(), getContextManager()); resultColumn = (ResultColumn) getNodeFactory().getNode( C_NodeTypes.RESULT_COLUMN, colDesc, valueNode, getContextManager()); /* Build the ResultColumnList to return */ rcList.addResultColumn(resultColumn); } return rcList; } public boolean needsSpecialRCLBinding() { return true; } boolean isUpdatableCursor() throws StandardException { return true; } protected void markUpdatableByCursor(Vector updateColumns) { super.markUpdatableByCursor(updateColumns); forUpdatePresent = true; emptyForUpdate = ((updateColumns == null) || (updateColumns.size() == 0)); } private int[] getForUpdateColumnList() { int[] tempList = new int[getNumColumnsReturned()]; int offset = 0; for (int col = 0; col < tempList.length; col++) { if (resultColumns.updatableByCursor(col)) tempList[offset++] = col + 1; // JDBC id } int[] list; if (offset == tempList.length) list = tempList; else { list = new int[offset]; System.arraycopy(tempList, 0, list, 0, offset); } return list; } /* ** VTIEnvironment */ public final boolean isCompileTime() { return true; } public String getOriginalSQL() { return getCompilerContext().getParser().getSQLtext(); } public final int getStatementIsolationLevel() { return ExecutionContext.CS_TO_JDBC_ISOLATION_LEVEL_MAP[getCompilerContext().getScanIsolationLevel()]; } public void setSharedState(String key, java.io.Serializable value) { if (key == null) return; if (compileTimeConstants == null) compileTimeConstants = new FormatableHashtable(); compileTimeConstants.put(key, value); } public Object getSharedState(String key) { if ((key == null) || (compileTimeConstants == null)) return null; return compileTimeConstants.get(key); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -