assertTrue(n instanceof NestLoopPlanNode);
NestLoopPlanNode nl = (NestLoopPlanNode) n;
assertEquals(ExpressionType.COMPARE_EQUAL, nl.getJoinPredicate().getExpressionType());
assertNull(nl.getWherePredicate());
assertEquals(2, nl.getChildCount());
SeqScanPlanNode c0 = (SeqScanPlanNode) nl.getChild(0);
assertNull(c0.getPredicate());
SeqScanPlanNode c1 = (SeqScanPlanNode) nl.getChild(1);
assertNull(c1.getPredicate());
// R1.C = R2.C Inner-Outer join Expr stays at the NLJ as Join predicate
// R1.A > 0 Outer Join Expr stays at the the NLJ as pre-join predicate
// R2.A < 0 Inner Join Expr is pushed down to the inner SeqScan node
pn = compile("select * FROM R1 LEFT JOIN R2 ON R1.C = R2.C AND R1.A > 0 AND R2.A < 0");
n = pn.getChild(0).getChild(0);
assertTrue(n instanceof NestLoopPlanNode);
nl = (NestLoopPlanNode) n;
assertNotNull(nl.getPreJoinPredicate());
AbstractExpression p = nl.getPreJoinPredicate();
assertEquals(ExpressionType.COMPARE_GREATERTHAN, p.getExpressionType());
assertNotNull(nl.getJoinPredicate());
p = nl.getJoinPredicate();
assertEquals(ExpressionType.COMPARE_EQUAL, p.getExpressionType());
assertNull(nl.getWherePredicate());
assertEquals(2, nl.getChildCount());
c0 = (SeqScanPlanNode) nl.getChild(0);
assertNull(c0.getPredicate());
c1 = (SeqScanPlanNode) nl.getChild(1);
assertNotNull(c1.getPredicate());
p = c1.getPredicate();
assertEquals(ExpressionType.COMPARE_LESSTHAN, p.getExpressionType());
// R1.C = R2.C Inner-Outer join Expr stays at the NLJ as Join predicate
// (R1.A > 0 OR R2.A < 0) Inner-Outer join Expr stays at the NLJ as Join predicate
pn = compile("select * FROM R1 LEFT JOIN R2 ON R1.C = R2.C AND (R1.A > 0 OR R2.A < 0)");
n = pn.getChild(0).getChild(0);
assertTrue(n instanceof NestLoopPlanNode);
nl = (NestLoopPlanNode) n;
p = nl.getJoinPredicate();
assertEquals(ExpressionType.CONJUNCTION_AND, p.getExpressionType());
if (ExpressionType.CONJUNCTION_OR == p.getLeft().getExpressionType()) {
assertEquals(ExpressionType.CONJUNCTION_OR, p.getLeft().getExpressionType());
} else {
assertEquals(ExpressionType.CONJUNCTION_OR, p.getRight().getExpressionType());
}
assertNull(nl.getWherePredicate());
assertEquals(2, nl.getChildCount());
c0 = (SeqScanPlanNode) nl.getChild(0);
assertNull(c0.getPredicate());
c1 = (SeqScanPlanNode) nl.getChild(1);
assertNull(c1.getPredicate());
// R1.C = R2.C Inner-Outer join Expr stays at the NLJ as Join predicate
// R1.A > 0 Outer Where Expr is pushed down to the outer SeqScan node
// R2.A IS NULL Inner Where Expr stays at the the NLJ as post join (where) predicate
// (R1.C > R2.C OR R2.C IS NULL) Inner-Outer Where stays at the the NLJ as post join (where) predicate
pn = compile("select * FROM R1 LEFT JOIN R2 ON R1.C = R2.C WHERE R1.A > 0 AND R2.A IS NULL AND (R1.C > R2.C OR R2.C IS NULL)");
n = pn.getChild(0).getChild(0);
assertTrue(n instanceof NestLoopPlanNode);
nl = (NestLoopPlanNode) n;
assertEquals(JoinType.LEFT, nl.getJoinType());
assertNotNull(nl.getJoinPredicate());
p = nl.getJoinPredicate();
assertEquals(ExpressionType.COMPARE_EQUAL, p.getExpressionType());
AbstractExpression w = nl.getWherePredicate();
assertNotNull(w);
assertEquals(ExpressionType.CONJUNCTION_AND, w.getExpressionType());
assertEquals(ExpressionType.OPERATOR_IS_NULL, w.getRight().getExpressionType());
assertEquals(ExpressionType.CONJUNCTION_OR, w.getLeft().getExpressionType());
assertEquals(2, nl.getChildCount());
c0 = (SeqScanPlanNode) nl.getChild(0);
assertEquals(ExpressionType.COMPARE_GREATERTHAN, c0.getPredicate().getExpressionType());
c1 = (SeqScanPlanNode) nl.getChild(1);
assertNull(c1.getPredicate());
// R3.A = R2.A Inner-Outer index join Expr. NLJ predicate.
// R3.A > 3 Index Outer where expr pushed down to IndexScanPlanNode
// R3.C < 0 non-index Outer where expr pushed down to IndexScanPlanNode as a predicate
pn = compile("select * FROM R3 LEFT JOIN R2 ON R3.A = R2.A WHERE R3.A > 3 AND R3.C < 0");