// 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);
// If there is a bit map of referenced columns, use it to
// figure out what the next column is, otherwise just go
// to the next column.
if (referencedCols != null)
colNum = referencedCols.anySetBit(colNum);
else
colNum++;
}
// generate:
// return fieldX;
// and add to the end of exprFun's body.
exprFun.getField(lf);
exprFun.methodReturn();
// we are done putting stuff in exprFun:
exprFun.complete();
return exprFun;
}