Optimizable optTable,
LocalField rowField,
boolean isStartKey)
throws StandardException
{
MethodBuilder mb;
/* Code gets generated in constructor if comparison against
* a constant, otherwise gets generated in the current
* statement block.
*/
boolean withKnownConstant = false;
if (pred.compareWithKnownConstant(optTable, false))
{
withKnownConstant = true;
mb = acb.getConstructor();
}
else
{
mb = exprFun;
}
int[] baseColumns = optTable.getTrulyTheBestAccessPath().
getConglomerateDescriptor().
getIndexDescriptor().baseColumnPositions();
boolean[] isAscending = optTable.getTrulyTheBestAccessPath().
getConglomerateDescriptor().
getIndexDescriptor().isAscending();
/* If the predicate is an IN-list probe predicate then we are
* using it as a start/stop key "placeholder", to be over-ridden
* at execution time. Put differently, we want to generate
* "column = ?" as a start/stop key and then use the "?" value
* as a placeholder into which we'll plug the various IN values
* at execution time.
*
* In that case "isIn" will be false here, which is fine: there's
* no need to generate dynamic start/stop keys like we do for
* "normal" IN lists because we're just using the key as a place-
* holder. So by generating the probe predicate ("column = ?")
* as a normal one-sided start/stop key, we get our requisite
* execution-time placeholder and that's that. For more on how
* we use this "placeholder", see MultiProbeTableScanResultSet.
*
* Note that we generate the corresponding IN-list values
* separately (see generateInListValues() in this class).
*/
boolean isIn = pred.getAndNode().getLeftOperand() instanceof InListOperatorNode;
/*
** Generate statements of the form
**
** r.setColumn(columnNumber, columnExpression);
**
** and put the generated statement in the allocator function.
*/
mb.getField(rowField);
mb.push(columnNumber + 1);
// second arg
if (isIn)
{
pred.getSourceInList().generateStartStopKey(
isAscending[columnNumber], isStartKey, acb, mb);
}
else
pred.generateExpressionOperand(optTable, baseColumns[columnNumber], acb, mb);
mb.upCast(ClassName.DataValueDescriptor);
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Row, "setColumn", "void", 2);
/* Also tell the row if this column uses ordered null semantics */
if (!isIn)
{
RelationalOperator relop = pred.getRelop();
boolean setOrderedNulls = relop.orderedNulls();
/* beetle 4464, performance work. If index column is not nullable
* (which is frequent), we should treat it as though nulls are
* ordered (indeed because they don't exist) so that we do not have
* to check null at scan time for each row, each column. This is
* an overload to "is null" operator, so that we have less overhead,
* provided that they don't interfere. It doesn't interfere if it
* doesn't overload if key is null. If key is null, but operator
* is not orderedNull type (is null), skipScan will use this flag
* (false) to skip scan.
*/
if ((! setOrderedNulls) &&
! relop.getColumnOperand(optTable).getTypeServices().isNullable())
{
if (withKnownConstant)
setOrderedNulls = true;
else
{
ValueNode keyExp =
relop.getExpressionOperand(
optTable.getTableNumber(),
baseColumns[columnNumber],
(FromTable)optTable);
if (keyExp instanceof ColumnReference)
setOrderedNulls =
! ((ColumnReference) keyExp).getTypeServices().isNullable();
}
}
if (setOrderedNulls)
{
mb.getField(rowField);
mb.push(columnNumber);
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.ExecIndexRow, "orderedNulls", "void", 1);
}
}
}