📄 resultcolumnlist.java
字号:
{ generateCore(acb, mb, false); } /** * Generate the code to place the columns' values into * a row variable named "r". This wrapper is here * rather than in ResultColumn, because that class does * not know about the position of the columns in the list. * * @exception StandardException Thrown on error */ void generateNulls(ActivationClassBuilder acb, MethodBuilder mb) throws StandardException { generateCore(acb, mb, true); } /** * Generate the code to place the columns' values into * a row variable named "r". This wrapper is here * rather than in ResultColumn, because that class does * not know about the position of the columns in the list. * * This is the method that does the work. */ void generateCore(ExpressionClassBuilder acb, MethodBuilder mb, boolean genNulls) throws StandardException { // generate the function and initializer: // private ExecRow fieldX; // In the constructor: // fieldX = getExecutionFactory().getValueRow(# cols); // private ExecRow exprN() // { // fieldX.setColumn(1, col(1).generateColumn(ps))); // ... and so on for each column ... // return fieldX; // } // static Method exprN = method pointer to exprN; // this sets up the method and the static field. MethodBuilder userExprFun = acb.newUserExprFun(); /* Declare the field */ LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.ExecRow); // Generate the code to create the row in the constructor genCreateRow(acb, field, "getValueRow", ClassName.ExecRow, size()); ResultColumn rc; int size = size(); MethodBuilder cb = acb.getConstructor(); for (int index = 0; index < size; index++) { // generate statements of the form // fieldX.setColumn(columnNumber, (DataValueDescriptor) columnExpr); // and add them to exprFun. rc = (ResultColumn) elementAt(index); /* If we are not generating nulls, then we can skip this RC if * it is simply propagating a column from the source result set. */ if (!genNulls) { ValueNode sourceExpr = rc.getExpression(); if (sourceExpr instanceof VirtualColumnNode && ! ( ((VirtualColumnNode) sourceExpr).getCorrelated())) { continue; } if (sourceExpr instanceof ColumnReference && ! ( ((ColumnReference) sourceExpr).getCorrelated())) { continue; } } // row add is 1-based, and iterator index is 0-based if (SanityManager.DEBUG) { if (index + 1 != rc.getVirtualColumnId()) { SanityManager.THROWASSERT( "VirtualColumnId (" + rc.getVirtualColumnId() + ") does not agree with position within Vector (" + (index + 1) + ")"); } } // we need the expressions to be Columns exactly. /* SPECIAL CASE: Expression is a non-null constant. * Generate the setColumn() call in the constructor * so that it will only be executed once per instantiation. * * Increase the statement counter in constructor. Code size in * constructor can become too big (more than 64K) for Java compiler * to handle (beetle 4293). We set constant columns in other * methods if constructor has too many statements already. */ if ( (! genNulls) && (rc.getExpression() instanceof ConstantNode) && ! ((ConstantNode) rc.getExpression()).isNull() && ! cb.statementNumHitLimit(1)) { cb.getField(field); // instance cb.push(index + 1); // first arg; rc.generateExpression(acb, cb); cb.cast(ClassName.DataValueDescriptor); // second arg cb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "setColumn", "void", 2); continue; } userExprFun.getField(field); // instance userExprFun.push(index + 1); // arg1 /* We want to reuse the null values instead of doing a new each time * if the caller said to generate nulls or the underlying expression * is a typed null value. */ boolean needDVDCast = true; if (rc.isAutoincrementGenerated()) { // (com.ibm.db2j.impl... DataValueDescriptor) // this.getSetAutoincValue(column_number) userExprFun.pushThis(); userExprFun.push(rc.getColumnPosition()); userExprFun.push(rc.getTableColumnDescriptor().getAutoincInc()); userExprFun.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation, "getSetAutoincrementValue", ClassName.DataValueDescriptor, 2); needDVDCast = false; } else if (genNulls || ((rc.getExpression() instanceof ConstantNode) && ((ConstantNode) rc.getExpression()).isNull())) { userExprFun.getField(field); userExprFun.push(index + 1); userExprFun.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "getColumn", ClassName.DataValueDescriptor, 1); // the express acb.generateNullWithExpress(userExprFun, rc.getTypeCompiler()); } else { rc.generateExpression(acb, userExprFun); } if (needDVDCast) userExprFun.cast(ClassName.DataValueDescriptor); userExprFun.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "setColumn", "void", 2); } userExprFun.getField(field); userExprFun.methodReturn(); // we are now done modifying userExprFun userExprFun.complete(); // what we return is the access of the field, i.e. the pointer to the method. acb.pushMethodReference(mb, userExprFun); } /** * Build an empty row with the size and shape of the ResultColumnList. * * @return an empty row of the correct size and shape. * @exception StandardException Thrown on error */ public ExecRow buildEmptyRow() throws StandardException { int columnCount = size(); ExecRow row = getExecutionFactory().getValueRow( columnCount ); int position = 1; for (int index = 0; index < columnCount; index++) { ResultColumn rc = (ResultColumn) elementAt(index); DataTypeDescriptor dataType = rc.getTypeServices(); DataValueDescriptor dataValue = dataType.getNull(); row.setColumn( position++, dataValue ); } return row; } /** * Build an empty index row for the given conglomerate. * * @return an empty row of the correct size and shape. * @exception StandardException Thrown on error */ public ExecRow buildEmptyIndexRow(TableDescriptor td, ConglomerateDescriptor cd, StoreCostController scc, DataDictionary dd) throws StandardException { ResultColumn rc; if (SanityManager.DEBUG) { if (! cd.isIndex()) { SanityManager.THROWASSERT("ConglomerateDescriptor expected to be for index: " + cd); } } int[] baseCols = cd.getIndexDescriptor().baseColumnPositions(); ExecRow row = getExecutionFactory().getValueRow(baseCols.length + 1); for (int i = 0; i < baseCols.length; i++) { ColumnDescriptor coldes = td.getColumnDescriptor(baseCols[i]); DataTypeDescriptor dataType = coldes.getType(); // rc = getResultColumn(baseCols[i]); // rc = (ResultColumn) at(baseCols[i] - 1); // dataType = rc.getTypeServices(); DataValueDescriptor dataValue = dataType.getNull(); row.setColumn(i + 1, dataValue ); } RowLocation rlTemplate = scc.newRowLocationTemplate(); row.setColumn(baseCols.length + 1, rlTemplate); return row; } /** Generates a row with the size and shape of the ResultColumnList. Some structures, like FromBaseTable and DistinctNode, need to generate rowAllocator functions to get a row the size and shape of their ResultColumnList. We return the method pointer, which is a field access in the generated class. @exception StandardException */ void generateHolder(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException { generateHolder(acb, mb, (FormatableBitSet) null, (FormatableBitSet) null); } /** Generates a row with the size and shape of the ResultColumnList. Some structures, like FromBaseTable and DistinctNode, need to generate rowAllocator functions to get a row the size and shape of their ResultColumnList. We return the method pointer, which is a field access in the generated class. @exception StandardException */ void generateHolder(ExpressionClassBuilder acb, MethodBuilder mb, FormatableBitSet referencedCols, FormatableBitSet propagatedCols) throws StandardException { // what we return is a pointer to the method. acb.pushMethodReference(mb, generateHolderMethod(acb, referencedCols, propagatedCols)); } MethodBuilder generateHolderMethod(ExpressionClassBuilder acb, FormatableBitSet referencedCols, FormatableBitSet propagatedCols) throws StandardException { int numCols; String rowAllocatorMethod; String rowAllocatorType; int highestColumnNumber = -1; if (referencedCols != null) { // Find the number of the last column referenced in the table for (int i = referencedCols.anySetBit(); i != -1; i = referencedCols.anySetBit(i)) { highestColumnNumber = i; } } else { highestColumnNumber = size() - 1; } // Within the constructor: // fieldX = getExecutionFactory().getValueRow(# cols); // The body of the new method: // { // fieldX.setColumn(1, col(1).generateColumn(ps))); // ... and so on for each column ... // return fieldX; // } // static Method exprN = method pointer to exprN; // this sets up the method and the static field MethodBuilder exprFun = acb.newExprFun(); // Allocate the right type of row, depending on // whether we're scanning an index or a heap. if (indexRow) { rowAllocatorMethod = "getIndexableRow"; rowAllocatorType = ClassName.ExecIndexRow; } else { rowAllocatorMethod = "getValueRow"; rowAllocatorType = ClassName.ExecRow; } numCols = size(); /* Declare the field */ LocalField lf = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.ExecRow); // Generate the code to create the row in the constructor genCreateRow(acb, lf, rowAllocatorMethod, rowAllocatorType, highestColumnNumber + 1); // now we fill in the body of the function int colNum; // If there is a referenced column map, the first column to fill // in is the first one in the bit map - otherwise, it is // column 0. if (referencedCols != null) colNum = referencedCols.anySetBit(); else colNum = 0; for (int index = 0; index < numCols; index++) { ResultColumn rc = ((ResultColumn) elementAt(index)); /* Special code generation for RID since expression is CurrentRowLocationNode. * Really need yet another node type that does its own code generation. */ if (rc.getExpression() instanceof CurrentRowLocationNode) { ConglomerateController cc = null; int savedItem; RowLocation rl; cc = getLanguageConnectionContext(). getTransactionCompile().openConglomerate( conglomerateId, false, 0, TransactionController.MODE_RECORD, TransactionController.ISOLATION_READ_COMMITTED); try { rl = cc.newRowLocationTemplate(); } finally { if (cc != null) { cc.close(); } } savedItem = acb.addItem(rl); // get the RowLocation template exprFun.getField(lf); // instance for setColumn exprFun.push(highestColumnNumber + 1); // first arg exprFun.pushThis(); // instance for getRowLocationTemplate exprFun.push(savedItem); // first arg exprFun.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Activation, "getRowLocationTemplate", ClassName.RowLocation, 1); exprFun.upCast(ClassName.DataValueDescriptor); exprFun.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "setColumn", "void", 2); continue; } /* Skip over those columns whose source is the immediate * child result set. (No need to generate a wrapper * for a SQL NULL when we are smart enough not to pass * that wrapper to the store.) * NOTE: Believe it or not, we have to check for the case * where referencedCols is not null, but no bits are set. * This can happen when we need to get all of the columns * from the heap due to a check constraint. */ if (propagatedCols != null && propagatedCols.getNumBitsSet() != 0) { /* We can skip this RC if it is simply propagating * a column from the source result set. */ ValueNode sourceExpr = rc.getExpression(); if (sourceExpr instanceof VirtualColumnNode) { // There is a referenced columns bit set, so use // it to figure out what the next column number is. // colNum = referencedCols.anySetBit(colNum); continue; } } // generate the column space creation call // generate statements of the form // r.setColumn(columnNumber, columnShape); // // This assumes that there are no "holes" in the column positions, // and that column positions reflect the stored format/order exprFun.getField(lf); // instance exprFun.push(colNum + 1); // first arg rc.generateHolder(acb, exprFun); exprFun.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "setColumn", "void", 2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -