*** a/src/backend/executor/nodeNestloop.c --- b/src/backend/executor/nodeNestloop.c *************** *** 26,31 **** --- 26,141 ---- #include "utils/memutils.h" + TupleTableSlot * + ExecNewMergeJoin(NestLoopState *node) + { + List *joinqual; + List *otherqual; + bool qualResult; + int compareResult; + PlanState *innerPlan; + TupleTableSlot *innerTupleSlot; + PlanState *outerPlan; + TupleTableSlot *outerTupleSlot; + ExprContext *econtext; + static bool newOuter = true; + static bool markpos = true; + + + /* + * get information from node + */ + innerPlan = innerPlanState(node); + outerPlan = outerPlanState(node); + econtext = node->js.ps.ps_ExprContext; + joinqual = node->js.joinqual; + otherqual = node->js.ps.qual; + + /* + * Check to see if we're still projecting out tuples from a previous join + * tuple (because there is a function-returning-set in the projection + * expressions). If so, try to project another one. + */ + if (node->js.ps.ps_TupFromTlist) + { + TupleTableSlot *result; + ExprDoneCond isDone; + + result = ExecProject(node->js.ps.ps_ProjInfo, &isDone); + if (isDone == ExprMultipleResult) + return result; + /* Done with that source tuple... */ + node->js.ps.ps_TupFromTlist = false; + } + + /* + * Reset per-tuple memory context to free any expression evaluation + * storage allocated in the previous tuple cycle. Note this can't happen + * until we're done projecting out tuples from a join tuple. + */ + ResetExprContext(econtext); + + /* + * ok, everything is setup.. let's go to work + */ + for (;;) + { + if (newOuter) + { + outerTupleSlot = ExecProcNode(outerPlan); + node->nl_OuterTupleSlot = outerTupleSlot; + if (TupIsNull(outerTupleSlot)) + { + return NULL; + } + + newOuter = false; + markpos = true; + + ExecRestrPos(innerPlan); + } + + innerTupleSlot = ExecProcNode(innerPlan); + node->nl_InnerTupleSlot = innerTupleSlot; + if (TupIsNull(innerTupleSlot)) + { + newOuter = true; + continue; + + } + + outerTupleSlot = node->nl_OuterTupleSlot; + innerTupleSlot = node->nl_InnerTupleSlot; + econtext->ecxt_outertuple = outerTupleSlot; + econtext->ecxt_innertuple = innerTupleSlot; + + qualResult = ExecQual(joinqual, econtext, false); + if (qualResult) + { + TupleTableSlot *result; + ExprDoneCond isDone; + + if (markpos) + { + ExecMarkPos(innerPlan); + //MarkInnerTuple(node->nl_InnerTupleSlot, node); + ExecCopySlot(node->nl_MarkedTupleSlot, innerTupleSlot); + markpos = false; + } + + result = ExecProject(node->js.ps.ps_ProjInfo, + &isDone); + if (isDone != ExprEndResult) + { + node->js.ps.ps_TupFromTlist = + (isDone == ExprMultipleResult); + return result; + } + } + } + } + + /* ---------------------------------------------------------------- * ExecNestLoop(node) * *************** *** 69,74 **** ExecNestLoop(NestLoopState *node) --- 179,187 ---- ExprContext *econtext; ListCell *lc; + if (node->sorted_child) + return ExecNewMergeJoin(node); + /* * get information from the node */ *************** *** 381,386 **** ExecInitNestLoop(NestLoop *node, EState *estate, int eflags) --- 494,507 ---- nlstate->nl_NeedNewOuter = true; nlstate->nl_MatchedOuter = false; + if (node->sorted_child) + { + nlstate->nl_MarkedTupleSlot = ExecInitExtraTupleSlot(estate); + nlstate->nl_InnerTupleSlot = ExecInitExtraTupleSlot(estate); + nlstate->nl_OuterTupleSlot = ExecInitExtraTupleSlot(estate); + nlstate->sorted_child = true; + } + NL1_printf("ExecInitNestLoop: %s\n", "node initialized"); *** a/src/backend/optimizer/plan/createplan.c --- b/src/backend/optimizer/plan/createplan.c *************** *** 1252,1277 **** create_indexscan_plan(PlannerInfo *root, replace_nestloop_params(root, (Node *) indexorderbys); } ! /* Finally ready to build the plan node */ ! if (indexonly) ! scan_plan = (Scan *) make_indexonlyscan(tlist, qpqual, baserelid, indexoid, fixed_indexquals, fixed_indexorderbys, ! best_path->indexinfo->indextlist, best_path->indexscandir); ! else ! scan_plan = (Scan *) make_indexscan(tlist, ! qpqual, ! baserelid, ! indexoid, ! fixed_indexquals, ! stripped_indexquals, ! fixed_indexorderbys, ! indexorderbys, ! best_path->indexscandir); copy_path_costsize(&scan_plan->plan, &best_path->path); --- 1252,1292 ---- replace_nestloop_params(root, (Node *) indexorderbys); } ! if (!enable_material) ! { ! scan_plan = (Scan *) make_indexscan(tlist, ! NULL, ! baserelid, ! indexoid, ! NULL, ! NULL, ! NULL, ! NULL, ! best_path->indexscandir); ! } ! else ! { ! /* Finally ready to build the plan node */ ! if (indexonly) ! scan_plan = (Scan *) make_indexonlyscan(tlist, ! qpqual, ! baserelid, ! indexoid, ! fixed_indexquals, ! fixed_indexorderbys, ! best_path->indexinfo->indextlist, ! best_path->indexscandir); ! else ! scan_plan = (Scan *) make_indexscan(tlist, qpqual, baserelid, indexoid, fixed_indexquals, + stripped_indexquals, fixed_indexorderbys, ! indexorderbys, best_path->indexscandir); ! } copy_path_costsize(&scan_plan->plan, &best_path->path); *************** *** 2091,2096 **** create_nestloop_plan(PlannerInfo *root, --- 2106,2153 ---- prev = cell; } + if (!enable_material) + { + int numsortkeys = 1; + AttrNumber *sortColIdx = palloc(sizeof(AttrNumber)); + Oid *sortOperators = palloc(sizeof(Oid)); + Oid *collations = palloc(sizeof(Oid)); + bool *nullsFirst = palloc(sizeof(bool)); + double limit_tuples = -1; + + sortColIdx[0] = 1; + sortOperators[0] = 97; + collations[0] = 0; + nullsFirst[0] = 0; + + + if (outer_plan->type != T_IndexScan) + { + outer_plan = make_sort(root, + outer_plan, + numsortkeys, + sortColIdx, + sortOperators, + collations, + nullsFirst, + limit_tuples); + } + + if (inner_plan->type != T_IndexScan) + { + inner_plan = make_sort(root, + inner_plan, + numsortkeys, + sortColIdx, + sortOperators, + collations, + nullsFirst, + limit_tuples); + } + + } + + join_plan = make_nestloop(tlist, joinclauses, otherclauses, *************** *** 2101,2106 **** create_nestloop_plan(PlannerInfo *root, --- 2158,2168 ---- copy_path_costsize(&join_plan->join.plan, &best_path->path); + if (!enable_material) + join_plan->sorted_child = true; + else + join_plan->sorted_child = false; + return join_plan; } *** a/src/include/nodes/execnodes.h --- b/src/include/nodes/execnodes.h *************** *** 1533,1538 **** typedef struct NestLoopState --- 1533,1542 ---- bool nl_NeedNewOuter; bool nl_MatchedOuter; TupleTableSlot *nl_NullInnerTupleSlot; + bool sorted_child; + TupleTableSlot *nl_InnerTupleSlot; + TupleTableSlot *nl_OuterTupleSlot; + TupleTableSlot *nl_MarkedTupleSlot; } NestLoopState; /* ---------------- *** a/src/include/nodes/plannodes.h --- b/src/include/nodes/plannodes.h *************** *** 524,529 **** typedef struct NestLoop --- 524,530 ---- { Join join; List *nestParams; /* list of NestLoopParam nodes */ + bool sorted_child; } NestLoop; typedef struct NestLoopParam