int numTables)
throws StandardException
{
AndNode andNode;
BinaryComparisonOperatorNode bcoNode = null;
JBitSet tableMap;
Predicate predicate;
ResultColumn firstRC;
ResultColumnList resultColumns;
UnaryComparisonOperatorNode ucoNode = null;
ValueNode oldWhereClause;
ValueNode rightOperand;
/* We have to ensure that the resultSet immediately under us has
* a PredicateList, otherwise we can't push the predicate down.
*/
resultSet = resultSet.ensurePredicateList(numTables);
/* RESOLVE - once we understand how correlated columns will work,
* we probably want to mark leftOperand as a correlated column
*/
resultColumns = resultSet.getResultColumns();
/*
** Create a new PR node. Put it over the original subquery. resulSet
** is now the new PR. We give the chance that things under the PR node
** can be materialized. See beetle 4373.
*/
ResultColumnList newRCL = resultColumns.copyListAndObjects();
newRCL.genVirtualColumnNodes(resultSet, resultColumns);
resultSet = (ResultSetNode) getNodeFactory().getNode(
C_NodeTypes.PROJECT_RESTRICT_NODE,
resultSet, // child
newRCL, // result columns
null, // restriction
null, // restriction list
null, // project subqueries
null, // restrict subqueries
null,
getContextManager());
resultColumns = newRCL;
firstRC = (ResultColumn) resultColumns.elementAt(0);
rightOperand = firstRC.getExpression();
bcoNode = getNewJoinCondition(leftOperand, rightOperand);
ValueNode andLeft = bcoNode;
/* For NOT IN or ALL, and if either side of the comparison is nullable, and the
* subquery can not be flattened (because of that), we need to add IS NULL node
* on top of the nullables, such that the behavior is (beetle 5173):
*
* (1) If we have nulls in right operand, no row is returned.
* (2) If subquery result is empty before applying join predicate, every
* left row (including NULLs) is returned.
* (3) Otherwise, return {all left row} - {NULLs}
*/
if (isNOT_IN() || isALL())
{
boolean leftNullable = leftOperand.getTypeServices().isNullable();
boolean rightNullable = rightOperand.getTypeServices().isNullable();
if (leftNullable || rightNullable)
{
/* Create a normalized structure.
*/
BooleanConstantNode falseNode = (BooleanConstantNode) getNodeFactory().getNode(
C_NodeTypes.BOOLEAN_CONSTANT_NODE,
Boolean.FALSE,
getContextManager());
OrNode newOr = (OrNode) getNodeFactory().getNode(
C_NodeTypes.OR_NODE,
bcoNode,
falseNode,
getContextManager());
newOr.postBindFixup();
andLeft = newOr;
if (leftNullable)
{
UnaryComparisonOperatorNode leftIsNull = (UnaryComparisonOperatorNode)
getNodeFactory().getNode(
C_NodeTypes.IS_NULL_NODE,
leftOperand,
getContextManager());
leftIsNull.bindComparisonOperator();
newOr = (OrNode) getNodeFactory().getNode(
C_NodeTypes.OR_NODE,
leftIsNull,
andLeft,
getContextManager());
newOr.postBindFixup();
andLeft = newOr;
}
if (rightNullable)
{
UnaryComparisonOperatorNode rightIsNull = (UnaryComparisonOperatorNode)
getNodeFactory().getNode(
C_NodeTypes.IS_NULL_NODE,
rightOperand,
getContextManager());
rightIsNull.bindComparisonOperator();
newOr = (OrNode) getNodeFactory().getNode(
C_NodeTypes.OR_NODE,
rightIsNull,
andLeft,
getContextManager());
newOr.postBindFixup();
andLeft = newOr;
}
}
}
/* Place an AndNode above the <BinaryComparisonOperator> */
andNode = (AndNode) getNodeFactory().getNode(
C_NodeTypes.AND_NODE,
andLeft,
getTrueNode(),
getContextManager());
/* Build the referenced table map for the new predicate */
tableMap = new JBitSet(numTables);
andNode.postBindFixup();
/* Put the AndNode under a Predicate */
predicate = (Predicate) getNodeFactory().getNode(
C_NodeTypes.PREDICATE,