Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 19924 Details for
Bug 32248
postgresql-7.3.4-r1.ebuild (Update)
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch to PostgreSQL: recursive queries
hier-Pg7.3.1-0.3.diff (text/plain), 104.59 KB, created by
Christian Andreetta (RETIRED)
on 2003-10-29 01:34:05 UTC
(
hide
)
Description:
Patch to PostgreSQL: recursive queries
Filename:
MIME Type:
Creator:
Christian Andreetta (RETIRED)
Created:
2003-10-29 01:34:05 UTC
Size:
104.59 KB
patch
obsolete
>diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/commands/explain.c postgresql-7.3.1-evg/src/backend/commands/explain.c >*** postgresql-7.3.1/src/backend/commands/explain.c Thu Dec 12 20:16:58 2002 >--- postgresql-7.3.1-evg/src/backend/commands/explain.c Thu Dec 26 17:02:14 2002 >*************** >*** 306,311 **** >--- 306,314 ---- > case T_Hash: > pname = "Hash"; > break; >+ case T_Conn: >+ pname = "Hier"; >+ break; > default: > pname = "???"; > break; >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/executor/Makefile postgresql-7.3.1-evg/src/backend/executor/Makefile >*** postgresql-7.3.1/src/backend/executor/Makefile Mon May 13 04:43:02 2002 >--- postgresql-7.3.1-evg/src/backend/executor/Makefile Thu Dec 26 17:02:14 2002 >*************** >*** 18,24 **** > nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \ > nodeNestloop.o nodeFunctionscan.o nodeResult.o nodeSeqscan.o \ > nodeSetOp.o nodeSort.o nodeUnique.o nodeLimit.o nodeGroup.o \ >! nodeSubplan.o nodeSubqueryscan.o nodeTidscan.o spi.o > > all: SUBSYS.o > >--- 18,24 ---- > nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \ > nodeNestloop.o nodeFunctionscan.o nodeResult.o nodeSeqscan.o \ > nodeSetOp.o nodeSort.o nodeUnique.o nodeLimit.o nodeGroup.o \ >! nodeSubplan.o nodeSubqueryscan.o nodeTidscan.o spi.o nodeConn.o > > all: SUBSYS.o > >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/executor/execAmi.c postgresql-7.3.1-evg/src/backend/executor/execAmi.c >*** postgresql-7.3.1/src/backend/executor/execAmi.c Fri Jun 21 01:29:27 2002 >--- postgresql-7.3.1-evg/src/backend/executor/execAmi.c Thu Dec 26 17:02:14 2002 >*************** >*** 37,42 **** >--- 37,43 ---- > #include "executor/nodeSubqueryscan.h" > #include "executor/nodeFunctionscan.h" > #include "executor/nodeUnique.h" >+ #include "executor/nodeConn.h" > > > /* ---------------------------------------------------------------- >*************** >*** 157,162 **** >--- 158,167 ---- > ExecReScanAppend((Append *) node, exprCtxt, parent); > break; > >+ case T_Conn: >+ ExecReScanConn((Conn *) node, exprCtxt, parent); >+ break; >+ > default: > elog(ERROR, "ExecReScan: node type %d not supported", > nodeTag(node)); >*************** >*** 208,213 **** >--- 213,222 ---- > ExecTidMarkPos((TidScan *) node); > break; > >+ case T_Conn: >+ ExecConnMarkPos((Conn *) node); >+ break; >+ > default: > /* don't make hard error unless caller asks to restore... */ > elog(LOG, "ExecMarkPos: node type %d not supported", >*************** >*** 248,253 **** >--- 257,266 ---- > > case T_Sort: > ExecSortRestrPos((Sort *) node); >+ break; >+ >+ case T_Conn: >+ ExecConnRestrPos((Conn *) node); > break; > > default: >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/executor/execProcnode.c postgresql-7.3.1-evg/src/backend/executor/execProcnode.c >*** postgresql-7.3.1/src/backend/executor/execProcnode.c Fri Jun 21 01:29:27 2002 >--- postgresql-7.3.1-evg/src/backend/executor/execProcnode.c Thu Dec 26 17:02:14 2002 >*************** >*** 100,105 **** >--- 100,106 ---- > #include "executor/nodeUnique.h" > #include "miscadmin.h" > #include "tcop/tcopprot.h" >+ #include "executor/nodeConn.h" > > /* ------------------------------------------------------------------------ > * ExecInitNode >*************** >*** 224,229 **** >--- 225,234 ---- > result = ExecInitAgg((Agg *) node, estate, parent); > break; > >+ case T_Conn: >+ result = ExecInitConn((Conn *) node, estate, parent); >+ break; >+ > default: > elog(ERROR, "ExecInitNode: node type %d unsupported", > (int) nodeTag(node)); >*************** >*** 357,362 **** >--- 362,371 ---- > result = ExecAgg((Agg *) node); > break; > >+ case T_Conn: >+ result = ExecConn((Conn *) node); >+ break; >+ > default: > elog(ERROR, "ExecProcNode: node type %d unsupported", > (int) nodeTag(node)); >*************** >*** 444,449 **** >--- 453,461 ---- > case T_Agg: > return ExecCountSlotsAgg((Agg *) node); > >+ case T_Conn: >+ return ExecCountSlotsConn((Conn *) node); >+ > default: > elog(ERROR, "ExecCountSlotsNode: node type %d unsupported", > (int) nodeTag(node)); >*************** >*** 570,575 **** >--- 582,591 ---- > ExecEndAgg((Agg *) node); > break; > >+ case T_Conn: >+ ExecEndConn((Conn *) node); >+ break; >+ > default: > elog(ERROR, "ExecEndNode: node type %d unsupported", > (int) nodeTag(node)); >*************** >*** 745,750 **** >--- 761,774 ---- > } > break; > >+ case T_Conn: >+ { >+ ConnectState *connstate = ((Conn *) node)->connstate; >+ >+ slot = connstate->csstate.cstate.cs_ResultTupleSlot; >+ } >+ break; >+ > default: > > /* >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/executor/execQual.c postgresql-7.3.1-evg/src/backend/executor/execQual.c >*** postgresql-7.3.1/src/backend/executor/execQual.c Thu Sep 5 01:31:17 2002 >--- postgresql-7.3.1-evg/src/backend/executor/execQual.c Wed Jan 15 18:25:13 2003 >*************** >*** 52,57 **** >--- 52,58 ---- > static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext, > bool *isNull, ExprDoneCond *isDone); > static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull); >+ static Datum ExecEvalFakeVar(FakeVar *variable, ExprContext *econtext, bool *isNull); > static Datum ExecEvalOper(Expr *opClause, ExprContext *econtext, > bool *isNull, ExprDoneCond *isDone); > static Datum ExecEvalDistinct(Expr *opClause, ExprContext *econtext, >*************** >*** 359,364 **** >--- 360,366 ---- > * We assume it's OK to point to the existing tupleDescriptor, rather > * than copy that too. > */ >+ > if (attnum == InvalidAttrNumber) > { > MemoryContext oldContext; >*************** >*** 373,378 **** >--- 375,436 ---- > MemoryContextSwitchTo(oldContext); > return PointerGetDatum(tempSlot); > } >+ result = heap_getattr(heapTuple, /* tuple containing attribute */ >+ attnum, /* attribute number of desired >+ * attribute */ >+ tuple_type, /* tuple descriptor of tuple */ >+ isNull); /* return: is attribute null? */ >+ return result; >+ } >+ >+ /* Same as ExecEvalVar but returns only value from current tuple, or >+ * (Datum) ) if tuple slot if undefined. >+ */ >+ static Datum >+ ExecEvalFakeVar(FakeVar *variable, ExprContext *econtext, bool *isNull) >+ { >+ Datum result; >+ TupleTableSlot *slot; >+ AttrNumber attnum; >+ HeapTuple heapTuple; >+ TupleDesc tuple_type; >+ /* >+ * get the slot we want >+ */ >+ /* FakeVars can't be OUTER or INNER so get the tuple only from >+ * the relation being scanned. >+ */ >+ slot = econtext->ecxt_scantuple; >+ >+ /* if slot is undefined, then we're on layer under Hier where FakeVar not really exist, >+ * so show our fake nature, and return 0. >+ */ >+ if(!slot){ >+ if(variable->vartype != INT4OID) >+ elog(ERROR,"ExecEvalFakeVar: FakeVars with type other than INT4 not supported (internal error)"); >+ return Int32GetDatum(0); >+ } >+ /* >+ * extract tuple information from the slot >+ */ >+ heapTuple = slot->val; >+ tuple_type = slot->ttc_tupleDescriptor; >+ >+ attnum = variable->varattno; >+ >+ /* (See prolog of ExecEvalVar for explanation of this Assert) */ >+ >+ >+ if(attnum - 1 >= tuple_type->natts ){ >+ return Int32GetDatum(0); >+ } >+ Assert(attnum <= 0 || >+ (attnum - 1 <= tuple_type->natts - 1 && >+ tuple_type->attrs[attnum - 1] != NULL && >+ variable->vartype == tuple_type->attrs[attnum - 1]->atttypid)); >+ >+ if (attnum == InvalidAttrNumber) >+ elog(ERROR,"ExecEvalFakeVar: invalid attnum %u (internal error)",attnum); > > result = heap_getattr(heapTuple, /* tuple containing attribute */ > attnum, /* attribute number of desired >*************** >*** 1680,1685 **** >--- 1738,1746 ---- > { > case T_Var: > retDatum = ExecEvalVar((Var *) expression, econtext, isNull); >+ break; >+ case T_FakeVar: >+ retDatum = ExecEvalFakeVar((FakeVar *) expression, econtext, isNull); > break; > case T_Const: > { >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/executor/nodeConn.c postgresql-7.3.1-evg/src/backend/executor/nodeConn.c >*** postgresql-7.3.1/src/backend/executor/nodeConn.c Thu Jan 1 04:00:00 1970 >--- postgresql-7.3.1-evg/src/backend/executor/nodeConn.c Thu Dec 26 17:02:14 2002 >*************** >*** 0 **** >--- 1,344 ---- >+ /*------------------------------------------------------------------------- * >+ * nodeConn.c >+ * Routines to handle connecting of relations. >+ * >+ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group >+ * Portions Copyright (c) 1994, Regents of the University of California >+ * >+ * Based on nodeSort.c, by Evgen Potemkin evgent@terminal.ru, 11.2002 >+ * >+ *------------------------------------------------------------------------- >+ */ >+ >+ #include "postgres.h" >+ >+ #include "executor/execdebug.h" >+ #include "executor/nodeConn.h" >+ #include "utils/tupleconn.h" >+ #include "miscadmin.h" >+ #include "utils/memutils.h" >+ >+ #include "nodes/print.h" >+ >+ /* ---------------------------------------------------------------- >+ * ExecConn >+ * >+ * Connects tuples from the outer subtree of the node using tupleconn, >+ * which saves the results in a temporary file or memory. After the >+ * initial call, returns a tuple from the file with each call. >+ * >+ * Conditions: >+ * -- none. >+ * >+ * Initial States: >+ * -- the outer child is prepared to return the first tuple. >+ * ---------------------------------------------------------------- >+ */ >+ TupleTableSlot * >+ ExecConn(Conn *node) >+ { >+ EState *estate; >+ TupleTableSlot *slot; >+ HeapTuple heapTuple; >+ Plan *outerNode; >+ ConnectState *connstate; >+ ScanDirection dir; >+ Tupleconnstate *tupleconnstate; >+ bool should_free; >+ List *squal; >+ ExprContext *econtext; >+ int head; >+ bool ok; >+ >+ /* >+ * get state info from node >+ */ >+ >+ estate = node->plan.state; >+ dir = estate->es_direction; >+ connstate=node->connstate; >+ tupleconnstate = (Tupleconnstate *) connstate->tupleconnstate; >+ >+ if (!connstate->conn_Done) >+ { >+ TupleDesc tupDesc; >+ >+ SO1_printf("ExecConn: %s\n", >+ "connecting subplan"); >+ >+ /* >+ * Want to scan subplan in the forward direction while creating >+ * the data for processing. >+ */ >+ >+ /* >+ * Initialize tupleconn module. >+ */ >+ SO1_printf("ExecConn: %s\n", >+ "calling tupleconn_begin"); >+ >+ outerNode = outerPlan((Plan *) node); >+ tupDesc = ExecGetTupType(outerNode); >+ >+ tupleconnstate = tupleconn_begin_heap(SortMem,tupDesc,node->connOp); >+ connstate->tupleconnstate = (void *) tupleconnstate; >+ >+ >+ /* >+ * Scan the subplan and feed all the tuples to tupleconn. >+ */ >+ squal=(List *)node->startQual; >+ >+ econtext = connstate->csstate.cstate.cs_ExprContext; >+ >+ ResetExprContext(econtext); >+ >+ for (;;) >+ { >+ slot = ExecProcNode(outerNode, (Plan *) node); >+ >+ if (TupIsNull(slot)) >+ break; >+ econtext->ecxt_scantuple = slot; >+ /* check if tuple is a head of tree */ >+ head = ExecQual(squal, econtext, false); >+ /* store it */ >+ tupleconn_puttuple(tupleconnstate, (void *) slot->val,head); >+ } >+ >+ ExecAssignResultType(&connstate->csstate.cstate, tupDesc, false); >+ >+ tupleconn_donestoring(tupleconnstate); >+ /* connect them. >+ * parentExpr, childExpr, econtext is not needed in tupleconn, >+ * so pass them only for connecting stage. >+ */ >+ tupleconn_performconn(tupleconnstate,node->parentExpr,node->childExpr,econtext); >+ /* >+ * finally set the connected flag to true >+ */ >+ connstate->conn_Done = true; >+ SO1_printf(stderr, "ExecConn: connecting done.\n"); >+ } >+ SO1_printf("ExecConn: %s\n", >+ "retrieving tuple from tupleconn"); >+ >+ /* >+ * Get the first or next tuple from tupleconn. Returns NULL if no more >+ * tuples. >+ */ >+ squal = ((Plan *)node)->qual; >+ ok=0; >+ econtext = connstate->csstate.cstate.cs_ExprContext; >+ /* everywhere here slot is the same pointer, so get it here */ >+ slot = connstate->csstate.cstate.cs_ResultTupleSlot; >+ /* Apply HAVING clause to post-qual tuples */ >+ do{ >+ /* if qual present, clear context */ >+ if(squal) ResetExprContext(econtext); >+ heapTuple = tupleconn_getheaptuple(tupleconnstate, >+ &should_free); >+ ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free); >+ if(!squal) break; /* don't qual */ >+ if(!heapTuple) break; /* no more tuples */ >+ econtext->ecxt_scantuple = slot; >+ /* if tuple satisfy qual, pass it, else get next */ >+ ok=ExecQual(squal, econtext, false); >+ }while(!ok); >+ >+ if(squal) ResetExprContext(econtext); >+ return slot; >+ } >+ >+ /* Everything below is same as nodeSort.c >+ */ >+ /* ---------------------------------------------------------------- >+ * ExecInitConn >+ * >+ * Creates the run-time state information for the conn node >+ * produced by the planner and initailizes its outer subtree. >+ * ---------------------------------------------------------------- >+ */ >+ bool >+ ExecInitConn(Conn *node, EState *estate, Plan *parent) >+ { >+ ConnectState *connstate; >+ Plan *outerPlan; >+ >+ SO1_printf("ExecInitConn: %s\n", >+ "initializing conn node"); >+ /* >+ * assign the node's execution state >+ */ >+ node->plan.state = estate; >+ >+ /* >+ * create state structure >+ */ >+ connstate = makeNode(ConnectState); >+ connstate->conn_Done = false; >+ connstate->tupleconnstate = NULL; >+ >+ node->connstate=connstate; >+ /* >+ * Miscellaneous initialization >+ */ >+ ExecAssignExprContext(estate, &connstate->csstate.cstate); >+ #define CONN_NSLOTS 2 >+ >+ /* >+ * tuple table initialization >+ */ >+ ExecInitResultTupleSlot(estate, &connstate->csstate.cstate); >+ ExecInitScanTupleSlot(estate, &connstate->csstate); >+ /* >+ * initializes child nodes >+ */ >+ outerPlan = outerPlan((Plan *) node); >+ ExecInitNode(outerPlan, estate, (Plan *) node); >+ >+ /* >+ * initialize tuple type. no need to initialize projection info >+ * because this node doesn't do projections. >+ */ >+ ExecAssignResultTypeFromOuterPlan((Plan *) node, &connstate->csstate.cstate); >+ ExecAssignScanTypeFromOuterPlan((Plan *) node, &connstate->csstate); >+ connstate->csstate.cstate.cs_ProjInfo = NULL; >+ >+ SO1_printf("ExecInitConn: %s\n", >+ "conn node initialized"); >+ >+ return TRUE; >+ } >+ >+ int >+ ExecCountSlotsConn(Conn *node) >+ { >+ return ExecCountSlotsNode(outerPlan((Plan *) node)) + >+ ExecCountSlotsNode(innerPlan((Plan *) node))+CONN_NSLOTS; >+ } >+ >+ /* ---------------------------------------------------------------- >+ * ExecEndConn(node) >+ * ---------------------------------------------------------------- >+ */ >+ void >+ ExecEndConn(Conn *node) >+ { >+ Plan *outerPlan; >+ ConnectState *connstate; >+ >+ /* >+ * get info from the conn state >+ */ >+ SO1_printf("ExecEndConn: %s\n", >+ "shutting down conn node"); >+ connstate=node->connstate; >+ >+ /* >+ * shut down the subplan >+ */ >+ outerPlan = outerPlan((Plan *) node); >+ ExecEndNode(outerPlan, (Plan *) node); >+ >+ /* >+ * clean out the tuple table >+ */ >+ ExecClearTuple(connstate->csstate.cstate.cs_ResultTupleSlot); >+ ExecClearTuple(connstate->csstate.css_ScanTupleSlot); >+ >+ /* >+ * Release tupleconn resources >+ */ >+ if (connstate->tupleconnstate != NULL) >+ tupleconn_end((Tupleconnstate *) connstate->tupleconnstate); >+ connstate->tupleconnstate = NULL; >+ >+ pfree(connstate); >+ node->connstate = NULL; >+ >+ SO1_printf("ExecEndConn: %s\n", >+ "conn node shutdown"); >+ } >+ >+ /* ---------------------------------------------------------------- >+ * ExecConnMarkPos >+ * >+ * Calls tupleconn to save the current position in the processed file. >+ * ---------------------------------------------------------------- >+ */ >+ void >+ ExecConnMarkPos(Conn *node) >+ { >+ ConnectState *connstate = node->connstate; >+ >+ /* >+ * if we haven't processed yet, just return >+ */ >+ if (!connstate->conn_Done) >+ return; >+ >+ tupleconn_markpos((Tupleconnstate *) connstate->tupleconnstate); >+ } >+ >+ /* ---------------------------------------------------------------- >+ * ExecConnRestrPos >+ * >+ * Calls tupleconn to restore the last saved processed file position. >+ * ---------------------------------------------------------------- >+ */ >+ void >+ ExecConnRestrPos(Conn *node) >+ { >+ ConnectState *connstate = node->connstate; >+ >+ /* >+ * if we haven't processed yet, just return. >+ */ >+ if (!connstate->conn_Done) >+ return; >+ >+ /* >+ * restore the scan to the previously marked position >+ */ >+ tupleconn_restorepos((Tupleconnstate *) connstate->tupleconnstate); >+ } >+ >+ void >+ ExecReScanConn(Conn *node, ExprContext *exprCtxt, Plan *parent) >+ { >+ ConnectState *connstate = node->connstate; >+ >+ /* >+ * If we haven't processed yet, just return. If outerplan' chgParam is >+ * not NULL then it will be re-scanned by ExecProcNode, else - no >+ * reason to re-scan it at all. >+ */ >+ if (!connstate->conn_Done) >+ return; >+ >+ ExecClearTuple(node->connstate->csstate.cstate.cs_ResultTupleSlot); >+ >+ /* >+ * If subnode is to be rescanned then we forget previous process results; >+ * we have to re-read the subplan and re-connect. >+ * >+ * Otherwise we can just rewind and rescan the processed output. >+ */ >+ >+ if (((Plan *) node)->lefttree->chgParam != NULL) >+ { >+ connstate->conn_Done = false; >+ tupleconn_end((Tupleconnstate *) connstate->tupleconnstate); >+ connstate->tupleconnstate = NULL; >+ } >+ else >+ tupleconn_rescan((Tupleconnstate *) connstate->tupleconnstate); >+ >+ /* >+ * if chgParam of subnode is not null then plan will be re-scanned by >+ * first ExecProcNode. >+ */ >+ if (((Plan *) node)->lefttree->chgParam == NULL) >+ ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node); >+ } >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/nodes/copyfuncs.c postgresql-7.3.1-evg/src/backend/nodes/copyfuncs.c >*** postgresql-7.3.1/src/backend/nodes/copyfuncs.c Tue Oct 15 03:14:34 2002 >--- postgresql-7.3.1-evg/src/backend/nodes/copyfuncs.c Thu Dec 26 17:02:14 2002 >*************** >*** 465,470 **** >--- 465,493 ---- > return newnode; > } > >+ /* ---------------- >+ * _copyConn >+ * ---------------- >+ */ >+ static Conn * >+ _copyConn(Conn *from) >+ { >+ Conn *newnode = makeNode(Conn); >+ /* >+ * copy node superclass fields >+ */ >+ CopyPlanFields((Plan *) from, (Plan *) newnode); >+ >+ Node_Copy(from,newnode,startQual); >+ >+ Node_Copy(from,newnode,parentExpr); >+ Node_Copy(from,newnode,childExpr); >+ >+ newnode->connOp = from->connOp; >+ >+ return newnode; >+ } >+ > > /* ---------------- > * _copySort >*************** >*** 751,756 **** >--- 774,798 ---- > } > > /* ---------------- >+ * _copyVar >+ * ---------------- >+ */ >+ static FakeVar * >+ _copyFakeVar(FakeVar *from) >+ { >+ FakeVar *newnode = makeNode(FakeVar); >+ >+ /* >+ * copy remainder of node >+ */ >+ newnode->varattno = from->varattno; >+ newnode->vartype = from->vartype; >+ newnode->vartypmod = from->vartypmod; >+ >+ return newnode; >+ } >+ >+ /* ---------------- > * _copyOper > * ---------------- > */ >*************** >*** 1493,1498 **** >--- 1535,1556 ---- > return newnode; > } > >+ /* see _equalHierClause */ >+ static HierClause * >+ _copyHierClause(HierClause *from) >+ { >+ HierClause *newnode = makeNode(HierClause); >+ >+ Node_Copy(from,newnode,startQual); >+ >+ Node_Copy(from,newnode,parentExpr); >+ Node_Copy(from,newnode,childExpr); >+ >+ newnode->connOp = from->connOp; >+ >+ return newnode; >+ } >+ > static SortClause * > _copySortClause(SortClause *from) > { >*************** >*** 1802,1807 **** >--- 1860,1867 ---- > Node_Copy(from, newnode, limitOffset); > Node_Copy(from, newnode, limitCount); > >+ Node_Copy(from, newnode, hierClause); >+ > Node_Copy(from, newnode, setOperations); > > newnode->resultRelations = listCopy(from->resultRelations); >*************** >*** 2807,2812 **** >--- 2867,2878 ---- > case T_SubPlan: > retval = _copySubPlan(from); > break; >+ case T_Conn: >+ retval = _copyConn(from); >+ break; >+ case T_HierClause: >+ retval = _copyHierClause(from); >+ break; > > /* > * PRIMITIVE NODES >*************** >*** 2819,2824 **** >--- 2885,2893 ---- > break; > case T_Expr: > retval = _copyExpr(from); >+ break; >+ case T_FakeVar: >+ retval = _copyFakeVar(from); > break; > case T_Var: > retval = _copyVar(from); >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/nodes/equalfuncs.c postgresql-7.3.1-evg/src/backend/nodes/equalfuncs.c >*** postgresql-7.3.1/src/backend/nodes/equalfuncs.c Tue Oct 15 03:14:34 2002 >--- postgresql-7.3.1-evg/src/backend/nodes/equalfuncs.c Thu Dec 26 17:02:14 2002 >*************** >*** 124,129 **** >--- 124,142 ---- > } > > static bool >+ _equalFakeVar(FakeVar *a, FakeVar *b) >+ { >+ if (a->varattno != b->varattno) >+ return false; >+ if (a->vartype != b->vartype) >+ return false; >+ if (a->vartypmod != b->vartypmod) >+ return false; >+ >+ return true; >+ } >+ >+ static bool > _equalOper(Oper *a, Oper *b) > { > if (a->opno != b->opno) >*************** >*** 609,614 **** >--- 622,629 ---- > return false; > if (!equal(a->limitCount, b->limitCount)) > return false; >+ if (!equal(a->hierClause, b->hierClause)) >+ return false; > if (!equal(a->setOperations, b->setOperations)) > return false; > if (!equali(a->resultRelations, b->resultRelations)) >*************** >*** 624,629 **** >--- 639,663 ---- > } > > static bool >+ _equalHierClause(HierClause *a, HierClause *b) >+ { >+ if (!equal(a->startQual, b->startQual)) >+ return false; >+ if (!equal(a->parentExpr, b->parentExpr)) >+ return false; >+ if (!equal(a->childExpr, b->childExpr)) >+ return false; >+ /* we can skip comparing the connOpName because in the DB >+ * can't exist at the same time several operators with >+ * same name and parameters, it's checked by PG. >+ */ >+ if (a->connOp != b->connOp) >+ return false; >+ >+ return true; >+ } >+ >+ static bool > _equalInsertStmt(InsertStmt *a, InsertStmt *b) > { > if (!equal(a->relation, b->relation)) >*************** >*** 2033,2038 **** >--- 2067,2075 ---- > case T_Var: > retval = _equalVar(a, b); > break; >+ case T_FakeVar: >+ retval = _equalFakeVar(a, b); >+ break; > case T_Oper: > retval = _equalOper(a, b); > break; >*************** >*** 2432,2437 **** >--- 2469,2477 ---- > break; > case T_InsertDefault: > retval = _equalInsertDefault(a, b); >+ break; >+ case T_HierClause: >+ retval = _equalHierClause(a, b); > break; > > default: >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/nodes/outfuncs.c postgresql-7.3.1-evg/src/backend/nodes/outfuncs.c >*** postgresql-7.3.1/src/backend/nodes/outfuncs.c Tue Oct 15 03:14:34 2002 >--- postgresql-7.3.1-evg/src/backend/nodes/outfuncs.c Thu Dec 26 17:02:14 2002 >*************** >*** 295,300 **** >--- 295,303 ---- > appendStringInfo(str, " :limitCount "); > _outNode(str, node->limitCount); > >+ appendStringInfo(str, " :hierClause "); >+ _outNode(str, node->hierClause); >+ > appendStringInfo(str, " :setOperations "); > _outNode(str, node->setOperations); > >*************** >*** 305,310 **** >--- 308,328 ---- > } > > static void >+ _outHierClause(StringInfo str, HierClause *node) >+ { >+ appendStringInfo(str, " HIERCLAUSE :startQual "); >+ _outNode(str, node->startQual); >+ >+ appendStringInfo(str, " :parentExpr "); >+ _outNode(str, node->parentExpr); >+ >+ appendStringInfo(str, " :childExpr "); >+ _outNode(str, node->childExpr); >+ >+ appendStringInfo(str, " :connOp %u ",node->connOp); >+ } >+ >+ static void > _outSortClause(StringInfo str, SortClause *node) > { > appendStringInfo(str, " SORTCLAUSE :tleSortGroupRef %u :sortop %u ", >*************** >*** 592,597 **** >--- 610,633 ---- > appendStringInfo(str, " :keycount %d ", node->keycount); > } > >+ /* >+ * Conn is a subclass of Plan >+ */ >+ static void >+ _outConn(StringInfo str, Conn *node) >+ { >+ appendStringInfo(str, " CONN "); >+ _outPlanInfo(str, (Plan *) node); >+ appendStringInfo(str, " :startQual "); >+ _outNode(str, node->startQual); >+ >+ appendStringInfo(str, " :parentExpr "); >+ _outNode(str, node->parentExpr); >+ appendStringInfo(str, " :childExpr "); >+ _outNode(str, node->childExpr); >+ appendStringInfo(str, " :connOp %u ",node->connOp); >+ } >+ > static void > _outAgg(StringInfo str, Agg *node) > { >*************** >*** 768,780 **** > node->vartype, > node->vartypmod); > >! appendStringInfo(str, " :varlevelsup %u :varnoold %u :varoattno %d", > node->varlevelsup, > node->varnoold, > node->varoattno); > } > > /* > * Const is a subclass of Expr > */ > static void >--- 804,829 ---- > node->vartype, > node->vartypmod); > >! appendStringInfo(str, " :varlevelsup %u :varnoold %u :varoattno %d ", > node->varlevelsup, > node->varnoold, > node->varoattno); > } > > /* >+ * FakeVar is a subclass of Expr >+ */ >+ static void >+ _outFakeVar(StringInfo str, FakeVar *node) >+ { >+ appendStringInfo(str, >+ " FAKEVAR :varattno %d :vartype %u :vartypmod %d ", >+ node->varattno, >+ node->vartype, >+ node->vartypmod); >+ } >+ >+ /* > * Const is a subclass of Expr > */ > static void >*************** >*** 1660,1665 **** >--- 1709,1717 ---- > case T_Var: > _outVar(str, obj); > break; >+ case T_FakeVar: >+ _outFakeVar(str, obj); >+ break; > case T_Const: > _outConst(str, obj); > break; >*************** >*** 1777,1782 **** >--- 1829,1840 ---- > case T_FuncCall: > _outFuncCall(str, obj); > break; >+ case T_Conn: >+ _outConn(str, obj); >+ break; >+ case T_HierClause: >+ _outHierClause(str, obj); >+ break; > > default: > elog(WARNING, "_outNode: don't know how to print type %d ", >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/nodes/readfuncs.c postgresql-7.3.1-evg/src/backend/nodes/readfuncs.c >*** postgresql-7.3.1/src/backend/nodes/readfuncs.c Tue Oct 15 03:14:34 2002 >--- postgresql-7.3.1-evg/src/backend/nodes/readfuncs.c Thu Dec 26 17:02:14 2002 >*************** >*** 183,188 **** >--- 183,191 ---- > token = pg_strtok(&length); /* skip :limitCount */ > local_node->limitCount = nodeRead(true); > >+ token = pg_strtok(&length); /* skip :hierClause */ >+ local_node->hierClause = nodeRead(true); >+ > token = pg_strtok(&length); /* skip :setOperations */ > local_node->setOperations = nodeRead(true); > >*************** >*** 195,200 **** >--- 198,232 ---- > } > > /* ---------------- >+ * _readHierClause >+ * ---------------- >+ */ >+ static HierClause * >+ _readHierClause(void) >+ { >+ HierClause *local_node; >+ char *token; >+ int length; >+ >+ local_node = makeNode(HierClause); >+ >+ token = pg_strtok(&length); /* skip :startQual */ >+ local_node->startQual = (Node *) nodeRead(true); /* get startQual */ >+ >+ token = pg_strtok(&length); /* skip :parentExpr */ >+ local_node->parentExpr = (Node *) nodeRead(true); /* get startQual */ >+ >+ token = pg_strtok(&length); /* skip :childExpr */ >+ local_node->childExpr = (Node *) nodeRead(true); /* get startQual */ >+ >+ token = pg_strtok(&length); /* skip :connOp */ >+ token = pg_strtok(&length); /* get connOp */ >+ local_node->connOp = atooid(token); >+ >+ return local_node; >+ } >+ >+ /* ---------------- > * _readNotifyStmt > * ---------------- > */ >*************** >*** 673,678 **** >--- 705,744 ---- > } > > /* ---------------- >+ * _readConn >+ * >+ * Conn is a subclass of Plan >+ * ---------------- >+ */ >+ static Conn * >+ _readConn(void) >+ { >+ Conn *local_node; >+ char *token; >+ int length; >+ >+ local_node = makeNode(Conn); >+ >+ _getPlan((Plan *) local_node); >+ >+ token = pg_strtok(&length); /* skip :startQual */ >+ local_node->startQual = nodeRead(true); /* get startQual */ >+ >+ token = pg_strtok(&length); /* skip :parentExpr */ >+ local_node->parentExpr = nodeRead(true); /* get startQual */ >+ >+ token = pg_strtok(&length); /* skip :childExpr */ >+ local_node->childExpr = nodeRead(true); /* get startQual */ >+ >+ >+ token = pg_strtok(&length); /* skip :connop */ >+ token = pg_strtok(&length); /* get connop */ >+ local_node->connOp = atoui(token); >+ >+ return local_node; >+ } >+ >+ /* ---------------- > * _readSort > * > * Sort is a subclass of Plan >*************** >*** 1013,1018 **** >--- 1079,1114 ---- > } > > /* ---------------- >+ * _readFakeVar >+ * >+ * FakeVar is a subclass of Expr >+ * ---------------- >+ */ >+ static FakeVar * >+ _readFakeVar(void) >+ { >+ FakeVar *local_node; >+ char *token; >+ int length; >+ >+ local_node = makeNode(FakeVar); >+ >+ token = pg_strtok(&length); /* eat :varattno */ >+ token = pg_strtok(&length); /* get varattno */ >+ local_node->varattno = atoi(token); >+ >+ token = pg_strtok(&length); /* eat :vartype */ >+ token = pg_strtok(&length); /* get vartype */ >+ local_node->vartype = atooid(token); >+ >+ token = pg_strtok(&length); /* eat :vartypmod */ >+ token = pg_strtok(&length); /* get vartypmod */ >+ local_node->vartypmod = atoi(token); >+ >+ return local_node; >+ } >+ >+ /* ---------------- > * _readArrayRef > * > * ArrayRef is a subclass of Expr >*************** >*** 2272,2277 **** >--- 2368,2379 ---- > return_value = _readBooleanTest(); > else if (length == 14 && strncmp(token, "CONSTRAINTTEST", length) == 0) > return_value = _readConstraintTest(); >+ else if (length == 4 && strncmp(token, "CONN", length) == 0) >+ return_value = _readConn(); >+ else if (length == 10 && strncmp(token, "HIERCLAUSE", length) == 0) >+ return_value = _readHierClause(); >+ else if (length == 7 && strncmp(token, "FAKEVAR", length) == 0) >+ return_value = _readFakeVar(); > else > elog(ERROR, "badly formatted planstring \"%.10s\"...", token); > >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/optimizer/path/costsize.c postgresql-7.3.1-evg/src/backend/optimizer/path/costsize.c >*** postgresql-7.3.1/src/backend/optimizer/path/costsize.c Thu Sep 5 01:31:20 2002 >--- postgresql-7.3.1-evg/src/backend/optimizer/path/costsize.c Thu Dec 26 17:02:14 2002 >*************** >*** 512,517 **** >--- 512,582 ---- > } > > >+ void >+ cost_conn(Path *path, Query *root, >+ List *pathkeys, double tuples, int width) >+ { >+ Cost startup_cost = 0; >+ Cost run_cost = 0; >+ double nbytes = relation_byte_size(tuples, width); >+ long sortmembytes = SortMem * 1024L; >+ double x,cmpamnt,i,j; >+ >+ /* >+ * We want to be sure the cost of a sort is never estimated as zero, >+ * even if passed-in tuple count is zero. Besides, mustn't do >+ * log(0)... >+ */ >+ if (tuples < 2.0) >+ tuples = 2.0; >+ >+ x = log(tuples)/log(log(tuples)); >+ x = floor(x); //number of runs, slightly overestimated >+ >+ cmpamnt=0.0; >+ for(i=1;i<x;i++) >+ for(j=0;j<x-i-1;j++) >+ cmpamnt+=pow(x,x-j); >+ cmpamnt=floor(cmpamnt/2);// rought amount of compares = half of worst case >+ if (cmpamnt < 1.0) >+ cmpamnt=1.0; >+ /* >+ * CPU costs >+ * >+ * assume: cost of comparation + cost of evaluating parent and child expr == >+ * 3 * cost of comparation >+ * cost is: 3 * cost of comparation * >+ * ( amount of compares + check every tuple for being top node ) >+ * if HAVING clause present then add cost of qualification of every tuple. >+ * assume we're connected all of input tuples, in real this may be not a true, so >+ * we're estimating the worst case. >+ */ >+ startup_cost += 3 * cpu_operator_cost * ( cmpamnt + tuples ); >+ if(root->havingQual){ >+ startup_cost += cpu_operator_cost * tuples; >+ } >+ >+ /* disk costs */ >+ if (nbytes > sortmembytes) >+ { >+ double npages = ceil(nbytes / BLCKSZ); >+ double npageaccesses; >+ >+ npageaccesses = 2.0 * npages * x; >+ /* Assume half are sequential (cost 1), half are not */ >+ startup_cost += npageaccesses * >+ (1.0 + cost_nonsequential_access(npages)) * 0.5; >+ } >+ >+ /* >+ * Note: should we bother to assign a nonzero run_cost to reflect the >+ * overhead of extracting tuples from the sort result? Probably not >+ * worth worrying about. >+ */ >+ path->startup_cost = startup_cost; >+ path->total_cost = startup_cost + run_cost; >+ } >+ > /* > * cost_nestloop > * Determines and returns the cost of joining two relations using the >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/optimizer/plan/createplan.c postgresql-7.3.1-evg/src/backend/optimizer/plan/createplan.c >*** postgresql-7.3.1/src/backend/optimizer/plan/createplan.c Fri Nov 15 06:37:08 2002 >--- postgresql-7.3.1-evg/src/backend/optimizer/plan/createplan.c Thu Dec 26 17:02:14 2002 >*************** >*** 833,838 **** >--- 833,839 ---- > case T_FunctionScan: > case T_Material: > case T_Sort: >+ case T_Conn: > /* OK, these inner plans support mark/restore */ > break; > >*************** >*** 1547,1552 **** >--- 1548,1597 ---- > node->keycount = keycount; > > return node; >+ } >+ >+ /* called in same terms as make_sort. >+ * copy fileds from HierClause to newly created Conn node, >+ * and calc costs >+ */ >+ Conn * >+ make_conn(Query *root, >+ List *tlist, >+ Plan *lefttree) >+ { >+ Conn *node = makeNode(Conn); >+ Plan *plan = &node->plan; >+ HierClause *hier = (HierClause *)root->hierClause; >+ >+ Path conn_path; /* dummy for result of cost_conn */ >+ >+ copy_plan_costsize(plan, lefttree); /* only care about copying size */ >+ cost_conn(&conn_path, root, NIL, >+ lefttree->plan_rows, lefttree->plan_width); >+ plan->startup_cost = conn_path.startup_cost + lefttree->startup_cost; >+ plan->total_cost = conn_path.total_cost + lefttree->total_cost; >+ >+ plan->plan_rows = lefttree->plan_rows; >+ plan->plan_width = lefttree->plan_width; >+ plan->state = (EState *) NULL; >+ plan->targetlist = tlist; >+ plan->qual = (List *)root->havingQual; >+ plan->lefttree = lefttree; >+ plan->righttree = NULL; >+ node->startQual = hier->startQual; >+ >+ if(length((List *)hier->parentExpr)>1) >+ elog(ERROR,"make_conn: parent expression can't be a list"); >+ else >+ node->parentExpr = lfirst((List *)hier->parentExpr); >+ >+ if(length((List *)hier->childExpr)>1) >+ elog(ERROR,"make_conn: parent expression can't be a list"); >+ else >+ node->childExpr = lfirst((List *)hier->childExpr); >+ >+ node->connOp = hier->connOp; >+ return node; > } > > /* >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/optimizer/plan/initsplan.c postgresql-7.3.1-evg/src/backend/optimizer/plan/initsplan.c >*** postgresql-7.3.1/src/backend/optimizer/plan/initsplan.c Thu Sep 5 01:31:21 2002 >--- postgresql-7.3.1-evg/src/backend/optimizer/plan/initsplan.c Thu Dec 26 17:02:14 2002 >*************** >*** 168,174 **** > foreach(temp, vars) > { > Var *var = (Var *) lfirst(temp); >! RelOptInfo *rel = find_base_rel(root, var->varno); > > add_var_to_tlist(rel, var); > >--- 168,179 ---- > foreach(temp, vars) > { > Var *var = (Var *) lfirst(temp); >! RelOptInfo *rel; >! /* skip FakeVars */ >! if(IsA((Node *)var, FakeVar)) >! continue; >! >! rel = find_base_rel(root, var->varno); > > add_var_to_tlist(rel, var); > >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/optimizer/plan/planner.c postgresql-7.3.1-evg/src/backend/optimizer/plan/planner.c >*** postgresql-7.3.1/src/backend/optimizer/plan/planner.c Fri Dec 6 01:46:55 2002 >--- postgresql-7.3.1-evg/src/backend/optimizer/plan/planner.c Thu Dec 26 17:02:14 2002 >*************** >*** 39,45 **** > #define EXPRKIND_TARGET 0 > #define EXPRKIND_WHERE 1 > #define EXPRKIND_HAVING 2 >! > > static Node *pull_up_subqueries(Query *parse, Node *jtnode, > bool below_outer_join); >--- 39,45 ---- > #define EXPRKIND_TARGET 0 > #define EXPRKIND_WHERE 1 > #define EXPRKIND_HAVING 2 >! #define EXPRKIND_STARTWITH 3 > > static Node *pull_up_subqueries(Query *parse, Node *jtnode, > bool below_outer_join); >*************** >*** 170,175 **** >--- 170,184 ---- > parse->havingQual = preprocess_expression(parse, parse->havingQual, > EXPRKIND_HAVING); > >+ if(parse->hierClause){ >+ ((HierClause *)parse->hierClause)->startQual = preprocess_expression(parse, ((HierClause *)parse->hierClause)->startQual, >+ EXPRKIND_STARTWITH); >+ >+ ((HierClause *)parse->hierClause)->parentExpr = preprocess_expression(parse, ((HierClause *)parse->hierClause)->parentExpr, >+ EXPRKIND_STARTWITH); >+ ((HierClause *)parse->hierClause)->childExpr = preprocess_expression(parse, ((HierClause *)parse->hierClause)->childExpr, >+ EXPRKIND_STARTWITH); >+ } > /* Also need to preprocess expressions for function RTEs */ > foreach(lst, parse->rtable) > { >*************** >*** 210,227 **** > * declared as Node *. Also note that contain_agg_clause does not > * recurse into sub-selects, which is exactly what we need here. > */ >! newHaving = NIL; >! foreach(lst, (List *) parse->havingQual) >! { >! Node *havingclause = (Node *) lfirst(lst); > >! if (contain_agg_clause(havingclause)) >! newHaving = lappend(newHaving, havingclause); >! else >! parse->jointree->quals = (Node *) >! lappend((List *) parse->jointree->quals, havingclause); >! } >! parse->havingQual = (Node *) newHaving; > > /* > * Do the main planning. If we have an inherited target relation, >--- 219,238 ---- > * declared as Node *. Also note that contain_agg_clause does not > * recurse into sub-selects, which is exactly what we need here. > */ >! if(!parse->hierClause){ >! newHaving = NIL; >! foreach(lst, (List *) parse->havingQual) >! { >! Node *havingclause = (Node *) lfirst(lst); > >! if (contain_agg_clause(havingclause)) >! newHaving = lappend(newHaving, havingclause); >! else >! parse->jointree->quals = (Node *) >! lappend((List *) parse->jointree->quals, havingclause); >! } >! parse->havingQual = (Node *) newHaving; >! } > > /* > * Do the main planning. If we have an inherited target relation, >*************** >*** 375,380 **** >--- 386,404 ---- > ResolveNew(parse->havingQual, > varno, 0, subtlist, CMD_SELECT, 0); > >+ if(parse->hierClause){ >+ ((HierClause *)parse->hierClause)->startQual = >+ ResolveNew(((HierClause *)parse->hierClause)->startQual, >+ varno, 0, subtlist, CMD_SELECT, 0); >+ >+ ((HierClause *)parse->hierClause)->parentExpr = >+ ResolveNew(((HierClause *)parse->hierClause)->parentExpr, >+ varno, 0, subtlist, CMD_SELECT, 0); >+ ((HierClause *)parse->hierClause)->childExpr = >+ ResolveNew(((HierClause *)parse->hierClause)->childExpr, >+ varno, 0, subtlist, CMD_SELECT, 0); >+ } >+ > foreach(rt, parse->rtable) > { > RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); >*************** >*** 499,510 **** > > /* > * Can't pull up a subquery involving grouping, aggregation, sorting, >! * or limiting. > */ > if (subquery->hasAggs || > subquery->groupClause || > subquery->havingQual || > subquery->sortClause || > subquery->distinctClause || > subquery->limitOffset || > subquery->limitCount) >--- 523,535 ---- > > /* > * Can't pull up a subquery involving grouping, aggregation, sorting, >! * limiting or connecting. > */ > if (subquery->hasAggs || > subquery->groupClause || > subquery->havingQual || > subquery->sortClause || >+ subquery->hierClause || > subquery->distinctClause || > subquery->limitOffset || > subquery->limitCount) >*************** >*** 1290,1295 **** >--- 1315,1323 ---- > * If aggregate is present, insert the Agg node > * > * HAVING clause, if any, becomes qual of the Agg node >+ * >+ * if there is no hasAggs, then it becomes qual for the >+ * Conn node, if it is present > */ > if (parse->hasAggs) > { >*************** >*** 1298,1308 **** > result_plan); > /* Note: Agg does not affect any existing sort order of the tuples */ > } >- else >- { >- /* If there are no Aggs, we shouldn't have any HAVING qual anymore */ >- Assert(parse->havingQual == NULL); >- } > > /* > * If we were not able to make the plan come out in the right order, >--- 1326,1331 ---- >*************** >*** 1324,1329 **** >--- 1347,1367 ---- > parse->distinctClause); > } > >+ /* >+ * If there is a CONNECT BY clause, add the CONN node >+ */ >+ if (parse->hierClause) >+ { >+ result_plan = (Plan *) make_connplan(parse, tlist, result_plan); >+ } >+ else >+ { >+ /* If there are no Aggs and no hierClause , we shouldn't have >+ * any HAVING qual anymore >+ */ >+ if(!parse->hasAggs) Assert(parse->havingQual == NULL); >+ } >+ > /* > * Finally, if there is a LIMIT/OFFSET clause, add the LIMIT node. > */ >*************** >*** 1388,1394 **** > * If we're not grouping or aggregating, nothing to do here; > * query_planner should receive the unmodified target list. > */ >! if (!parse->hasAggs && !parse->groupClause && !parse->havingQual) > return tlist; > > /* >--- 1426,1432 ---- > * If we're not grouping or aggregating, nothing to do here; > * query_planner should receive the unmodified target list. > */ >! if (!parse->hasAggs && !parse->groupClause && !(parse->havingQual && !parse->hierClause)) > return tlist; > > /* >*************** >*** 1548,1553 **** >--- 1586,1601 ---- > Assert(keyno > 0); > > return (Plan *) make_sort(parse, sort_tlist, plannode, keyno); >+ } >+ >+ /* >+ * make_connplan >+ * Add a Conn node to implement an explicit CONNECT BY clause. >+ */ >+ Plan * >+ make_connplan(Query *parse, List *tlist, Plan *plannode) >+ { >+ return (Plan *) make_conn(parse, tlist, plannode); > } > > /* >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/optimizer/plan/setrefs.c postgresql-7.3.1-evg/src/backend/optimizer/plan/setrefs.c >*** postgresql-7.3.1/src/backend/optimizer/plan/setrefs.c Thu Sep 5 01:31:21 2002 >--- postgresql-7.3.1-evg/src/backend/optimizer/plan/setrefs.c Thu Dec 26 17:02:14 2002 >*************** >*** 23,28 **** >--- 23,30 ---- > #include "optimizer/tlist.h" > #include "optimizer/var.h" > #include "parser/parsetree.h" >+ #include "catalog/pg_type.h" >+ > > > typedef struct >*************** >*** 162,167 **** >--- 164,178 ---- > fix_expr_references(plan, > (Node *) ((HashJoin *) plan)->hashclauses); > break; >+ case T_Conn: >+ set_uppernode_references(plan, (Index) 0); >+ fix_expr_references(plan, (Node *) plan->targetlist); >+ fix_expr_references(plan, (Node *) plan->qual); >+ fix_expr_references(plan, (Node *)((Conn *) plan)->startQual); >+ >+ fix_expr_references(plan, (Node *)((Conn *) plan)->parentExpr); >+ fix_expr_references(plan, (Node *)((Conn *) plan)->childExpr); >+ break; > case T_Material: > case T_Sort: > case T_Unique: >*************** >*** 361,366 **** >--- 372,395 ---- > subvarno, > subplan_targetlist, > tlist_has_non_vars); >+ if(IsA( plan, Conn)){ >+ ((Conn *)plan)->startQual = >+ replace_vars_with_subplan_refs((Node *) ((Conn *)plan)->startQual, >+ subvarno, >+ subplan_targetlist, >+ tlist_has_non_vars); >+ >+ ((Conn *)plan)->parentExpr = >+ replace_vars_with_subplan_refs((Node *) ((Conn *)plan)->parentExpr, >+ subvarno, >+ subplan_targetlist, >+ tlist_has_non_vars); >+ ((Conn *)plan)->childExpr = >+ replace_vars_with_subplan_refs((Node *) ((Conn *)plan)->childExpr, >+ subvarno, >+ subplan_targetlist, >+ tlist_has_non_vars); >+ } > } > > /* >*************** >*** 508,514 **** > { > if (node == NULL) > return NULL; >! if (IsA(node, Var)) > { > Var *var = (Var *) node; > Resdom *resdom; >--- 537,552 ---- > { > if (node == NULL) > return NULL; >! if (IsA(node, FakeVar)) >! { >! /* FakeVar isn't present on subplan so just copy it*/ >! FakeVar *var = (FakeVar *) node; >! FakeVar *newvar; >! >! newvar = (FakeVar *) copyObject((Node *)var); >! return (Node *) newvar; >! } >! else if (IsA(node, Var)) > { > Var *var = (Var *) node; > Resdom *resdom; >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/optimizer/plan/subselect.c postgresql-7.3.1-evg/src/backend/optimizer/plan/subselect.c >*** postgresql-7.3.1/src/backend/optimizer/plan/subselect.c Thu Sep 5 01:31:21 2002 >--- postgresql-7.3.1-evg/src/backend/optimizer/plan/subselect.c Thu Dec 26 17:02:14 2002 >*************** >*** 355,360 **** >--- 355,361 ---- > case T_Material: > case T_FunctionScan: > case T_Sort: >+ case T_Conn: > > /* > * Don't add another Material node if there's one >*************** >*** 699,704 **** >--- 700,706 ---- > case T_SetOp: > case T_Limit: > case T_Group: >+ case T_Conn: > break; > > default: >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/optimizer/util/clauses.c postgresql-7.3.1-evg/src/backend/optimizer/util/clauses.c >*** postgresql-7.3.1/src/backend/optimizer/util/clauses.c Wed Sep 11 19:48:54 2002 >--- postgresql-7.3.1-evg/src/backend/optimizer/util/clauses.c Thu Dec 26 17:02:15 2002 >*************** >*** 453,459 **** > (void *) listptr); > } > >- > /***************************************************************************** > * Support for expressions returning sets > *****************************************************************************/ >--- 453,458 ---- >*************** >*** 1007,1012 **** >--- 1006,1013 ---- > Var *var = (Var *) lfirst(i); > List *vi; > >+ if(IsA(lfirst(i), FakeVar)) /* skip FakeVars, because they're not fetched from tables */ >+ continue; > if (!intMember(var->varno, varno_list)) > varno_list = lconsi(var->varno, varno_list); > foreach(vi, var_list) >*************** >*** 1824,1829 **** >--- 1825,1831 ---- > { > case T_Const: > case T_Var: >+ case T_FakeVar: > case T_Param: > case T_RangeTblRef: > /* primitive node types with no subnodes */ >*************** >*** 1977,1982 **** >--- 1979,1995 ---- > return true; > } > break; >+ case T_HierClause: >+ { >+ HierClause *hier = (HierClause *)node; >+ if (walker(hier->startQual, context)) >+ return true; >+ if (walker(hier->parentExpr, context)) >+ return true; >+ if (walker(hier->childExpr, context)) >+ return true; >+ } >+ break; > default: > elog(ERROR, "expression_tree_walker: Unexpected node type %d", > nodeTag(node)); >*************** >*** 2018,2023 **** >--- 2031,2039 ---- > return true; > if (walker(query->havingQual, context)) > return true; >+ if (walker(query->hierClause, context)) >+ return true; >+ > foreach(rt, query->rtable) > { > RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); >*************** >*** 2134,2140 **** > switch (nodeTag(node)) > { > case T_Const: >! case T_Var: > case T_Param: > case T_RangeTblRef: > /* primitive node types with no subnodes */ >--- 2150,2157 ---- > switch (nodeTag(node)) > { > case T_Const: >! case T_FakeVar: >! case T_Var: > case T_Param: > case T_RangeTblRef: > /* primitive node types with no subnodes */ >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/optimizer/util/var.c postgresql-7.3.1-evg/src/backend/optimizer/util/var.c >*** postgresql-7.3.1/src/backend/optimizer/util/var.c Wed Sep 11 19:48:54 2002 >--- postgresql-7.3.1-evg/src/backend/optimizer/util/var.c Thu Dec 26 17:02:15 2002 >*************** >*** 255,260 **** >--- 255,262 ---- > { > if (node == NULL) > return false; >+ if(IsA(node, FakeVar)) /* fake vars are vars too */ >+ return true; > if (IsA(node, Var)) > { > if (((Var *) node)->varlevelsup == 0) >*************** >*** 301,306 **** >--- 303,316 ---- > { > if (((Var *) node)->varlevelsup == 0 || context->includeUpperVars) > context->varlist = lappend(context->varlist, node); >+ return false; >+ } >+ if (IsA(node, FakeVar)) >+ { >+ /* same as Var but because of FakeVar->varlevelsup == 0 is always true (ideologically), >+ * always append >+ */ >+ context->varlist = lappend(context->varlist, node); > return false; > } > return expression_tree_walker(node, pull_var_clause_walker, >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/parser/analyze.c postgresql-7.3.1-evg/src/backend/parser/analyze.c >*** postgresql-7.3.1/src/backend/parser/analyze.c Tue Oct 22 03:06:19 2002 >--- postgresql-7.3.1-evg/src/backend/parser/analyze.c Thu Dec 26 17:02:15 2002 >*************** >*** 1659,1664 **** >--- 1659,1667 ---- > /* transform WHERE */ > qual = transformWhereClause(pstate, stmt->whereClause); > >+ /* transform CONNECT BY , START WITH clause */ >+ qry->hierClause=transformHierClause(pstate,qry,stmt->hierClause); >+ > /* > * Initial processing of HAVING clause is just like WHERE clause. > * Additional work will be done in optimizer/plan/planner.c. >*************** >*** 1683,1689 **** > > qry->hasSubLinks = pstate->p_hasSubLinks; > qry->hasAggs = pstate->p_hasAggs; >! if (pstate->p_hasAggs || qry->groupClause || qry->havingQual) > parseCheckAggregates(pstate, qry, qual); > > qry->rtable = pstate->p_rtable; >--- 1686,1692 ---- > > qry->hasSubLinks = pstate->p_hasSubLinks; > qry->hasAggs = pstate->p_hasAggs; >! if (pstate->p_hasAggs || qry->groupClause || (qry->havingQual && !qry->hierClause) ) > parseCheckAggregates(pstate, qry, qual); > > qry->rtable = pstate->p_rtable; >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/parser/gram.y postgresql-7.3.1-evg/src/backend/parser/gram.y >*** postgresql-7.3.1/src/backend/parser/gram.y Sat Nov 2 22:41:21 2002 >--- postgresql-7.3.1-evg/src/backend/parser/gram.y Thu Dec 26 17:02:15 2002 >*************** >*** 311,316 **** >--- 311,318 ---- > %type <list> constraints_set_list > %type <boolean> constraints_set_mode > >+ %type <node> startwith_clause >+ %type <list> connectby_clause hier_clause > > /* > * If you make any token changes, update the keyword table in >*************** >*** 329,336 **** > CACHE CALLED CASCADE CASE CAST CHAIN CHAR_P > CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE > CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT >! COMMITTED CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT COPY CREATE CREATEDB >! CREATEUSER CROSS CURRENT_DATE CURRENT_TIME > CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE > > DATABASE DAY_P DEALLOCATE DEC DECIMAL DECLARE DEFAULT >--- 331,338 ---- > CACHE CALLED CASCADE CASE CAST CHAIN CHAR_P > CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE > CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT >! COMMITTED CONNECT CONSTRAINT CONSTRAINTS CONVERSION_P CONVERT >! COPY CREATE CREATEDB CREATEUSER CROSS CURRENT_DATE CURRENT_TIME > CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE > > DATABASE DAY_P DEALLOCATE DEC DECIMAL DECLARE DEFAULT >*************** >*** 4232,4238 **** > simple_select: > SELECT opt_distinct target_list > into_clause from_clause where_clause >! group_clause having_clause > { > SelectStmt *n = makeNode(SelectStmt); > n->distinctClause = $2; >--- 4234,4240 ---- > simple_select: > SELECT opt_distinct target_list > into_clause from_clause where_clause >! group_clause hier_clause having_clause > { > SelectStmt *n = makeNode(SelectStmt); > n->distinctClause = $2; >*************** >*** 4242,4248 **** > n->fromClause = $5; > n->whereClause = $6; > n->groupClause = $7; >! n->havingClause = $8; > $$ = (Node *)n; > } > | select_clause UNION opt_all select_clause >--- 4244,4251 ---- > n->fromClause = $5; > n->whereClause = $6; > n->groupClause = $7; >! n->havingClause = $9; >! n->hierClause = $8; > $$ = (Node *)n; > } > | select_clause UNION opt_all select_clause >*************** >*** 4264,4269 **** >--- 4267,4295 ---- > | /*EMPTY*/ { $$ = NULL; } > ; > >+ hier_clause: connectby_clause startwith_clause >+ { >+ $$ = makeList2($1,$2); >+ } >+ | startwith_clause connectby_clause >+ { >+ $$ = makeList2($2,$1); >+ } >+ | /* EMPTY */ { $$ = NULL; } >+ ; >+ >+ connectby_clause: CONNECT BY PRIOR c_expr all_Op c_expr >+ { >+ $$ = makeList3($4,makeString($5),$6); >+ } >+ | CONNECT BY a_expr all_Op PRIOR a_expr >+ { >+ $$ = makeList3($6,makeString($4),$3); >+ } >+ ; >+ startwith_clause: START WITH a_expr { $$ = $3; } >+ ; >+ > /* > * Redundancy here is needed to avoid shift/reduce conflicts, > * since TEMP is not a reserved word. See also OptTemp. >*************** >*** 7074,7080 **** > | PENDANT > | PRECISION > | PREPARE >- | PRIOR > | PRIVILEGES > | PROCEDURAL > | PROCEDURE >--- 7100,7105 ---- >*************** >*** 7102,7108 **** > | SHOW > | SIMPLE > | STABLE >- | START > | STATEMENT > | STATISTICS > | STDIN >--- 7127,7132 ---- >*************** >*** 7239,7244 **** >--- 7263,7269 ---- > | CHECK > | COLLATE > | COLUMN >+ | CONNECT > | CONSTRAINT > | CREATE > | CURRENT_DATE >*************** >*** 7279,7288 **** >--- 7304,7315 ---- > | ORDER > | PLACING > | PRIMARY >+ | PRIOR > | REFERENCES > | SELECT > | SESSION_USER > | SOME >+ | START > | TABLE > | THEN > | TO >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/parser/keywords.c postgresql-7.3.1-evg/src/backend/parser/keywords.c >*** postgresql-7.3.1/src/backend/parser/keywords.c Thu Sep 19 02:35:22 2002 >--- postgresql-7.3.1-evg/src/backend/parser/keywords.c Thu Dec 26 17:02:15 2002 >*************** >*** 79,84 **** >--- 79,85 ---- > {"comment", COMMENT}, > {"commit", COMMIT}, > {"committed", COMMITTED}, >+ {"connect",CONNECT}, > {"constraint", CONSTRAINT}, > {"constraints", CONSTRAINTS}, > {"conversion", CONVERSION_P}, >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/parser/parse_clause.c postgresql-7.3.1-evg/src/backend/parser/parse_clause.c >*** postgresql-7.3.1/src/backend/parser/parse_clause.c Mon Dec 16 22:39:56 2002 >--- postgresql-7.3.1-evg/src/backend/parser/parse_clause.c Thu Dec 26 17:02:15 2002 >*************** >*** 38,45 **** > #define ORDER_CLAUSE 0 > #define GROUP_CLAUSE 1 > #define DISTINCT_ON_CLAUSE 2 >! >! static char *clauseText[] = {"ORDER BY", "GROUP BY", "DISTINCT ON"}; > > static void extractRemainingColumns(List *common_colnames, > List *src_colnames, List *src_colvars, >--- 38,46 ---- > #define ORDER_CLAUSE 0 > #define GROUP_CLAUSE 1 > #define DISTINCT_ON_CLAUSE 2 >! #define CONNECT_CLAUSE 3 >! >! static char *clauseText[] = {"ORDER BY", "GROUP BY", "DISTINCT ON","CONNECT BY"}; > > static void extractRemainingColumns(List *common_colnames, > List *src_colnames, List *src_colvars, >*************** >*** 1171,1176 **** >--- 1172,1247 ---- > } > > return glist; >+ } >+ >+ /* >+ * transformConnectClause - >+ * transform a Connect By clause >+ * >+ */ >+ Node * >+ transformHierClause(ParseState *pstate, Query *qry, List *hier) >+ { >+ List *clist = NIL; >+ TargetEntry *tle; >+ HierClause *node; >+ List *tlist=qry->targetList; >+ FakeVar *var; >+ >+ if(!hier) return NULL; >+ >+ node=makeNode(HierClause); >+ >+ clist=lfirst(hier);//get conn_list >+ >+ /* add a field '_level_', in result there will be deepness of tuple >+ * in result tree. >+ * must be added before tranformation parent/child Expr, >+ * because in they transformation process may be added some resjunk >+ * var nodes to tlist, scanRTEForColumn() not supports mix of junk/non-junk >+ * nodes. >+ */ >+ var = makeNode(FakeVar); >+ var->varattno = 0; >+ var->vartype = INT4OID; >+ var->vartypmod = -1; >+ >+ tle = transformTargetEntry(pstate, (Node *)var, NULL, "_level_", false); >+ lappend(tlist, tle); >+ >+ /* transform parent and child expressions */ >+ pstate->p_curTlist = tlist; /* also see in parser/parse_node.h */ >+ pstate->p_addTle = true; /* we may add to tagetlist some junk attributes, >+ * which needed by this expressions but not present in >+ * user given targetlist. only vars is added */ >+ node->parentExpr = transformExpr(pstate,lfirst(clist)); >+ node->childExpr = transformExpr(pstate,lfirst(lnext(lnext(clist))));//lthird >+ pstate->p_addTle = false; >+ >+ /* fetch operatior OID for connecting tuples */ >+ node->connOp = compatible_oper_opid(makeList1(lsecond(clist)), >+ exprType(node->parentExpr), >+ exprType(node->childExpr), >+ true); >+ >+ if(node->connOp == InvalidOid){ >+ elog(ERROR,"CONNECT BY: can't find operator '%s' for connecting on chosen fields",(char *)lsecond(clist)); >+ } >+ >+ /* transform StartQual, see note above, on parent/child Expr*/ >+ pstate->p_addTle = true; >+ node->startQual=transformWhereClause(pstate,lsecond(hier)); >+ pstate->p_addTle = false; >+ pstate->p_curTlist = NULL;// clear >+ >+ pstate->p_hierLevelColIdx = tle->resdom->resno; >+ >+ /* transformExpr return to us our's pointer, so we can to set >+ * attno here, for FakeVar attno is the number in targetlist >+ */ >+ var->varattno = tle->resdom->resno; >+ >+ return (Node *)node; > } > > /* >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/parser/parse_expr.c postgresql-7.3.1-evg/src/backend/parser/parse_expr.c >*** postgresql-7.3.1/src/backend/parser/parse_expr.c Thu Sep 19 02:35:22 2002 >--- postgresql-7.3.1-evg/src/backend/parser/parse_expr.c Thu Dec 26 17:02:15 2002 >*************** >*** 29,34 **** >--- 29,35 ---- > #include "parser/parse_oper.h" > #include "parser/parse_relation.h" > #include "parser/parse_type.h" >+ #include "parser/parse_target.h" > #include "utils/builtins.h" > #include "utils/lsyscache.h" > #include "utils/syscache.h" >*************** >*** 633,640 **** > * taking a conservative approach, and only accepting node > * types that are demonstrably necessary to accept. > *********************************************/ >- case T_Expr: > case T_Var: > case T_Const: > case T_Param: > case T_Aggref: >--- 634,642 ---- > * taking a conservative approach, and only accepting node > * types that are demonstrably necessary to accept. > *********************************************/ > case T_Var: >+ case T_Expr: >+ case T_FakeVar: > case T_Const: > case T_Param: > case T_Aggref: >*************** >*** 662,669 **** >--- 664,697 ---- > static Node * > transformIndirection(ParseState *pstate, Node *basenode, List *indirection) > { >+ TargetEntry *tle; >+ List *tl; >+ bool found; >+ > if (indirection == NIL) >+ { >+ /* If node is Var, and tle addition flag is set then we must add var to targetlist >+ * if it's not presen in tlist >+ * ( also see parser/parse_node.h, parser/parse_clause.c:transformHierClause()) >+ */ >+ if(IsA(basenode, Var) && pstate->p_addTle){ >+ found = false; >+ /* search for var */ >+ foreach(tl, pstate->p_curTlist){ >+ tle = lfirst(tl); >+ if(equal(basenode,tle->expr)){ >+ found = true; >+ break; >+ } >+ } >+ /* if not fount, make tle and add to tlist */ >+ if(!found){ >+ tle = transformTargetEntry(pstate,basenode,basenode,NULL,true); >+ lappend(pstate->p_curTlist,tle); >+ } >+ } > return basenode; >+ } > return (Node *) transformArraySubscripts(pstate, > basenode, > exprType(basenode), >*************** >*** 740,748 **** >--- 768,789 ---- > rv->inhOpt = INH_DEFAULT; > node = (Node *) rv; > } >+ else if (pstate->p_hierLevelColIdx!=0 && !strcmp(name,"_level_")) >+ { >+ /* If nothing of above and present hier clause and name is '_level_' >+ * then make fake variable >+ */ >+ FakeVar *var = makeNode(FakeVar); >+ >+ var->varattno = pstate->p_hierLevelColIdx; >+ var->vartype = INT4OID; >+ var->vartypmod = -1; >+ node = (Node *)var; >+ } > else > elog(ERROR, "Attribute \"%s\" not found", name); > } >+ > break; > } > case 2: >*************** >*** 875,880 **** >--- 916,924 ---- > > switch (nodeTag(expr)) > { >+ case T_FakeVar: >+ type = ((FakeVar *) expr)->vartype; >+ break; > case T_Var: > type = ((Var *) expr)->vartype; > break; >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/utils/adt/ruleutils.c postgresql-7.3.1-evg/src/backend/utils/adt/ruleutils.c >*** postgresql-7.3.1/src/backend/utils/adt/ruleutils.c Fri Sep 20 04:40:56 2002 >--- postgresql-7.3.1-evg/src/backend/utils/adt/ruleutils.c Thu Dec 26 17:02:15 2002 >*************** >*** 1929,1934 **** >--- 1929,1939 ---- > get_const_expr((Const *) node, context); > break; > >+ case T_FakeVar: >+ { >+ appendStringInfo(buf, "FakeVar"); >+ } >+ break; > case T_Var: > { > Var *var = (Var *) node; >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/utils/sort/Makefile postgresql-7.3.1-evg/src/backend/utils/sort/Makefile >*** postgresql-7.3.1/src/backend/utils/sort/Makefile Thu Aug 31 21:10:59 2000 >--- postgresql-7.3.1-evg/src/backend/utils/sort/Makefile Thu Dec 26 17:02:15 2002 >*************** >*** 12,18 **** > top_builddir = ../../../.. > include $(top_builddir)/src/Makefile.global > >! OBJS = logtape.o tuplesort.o tuplestore.o > > all: SUBSYS.o > >--- 12,18 ---- > top_builddir = ../../../.. > include $(top_builddir)/src/Makefile.global > >! OBJS = logtape.o tuplesort.o tuplestore.o tupleconn.o > > all: SUBSYS.o > >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/backend/utils/sort/tupleconn.c postgresql-7.3.1-evg/src/backend/utils/sort/tupleconn.c >*** postgresql-7.3.1/src/backend/utils/sort/tupleconn.c Thu Jan 1 04:00:00 1970 >--- postgresql-7.3.1-evg/src/backend/utils/sort/tupleconn.c Thu Jan 23 15:21:22 2003 >*************** >*** 0 **** >--- 1,1027 ---- >+ /*------------------------------------------------------------------------- >+ * >+ * tupleconn.c >+ * Routines for tuple connecting. >+ * >+ * Based on tuplestore.c, tuplesort.c. >+ * (c) by Evgen Potemkin evgent@terminal.ru, 11.2002 >+ * >+ *------------------------------------------------------------------------- >+ */ >+ >+ #include "postgres.h" >+ >+ #include "access/heapam.h" >+ #include "storage/buffile.h" >+ #include "utils/tupleconn.h" >+ #include "utils/tuplesort.h" >+ >+ #include "access/nbtree.h" >+ #include "catalog/catname.h" >+ #include "catalog/pg_amop.h" >+ #include "catalog/pg_amproc.h" >+ #include "catalog/pg_operator.h" >+ #include "miscadmin.h" >+ #include "utils/datum.h" >+ #include "utils/fmgroids.h" >+ #include "utils/lsyscache.h" >+ #include "utils/syscache.h" >+ >+ #include "parser/parse_expr.h" >+ #include "nodes/execnodes.h" >+ #include "executor/executor.h" >+ /* >+ * Possible states of a Tupleconn object. These denote the states that >+ * persist between calls of Tupleconn routines. >+ */ >+ typedef enum >+ { >+ TCS_INITIAL, /* Loading tuples; still within memory >+ * limit */ >+ TCS_WRITEFILE, /* Loading tuples; writing to temp file */ >+ TCS_READMEM, /* Reading tuples; entirely in memory */ >+ TCS_READFILE /* Reading tuples from temp file */ >+ } TupConnStatus; >+ >+ >+ /* >+ * connection tree >+ */ >+ typedef struct _ConnectTree ConnectTree; >+ struct _ConnectTree{ >+ ConnectTree *next; /* next sibling*/ >+ ConnectTree *prev; /* previous sibling */ >+ ConnectTree *sub; /* child */ >+ ConnectTree *sup; /* parent */ >+ int level; /* deep of this node, starts from 1*/ >+ int tuple; /* index of tuple in memtuples/used/out_store */ >+ }; >+ >+ /* >+ * Information about tuples stored in buffile >+ */ >+ typedef struct OutStore{ >+ int fileno; /* BufFile fileno */ >+ long offs; /* BufFile offs */ >+ int len; /* tuple length*/ >+ HeapTuple tup; /* in-memory tuple copy, NULL if none */ >+ }OutStore; >+ >+ /* >+ * Datum cache >+ */ >+ typedef struct DtCache{ >+ Datum pntdt_val; /* cached pntExpr value of tuple*/ >+ Datum chlddt_val; /* cached chdlExpr value of tuple*/ >+ bool pntdt_isnull; /* cached pntExpr is_null value of tuple*/ >+ bool chlddt_isnull; /* cached chdlExpr is_null value of tuple*/ >+ bool pnt_c; /* parent value is cached flag*/ >+ bool chld_c; /* child value is cached flag*/ >+ }DtCache; >+ /* >+ * Private state of a Tupleconn operation. >+ */ >+ struct Tupleconnstate >+ { >+ TupConnStatus status; /* enumerated value as shown above */ >+ long availMem; /* remaining memory available, in bytes */ >+ BufFile *myfile; /* underlying file, or NULL if none */ >+ >+ /* >+ * Tree and supporting stuff, explanation at _performconn function >+ */ >+ MemoryContext tree_ctx; >+ ConnectTree *head; /* head of the result list */ >+ ConnectTree **pnt; /* parent nodes on curent level*/ >+ int pntlast; /* actual amount of parents on current level */ >+ int pntsize; /* size of pnt array */ >+ ConnectTree **chld; /* array of child nodes */ >+ int chldlast; /* actual amount of childs on current level */ >+ int chldsize; /* size of chld array */ >+ ConnectTree *last; /* last added/fetched node */ >+ bool skip_node; /* used in gettuple, mean don't fall to ->sub because >+ * we're going from that*/ >+ char *used; /* array of flags - was tuple (connected already|is null) or not */ >+ TupleDesc tupDesc; >+ AttrNumber level; /* tuple's '_level_' attribute number */ >+ FmgrInfo connFn; /* comparation function */ >+ >+ OutStore *out_store; /* array of info about tuples in buffile for faster random access */ >+ DtCache *cache; /* cache for datums returned by ExecEvalExpr */ >+ >+ void *(*copytup) (Tupleconnstate *state, void *tup); >+ void (*writetup) (Tupleconnstate *state, void *tup, bool free, int idx); >+ void *(*readtup) (Tupleconnstate *state, int idx); >+ >+ void **memtuples; /* array of pointers to palloc'd tuples */ >+ int memtupsize; /* allocated length of memtuples array */ >+ >+ int tupcount; /* number of tuples currently present */ >+ >+ bool eof_reached; /* reached EOF (needed for cursors) */ >+ >+ /* markpos_xxx holds marked position for mark and restore */ >+ bool markpos_eof; /* saved "eof_reached" */ >+ ConnectTree *markpos_last; /* saved "last" pointer */ >+ bool markpos_skip; /* saved "skip" flag */ >+ }; >+ >+ >+ #define COPYTUP(state,tup) ((*(state)->copytup) (state, tup)) >+ #define WRITETUP(state,tup,free,idx) ((*(state)->writetup) (state, tup, free, idx)) >+ #define READTUP(state,idx) ((*(state)->readtup) (state, idx)) >+ #define LACKMEM(state) ((state)->availMem < 0) >+ #define USEMEM(state,amt) ((state)->availMem -= (amt)) >+ #define FREEMEM(state,amt) ((state)->availMem += (amt)) >+ >+ >+ >+ static Tupleconnstate *tupleconn_begin_common(int maxKBytes); >+ static void dumptuples(Tupleconnstate *state); >+ >+ static void *copytup_heap(Tupleconnstate *state, void *tup); >+ static void writetup_heap(Tupleconnstate *state, void *tup, bool free, int idx); >+ static void *readtup_heap(Tupleconnstate *state, int idx); >+ void SelectConnFunction(Oid sortOperator,RegProcedure *sortFunction, >+ SortFunctionKind *kind); >+ void *setlevel(Tupleconnstate * state,int level, void *tuple, bool free_it); >+ >+ ConnectTree *add_next(Tupleconnstate * state,ConnectTree *tr,int tup,int level); >+ ConnectTree *add_sub(Tupleconnstate * state,ConnectTree *tr,int tup,int level); >+ >+ >+ /* >+ * Init all >+ */ >+ static Tupleconnstate * >+ tupleconn_begin_common(int maxKBytes) >+ { >+ Tupleconnstate *state; >+ >+ state = (Tupleconnstate *) palloc(sizeof(Tupleconnstate)); >+ >+ MemSet((char *) state, 0, sizeof(Tupleconnstate)); >+ >+ state->status = TCS_INITIAL; >+ state->availMem = maxKBytes * 1024L; >+ state->myfile = NULL; >+ state->out_store = NULL; >+ >+ state->tree_ctx = AllocSetContextCreate(CurrentMemoryContext,"Temporary connby storage",8*1024,8*1024,8*1024); >+ >+ state->tupcount = 0; >+ if (maxKBytes > 0) >+ state->memtupsize = 1024; /* initial guess */ >+ else >+ state->memtupsize = 1; /* won't really need any space */ >+ state->memtuples = (void **) palloc(state->memtupsize * sizeof(void *)); >+ >+ state->pntlast=0; >+ state->chldlast=0; >+ state->pntsize=1024; /* initial guess */ >+ state->chldsize=1024; /* initial guess */ >+ state->pnt=(ConnectTree **)palloc(state->pntsize * sizeof(void *)); >+ state->chld=(ConnectTree **)palloc(state->pntsize * sizeof(void *)); >+ >+ state->used = (char *) palloc(state->memtupsize * sizeof(char)); >+ state->level=0; >+ return state; >+ } >+ >+ Tupleconnstate * >+ tupleconn_begin_heap(int maxKBytes, TupleDesc tupDesc, Oid connOp) >+ { >+ RegProcedure connFunc; >+ SortFunctionKind connFnKind; >+ >+ Tupleconnstate *state = tupleconn_begin_common(maxKBytes); >+ >+ state->copytup = copytup_heap; >+ state->writetup = writetup_heap; >+ state->readtup = readtup_heap; >+ >+ state->tupDesc=tupDesc; >+ >+ SelectConnFunction(connOp, &connFunc, >+ &connFnKind); >+ if(connFnKind != SORTFUNC_CMP){ >+ elog(ERROR,"tupleconn: Can't find suitable function for comparison"); >+ } >+ fmgr_info(connFunc,&state->connFn); >+ return state; >+ } >+ >+ /* >+ * tupleconn_end >+ * >+ * Release resources and clean up. >+ */ >+ void >+ tupleconn_end(Tupleconnstate *state) >+ { >+ int i; >+ /* common frees */ >+ >+ pfree(state->pnt); >+ pfree(state->chld); >+ pfree(state->used); >+ >+ /* free tree, if any */ >+ state->last = state->head; >+ // release tree and cache >+ MemoryContextDelete(state->tree_ctx); >+ >+ /* free tuples, from out_store or memtuples*/ >+ if (state->myfile){ >+ BufFileClose(state->myfile); >+ for(i=0;i<state->tupcount;i++){ >+ if(state->out_store[i].tup!=NULL){ >+ pfree(state->out_store[i].tup); >+ FREEMEM(state,state->out_store[i].len); >+ state->out_store[i].tup=NULL; >+ } >+ } >+ }else{ >+ for (i = 0; i < state->tupcount; i++) >+ pfree(state->memtuples[i]); >+ pfree(state->memtuples); >+ } >+ >+ } >+ >+ /* >+ * Accept one tuple while collecting input data. >+ * >+ * Note that the input tuple is always copied; the caller need not save it. >+ */ >+ void >+ tupleconn_puttuple(Tupleconnstate *state, void *tuple,int head) >+ { >+ /* >+ * Copy the tuple. (Must do this even in WRITEFILE case.) >+ */ >+ tuple = COPYTUP(state, tuple); >+ >+ /* common thing */ >+ if(head){//it's a head tuple,add it to head list >+ //add autogrow for pnt >+ state->last = add_next(state,state->last,state->tupcount,1); >+ if(!state->head) state->head = state->last; >+ state->pnt[state->pntlast++] = state->last; >+ state->used[state->tupcount] = 1; >+ }else{ >+ state->used[state->tupcount] = 0; >+ } >+ >+ switch (state->status) >+ { >+ case TCS_INITIAL: >+ >+ /* >+ * Stash the tuple in the in-memory array. >+ */ >+ if (state->tupcount >= state->memtupsize-1) >+ { >+ /* Grow the arrays as needed. */ >+ state->memtupsize *= 2; >+ state->memtuples = (void **) >+ repalloc(state->memtuples, >+ state->memtupsize * sizeof(void *)); >+ state->used = (char *) >+ repalloc(state->used, >+ state->memtupsize * sizeof(char)); >+ MemSet((char *) (state->used+sizeof(char)*(state->memtupsize>>1)), 0, sizeof(char)*(state->memtupsize>>1)); >+ } >+ state->memtuples[state->tupcount++] = tuple; >+ >+ /* >+ * Done if we still fit in available memory. >+ */ >+ if (!LACKMEM(state)) >+ break; >+ >+ /* >+ * Nope; time to switch to tape-based operation. >+ */ >+ state->myfile = BufFileCreateTemp(); >+ state->status = TCS_WRITEFILE; >+ state->out_store = palloc(state->memtupsize * sizeof(OutStore)); >+ dumptuples(state); >+ break; >+ case TCS_WRITEFILE: >+ if (state->tupcount >= state->memtupsize-1) >+ { >+ /* Grow the arrays as needed. */ >+ state->memtupsize *= 2; >+ state->out_store = (OutStore *) >+ repalloc(state->out_store, >+ state->memtupsize * sizeof(OutStore)); >+ state->used = (char *) >+ repalloc(state->used, >+ state->memtupsize * sizeof(char)); >+ MemSet((char *) (state->used+sizeof(char)*(state->memtupsize>>1)), 0, sizeof(char)*(state->memtupsize>>1)); >+ } >+ WRITETUP(state, tuple,!head,state->tupcount++); >+ break; >+ default: >+ elog(ERROR, "tupleconn_puttuple: invalid state (internal error)"); >+ break; >+ } >+ >+ } >+ >+ /* >+ * All tuples have been provided; finish writing. >+ */ >+ void >+ tupleconn_donestoring(Tupleconnstate *state) >+ { >+ switch (state->status) >+ { >+ case TCS_INITIAL: >+ /* >+ * We were able to accumulate all the tuples within the >+ * allowed amount of memory. Just set up to connect and scan them. >+ */ >+ state->status = TCS_READMEM; >+ break; >+ case TCS_WRITEFILE: >+ /* >+ * Set up for connecting/reading from tape. >+ */ >+ state->status = TCS_READFILE; >+ break; >+ default: >+ elog(ERROR, "tupleconn_donestoring: invalid state "); >+ break; >+ } >+ state->eof_reached = false; >+ state->markpos_eof = false; >+ state->last=state->head; >+ state->level=0; >+ } >+ >+ /* >+ * tupleconn_performconn: perform connection on tuples >+ * Algorithm: in puttuple has been made list of top parent nodes, >+ * in each iteration we try to find all non-connected tuples which >+ * 'child' attribute is equal to 'parent' attribute in one of parent >+ * nodes, if so - tuple becomes a child of corresponding parent node. >+ * at end of iteration collected childs becomes the parents for next >+ * iteration. >+ * If no childs were find algorithm stops. >+ * Scan for childs in one iteration going on full array of stored >+ * tuples - this preserves order of tuples from subplan. for example >+ * if subplan was alphabetically sorted, childs on one level of each >+ * parent will be also alphabetically sorted. >+ * In case of file storage at end of algorithm all tuples resides only >+ * on tape. >+ * >+ * Clause was: >+ * CONNECT BY PRIOR expr Op expr >+ * here: >+ * PRIOR expr is - parentExpr, checked against parent tuple >+ * Op - is connOp operator, performs comparation >+ * expr (the rest) - is childExpr, checked against child tuple >+ */ >+ void >+ tupleconn_performconn(Tupleconnstate *state, >+ Node *parentExpr, Node *childExpr, ExprContext *econtext){ >+ int ok=0,i,j,ti,level=1; >+ ConnectTree **t; >+ int32 is_parent; >+ Datum dt1,dt2; >+ bool p_isnull,isnull,conn; >+ HeapTuple pnt,chld; >+ TupleDesc tupDesc; >+ TupleTableSlot *slot; >+ MemoryContext morig; >+ int16 pnt_typlen; >+ bool pnt_typbyval; >+ int16 chld_typlen; >+ bool chld_typbyval; >+ Size datalen; >+ char *newVal; >+ >+ if(!state->head) return; /* trivial case, don't connect anything */ >+ >+ /* check status */ >+ switch(state->status){ >+ case TCS_READMEM: >+ case TCS_READFILE: >+ break; >+ default: >+ elog(ERROR,"tupleconn: invalid state in performconn (internal error)"); >+ } >+ >+ tupDesc=state->tupDesc; >+ >+ /* get child and parent exprs typlens for cache */ >+ get_typlenbyval(exprType(parentExpr), &pnt_typlen, &pnt_typbyval); >+ get_typlenbyval(exprType(childExpr), &chld_typlen, &chld_typbyval); >+ >+ /* alloc cache in temp space */ >+ morig = MemoryContextSwitchTo(state->tree_ctx); >+ state->cache = (DtCache *)palloc(sizeof(DtCache)*state->tupcount); >+ MemoryContextSwitchTo(morig); >+ MemSet(state->cache, 0, sizeof(DtCache)*state->tupcount); >+ >+ /* make for ExecEvalExpr temporary slot */ >+ slot=makeNode(TupleTableSlot); >+ slot->ttc_tupleDescriptor = tupDesc; >+ slot->ttc_buffer = InvalidBuffer; >+ slot->ttc_shouldFreeDesc = false; >+ slot->ttc_shouldFree = true; >+ slot->ttc_descIsNew = false; >+ >+ /* set slot for ExecExvalExpr */ >+ econtext->ecxt_scantuple = slot; >+ >+ while(!ok){ >+ ok=1; >+ for(i=0;i<state->tupcount;i++){//scan through array of tuples >+ /* skip already connected and null tuples */ >+ CHECK_FOR_INTERRUPTS(); >+ if(!state->used[i]){ >+ ResetExprContext(econtext); >+ /* get tuple for connecting */ >+ /* if cached - use cache, in not - retrieve tuple, and build cache */ >+ if(state->cache[i].chld_c){ >+ dt1 = state->cache[i].chlddt_val; >+ }else{ >+ if(state->status == TCS_READMEM) { >+ chld=(HeapTuple)state->memtuples[i]; >+ slot->val = chld; >+ dt1 = ExecEvalExpr(childExpr,econtext,&isnull,NULL); >+ } else { //READFILE >+ chld=READTUP(state,i); >+ Assert(chld!=NULL); >+ slot->val = chld; >+ /* get value of child expr, >+ * in case of variable node is equal to >+ * dt1=heap_getattr(chld, attno1, tupDesc, &isnull); >+ */ >+ dt1 = ExecEvalExpr(childExpr,econtext,&isnull,NULL); >+ } >+ /* no need in storing isnull, because when we first time >+ * evaluating expr and it's null then it marked as used >+ * and don't checked anymore, thus cache not involved >+ */ >+ state->cache[i].chld_c = true; >+ /* store it if it's not null */ >+ if(!isnull){ >+ if(chld_typbyval){ >+ state->cache[i].chlddt_val = dt1; >+ }else { >+ /* copy datum data to temp space*/ >+ datalen = datumGetSize(dt1, false, chld_typlen); >+ morig = MemoryContextSwitchTo(state->tree_ctx); >+ newVal = (char *) palloc(datalen); >+ MemoryContextSwitchTo(morig); >+ memcpy(newVal, DatumGetPointer(dt1), datalen); >+ state->cache[i].chlddt_val = PointerGetDatum(newVal); >+ state->cache[i].chlddt_isnull = false; >+ dt1 = PointerGetDatum(newVal); >+ } >+ } >+ /* free tuple, since we don't need it further, till _gettuple */ >+ if(state->status != TCS_READMEM) { >+ pfree(chld); >+ FREEMEM(state,((HeapTuple)chld)->t_len+HEAPTUPLESIZE); >+ state->out_store[i].tup=NULL; >+ } >+ } >+ conn=false; >+ if(!isnull){ >+ /* scan through nodes array of previous level, >+ * until connect it or array is exhausted >+ */ >+ for(j=0;j<state->pntlast && !conn;j++){ >+ /* get parent tuple */ >+ /* if cached - use cache, in not - retrieve tuple, and build cache */ >+ if(state->cache[state->pnt[j]->tuple].pnt_c){ >+ dt2 = state->cache[state->pnt[j]->tuple].pntdt_val; >+ p_isnull = state->cache[state->pnt[j]->tuple].pntdt_isnull; >+ }else{ >+ if(state->status == TCS_READMEM) { >+ pnt=(HeapTuple)state->memtuples[state->pnt[j]->tuple]; >+ slot->val = pnt; >+ dt2 = ExecEvalExpr(parentExpr,econtext,&p_isnull,NULL); >+ } else { >+ // if tuple parent value is not cached and tuple isn't in mem, >+ // then read it and build cache >+ pnt=state->out_store[state->pnt[j]->tuple].tup; >+ >+ if(pnt==NULL){ >+ pnt=READTUP(state,state->pnt[j]->tuple); >+ } >+ Assert(pnt!=NULL); /*elog(ERROR,"tupleconn: parent tuple is null (internal error)");*/ >+ >+ slot->val = pnt; >+ /* get value of parent expr */ >+ dt2 = ExecEvalExpr(parentExpr,econtext,&p_isnull,NULL); >+ } >+ state->cache[state->pnt[j]->tuple].pntdt_isnull = p_isnull; >+ state->cache[state->pnt[j]->tuple].pnt_c = true; >+ /* cache it, if it's not null*/ >+ if(!p_isnull){ >+ if(pnt_typbyval){ >+ state->cache[state->pnt[j]->tuple].pntdt_val = dt2; >+ }else{ >+ /* copy datum data to temp space */ >+ datalen = datumGetSize(dt2, false, pnt_typlen); >+ morig = MemoryContextSwitchTo(state->tree_ctx); >+ newVal = (char *) palloc(datalen); >+ MemoryContextSwitchTo(morig); >+ memcpy(newVal, DatumGetPointer(dt2), datalen); >+ state->cache[state->pnt[j]->tuple].pntdt_val = PointerGetDatum(newVal); >+ state->cache[state->pnt[j]->tuple].pntdt_isnull = false; >+ dt2 = PointerGetDatum(newVal); >+ } >+ } >+ /* free tuple, same as child */ >+ if(state->status != TCS_READMEM) { >+ pfree(pnt); >+ FREEMEM(state,((HeapTuple)pnt)->t_len+HEAPTUPLESIZE); >+ state->out_store[state->pnt[j]->tuple].tup = NULL; >+ } >+ } >+ if(!p_isnull){ >+ /* apply connOp operator on parent and child expr results, >+ * if 0 (in case of CMP means they're equal) connect them >+ */ >+ is_parent=DatumGetInt32(FunctionCall2(&state->connFn,dt1,dt2)); >+ if(is_parent==0){ >+ ok=0; >+ /* stop scan of parents */ >+ conn=true; >+ /* connect tuples (make node of the connect tree)*/ >+ state->chld[state->chldlast++]=add_sub(state,state->pnt[j],i,level+1); >+ state->used[i]=1; >+ if(state->chldlast>=state->chldsize-1){ >+ /* grow array of connected tuples as necessary */ >+ state->chldsize *= 2; >+ state->chld = (ConnectTree **) >+ repalloc(state->chld, >+ state->chldsize * sizeof(void *)); >+ } >+ } >+ } >+ } >+ }else{ >+ /* mark it as used since it has null child value and can't be >+ * connected to any node >+ * may be better to add nullcheck on this field at parse stage to whereClause, >+ */ >+ state->used[i]=1; >+ } >+ } >+ } >+ /* swap pnt & chld arrays */ >+ t=state->pnt; >+ ti=state->pntsize; >+ >+ state->pnt=state->chld; >+ state->pntsize=state->chldsize; >+ state->pntlast=state->chldlast; >+ >+ state->chld=t; >+ state->chldsize=ti; >+ state->chldlast=0; >+ >+ level++; >+ } >+ /* free anything temporal */ >+ ResetExprContext(econtext); >+ pfree(slot); >+ econtext->ecxt_scantuple = NULL; >+ pfree(state->cache); >+ state->cache=NULL; >+ /* find _level_ attribute, will be used at setlevel() below */ >+ for(i=state->tupDesc->natts-1;i>0;i--){ >+ if(!strcmp(state->tupDesc->attrs[i]->attname.data,"_level_")) state->level=i; >+ } >+ } >+ >+ /* set _level_ column to proper value >+ * first decompose tuple. if we're found _level_ column, >+ * set it to proper value. them form new tuple. >+ * in tape case free original tuple. >+ */ >+ void * >+ setlevel(Tupleconnstate *state,int level, void *tuple,bool free_it){ >+ #define REALLOCATTRS 64 >+ Datum valuesArray[REALLOCATTRS]; >+ char nullsArray[REALLOCATTRS]; >+ Datum *values; >+ char *nulls; >+ HeapTuple newtup,tup = (HeapTuple)tuple; >+ TupleDesc tdesc = state->tupDesc; >+ int natts,i; >+ >+ >+ if(!tuple) return NULL; >+ natts = tdesc->natts; >+ /* prepare arrays */ >+ if(natts>REALLOCATTRS){ >+ values = palloc(natts * sizeof(Datum)); >+ nulls = palloc(natts * sizeof(char)); >+ }else{ >+ values = valuesArray; >+ nulls = nullsArray; >+ } >+ /* decompose tuple and substitute attr _level_ with real value */ >+ for (i = 0; i < natts; i++){ >+ bool isnull; >+ if(i != state->level){ >+ values[i] = heap_getattr(tup, >+ i + 1, >+ tdesc, >+ &isnull); >+ if (isnull) >+ nulls[i] = 'n'; >+ else >+ nulls[i] = ' '; >+ }else{ >+ values[state->level]=Int32GetDatum(level); >+ nulls[i] = ' '; >+ } >+ } >+ /* form new */ >+ tup = heap_formtuple(state->tupDesc,values,nulls); >+ >+ if(natts>REALLOCATTRS){ >+ pfree(values); >+ pfree(nulls); >+ } >+ if(free_it){ >+ /* make full copy of modified tuple and free original */ >+ newtup = heap_copytuple(tup); >+ tup = newtup; >+ FREEMEM(state,((HeapTuple)tuple)->t_len+HEAPTUPLESIZE); >+ heap_freetuple(tuple); >+ tup = newtup; >+ } >+ >+ return tup; >+ } >+ /* >+ * Fetch the next tuple in forward only direction. >+ * Returns NULL if no more tuples. If should_free is set, the >+ * caller must pfree the returned tuple when done with it. >+ */ >+ /* FIXME: add backward direction in future >+ */ >+ void * >+ tupleconn_gettuple(Tupleconnstate *state, >+ bool *should_free) >+ { >+ void *tup=NULL; >+ int level=0; >+ >+ if (state->eof_reached || !state->head) return NULL; >+ >+ /* check status */ >+ switch (state->status) >+ { >+ case TCS_READMEM: >+ *should_free = false; >+ break; >+ case TCS_READFILE: >+ *should_free = true; >+ break; >+ default: >+ elog(ERROR, "tupleconn_gettuple: invalid state"); >+ return NULL; /* keep compiler happy */ >+ } >+ >+ while(!tup) { >+ if(!state->skip_node) { >+ if(state->status == TCS_READMEM){ >+ tup=state->memtuples[state->last->tuple]; >+ }else{ >+ tup=READTUP(state,state->last->tuple); >+ /* will be freed in setlevel(), but setlevel() >+ * can't clear tuple's out_store[] cell, so clear it here >+ */ >+ state->out_store[state->last->tuple].tup=NULL; >+ } >+ level=state->last->level; >+ } >+ if(!state->skip_node && state->last->sub) state->last=state->last->sub; >+ else if(state->last->next){ >+ state->last=state->last->next; >+ state->skip_node = false; >+ } else if(state->last->sup){ >+ state->last=state->last->sup; >+ state->skip_node=true; >+ } else { >+ state->eof_reached = true; >+ break; >+ } >+ } >+ return setlevel(state,level,tup,*should_free); >+ } >+ >+ /* >+ * dumptuples - remove tuples from memory and write to tape >+ */ >+ static void >+ dumptuples(Tupleconnstate *state) >+ { >+ int i,j; >+ bool b; >+ for (i = 0, j = 0; i < state->tupcount; i++){ >+ /* don't free pnt list, because we will use it soon, in tupleconn_performconn() */ >+ if(j < state->pntlast && i == state->pnt[j]->tuple){ >+ b=false; >+ j++; >+ }else b=true; >+ WRITETUP(state, state->memtuples[i],b,i); >+ } >+ } >+ >+ /* >+ * tupleconn_rescan - rewind and replay the scan >+ */ >+ void >+ tupleconn_rescan(Tupleconnstate *state) >+ { >+ >+ /* check status */ >+ switch (state->status) >+ { >+ case TCS_READMEM: >+ case TCS_READFILE: >+ break; >+ default: >+ elog(ERROR, "tupleconn_rescan: invalid state"); >+ break; >+ } >+ state->eof_reached = false; >+ state->markpos_eof = false; >+ >+ state->last = state->head; >+ } >+ >+ /* >+ * tupleconn_markpos - saves current position in the tuple sequence >+ */ >+ void >+ tupleconn_markpos(Tupleconnstate *state) >+ { >+ >+ /* check status */ >+ switch (state->status) >+ { >+ case TCS_READMEM: >+ case TCS_READFILE: >+ break; >+ default: >+ elog(ERROR, "tupleconn_markpos: invalid state"); >+ break; >+ } >+ state->markpos_eof = state->eof_reached; >+ >+ /* file/memtuples positions can be retrieved by state->last >+ * so don't save them >+ */ >+ state->markpos_last = state->last; >+ state->markpos_skip = state->skip_node; >+ } >+ >+ /* >+ * tupleconn_restorepos - restores current position in connection tree to >+ * last saved position >+ */ >+ void >+ tupleconn_restorepos(Tupleconnstate *state) >+ { >+ >+ /* check status */ >+ switch (state->status) >+ { >+ case TCS_READMEM: >+ case TCS_READFILE: >+ break; >+ default: >+ elog(ERROR, "tupleconn_restorepos: invalid state"); >+ break; >+ } >+ state->eof_reached = state->markpos_eof; >+ >+ state->last = state->markpos_last; >+ state->skip_node = state->markpos_skip; >+ } >+ >+ /* >+ * Routines specialized for HeapTuple case >+ */ >+ >+ static void * >+ copytup_heap(Tupleconnstate *state, void *tup) >+ { >+ HeapTuple tuple = (HeapTuple) tup; >+ >+ USEMEM(state, HEAPTUPLESIZE + tuple->t_len); >+ return (void *) heap_copytuple(tuple); >+ } >+ >+ /* >+ * tree building procedures >+ */ >+ >+ /* add new node next to given, set and return it */ >+ ConnectTree * >+ add_next(Tupleconnstate *state,ConnectTree *tr,int tup,int level){ >+ ConnectTree *t; >+ MemoryContext morig; >+ >+ morig=MemoryContextSwitchTo(state->tree_ctx); >+ t=palloc(sizeof(ConnectTree)); >+ MemoryContextSwitchTo(morig); >+ memset(t,0,sizeof(ConnectTree)); >+ t->tuple=tup; >+ t->level=level; >+ if(tr){ >+ tr->next=t; >+ t->prev=tr; >+ } >+ return t; >+ } >+ >+ /* add new node as child to given, set and return it */ >+ ConnectTree * >+ add_sub(Tupleconnstate *state,ConnectTree *tr,int tup,int level){ >+ ConnectTree *t,*t1; >+ MemoryContext morig; >+ >+ morig=MemoryContextSwitchTo(state->tree_ctx); >+ t=palloc(sizeof(ConnectTree)); >+ MemoryContextSwitchTo(morig); >+ memset(t,0,sizeof(ConnectTree)); >+ t->tuple=tup; >+ t->level=level; >+ if(!tr->sub){ >+ tr->sub=t; >+ t->sup=tr; >+ }else{ >+ for(t1=tr->sub;t1->next;t1=t1->next); >+ t1->next=t; >+ t->prev=t1; >+ t->sup=tr; >+ } >+ return t; >+ } >+ >+ >+ /* >+ * File storage procedures >+ * this part taken from tuplestore.c, with addition for >+ * maintaining out_store[]. >+ * because of all on-tape tuple placement info is stored in >+ * out_store[], don't bother to write it on a tape, only >+ * tuple body is stored. >+ */ >+ >+ /* >+ * We don't bother to write the HeapTupleData part of the tuple. >+ */ >+ >+ static void >+ writetup_heap(Tupleconnstate *state, void *tup, bool free, int idx) >+ { >+ HeapTuple tuple = (HeapTuple) tup; >+ >+ /* fill placement info */ >+ state->out_store[idx].len = tuple->t_len; >+ BufFileTell(state->myfile, >+ &state->out_store[idx].fileno, >+ &state->out_store[idx].offs); >+ >+ if (BufFileWrite(state->myfile, (void *) tuple->t_data, >+ tuple->t_len) != (size_t) tuple->t_len) >+ elog(ERROR, "tupleconn: write failed"); >+ >+ /* explanation in dumptuples */ >+ if(free){ >+ // FREEMEM(state, HEAPTUPLESIZE + tuple->t_len); >+ heap_freetuple(tuple); >+ state->out_store[idx].tup = NULL; >+ }else{ >+ state->out_store[idx].tup = (HeapTuple)tup; >+ } >+ } >+ >+ static void * >+ readtup_heap(Tupleconnstate *state, int idx) >+ { >+ unsigned int tuplen = state->out_store[idx].len + HEAPTUPLESIZE; >+ /* add block readings */ >+ HeapTuple tuple = (HeapTuple) palloc(tuplen); >+ >+ USEMEM(state, tuplen); >+ /* reconstruct the HeapTupleData portion */ >+ tuple->t_len = state->out_store[idx].len ; >+ ItemPointerSetInvalid(&(tuple->t_self)); >+ tuple->t_datamcxt = CurrentMemoryContext; >+ tuple->t_data = (HeapTupleHeader) (((char *) tuple) + HEAPTUPLESIZE); >+ /* seek to the tuple */ >+ if(BufFileSeek(state->myfile, >+ state->out_store[idx].fileno, >+ state->out_store[idx].offs,SEEK_SET)!=0) >+ elog(ERROR,"tupleconn: can't seek in readtup_heap"); >+ >+ /* read in the tuple proper */ >+ if (BufFileRead(state->myfile, (void *) tuple->t_data, >+ tuple->t_len) != (size_t) tuple->t_len) >+ elog(ERROR, "tupleconn: unexpected end of data"); >+ >+ state->out_store[idx].tup = tuple; >+ return (void *) tuple; >+ } >+ >+ /* >+ * Select comparation function >+ * made from SelectSortFunction() in nodeSort.c. >+ * differences is the name:) and strategy of operator >+ * being searched (here is BTEqualStrategyNumber) >+ */ >+ >+ void >+ SelectConnFunction(Oid connOperator, >+ RegProcedure *connFunction, >+ SortFunctionKind *kind) >+ { >+ Relation relation; >+ HeapScanDesc scan; >+ ScanKeyData skey[1]; >+ HeapTuple tuple; >+ Form_pg_operator optup; >+ Oid opclass = InvalidOid; >+ >+ ScanKeyEntryInitialize(&skey[0], 0x0, >+ Anum_pg_amop_amopopr, >+ F_OIDEQ, >+ ObjectIdGetDatum(connOperator)); >+ >+ relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock); >+ scan = heap_beginscan(relation, SnapshotNow, 1, skey); >+ >+ while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) >+ { >+ Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple); >+ >+ if (!opclass_is_btree(aform->amopclaid)) >+ continue; >+ if (aform->amopstrategy == BTEqualStrategyNumber) >+ { >+ opclass = aform->amopclaid; >+ *kind = SORTFUNC_CMP; >+ break; /* done looking */ >+ } >+ } >+ >+ heap_endscan(scan); >+ heap_close(relation, AccessShareLock); >+ >+ if (OidIsValid(opclass)) >+ { >+ /* Found a suitable opclass, get its comparator support function */ >+ tuple = SearchSysCache(AMPROCNUM, >+ ObjectIdGetDatum(opclass), >+ Int16GetDatum(BTORDER_PROC), >+ 0, 0); >+ if (HeapTupleIsValid(tuple)) >+ { >+ Form_pg_amproc aform = (Form_pg_amproc) GETSTRUCT(tuple); >+ >+ *connFunction = aform->amproc; >+ ReleaseSysCache(tuple); >+ Assert(RegProcedureIsValid(*connFunction)); >+ return; >+ } >+ } >+ >+ /* >+ * Can't find a comparator, so use the operator as-is. Decide whether >+ * it is forward or reverse conn by looking at its name (grotty, but >+ * this only matters for deciding which end NULLs should get conned >+ * to). >+ */ >+ tuple = SearchSysCache(OPEROID, >+ ObjectIdGetDatum(connOperator), >+ 0, 0, 0); >+ if (!HeapTupleIsValid(tuple)) >+ elog(ERROR, "SelectConnFunction: cache lookup failed for operator %u", >+ connOperator); >+ optup = (Form_pg_operator) GETSTRUCT(tuple); >+ if (strcmp(NameStr(optup->oprname), ">") == 0) >+ *kind = SORTFUNC_REVLT; >+ else >+ *kind = SORTFUNC_LT; >+ *connFunction = optup->oprcode; >+ ReleaseSysCache(tuple); >+ >+ Assert(RegProcedureIsValid(*connFunction)); >+ } >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/include/executor/nodeConn.h postgresql-7.3.1-evg/src/include/executor/nodeConn.h >*** postgresql-7.3.1/src/include/executor/nodeConn.h Thu Jan 1 04:00:00 1970 >--- postgresql-7.3.1-evg/src/include/executor/nodeConn.h Thu Dec 26 17:02:15 2002 >*************** >*** 0 **** >--- 1,27 ---- >+ /*------------------------------------------------------------------------- >+ * >+ * nodeSort.h >+ * >+ * >+ * >+ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group >+ * Portions Copyright (c) 1994, Regents of the University of California >+ * >+ * $Id: nodeSort.h,v 1.14 2001/11/05 17:46:33 momjian Exp $ >+ * >+ *------------------------------------------------------------------------- >+ */ >+ #ifndef NODECONN_H >+ #define NODECONN_H >+ >+ #include "nodes/plannodes.h" >+ >+ extern TupleTableSlot *ExecConn(Conn *node); >+ extern bool ExecInitConn(Conn *node, EState *estate, Plan *parent); >+ extern int ExecCountSlotsConn(Conn *node); >+ extern void ExecEndConn(Conn *node); >+ extern void ExecConnMarkPos(Conn *node); >+ extern void ExecConnRestrPos(Conn *node); >+ extern void ExecReScanConn(Conn *node, ExprContext *exprCtxt, Plan *parent); >+ >+ #endif /* NODECONN_H */ >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/include/nodes/execnodes.h postgresql-7.3.1-evg/src/include/nodes/execnodes.h >*** postgresql-7.3.1/src/include/nodes/execnodes.h Thu Sep 5 01:31:42 2002 >--- postgresql-7.3.1-evg/src/include/nodes/execnodes.h Thu Dec 26 17:02:15 2002 >*************** >*** 709,714 **** >--- 709,728 ---- > } SortState; > > /* ---------------- >+ * ConnectState information >+ * >+ * conn_Done indicates whether connection has been performed yet >+ * tupleconnstate private state of tuplesort.c >+ * ---------------- >+ */ >+ typedef struct ConnectState >+ { >+ CommonScanState csstate; /* its first field is NodeTag */ >+ bool conn_Done; >+ void *tupleconnstate; >+ } ConnectState; >+ >+ /* ---------------- > * UniqueState information > * > * Unique nodes are used "on top of" sort nodes to discard >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/include/nodes/nodes.h postgresql-7.3.1-evg/src/include/nodes/nodes.h >*** postgresql-7.3.1/src/include/nodes/nodes.h Fri Oct 11 09:16:44 2002 >--- postgresql-7.3.1-evg/src/include/nodes/nodes.h Thu Dec 26 17:02:15 2002 >*************** >*** 41,46 **** >--- 41,47 ---- > T_Limit, > T_Material, > T_Sort, >+ T_Conn, > T_Agg, > T_Unique, > T_Hash, >*************** >*** 58,63 **** >--- 59,65 ---- > T_Fjoin, > T_Expr, > T_Var, >+ T_FakeVar, > T_Oper, > T_Const, > T_Param, >*************** >*** 111,116 **** >--- 113,119 ---- > T_AggState, > T_GroupState, > T_SortState, >+ T_ConnectState, > T_UniqueState, > T_HashState, > T_TidScanState, >*************** >*** 239,245 **** > T_InsertDefault, > T_CreateOpClassItem, > T_CompositeTypeStmt, >! > /* > * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h) > */ >--- 242,248 ---- > T_InsertDefault, > T_CreateOpClassItem, > T_CompositeTypeStmt, >! T_HierClause, > /* > * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h) > */ >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/include/nodes/parsenodes.h postgresql-7.3.1-evg/src/include/nodes/parsenodes.h >*** postgresql-7.3.1/src/include/nodes/parsenodes.h Tue Oct 15 03:14:35 2002 >--- postgresql-7.3.1-evg/src/include/nodes/parsenodes.h Thu Dec 26 17:02:15 2002 >*************** >*** 85,90 **** >--- 85,91 ---- > Node *setOperations; /* set-operation tree if this is top level > * of a UNION/INTERSECT/EXCEPT query */ > >+ Node *hierClause; /* CONNECT BY/START WITH clause */ > /* > * If the resultRelation turns out to be the parent of an inheritance > * tree, the planner will add all the child tables to the rtable and >*************** >*** 612,618 **** > */ > typedef SortClause GroupClause; > >! > /***************************************************************************** > * Optimizable Statements > *****************************************************************************/ >--- 613,635 ---- > */ > typedef SortClause GroupClause; > >! /* >! * HierClause - >! * representation of CONNECT BY/START WITH clauses >! * parsed: >! * CONNECT BY ( PRIOR expr ) ( op ) ( expr ) >! * first () is parentExpr >! * second () is connOpName >! * third () is childExpr >! */ >! typedef struct HierClause >! { >! NodeTag type; >! Node *parentExpr,*childExpr; >! Node *connOpName; >! Node *startQual; /* Quals for heads */ >! Oid connOp; /* operator for comparing parent & child exprs*/ >! } HierClause; > /***************************************************************************** > * Optimizable Statements > *****************************************************************************/ >*************** >*** 698,703 **** >--- 715,721 ---- > Node *whereClause; /* WHERE qualification */ > List *groupClause; /* GROUP BY clauses */ > Node *havingClause; /* HAVING conditional-expression */ >+ List *hierClause; /* CONNECT BY , START WITH clauses*/ > > /* > * These fields are used in both "leaf" SelectStmts and upper-level >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/include/nodes/plannodes.h postgresql-7.3.1-evg/src/include/nodes/plannodes.h >*** postgresql-7.3.1/src/include/nodes/plannodes.h Thu Sep 5 01:31:44 2002 >--- postgresql-7.3.1-evg/src/include/nodes/plannodes.h Thu Dec 26 17:02:15 2002 >*************** >*** 50,55 **** >--- 50,56 ---- > * SetOp SetOpState setopstate; > * Limit LimitState limitstate; > * Hash HashState hashstate; >+ * Conn ConnectState connstate; > * > * ---------------------------------------------------------------- > */ >*************** >*** 365,370 **** >--- 366,385 ---- > int keycount; > SortState *sortstate; > } Sort; >+ >+ /* ---------------- >+ * conn node >+ * ---------------- >+ */ >+ typedef struct Conn >+ { >+ Plan plan; >+ ConnectState *connstate; >+ Node *startQual; /* qual conditions for heads */ >+ Node *parentExpr; >+ Node *childExpr; >+ Oid connOp; >+ }Conn; > > /* ---------------- > * unique node >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/include/nodes/primnodes.h postgresql-7.3.1-evg/src/include/nodes/primnodes.h >*** postgresql-7.3.1/src/include/nodes/primnodes.h Thu Sep 19 02:35:24 2002 >--- postgresql-7.3.1-evg/src/include/nodes/primnodes.h Thu Dec 26 17:02:15 2002 >*************** >*** 261,266 **** >--- 261,291 ---- > AttrNumber varoattno; /* original value of varattno */ > } Var; > >+ /* FakeVar is same as Var, with several exeptions: >+ * >+ * it's not fetched from the tables. >+ * it's not passed to scan nodes so them don't see it. >+ * when we comes to moment when we must fetch value from nowhere >+ * (because of nonexistence of FakeVar as relation attr), we just return >+ * 0 as Datum. this made at executor/execQual.c:ExecEvalFakeVar(). >+ * FakeVar exist only for checking attrs in scan tuple with baseing on targetlist, >+ * not in outer or inner relations. so there is no varno. >+ * it never rewritten because of it's based on targetlist where it's present. >+ * so there is no *old fields. >+ * now supproted only INT4 type FakeVars (see at executor/execQual.c:ExecEvalFakeVar()). >+ * but may be extended. >+ */ >+ typedef struct FakeVar >+ { >+ NodeTag type; >+ AttrNumber varattno; /* attribute number of this var, or zero >+ * for all */ >+ Oid vartype; /* pg_type tuple OID for the type of this >+ * var */ >+ int32 vartypmod; /* pg_attribute typmod value */ >+ >+ } FakeVar; >+ > /* > * Const > */ >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/include/optimizer/cost.h postgresql-7.3.1-evg/src/include/optimizer/cost.h >*** postgresql-7.3.1/src/include/optimizer/cost.h Thu Sep 5 01:31:44 2002 >--- postgresql-7.3.1-evg/src/include/optimizer/cost.h Thu Dec 26 17:02:15 2002 >*************** >*** 57,62 **** >--- 57,64 ---- > RelOptInfo *baserel); > extern void cost_sort(Path *path, Query *root, > List *pathkeys, double tuples, int width); >+ extern void cost_conn(Path *path, Query *root, >+ List *pathkeys, double tuples, int width); > extern void cost_nestloop(Path *path, Query *root, > Path *outer_path, Path *inner_path, > List *restrictlist); >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/include/optimizer/planmain.h postgresql-7.3.1-evg/src/include/optimizer/planmain.h >*** postgresql-7.3.1/src/include/optimizer/planmain.h Thu Sep 5 01:31:45 2002 >--- postgresql-7.3.1-evg/src/include/optimizer/planmain.h Thu Dec 26 17:02:15 2002 >*************** >*** 33,38 **** >--- 33,39 ---- > Plan *lefttree, int keycount); > extern Sort *make_sort_from_pathkeys(Query *root, List *tlist, > Plan *lefttree, List *pathkeys); >+ extern Conn *make_conn(Query *root, List *tlist, Plan *lefttree); > extern Agg *make_agg(List *tlist, List *qual, Plan *lefttree); > extern Group *make_group(List *tlist, bool tuplePerGroup, int ngrp, > AttrNumber *grpColIdx, Plan *lefttree); >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/include/optimizer/planner.h postgresql-7.3.1-evg/src/include/optimizer/planner.h >*** postgresql-7.3.1/src/include/optimizer/planner.h Fri Jun 21 01:29:51 2002 >--- postgresql-7.3.1-evg/src/include/optimizer/planner.h Thu Dec 26 17:02:15 2002 >*************** >*** 23,27 **** >--- 23,29 ---- > > extern Plan *make_sortplan(Query *parse, List *tlist, > Plan *plannode, List *sortcls); >+ extern Plan *make_connplan(Query *parse, List *tlist, >+ Plan *plannode); > > #endif /* PLANNER_H */ >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/include/parser/parse_clause.h postgresql-7.3.1-evg/src/include/parser/parse_clause.h >*** postgresql-7.3.1/src/include/parser/parse_clause.h Fri Jun 21 01:29:51 2002 >--- postgresql-7.3.1-evg/src/include/parser/parse_clause.h Thu Dec 26 17:02:15 2002 >*************** >*** 23,28 **** >--- 23,29 ---- > extern Node *transformWhereClause(ParseState *pstate, Node *where); > extern List *transformGroupClause(ParseState *pstate, List *grouplist, > List *targetlist); >+ extern Node *transformHierClause(ParseState *pstate, Query *qry, List *hier); > extern List *transformSortClause(ParseState *pstate, List *orderlist, > List *targetlist); > extern List *transformDistinctClause(ParseState *pstate, List *distinctlist, >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/include/parser/parse_node.h postgresql-7.3.1-evg/src/include/parser/parse_node.h >*** postgresql-7.3.1/src/include/parser/parse_node.h Thu Sep 19 02:35:24 2002 >--- postgresql-7.3.1-evg/src/include/parser/parse_node.h Thu Dec 26 17:02:15 2002 >*************** >*** 46,51 **** >--- 46,64 ---- > bool p_hasSubLinks; > bool p_is_insert; > bool p_is_update; >+ >+ AttrNumber p_hierLevelColIdx; /* _level_ column number for hier clause, if any. >+ * set in transformHierClause() */ >+ bool p_addTle; /* flag used in parse_expr.c:transformIndirection(). >+ * if set all vars going thought will be checked against >+ * current targetlist (field below), and if not present, >+ * added to it as junk. >+ * this is needed in HierClause case. in parent/child Expr and startQual >+ * may be preset attributes which is not in targetlist given by user, so >+ * at transformation stage we'll add them. >+ */ >+ List *p_curTlist; /* current target list (see above)*/ >+ > Relation p_target_relation; > RangeTblEntry *p_target_rangetblentry; > } ParseState; >diff -P -r -d -c --exclude-from=exclude postgresql-7.3.1/src/include/utils/tupleconn.h postgresql-7.3.1-evg/src/include/utils/tupleconn.h >*** postgresql-7.3.1/src/include/utils/tupleconn.h Thu Jan 1 04:00:00 1970 >--- postgresql-7.3.1-evg/src/include/utils/tupleconn.h Thu Dec 26 17:02:15 2002 >*************** >*** 0 **** >--- 1,64 ---- >+ /*------------------------------------------------------------------------- >+ * >+ * tuplestore.h >+ * Generalized routines for temporary tuple storage. >+ * >+ * This module handles temporary storage of tuples for purposes such >+ * as Materialize nodes, hashjoin batch files, etc. It is essentially >+ * a dumbed-down version of tuplesort.c; it does no sorting of tuples >+ * but can only store a sequence of tuples and regurgitate it later. >+ * A temporary file is used to handle the data if it exceeds the >+ * space limit specified by the caller. >+ * >+ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group >+ * Portions Copyright (c) 1994, Regents of the University of California >+ * >+ * $Id: tuplestore.h,v 1.6 2001/11/05 17:46:36 momjian Exp $ >+ * >+ *------------------------------------------------------------------------- >+ */ >+ #ifndef TUPLECONN_H >+ #define TUPLECONN_H >+ >+ #include "access/htup.h" >+ #include "nodes/nodes.h" >+ #include "executor/executor.h" >+ >+ /* Tuplestorestate is an opaque type whose details are not known outside >+ * tuplestore.c. >+ */ >+ typedef struct Tupleconnstate Tupleconnstate; >+ >+ /* >+ * Currently we only need to store HeapTuples, but it would be easy >+ * to support the same behavior for IndexTuples and/or bare Datums. >+ */ >+ >+ extern Tupleconnstate *tupleconn_begin_heap( >+ int maxKBytes, TupleDesc tupDesc, Oid connOp); >+ >+ extern void tupleconn_puttuple(Tupleconnstate *state, void *tuple,int head); >+ >+ extern void tupleconn_donestoring(Tupleconnstate *state); >+ >+ extern void *tupleconn_gettuple(Tupleconnstate *state, >+ bool *should_free); >+ >+ #define tupleconn_getheaptuple(state, should_free) \ >+ ((HeapTuple) tupleconn_gettuple(state, should_free)) >+ >+ extern void tupleconn_end(Tupleconnstate *state); >+ >+ extern void tupleconn_performconn(Tupleconnstate *state, Node *parentExpr, Node *childExpr, ExprContext *econtext); >+ >+ /* >+ * These routines may only be called if randomAccess was specified 'true'. >+ * Likewise, backwards scan in gettuple/getdatum is only allowed if >+ * randomAccess was specified. >+ */ >+ >+ extern void tupleconn_rescan(Tupleconnstate *state); >+ extern void tupleconn_markpos(Tupleconnstate *state); >+ extern void tupleconn_restorepos(Tupleconnstate *state); >+ >+ #endif /* TUPLECONN_H */
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 32248
:
19923
|
19924
|
19925
|
19963
|
20007