Index: backend/commands/explain.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/commands/explain.c,v retrieving revision 1.65 diff --unified -r1.65 explain.c --- backend/commands/explain.c 2001/03/22 03:59:22 1.65 +++ backend/commands/explain.c 2001/06/30 23:21:14 @@ -261,11 +261,12 @@ case T_TidScan: if (((Scan *) plan)->scanrelid > 0) { - RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid, + RangeTblEntryRelation *rte = (RangeTblEntryRelation *) + rt_fetch(((Scan *) plan)->scanrelid, es->rtable); /* Assume it's on a real relation */ - Assert(rte->relname); + Assert( IsA(rte, RangeTblEntryRelation) ); appendStringInfo(str, " on %s", stringStringInfo(rte->relname)); @@ -355,11 +356,14 @@ { SubqueryScan *subqueryscan = (SubqueryScan *) plan; Plan *subnode = subqueryscan->subplan; - RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid, - es->rtable); + + RangeTblEntrySubSelect *rte = (RangeTblEntrySubSelect *) + rt_fetch(subqueryscan->scan.scanrelid, + es->rtable); + List *saved_rtable = es->rtable; - Assert(rte->subquery != NULL); + Assert(IsA(rte, RangeTblEntrySubSelect)); es->rtable = rte->subquery->rtable; for (i = 0; i < indent; i++) Index: backend/executor/execMain.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/executor/execMain.c,v retrieving revision 1.143 diff --unified -r1.143 execMain.c --- backend/executor/execMain.c 2001/06/01 02:41:35 1.143 +++ backend/executor/execMain.c 2001/06/30 23:25:35 @@ -341,11 +341,12 @@ case T_SubqueryScan: { SubqueryScan *scan = (SubqueryScan *) plan; - RangeTblEntry *rte; + RangeTblEntrySubSelect *rte; /* Recursively check the subquery */ - rte = rt_fetch(scan->scan.scanrelid, rangeTable); - Assert(rte->subquery != NULL); + rte = (RangeTblEntrySubSelect *) + rt_fetch(scan->scan.scanrelid, rangeTable); + Assert(IsA(rte, RangeTblEntrySubSelect)); ExecCheckQueryPerms(operation, rte->subquery, scan->subplan); break; } @@ -400,10 +401,10 @@ * If it's a subquery RTE, ignore it --- it will be checked when * ExecCheckPlanPerms finds the SubqueryScan node for it. */ - if (rte->subquery) - return; + if (!IsA(rte, RangeTblEntryRelation)) return; - relName = rte->relname; + + relName = ((RangeTblEntryRelation *)rte)->relname; /* * userid to check as: current user unless we have a setuid Index: backend/executor/nodeIndexscan.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/executor/nodeIndexscan.c,v retrieving revision 1.60 diff --unified -r1.60 nodeIndexscan.c --- backend/executor/nodeIndexscan.c 2001/05/27 20:42:18 1.60 +++ backend/executor/nodeIndexscan.c 2001/06/30 23:27:09 @@ -588,7 +588,7 @@ int **runtimeKeyInfo; bool have_runtime_keys; List *rangeTable; - RangeTblEntry *rtentry; + RangeTblEntryRelation *rtentry; Index relid; Oid reloid; Relation currentRelation; @@ -987,7 +987,9 @@ * open the base relation */ relid = node->scan.scanrelid; - rtentry = rt_fetch(relid, rangeTable); + rtentry = (RangeTblEntryRelation *)rt_fetch(relid, rangeTable); + Assert(IsA(rtentry, RangeTblEntryRelation)); + reloid = rtentry->relid; ExecOpenScanR(reloid, /* relation */ Index: backend/executor/nodeSeqscan.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/executor/nodeSeqscan.c,v retrieving revision 1.30 diff --unified -r1.30 nodeSeqscan.c --- backend/executor/nodeSeqscan.c 2001/05/27 20:42:19 1.30 +++ backend/executor/nodeSeqscan.c 2001/06/30 23:28:09 @@ -147,7 +147,7 @@ { Index relid; List *rangeTable; - RangeTblEntry *rtentry; + RangeTblEntryRelation *rtentry; Oid reloid; ScanDirection direction; Relation currentRelation; @@ -159,7 +159,10 @@ */ relid = node->scanrelid; rangeTable = estate->es_range_table; - rtentry = rt_fetch(relid, rangeTable); + + rtentry = (RangeTblEntryRelation *)rt_fetch(relid, rangeTable); + Assert(IsA(rtentry, RangeTblEntryRelation)); + reloid = rtentry->relid; direction = estate->es_direction; Index: backend/executor/nodeSubqueryscan.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/executor/nodeSubqueryscan.c,v retrieving revision 1.9 diff --unified -r1.9 nodeSubqueryscan.c --- backend/executor/nodeSubqueryscan.c 2001/05/27 20:42:20 1.9 +++ backend/executor/nodeSubqueryscan.c 2001/06/30 23:32:40 @@ -107,7 +107,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent) { SubqueryScanState *subquerystate; - RangeTblEntry *rte; + RangeTblEntrySubSelect *rte; EState *sp_estate; /* @@ -146,8 +146,10 @@ * * This should agree with ExecInitSubPlan */ - rte = rt_fetch(node->scan.scanrelid, estate->es_range_table); - Assert(rte->subquery != NULL); + rte = (RangeTblEntrySubSelect *)rt_fetch( + node->scan.scanrelid, + estate->es_range_table); + Assert(IsA(rte, RangeTblEntrySubSelect)); sp_estate = CreateExecutorState(); subquerystate->sss_SubEState = sp_estate; Index: backend/executor/nodeTidscan.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/executor/nodeTidscan.c,v retrieving revision 1.17 diff --unified -r1.17 nodeTidscan.c --- backend/executor/nodeTidscan.c 2001/05/27 20:42:20 1.17 +++ backend/executor/nodeTidscan.c 2001/06/30 23:31:30 @@ -385,7 +385,7 @@ int numTids; int tidPtr; List *rangeTable; - RangeTblEntry *rtentry; + RangeTblEntryRelation *rtentry; Oid relid; Oid reloid; Relation currentRelation; @@ -458,9 +458,11 @@ * open the base relation */ relid = node->scan.scanrelid; - rtentry = rt_fetch(relid, rangeTable); - reloid = rtentry->relid; + rtentry = (RangeTblEntryRelation *)rt_fetch(relid, rangeTable); + Assert(IsA(rtentry, RangeTblEntryRelation)); + + reloid = rtentry->relid; currentRelation = heap_open(reloid, AccessShareLock); scanstate->css_currentRelation = currentRelation; scanstate->css_currentScanDesc = 0; Index: backend/nodes/copyfuncs.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/nodes/copyfuncs.c,v retrieving revision 1.144 diff --unified -r1.144 copyfuncs.c --- backend/nodes/copyfuncs.c 2001/06/09 23:21:54 1.144 +++ backend/nodes/copyfuncs.c 2001/06/30 23:56:14 @@ -1448,15 +1448,8 @@ return newnode; } -static RangeTblEntry * -_copyRangeTblEntry(RangeTblEntry *from) -{ - RangeTblEntry *newnode = makeNode(RangeTblEntry); - - if (from->relname) - newnode->relname = pstrdup(from->relname); - newnode->relid = from->relid; - Node_Copy(from, newnode, subquery); +static void copy_rte_generic(RangeTblEntry *from, RangeTblEntry *newnode) { +/* copy generic fields */ Node_Copy(from, newnode, alias); Node_Copy(from, newnode, eref); newnode->inh = from->inh; @@ -1464,10 +1457,41 @@ newnode->checkForRead = from->checkForRead; newnode->checkForWrite = from->checkForWrite; newnode->checkAsUser = from->checkAsUser; +} +static RangeTblEntryRelation * +_copyRangeTblEntryRelation(RangeTblEntryRelation *from) +{ + RangeTblEntryRelation *newnode = makeNode(RangeTblEntryRelation); + copy_rte_generic( (RangeTblEntry *) from, (RangeTblEntry *) newnode); + newnode->relname = pstrdup(from->relname); + newnode->relid = from->relid; return newnode; } +static RangeTblEntrySubSelect * +_copyRangeTblEntrySubSelect(RangeTblEntrySubSelect *from) +{ + RangeTblEntrySubSelect *newnode = makeNode(RangeTblEntrySubSelect); + copy_rte_generic( (RangeTblEntry *) from, (RangeTblEntry *) newnode); + Node_Copy(from, newnode, subquery); + return newnode; +} + +static RangeTblEntryPortal * +_copyRangeTblEntryPortal(RangeTblEntryPortal *from) +{ + RangeTblEntryPortal *newnode = makeNode(RangeTblEntryPortal); + copy_rte_generic( (RangeTblEntry *) from, (RangeTblEntry *) newnode); + +/* XXX: can't deep copy TupleDesc, this may be a major problem! */ + newnode->tupleDesc = palloc (sizeof(TupleDesc)); + memcpy( newnode->tupleDesc, from->tupleDesc, sizeof(TupleDesc)); + + newnode->portal = pstrdup(from->portal); + return newnode; +} + static FkConstraint * _copyFkConstraint(FkConstraint *from) { @@ -2938,9 +2962,15 @@ break; case T_TargetEntry: retval = _copyTargetEntry(from); + break; + case T_RangeTblEntryRelation: + retval = _copyRangeTblEntryRelation(from); + break; + case T_RangeTblEntryPortal: + retval = _copyRangeTblEntryPortal(from); break; - case T_RangeTblEntry: - retval = _copyRangeTblEntry(from); + case T_RangeTblEntrySubSelect: + retval = _copyRangeTblEntrySubSelect(from); break; case T_SortClause: retval = _copySortClause(from); Index: backend/nodes/equalfuncs.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/nodes/equalfuncs.c,v retrieving revision 1.92 diff --unified -r1.92 equalfuncs.c --- backend/nodes/equalfuncs.c 2001/06/09 23:21:54 1.92 +++ backend/nodes/equalfuncs.c 2001/07/01 00:03:14 @@ -1626,14 +1626,8 @@ } static bool -_equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b) +_equalRangeTblEntryGeneric(RangeTblEntry *a, RangeTblEntry *b) { - if (!equalstr(a->relname, b->relname)) - return false; - if (a->relid != b->relid) - return false; - if (!equal(a->subquery, b->subquery)) - return false; if (!equal(a->alias, b->alias)) return false; if (!equal(a->eref, b->eref)) @@ -1648,11 +1642,45 @@ return false; if (a->checkAsUser != b->checkAsUser) return false; + return true; +} +static bool +_equalRangeTblEntryRelation(RangeTblEntryRelation *a, + RangeTblEntryRelation *b) +{ + if (!_equalRangeTblEntryGeneric( (RangeTblEntry *)a, (RangeTblEntry *) b)) + return false; + if (!equalstr(a->relname, b->relname)) + return false; + if (a->relid != b->relid) + return false; return true; } static bool +_equalRangeTblEntrySubSelect(RangeTblEntrySubSelect *a, + RangeTblEntrySubSelect *b) +{ + if (!_equalRangeTblEntryGeneric( (RangeTblEntry *)a, (RangeTblEntry *) b)) + return false; + if (!equal(a->subquery, b->subquery)) + return false; + return true; +} + +static bool +_equalRangeTblEntryPortal( RangeTblEntryPortal *a, + RangeTblEntryPortal *b) +{ + if (!_equalRangeTblEntryGeneric( (RangeTblEntry *)a, (RangeTblEntry *) b)) + return false; + if (!equalstr(a->portal, b->portal)) + return false; + return true; +} + +static bool _equalSortClause(SortClause *a, SortClause *b) { if (a->tleSortGroupRef != b->tleSortGroupRef) @@ -2103,9 +2131,15 @@ break; case T_TargetEntry: retval = _equalTargetEntry(a, b); + break; + case T_RangeTblEntryRelation: + retval = _equalRangeTblEntryRelation(a, b); + break; + case T_RangeTblEntryPortal: + retval = _equalRangeTblEntryPortal(a, b); break; - case T_RangeTblEntry: - retval = _equalRangeTblEntry(a, b); + case T_RangeTblEntrySubSelect: + retval = _equalRangeTblEntrySubSelect(a, b); break; case T_SortClause: retval = _equalSortClause(a, b); Index: backend/nodes/outfuncs.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/nodes/outfuncs.c,v retrieving revision 1.141 diff --unified -r1.141 outfuncs.c --- backend/nodes/outfuncs.c 2001/05/20 20:28:18 1.141 +++ backend/nodes/outfuncs.c 2001/07/01 00:18:51 @@ -966,14 +966,8 @@ } static void -_outRangeTblEntry(StringInfo str, RangeTblEntry *node) +_outRangeTblEntryGeneric(StringInfo str, RangeTblEntry *node) { - appendStringInfo(str, " RTE :relname "); - _outToken(str, node->relname); - appendStringInfo(str, " :relid %u ", - node->relid); - appendStringInfo(str, " :subquery "); - _outNode(str, node->subquery); appendStringInfo(str, " :alias "); _outNode(str, node->alias); appendStringInfo(str, " :eref "); @@ -987,6 +981,35 @@ node->checkAsUser); } +/* we put generic attributes last */ + +static void +_outRangeTblEntryRelation(StringInfo str, RangeTblEntryRelation *node) +{ + appendStringInfo(str, " RTEREL :relname "); + _outToken(str, node->relname); + appendStringInfo(str, " :relid %u ", + node->relid); + _outRangeTblEntryGeneric(str, (RangeTblEntry *) node); +} + +static void +_outRangeTblEntrySubSelect(StringInfo str, RangeTblEntrySubSelect *node) +{ + appendStringInfo(str, " RTESUBSELECT :subquery "); + _outNode(str, node->subquery); + _outRangeTblEntryGeneric(str, (RangeTblEntry *) node); +} + +static void +_outRangeTblEntryPortal(StringInfo str, RangeTblEntryPortal *node) +{ + appendStringInfo(str, " RTEPORTAL :portal "); + _outToken(str, node->portal); + _outRangeTblEntryGeneric(str, (RangeTblEntry *) node); +} + + /* * Path is a subclass of Node. */ @@ -1581,9 +1604,15 @@ break; case T_TargetEntry: _outTargetEntry(str, obj); + break; + case T_RangeTblEntryRelation: + _outRangeTblEntryRelation(str, obj); + break; + case T_RangeTblEntrySubSelect: + _outRangeTblEntrySubSelect(str, obj); break; - case T_RangeTblEntry: - _outRangeTblEntry(str, obj); + case T_RangeTblEntryPortal: + _outRangeTblEntryPortal(str, obj); break; case T_Path: _outPath(str, obj); Index: backend/nodes/print.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/nodes/print.c,v retrieving revision 1.47 diff --unified -r1.47 print.c --- backend/nodes/print.c 2001/03/22 03:59:32 1.47 +++ backend/nodes/print.c 2001/07/01 00:32:50 @@ -125,18 +125,27 @@ List *l; int i = 1; + RangeTblEntryRelation * rte_rel; + printf("resno\trelname(refname)\trelid\tinFromCl\n"); printf("-----\t----------------\t-----\t--------\n"); foreach(l, rtable) { RangeTblEntry *rte = lfirst(l); - if (rte->relname) + if (IsA(rte, RangeTblEntryRelation)) { + rte_rel = (RangeTblEntryRelation *) rte; printf("%d\t%s (%s)\t%u", - i, rte->relname, rte->eref->relname, rte->relid); - else + i, rte_rel->relname, rte->eref->relname, rte_rel->relid); + } + else if (IsA(rte, RangeTblEntrySubSelect)) { printf("%d\t[subquery] (%s)\t", i, rte->eref->relname); + } + else if (IsA(rte, RangeTblEntryPortal)) { + printf("%d\t[portal] (%s)\t", + i, rte->eref->relname); + } printf("\t%s\t%s\n", (rte->inh ? "inh" : ""), (rte->inFromCl ? "inFromCl" : "")); @@ -176,11 +185,13 @@ break; default: { - RangeTblEntry *rte; + RangeTblEntryRelation *rte; Assert(var->varno > 0 && (int) var->varno <= length(rtable)); - rte = rt_fetch(var->varno, rtable); +/* apilosov: this can be wrong XXX */ + rte = (RangeTblEntryRelation *) + rt_fetch(var->varno, rtable); relname = rte->eref->relname; attname = get_rte_attribute_name(rte, var->varattno); } @@ -357,16 +368,19 @@ p->plan_rows, p->plan_width); if (IsA(p, Scan) ||IsA(p, SeqScan)) { - RangeTblEntry *rte; + RangeTblEntryRelation *rte; - rte = rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable); + rte = (RangeTblEntryRelation *) + rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable); + Assert( IsA(rte, RangeTblEntryRelation)); StrNCpy(extraInfo, rte->relname, NAMEDATALEN); } else if (IsA(p, IndexScan)) { - RangeTblEntry *rte; + RangeTblEntryRelation *rte; - rte = rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable); + rte = (RangeTblEntryRelation *) + rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable); StrNCpy(extraInfo, rte->relname, NAMEDATALEN); } else Index: backend/nodes/readfuncs.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/nodes/readfuncs.c,v retrieving revision 1.110 diff --unified -r1.110 readfuncs.c --- backend/nodes/readfuncs.c 2001/06/05 05:26:04 1.110 +++ backend/nodes/readfuncs.c 2001/07/01 00:20:36 @@ -1364,25 +1364,11 @@ * ---------------- */ static RangeTblEntry * -_readRangeTblEntry(void) +_readRangeTblEntryGeneric(RangeTblEntry *local_node) { - RangeTblEntry *local_node; char *token; int length; - local_node = makeNode(RangeTblEntry); - - token = pg_strtok(&length); /* eat :relname */ - token = pg_strtok(&length); /* get :relname */ - local_node->relname = nullable_string(token, length); - - token = pg_strtok(&length); /* eat :relid */ - token = pg_strtok(&length); /* get :relid */ - local_node->relid = atooid(token); - - token = pg_strtok(&length); /* eat :subquery */ - local_node->subquery = nodeRead(true); /* now read it */ - token = pg_strtok(&length); /* eat :alias */ local_node->alias = nodeRead(true); /* now read it */ @@ -1412,6 +1398,50 @@ return local_node; } +static RangeTblEntryRelation * +_readRangeTblEntryRelation(void) +{ + RangeTblEntryRelation *local_node; + char *token; + int length; + + local_node = makeNode(RangeTblEntryRelation); + + token = pg_strtok(&length); /* eat :relname */ + token = pg_strtok(&length); /* get :relname */ + local_node->relname = nullable_string(token, length); + + token = pg_strtok(&length); /* eat :relid */ + token = pg_strtok(&length); /* get :relid */ + local_node->relid = atooid(token); + _readRangeTblEntryGeneric( (RangeTblEntry *)local_node); + return local_node; +} + +static RangeTblEntrySubSelect * +_readRangeTblEntrySubSelect(void) +{ + RangeTblEntrySubSelect *local_node; + char *token; + int length; + + local_node = makeNode(RangeTblEntrySubSelect); + + token = pg_strtok(&length); /* eat :subquery */ + local_node->subquery = nodeRead(true); /* now read it */ + + _readRangeTblEntryGeneric( (RangeTblEntry *)local_node); + + return local_node; +} + +static RangeTblEntryPortal * +_readRangeTblEntryPortal(void) +{ + elog(ERROR, "Cannot read RangeTblEntryPortal yet"); + return NULL; +} + /* ---------------- * _readPath * @@ -1930,8 +1960,12 @@ return_value = _readParam(); else if (length == 11 && strncmp(token, "TARGETENTRY", length) == 0) return_value = _readTargetEntry(); - else if (length == 3 && strncmp(token, "RTE", length) == 0) - return_value = _readRangeTblEntry(); + else if (length == 6 && strncmp(token, "RTEREL", length) == 0) + return_value = _readRangeTblEntryRelation(); + else if (length == 12 && strncmp(token, "RTESUBSELECT", length) == 0) + return_value = _readRangeTblEntrySubSelect(); + else if (length == 9 && strncmp(token, "RTEPORTAL", length) == 0) + return_value = _readRangeTblEntryPortal(); else if (length == 4 && strncmp(token, "PATH", length) == 0) return_value = _readPath(); else if (length == 9 && strncmp(token, "INDEXPATH", length) == 0) Index: backend/optimizer/path/allpaths.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/optimizer/path/allpaths.c,v retrieving revision 1.76 diff --unified -r1.76 allpaths.c --- backend/optimizer/path/allpaths.c 2001/06/05 17:13:51 1.76 +++ backend/optimizer/path/allpaths.c 2001/07/01 01:53:30 @@ -33,9 +33,9 @@ static void set_base_rel_pathlists(Query *root); static void set_plain_rel_pathlist(Query *root, RelOptInfo *rel, - RangeTblEntry *rte); + RangeTblEntryRelation *rte); static void set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, - Index rti, RangeTblEntry *rte, + Index rti, RangeTblEntryRelation *rte, List *inheritlist); static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed, List *initial_rels); @@ -100,6 +100,8 @@ if (rel->issubquery) { + RangeTblEntrySubSelect *rte_sel = (RangeTblEntrySubSelect *)rte; + Assert(IsA(rte, RangeTblEntrySubSelect)); /* Subquery --- generate a separate plan for it */ /* @@ -129,7 +131,7 @@ * decision not to push down, because it'd result in a worse * plan? */ - if (rte->subquery->setOperations == NULL) + if (rte_sel->subquery->setOperations == NULL) { /* OK to consider pushing down individual quals */ List *upperrestrictlist = NIL; @@ -147,7 +149,6 @@ } else { - /* * We need to replace Vars in the clause (which * must refer to outputs of the subquery) with @@ -157,10 +158,10 @@ * replaced with Params, so they need no work. */ clause = ResolveNew(clause, rti, 0, - rte->subquery->targetList, + rte_sel->subquery->targetList, CMD_SELECT, 0); - rte->subquery->havingQual = - make_and_qual(rte->subquery->havingQual, + rte_sel->subquery->havingQual = + make_and_qual(rte_sel->subquery->havingQual, clause); /* @@ -175,7 +176,7 @@ } /* Generate the plan for the subquery */ - rel->subplan = subquery_planner(rte->subquery, + rel->subplan = subquery_planner(rte_sel->subquery, -1.0 /* default case */ ); /* Copy number of output rows from subplan */ @@ -194,12 +195,15 @@ != NIL) { /* Relation is root of an inheritance tree, process specially */ - set_inherited_rel_pathlist(root, rel, rti, rte, inheritlist); + set_inherited_rel_pathlist(root, rel, rti, + (RangeTblEntryRelation *)rte, + inheritlist); } else { /* Plain relation */ - set_plain_rel_pathlist(root, rel, rte); + Assert( IsA( rte, RangeTblEntryRelation ) ); + set_plain_rel_pathlist(root, rel, (RangeTblEntryRelation *) rte); } } } @@ -209,7 +213,7 @@ * Build access paths for a plain relation (no subquery, no inheritance) */ static void -set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte) +set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntryRelation *rte) { /* Mark rel with estimated output rows, width, etc */ set_baserel_size_estimates(root, rel); @@ -259,7 +263,7 @@ */ static void set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, - Index rti, RangeTblEntry *rte, + Index rti, RangeTblEntryRelation *rte, List *inheritlist) { int parentRTindex = rti; @@ -295,11 +299,15 @@ foreach(il, inheritlist) { int childRTindex = lfirsti(il); - RangeTblEntry *childrte; + RangeTblEntryRelation *childrte; Oid childOID; RelOptInfo *childrel; + + childrte = (RangeTblEntryRelation *) + rt_fetch(childRTindex, root->rtable); + + Assert(IsA(childrte, RangeTblEntryRelation)); - childrte = rt_fetch(childRTindex, root->rtable); childOID = childrte->relid; /* Index: backend/optimizer/path/clausesel.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/optimizer/path/clausesel.c,v retrieving revision 1.45 diff --unified -r1.45 clausesel.c --- backend/optimizer/path/clausesel.c 2001/06/05 05:26:04 1.45 +++ backend/optimizer/path/clausesel.c 2001/07/01 00:44:28 @@ -383,7 +383,7 @@ { RangeTblEntry *rte = rt_fetch(var->varno, root->rtable); - if (rte->subquery) + if (IsA(rte, RangeTblEntrySubSelect)) { /* Index: backend/optimizer/plan/planner.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/optimizer/plan/planner.c,v retrieving revision 1.108 diff --unified -r1.108 planner.c --- backend/optimizer/plan/planner.c 2001/06/05 05:26:04 1.108 +++ backend/optimizer/plan/planner.c 2001/07/01 01:49:49 @@ -267,8 +267,10 @@ if (IsA(jtnode, RangeTblRef)) { int varno = ((RangeTblRef *) jtnode)->rtindex; - RangeTblEntry *rte = rt_fetch(varno, parse->rtable); + RangeTblEntrySubSelect *rte = (RangeTblEntrySubSelect *) + rt_fetch(varno, parse->rtable); Query *subquery = rte->subquery; + /* * Is this a subquery RTE, and if so, is the subquery simple @@ -277,7 +279,8 @@ * Note: even if the subquery itself is simple enough, we can't * pull it up if there is a reference to its whole tuple result. */ - if (subquery && is_simple_subquery(subquery) && + if (IsA( rte, RangeTblEntrySubSelect ) && + is_simple_subquery(subquery) && !contain_whole_tuple_var((Node *) parse, varno, 0)) { int rtoffset; Index: backend/optimizer/prep/preptlist.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/optimizer/prep/preptlist.c,v retrieving revision 1.42 diff --unified -r1.42 preptlist.c --- backend/optimizer/prep/preptlist.c 2001/03/22 03:59:38 1.42 +++ backend/optimizer/prep/preptlist.c 2001/07/01 00:48:06 @@ -58,7 +58,7 @@ { RangeTblEntry *rte = rt_fetch(result_relation, range_table); - if (rte->subquery != NULL || rte->relid == InvalidOid) + if (IsA(rte, RangeTblEntrySubSelect)) elog(ERROR, "preprocess_targetlist: subquery cannot be result relation"); } Index: backend/optimizer/prep/prepunion.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/optimizer/prep/prepunion.c,v retrieving revision 1.65 diff --unified -r1.65 prepunion.c --- backend/optimizer/prep/prepunion.c 2001/06/05 05:26:04 1.65 +++ backend/optimizer/prep/prepunion.c 2001/07/01 00:55:59 @@ -82,6 +82,7 @@ { SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations; Node *node; + RangeTblEntrySubSelect * rte; Query *leftmostQuery; Assert(topop && IsA(topop, SetOperationStmt)); @@ -94,8 +95,12 @@ while (node && IsA(node, SetOperationStmt)) node = ((SetOperationStmt *) node)->larg; Assert(node && IsA(node, RangeTblRef)); - leftmostQuery = rt_fetch(((RangeTblRef *) node)->rtindex, - parse->rtable)->subquery; + rte = (RangeTblEntrySubSelect *) + rt_fetch(((RangeTblRef *) node)->rtindex, parse->rtable); + Assert(rte && IsA(rte, RangeTblEntrySubSelect)); + + leftmostQuery = rte->subquery; + Assert(leftmostQuery != NULL); /* @@ -126,11 +131,13 @@ if (IsA(setOp, RangeTblRef)) { RangeTblRef *rtr = (RangeTblRef *) setOp; - RangeTblEntry *rte = rt_fetch(rtr->rtindex, parse->rtable); + RangeTblEntrySubSelect *rte = (RangeTblEntrySubSelect *) + rt_fetch(rtr->rtindex, parse->rtable); Query *subquery = rte->subquery; Plan *subplan, *plan; + Assert(IsA(rte, RangeTblEntrySubSelect)); Assert(subquery != NULL); /* @@ -532,16 +539,17 @@ List * expand_inherted_rtentry(Query *parse, Index rti, bool dup_parent) { - RangeTblEntry *rte = rt_fetch(rti, parse->rtable); + RangeTblEntryRelation *rte = (RangeTblEntryRelation *) rt_fetch(rti, parse->rtable); Oid parentOID = rte->relid; List *inhOIDs; List *inhRTIs; List *l; + Assert(IsA(rte, RangeTblEntryRelation)); /* Does RT entry allow inheritance? */ if (!rte->inh) return NIL; - Assert(parentOID != InvalidOid && rte->subquery == NULL); + /* Always clear the parent's inh flag, see above comments */ rte->inh = false; /* Fast path for common case of childless table */ @@ -565,7 +573,7 @@ foreach(l, inhOIDs) { Oid childOID = (Oid) lfirsti(l); - RangeTblEntry *childrte; + RangeTblEntryRelation *childrte; Index childRTindex; /* parent will be in the list too; skip it if not dup requested */ Index: backend/optimizer/util/clauses.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/optimizer/util/clauses.c,v retrieving revision 1.85 diff --unified -r1.85 clauses.c --- backend/optimizer/util/clauses.c 2001/05/20 20:28:19 1.85 +++ backend/optimizer/util/clauses.c 2001/07/01 13:36:49 @@ -1707,8 +1707,8 @@ { RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); - if (rte->subquery) - if (walker(rte->subquery, context)) + if (IsA(rte, RangeTblEntrySubSelect)) + if (walker( ((RangeTblEntrySubSelect *)rte)->subquery, context)) return true; } } @@ -2068,13 +2068,13 @@ foreach(rt, query->rtable) { - RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); + RangeTblEntrySubSelect *rte = (RangeTblEntrySubSelect *) lfirst(rt); - if (rte->subquery) + if (IsA(rte, RangeTblEntrySubSelect)) { - RangeTblEntry *newrte; + RangeTblEntrySubSelect *newrte; - FLATCOPY(newrte, rte, RangeTblEntry); + FLATCOPY(newrte, rte, RangeTblEntrySubSelect); CHECKFLATCOPY(newrte->subquery, rte->subquery, Query); MUTATE(newrte->subquery, newrte->subquery, Query *); rte = newrte; Index: backend/parser/analyze.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/parser/analyze.c,v retrieving revision 1.189 diff --unified -r1.189 analyze.c --- backend/parser/analyze.c 2001/06/04 23:27:23 1.189 +++ backend/parser/analyze.c 2001/06/30 22:18:39 @@ -1993,6 +1993,7 @@ Query *qry = makeNode(Query); SelectStmt *leftmostSelect; int leftmostRTI; + RangeTblEntrySubSelect * leftmostRTE; Query *leftmostQuery; SetOperationStmt *sostmt; char *into; @@ -2068,7 +2069,10 @@ node = ((SetOperationStmt *) node)->larg; Assert(node && IsA(node, RangeTblRef)); leftmostRTI = ((RangeTblRef *) node)->rtindex; - leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery; + leftmostRTE = (RangeTblEntrySubSelect *) rt_fetch(leftmostRTI, pstate->p_rtable); + Assert(node && IsA(leftmostRTE, RangeTblEntrySubSelect)); + leftmostQuery = leftmostRTE->subquery; + Assert(leftmostQuery != NULL); /* @@ -2337,7 +2341,7 @@ if (IsA(node, RangeTblRef)) { RangeTblRef *rtr = (RangeTblRef *) node; - RangeTblEntry *rte = rt_fetch(rtr->rtindex, pstate->p_rtable); + RangeTblEntrySubSelect *rte = (RangeTblEntrySubSelect *) rt_fetch(rtr->rtindex, pstate->p_rtable); Query *selectQuery = rte->subquery; List *result = NIL; List *tl; @@ -2850,17 +2854,25 @@ RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); ++i; - if (rte->subquery) + if (IsA(rte, RangeTblEntrySubSelect)) { /* FOR UPDATE of subquery is propagated to subquery's rels */ - transformForUpdate(rte->subquery, makeList1(NULL)); + transformForUpdate( ((RangeTblEntrySubSelect *)rte)->subquery, makeList1(NULL)); } - else + else if (IsA(rte, RangeTblEntryRelation)) { if (!intMember(i, rowMarks)) /* avoid duplicates */ rowMarks = lappendi(rowMarks, i); rte->checkForWrite = true; } + else if (IsA(rte, RangeTblEntryPortal)) + { + /* do nothing */ + } + else + { + elog(ERROR, "FOR UPDATE: unknown RTE type"); + } } } else @@ -2878,16 +2890,24 @@ ++i; if (strcmp(rte->eref->relname, relname) == 0) { - if (rte->subquery) + if (IsA(rte, RangeTblEntrySubSelect)) { /* propagate to subquery */ - transformForUpdate(rte->subquery, makeList1(NULL)); + transformForUpdate( ((RangeTblEntrySubSelect*) rte)->subquery, makeList1(NULL)); } - else + else if (IsA(rte, RangeTblEntryRelation)) { if (!intMember(i, rowMarks)) /* avoid duplicates */ rowMarks = lappendi(rowMarks, i); rte->checkForWrite = true; + } + else if (IsA(rte, RangeTblEntryPortal)) + { + /* do nothing */ + } + else + { + elog(ERROR, "FOR UPDATE: unknown RTE type"); } break; } Index: backend/parser/parse_clause.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/parser/parse_clause.c,v retrieving revision 1.80 diff --unified -r1.80 parse_clause.c --- backend/parser/parse_clause.c 2001/05/18 21:24:19 1.80 +++ backend/parser/parse_clause.c 2001/06/30 21:12:12 @@ -30,6 +30,7 @@ #include "parser/parse_target.h" #include "parser/parse_type.h" #include "utils/guc.h" +#include "utils/portal.h" #define ORDER_CLAUSE 0 @@ -79,6 +80,7 @@ /* * The grammar will have produced a list of RangeVars, + * FuncRangeVars, PortalRangeVars, * RangeSubselects, and/or JoinExprs. Transform each one (possibly * adding entries to the rtable), check for duplicate refnames, and * then add it to the joinlist and namespace. @@ -394,6 +396,52 @@ /* + * transformPortalRange --- transform FROM CURSOR FOO + */ +static RangeTblRef * +transformPortalRange(ParseState *pstate, PortalRangeVar *r) +{ + RangeTblEntry *rte; + RangeTblRef *rtr; + Portal portal; + QueryDesc *queryDesc; + TupleDesc tupleDesc; + EState *estate; + char *portalname; + + /* look up information for the portal */ + portalname = r->portal; + portal = GetPortalByName(portalname); + if (!PortalIsValid(portal)) + elog(NOTICE, "transformPortalRange: portal \"%s\" not found", + portalname); + + queryDesc = PortalGetQueryDesc(portal); + tupleDesc = PortalGetTupleDesc(portal); + estate = PortalGetState(portal); /* XXX: check state ? */ + + if (queryDesc->operation != CMD_SELECT) + elog(ERROR, "Expected SELECT query from the portal %s", portalname); + + /* + * OK, build an RTE for the subquery. + */ + rte = addRangeTableEntryForPortal(pstate, tupleDesc, portalname, r->name); + + /* + * We create a RangeTblRef, but we do not add it to the joinlist or + * namespace; our caller must do that if appropriate. + */ + rtr = makeNode(RangeTblRef); + /* assume new rte is at end */ + rtr->rtindex = length(pstate->p_rtable); + Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable)); + + return rtr; +} + + +/* * transformRangeSubselect --- transform a sub-SELECT appearing in FROM */ static RangeTblRef * @@ -482,6 +530,15 @@ RangeTblRef *rtr; rtr = transformTableEntry(pstate, (RangeVar *) n); + *containedRels = makeListi1(rtr->rtindex); + return (Node *) rtr; + } + if (IsA(n, PortalRangeVar)) + { + /* reference to cursor */ + RangeTblRef *rtr; + + rtr = transformPortalRange(pstate, (PortalRangeVar *) n); *containedRels = makeListi1(rtr->rtindex); return (Node *) rtr; } Index: backend/parser/parse_func.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/parser/parse_func.c,v retrieving revision 1.108 diff --unified -r1.108 parse_func.c --- backend/parser/parse_func.c 2001/05/19 01:57:11 1.108 +++ backend/parser/parse_func.c 2001/06/30 22:26:58 @@ -334,7 +334,7 @@ if (rteorjoin == NULL) rte = addImplicitRTE(pstate, refname); - else if (IsA(rteorjoin, RangeTblEntry)) + else if (IsA_RTE(rteorjoin)) rte = (RangeTblEntry *) rteorjoin; else if (IsA(rteorjoin, JoinExpr)) { @@ -385,7 +385,14 @@ * signal that the runtime representation will be a pointer * not an Oid. */ - if (rte->relname == NULL) + if (IsA(rte, RangeTblEntryPortal)) + { + /* RTE is a portal reference, possible? not supported yet */ + elog(ERROR, "Cannot pass tuple from portal %s to function %s", + refname, funcname); + } + + if (IsA(rte, RangeTblEntrySubSelect)) { /* * RTE is a subselect; must fail for lack of a specific type @@ -406,7 +413,7 @@ } } - toid = typenameTypeId(rte->relname); + toid = typenameTypeId( ((RangeTblEntryRelation *)rte)->relname); /* replace it in the arg list */ lfirst(i) = makeVar(vnum, Index: backend/parser/parse_node.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/parser/parse_node.c,v retrieving revision 1.54 diff --unified -r1.54 parse_node.c --- backend/parser/parse_node.c 2001/05/22 16:37:16 1.54 +++ backend/parser/parse_node.c 2001/06/30 22:42:29 @@ -170,31 +170,46 @@ vnum = RTERangeTablePosn(pstate, rte, &sublevels_up); - if (rte->relid != InvalidOid) + if (IsA(rte, RangeTblEntryRelation)) { /* Plain relation RTE --- get the attribute's type info */ + RangeTblEntryRelation * rte_rel=(RangeTblEntryRelation *)rte; HeapTuple tp; Form_pg_attribute att_tup; tp = SearchSysCache(ATTNUM, - ObjectIdGetDatum(rte->relid), + ObjectIdGetDatum(rte_rel->relid), Int16GetDatum(attrno), 0, 0); /* this shouldn't happen... */ if (!HeapTupleIsValid(tp)) elog(ERROR, "Relation %s does not have attribute %d", - rte->relname, attrno); + rte_rel->relname, attrno); att_tup = (Form_pg_attribute) GETSTRUCT(tp); vartypeid = att_tup->atttypid; type_mod = att_tup->atttypmod; ReleaseSysCache(tp); + } + else if (IsA(rte, RangeTblEntryPortal)) + { /* Portal RTE, get type info from tupleDesc */ + RangeTblEntryPortal * rte_portal=(RangeTblEntryPortal *)rte; + Form_pg_attribute att_tup; + + Assert( rte_portal->tupleDesc != NULL ); + Assert( attrno <= (rte_portal->tupleDesc->natts) ); + + att_tup = rte_portal->tupleDesc->attrs[attrno]; + + vartypeid = att_tup->atttypid; + type_mod = att_tup->atttypmod; } - else + else if (IsA(rte, RangeTblEntrySubSelect)) { /* Subselect RTE --- get type info from subselect's tlist */ List *tlistitem; + RangeTblEntrySubSelect * rte_sel=(RangeTblEntrySubSelect *)rte; - foreach(tlistitem, rte->subquery->targetList) + foreach(tlistitem, rte_sel->subquery->targetList) { TargetEntry *te = (TargetEntry *) lfirst(tlistitem); @@ -207,7 +222,11 @@ /* falling off end of list shouldn't happen... */ if (tlistitem == NIL) elog(ERROR, "Subquery %s does not have attribute %d", - rte->eref->relname, attrno); + rte_sel->eref->relname, attrno); + } + else + { + elog(ERROR, "make_var: Unknown RTE type"); } return makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up); Index: backend/parser/parse_relation.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/parser/parse_relation.c,v retrieving revision 1.55 diff --unified -r1.55 parse_relation.c --- backend/parser/parse_relation.c 2001/05/07 00:43:23 1.55 +++ backend/parser/parse_relation.c 2001/07/01 01:02:00 @@ -316,7 +316,7 @@ * If the RTE represents a table (not a sub-select), consider system * column names. */ - if (rte->relid != InvalidOid) + if (IsA(rte, RangeTblEntryRelation)) { attnum = specialAttNum(colname); if (attnum != InvalidAttrNumber) @@ -459,7 +459,7 @@ sublevels_up = 0; } - if (IsA(rteorjoin, RangeTblEntry)) + if (IsA_RTE(rteorjoin)) result = scanRTEForColumn(pstate, (RangeTblEntry *) rteorjoin, colname); else if (IsA(rteorjoin, JoinExpr)) @@ -491,7 +491,7 @@ bool inh, bool inFromCl) { - RangeTblEntry *rte = makeNode(RangeTblEntry); + RangeTblEntryRelation *rte = makeNode(RangeTblEntryRelation); char *refname = alias ? alias->relname : relname; LOCKMODE lockmode; Relation rel; @@ -502,7 +502,6 @@ rte->relname = relname; rte->alias = alias; - rte->subquery = NULL; /* * Get the rel's OID. This access also ensures that we have an @@ -567,10 +566,77 @@ if (pstate != NULL) pstate->p_rtable = lappend(pstate->p_rtable, rte); - return rte; + return (RangeTblEntry *) rte; } /* + * Add an entry for a portal reference or for a function-used-as-table + * to the pstate's range table (p_rtable). + * + * This is just like addRangeTableEntry() except that it makes a portal RTE. + */ +RangeTblEntry * +addRangeTableEntryForPortal(ParseState *pstate, + TupleDesc tupleDesc, + char *portalname, + Attr *alias + ) +{ + RangeTblEntryPortal *rte = makeNode(RangeTblEntryPortal); + char *refname = alias ? alias->relname : portalname; + Attr *eref; + int maxattrs; + int numaliases; + int varattno; + + rte->portal = portalname; + rte->alias = alias; + rte->tupleDesc = tupleDesc; + + eref = alias ? (Attr *) copyObject(alias) : makeAttr(refname, NULL); + numaliases = length(eref->attrs); + + /* fill in any unspecified alias columns */ + varattno = 0; + + maxattrs = tupleDesc->natts; + if (maxattrs < numaliases) + elog(ERROR, "Portal \"%s\" has %d columns available but %d aliases specified", + refname, maxattrs, numaliases); + + /* fill in any unspecified alias columns */ + for (varattno = numaliases; varattno < maxattrs; varattno++) + { + char *attrname; + + attrname = pstrdup(NameStr(tupleDesc->attrs[varattno]->attname)); + eref->attrs = lappend(eref->attrs, makeString(attrname)); + } + rte->eref = eref; + + /*---------- + * Flags: + * - this RTE should be expanded to include descendant tables, + * - this RTE is in the FROM clause, + * - this RTE should be checked for read/write access rights. + */ + rte->inh = false; + rte->inFromCl = true; + rte->checkForRead = false; + rte->checkForWrite = false; + rte->checkAsUser = InvalidOid; /* not set-uid by default, either */ + + /* + * Add completed RTE to pstate's range table list, but not to join + * list nor namespace --- caller must do that if appropriate. + */ + if (pstate != NULL) + pstate->p_rtable = lappend(pstate->p_rtable, rte); + + return (RangeTblEntry *) rte; +} + +/* * Add an entry for a subquery to the pstate's range table (p_rtable). * * This is just like addRangeTableEntry() except that it makes a subquery RTE. @@ -582,15 +648,13 @@ Attr *alias, bool inFromCl) { - RangeTblEntry *rte = makeNode(RangeTblEntry); + RangeTblEntrySubSelect *rte = makeNode(RangeTblEntrySubSelect); char *refname = alias->relname; Attr *eref; int numaliases; int varattno; List *tlistitem; - rte->relname = NULL; - rte->relid = InvalidOid; rte->subquery = subquery; rte->alias = alias; @@ -644,7 +708,7 @@ if (pstate != NULL) pstate->p_rtable = lappend(pstate->p_rtable, rte); - return rte; + return (RangeTblEntry *) rte; } /* @@ -746,13 +810,50 @@ /* Need the RT index of the entry for creating Vars */ rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up); - if (rte->relname) + if (IsA(rte, RangeTblEntryPortal)) { + /* Portal RTE */ + TupleDesc td; + int maxattrs; + td = ((RangeTblEntryPortal *) rte)->tupleDesc; + + maxattrs = td->natts; + + for (varattno = 0; varattno < maxattrs; varattno++) + { + Form_pg_attribute attr = td->attrs[varattno]; + + if (colnames) + { + char *label; + + if (varattno < length(rte->eref->attrs)) + label = strVal(nth(varattno, rte->eref->attrs)); + else + label = NameStr(attr->attname); + *colnames = lappend(*colnames, makeString(pstrdup(label))); + } + + if (colvars) + { + Var *varnode; + + varnode = makeVar(rtindex, attr->attnum, + attr->atttypid, attr->atttypmod, + sublevels_up); + + *colvars = lappend(*colvars, varnode); + } + } + } + if (IsA(rte, RangeTblEntryRelation)) + { /* Ordinary relation RTE */ Relation rel; int maxattrs; - rel = heap_openr(rte->relname, AccessShareLock); + rel = heap_openr( ( (RangeTblEntryRelation *) rte)->relname, + AccessShareLock); maxattrs = RelationGetNumberOfAttributes(rel); @@ -760,11 +861,6 @@ { Form_pg_attribute attr = rel->rd_att->attrs[varattno]; -#ifdef _DROP_COLUMN_HACK__ - if (COLUMN_IS_DROPPED(attr)) - continue; -#endif /* _DROP_COLUMN_HACK__ */ - if (colnames) { char *label; @@ -787,17 +883,15 @@ *colvars = lappend(*colvars, varnode); } } - - heap_close(rel, AccessShareLock); } - else + else if (IsA(rte, RangeTblEntrySubSelect)) { /* Subquery RTE */ List *aliasp = rte->eref->attrs; List *tlistitem; varattno = 0; - foreach(tlistitem, rte->subquery->targetList) + foreach(tlistitem,((RangeTblEntrySubSelect *)rte)->subquery->targetList) { TargetEntry *te = (TargetEntry *) lfirst(tlistitem); @@ -827,7 +921,11 @@ *colvars = lappend(*colvars, varnode); } } - } + } + else + { + elog(ERROR, "expandRTE: Unknown RTE type"); + } } /* @@ -903,11 +1001,11 @@ /* ---------- * get_rte_attribute_name - * Get an attribute name from a RangeTblEntry + * Get an attribute name from a RangeTblEntryRelation * * This is unlike get_attname() because we use aliases if available. * In particular, it will work on an RTE for a subselect, whereas - * get_attname() only works on real relations. + * get_attname() only works on real relations. ??? (below) * * "*" is returned if the given attnum is InvalidAttrNumber --- this case * occurs when a Var represents a whole tuple of a relation. @@ -916,12 +1014,14 @@ * not guaranteed unique, and may not even have scope across the whole * query. Cleanest fix would be to add refname/attname to Var nodes and * just print those, rather than indulging in this hack. + * * ---------- */ char * get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum) { char *attname; + RangeTblEntryRelation *rte_rel; if (attnum == InvalidAttrNumber) return "*"; @@ -937,17 +1037,18 @@ * if alias name list is too short (which probably can't happen * anymore). Neither of these cases is valid for a subselect RTE. */ - if (rte->relid == InvalidOid) + if (!IsA(rte, RangeTblEntryRelation)) elog(ERROR, "Invalid attnum %d for rangetable entry %s", attnum, rte->eref->relname); + rte_rel = (RangeTblEntryRelation *) rte; /* * Use the real name of the table's column */ - attname = get_attname(rte->relid, attnum); + attname = get_attname(rte_rel->relid, attnum); if (attname == NULL) elog(ERROR, "cache lookup of attribute %d in relation %u failed", - attnum, rte->relid); + attnum, rte_rel->relid); return attname; } @@ -1075,3 +1176,22 @@ pstate->parentParseState != NULL ? " in subquery" : "", refname); } + +/* + * getrelid + * + * Given the range index of a relation, return the corresponding + * relation OID. Note that InvalidOid will be returned if the + * RTE is for not for a relation. (SubSelect or Portal) + */ + +/* this used to be a #define */ +Oid getrelid (int rangeindex, List * rangetable) { + RangeTblEntry *rte = rt_fetch(rangeindex, rangetable); + if (IsA(rte, RangeTblEntryRelation)) { + return ((RangeTblEntryRelation *)rte)->relid; + } else { + return InvalidOid; + } +} + Index: backend/parser/parse_target.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/parser/parse_target.c,v retrieving revision 1.67 diff --unified -r1.67 parse_target.c --- backend/parser/parse_target.c 2001/05/21 18:42:08 1.67 +++ backend/parser/parse_target.c 2001/06/30 22:55:45 @@ -131,7 +131,7 @@ sublevels_up = 0; } - if (IsA(rteorjoin, RangeTblEntry)) + if (IsA_RTE(rteorjoin)) p_target = nconc(p_target, expandRelAttrs(pstate, (RangeTblEntry *) rteorjoin)); Index: backend/rewrite/rewriteDefine.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/rewrite/rewriteDefine.c,v retrieving revision 1.62 diff --unified -r1.62 rewriteDefine.c --- backend/rewrite/rewriteDefine.c 2001/05/03 21:16:48 1.62 +++ backend/rewrite/rewriteDefine.c 2001/07/01 01:06:41 @@ -445,10 +445,11 @@ { RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); - if (rte->subquery) + if ( IsA(rte, RangeTblEntrySubSelect) ) { /* Recurse into subquery in FROM */ - setRuleCheckAsUser(rte->subquery, userid); + setRuleCheckAsUser( ((RangeTblEntrySubSelect *) rte)->subquery, + userid); } else rte->checkAsUser = userid; Index: backend/rewrite/rewriteHandler.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/rewrite/rewriteHandler.c,v retrieving revision 1.95 diff --unified -r1.95 rewriteHandler.c --- backend/rewrite/rewriteHandler.c 2001/06/13 18:56:30 1.95 +++ backend/rewrite/rewriteHandler.c 2001/07/01 02:15:27 @@ -265,8 +265,9 @@ bool relIsUsed) { Query *rule_action; - RangeTblEntry *rte, - *subrte; + RangeTblEntry *rte; + RangeTblEntrySubSelect *rte_sel=NULL; /* pacify compiler */ + RangeTblEntryRelation *subrte; if (length(rule->actions) != 1) elog(ERROR, "ApplyRetrieveRule: expected just one rule action"); @@ -287,26 +288,46 @@ * VIEWs are really easy --- just plug the view query in as a * subselect, replacing the relation's original RTE. */ - rte = rt_fetch(rt_index, parsetree->rtable); + rte = (RangeTblEntry *) rt_fetch(rt_index, parsetree->rtable); - rte->relname = NULL; - rte->relid = InvalidOid; - rte->subquery = rule_action; - rte->inh = false; /* must not be set for a subquery */ + /* We have to mutate whatever RTE kind it was into RTESubSelect */ + if ( IsA(rte, RangeTblEntrySubSelect) ) { /* already was SubSelect */ + rte_sel=(RangeTblEntrySubSelect *) rte; + } else if (IsA(rte, RangeTblEntryRelation)) { + /* clone the RTE, then set subquery */ + rte_sel = makeNode(RangeTblEntrySubSelect); + rte_sel->alias = rte->alias; + rte_sel->eref = rte->eref; + rte_sel->inh = rte->inh; + rte_sel->inFromCl = rte->inFromCl; + /* these will be overwritten below, but copy them anyway */ + rte_sel->checkForRead = rte->checkForRead; + rte_sel->checkForWrite = rte->checkForWrite; + rte_sel->checkAsUser = rte->checkAsUser; + /* put the new RTE into RT table, overwriting old one */ + rt_store(rt_index, parsetree->rtable, rte_sel); + } else { + elog(ERROR, "ApplyRetrieveRule: unknown RTE type"); + } + rte_sel->subquery = rule_action; + rte_sel->inh = false; /* must not be set for a subquery */ + /* * We move the view's permission check data down to its rangetable. * The checks will actually be done against the *OLD* entry therein. */ - subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable); + subrte = (RangeTblEntryRelation *) + rt_fetch(PRS2_OLD_VARNO, rule_action->rtable); + Assert( IsA(subrte, RangeTblEntryRelation) ); Assert(subrte->relid == relation->rd_id); - subrte->checkForRead = rte->checkForRead; - subrte->checkForWrite = rte->checkForWrite; - subrte->checkAsUser = rte->checkAsUser; - - rte->checkForRead = false; /* no permission check on subquery itself */ - rte->checkForWrite = false; - rte->checkAsUser = InvalidOid; + subrte->checkForRead = rte_sel->checkForRead; + subrte->checkForWrite = rte_sel->checkForWrite; + subrte->checkAsUser = rte_sel->checkAsUser; + + rte_sel->checkForRead = false; /* no permission check on subquery itself */ + rte_sel->checkForWrite = false; + rte_sel->checkAsUser = InvalidOid; /* * FOR UPDATE of view? @@ -355,10 +376,11 @@ (rti == PRS2_OLD_VARNO || rti == PRS2_NEW_VARNO)) continue; - if (rte->subquery) + if (IsA(rte, RangeTblEntrySubSelect) ) { /* FOR UPDATE of subquery is propagated to subquery's rels */ - markQueryForUpdate(rte->subquery, false); + markQueryForUpdate( ((RangeTblEntrySubSelect *)rte)->subquery, + false); } else { @@ -423,6 +445,7 @@ while (rt_index < length(parsetree->rtable)) { RangeTblEntry *rte; + RangeTblEntryRelation *rte_rel; Relation rel; List *locks; RuleLock *rules; @@ -437,13 +460,24 @@ rte = rt_fetch(rt_index, parsetree->rtable); /* + * A portal RTE can't have associated rules, so there's nothing + * to do to this level of the query. + */ + + if (IsA(rte, RangeTblEntryPortal)) + { + continue; + } + + /* * A subquery RTE can't have associated rules, so there's nothing * to do to this level of the query, but we must recurse into the * subquery to expand any rule references in it. */ - if (rte->subquery) + if (IsA(rte, RangeTblEntrySubSelect)) { - rte->subquery = fireRIRrules(rte->subquery); + RangeTblEntrySubSelect * rte_sel = (RangeTblEntrySubSelect *) rte; + rte_sel->subquery = fireRIRrules(rte_sel->subquery); continue; } @@ -459,6 +493,8 @@ if (!relIsUsed && rt_index != parsetree->resultRelation) continue; + /* by here, rte must be RTERelation */ + rte_rel = (RangeTblEntryRelation *) rte; /* * This may well be the first access to the relation during the * current statement (it will be, if this Query was extracted from @@ -479,7 +515,7 @@ else lockmode = AccessShareLock; - rel = heap_openr(rte->relname, lockmode); + rel = heap_openr(rte_rel->relname, lockmode); /* * Check to see if relation's OID matches the RTE. If not, the RTE @@ -487,9 +523,9 @@ * Eventually we might want to reparse the referencing rule, but * for now all we can do is punt. */ - if (RelationGetRelid(rel) != rte->relid) + if (RelationGetRelid(rel) != rte_rel->relid) elog(ERROR, "Relation \"%s\" with OID %u no longer exists", - rte->relname, rte->relid); + rte_rel->relname, rte_rel->relid); /* * Collect the RIR rules that we must apply @@ -730,7 +766,7 @@ CmdType event; List *product_queries = NIL; int result_relation; - RangeTblEntry *rt_entry; + RangeTblEntryRelation *rt_entry; Relation rt_entry_relation; RuleLock *rt_entry_locks; @@ -756,7 +792,9 @@ */ result_relation = parsetree->resultRelation; Assert(result_relation != 0); - rt_entry = rt_fetch(result_relation, parsetree->rtable); + rt_entry = (RangeTblEntryRelation *) + rt_fetch(result_relation, parsetree->rtable); + Assert( IsA( rt_entry, RangeTblEntryRelation) ); /* * This may well be the first access to the result relation during the @@ -924,7 +962,7 @@ RangeTblEntry *rte = rt_fetch(query->resultRelation, query->rtable); - if (rte->subquery) + if (IsA(rte, RangeTblEntrySubSelect)) { switch (query->commandType) { Index: backend/rewrite/rewriteManip.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/rewrite/rewriteManip.c,v retrieving revision 1.57 diff --unified -r1.57 rewriteManip.c --- backend/rewrite/rewriteManip.c 2001/04/18 20:42:55 1.57 +++ backend/rewrite/rewriteManip.c 2001/07/01 01:23:47 @@ -531,7 +531,7 @@ getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr) { Query *selectquery; - RangeTblEntry *selectrte; + RangeTblEntrySubSelect *selectrte; RangeTblRef *rtr; if (subquery_ptr) @@ -559,7 +559,9 @@ elog(ERROR, "getInsertSelectQuery: expected to find SELECT subquery"); rtr = (RangeTblRef *) lfirst(parsetree->jointree->fromlist); Assert(IsA(rtr, RangeTblRef)); - selectrte = rt_fetch(rtr->rtindex, parsetree->rtable); + selectrte = (RangeTblEntrySubSelect *) + rt_fetch(rtr->rtindex, parsetree->rtable); + Assert(IsA(selectrte, RangeTblEntrySubSelect)); selectquery = selectrte->subquery; if (!(selectquery && IsA(selectquery, Query) && selectquery->commandType == CMD_SELECT)) Index: backend/utils/adt/ruleutils.c =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/backend/utils/adt/ruleutils.c,v retrieving revision 1.77 diff --unified -r1.77 ruleutils.c --- backend/utils/adt/ruleutils.c 2001/04/18 17:04:24 1.77 +++ backend/utils/adt/ruleutils.c 2001/07/01 01:36:48 @@ -636,13 +636,13 @@ deparse_context_for(char *relname, Oid relid) { deparse_namespace *dpns; - RangeTblEntry *rte; + RangeTblEntryRelation *rte; RangeTblRef *rtr; dpns = (deparse_namespace *) palloc(sizeof(deparse_namespace)); /* Build a minimal RTE for the rel */ - rte = makeNode(RangeTblEntry); + rte = makeNode(RangeTblEntryRelation); rte->relname = relname; rte->relid = relid; rte->eref = makeNode(Attr); @@ -1104,9 +1104,10 @@ if (IsA(setOp, RangeTblRef)) { RangeTblRef *rtr = (RangeTblRef *) setOp; - RangeTblEntry *rte = rt_fetch(rtr->rtindex, query->rtable); + RangeTblEntrySubSelect *rte = (RangeTblEntrySubSelect *) + rt_fetch(rtr->rtindex, query->rtable); Query *subquery = rte->subquery; - + Assert( IsA(rte, RangeTblEntrySubSelect) ); Assert(subquery != NULL); get_query_def(subquery, buf, context->namespaces); } @@ -1212,8 +1213,9 @@ get_insert_query_def(Query *query, deparse_context *context) { StringInfo buf = context->buf; - RangeTblEntry *select_rte = NULL; + RangeTblEntrySubSelect *select_rte = NULL; /* rte for underlying SELECT */ RangeTblEntry *rte; + RangeTblEntryRelation *rte_rel; char *sep; List *l; @@ -1224,19 +1226,21 @@ foreach(l, query->rtable) { rte = (RangeTblEntry *) lfirst(l); - if (rte->subquery == NULL) + if (!IsA(rte, RangeTblEntrySubSelect)) continue; if (select_rte) elog(ERROR, "get_insert_query_def: too many RTEs in INSERT!"); - select_rte = rte; + select_rte = (RangeTblEntrySubSelect *) rte; } /* * Start the query with INSERT INTO relname */ - rte = rt_fetch(query->resultRelation, query->rtable); + rte_rel = (RangeTblEntryRelation *) + rt_fetch(query->resultRelation, query->rtable); + Assert(IsA( rte_rel, RangeTblEntryRelation )); appendStringInfo(buf, "INSERT INTO %s", - quote_identifier(rte->relname)); + quote_identifier(rte_rel->relname)); /* Add the insert-column-names list */ sep = " ("; @@ -1285,13 +1289,16 @@ { StringInfo buf = context->buf; char *sep; - RangeTblEntry *rte; + RangeTblEntryRelation *rte; List *l; /* * Start the query with UPDATE relname SET */ - rte = rt_fetch(query->resultRelation, query->rtable); + rte = (RangeTblEntryRelation *) + rt_fetch(query->resultRelation, query->rtable); + + Assert(IsA( rte, RangeTblEntryRelation )); appendStringInfo(buf, "UPDATE %s%s SET ", only_marker(rte), quote_identifier(rte->relname)); @@ -1339,12 +1346,14 @@ get_delete_query_def(Query *query, deparse_context *context) { StringInfo buf = context->buf; - RangeTblEntry *rte; + RangeTblEntryRelation *rte; /* * Start the query with DELETE FROM relname */ - rte = rt_fetch(query->resultRelation, query->rtable); + rte = (RangeTblEntryRelation *) + rt_fetch(query->resultRelation, query->rtable); + Assert(IsA( rte, RangeTblEntryRelation )); appendStringInfo(buf, "DELETE FROM %s%s", only_marker(rte), quote_identifier(rte->relname)); @@ -2361,21 +2370,28 @@ int varno = ((RangeTblRef *) jtnode)->rtindex; RangeTblEntry *rte = rt_fetch(varno, query->rtable); - if (rte->relname) + if (IsA(rte, RangeTblEntryRelation)) { /* Normal relation RTE */ appendStringInfo(buf, "%s%s", - only_marker(rte), - quote_identifier(rte->relname)); + only_marker(rte), + quote_identifier( ((RangeTblEntryRelation *)rte)->relname)); } - else + else if (IsA(rte, RangeTblEntrySubSelect)) { /* Subquery RTE */ - Assert(rte->subquery != NULL); appendStringInfoChar(buf, '('); - get_query_def(rte->subquery, buf, context->namespaces); + get_query_def( ((RangeTblEntrySubSelect *)rte)->subquery, + buf, context->namespaces); appendStringInfoChar(buf, ')'); - } + } else if (IsA(rte, RangeTblEntryPortal)) + { + appendStringInfo(buf, " CURSOR %s", + ((RangeTblEntryPortal *)rte)->portal); + } else + elog(ERROR, "get_from_clause_item: unknown RTE type"); + + if (rte->alias != NULL) { appendStringInfo(buf, " %s", Index: include/nodes/nodes.h =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/include/nodes/nodes.h,v retrieving revision 1.90 diff --unified -r1.90 nodes.h --- include/nodes/nodes.h 2001/06/09 23:21:55 1.90 +++ include/nodes/nodes.h 2001/06/30 22:21:45 @@ -215,7 +215,7 @@ T_Constraint, T_DefElem, T_TargetEntry, - T_RangeTblEntry, + T_RangeTblEntryXXX, /* not used anymore */ T_SortClause, T_GroupClause, T_SubSelectXXX, /* not used anymore; tag# available */ @@ -225,6 +225,11 @@ T_RowMarkXXX, /* not used anymore; tag# available */ T_FkConstraint, T_PrivGrantee, + T_RangeTblEntryRelation, + T_RangeTblEntrySubSelect, + T_RangeTblEntryPortal, +/* T_FuncRangeVar, */ + T_PortalRangeVar, /* * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h) @@ -262,6 +267,10 @@ #define IsA_Join(jp) \ (IsA(jp, Join) || IsA(jp, NestLoop) || \ IsA(jp, MergeJoin) || IsA(jp, HashJoin)) + +#define IsA_RTE(rte) \ + (IsA(rte, RangeTblEntrySubSelect) || IsA(rte, RangeTblEntryPortal) || \ + IsA(rte, RangeTblEntryRelation)) /* ---------------------------------------------------------------- * extern declarations follow Index: include/nodes/parsenodes.h =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/include/nodes/parsenodes.h,v retrieving revision 1.131 diff --unified -r1.131 parsenodes.h --- include/nodes/parsenodes.h 2001/06/09 23:21:55 1.131 +++ include/nodes/parsenodes.h 2001/06/30 22:57:08 @@ -15,6 +15,7 @@ #define PARSENODES_H #include "nodes/primnodes.h" +#include "access/tupdesc.h" /***************************************************************************** * Query Tree @@ -909,6 +910,7 @@ Node *limitOffset; /* # of result tuples to skip */ Node *limitCount; /* # of result tuples to return */ List *forUpdate; /* FOR UPDATE clause */ + bool isFunc; /* select * from func(args) */ /* * These fields are used only in upper-level SelectStmts. @@ -1159,6 +1161,28 @@ } SortGroupBy; /* + * FuncRangeVar - range variable, used in FROM clauses + * select x,y from foo(1) as bar(x,y) + */ +typedef struct FuncRangeVar +{ + NodeTag type; + Node *func; + Attr *name; /* optional table alias & column aliases */ +} FuncRangeVar; + +/* + * PortalRangeVar - range variable, used in FROM clauses + * select x,y from cursor foo + */ +typedef struct PortalRangeVar +{ + NodeTag type; + char *portal; + Attr *name; /* optional table alias & column aliases */ +} PortalRangeVar; + +/* * RangeVar - range variable, used in FROM clauses */ typedef struct RangeVar @@ -1265,32 +1289,46 @@ * (This allows rules to act as setuid gateways.) *-------------------- */ +#define RTE_COMMON_FIELDS \ + NodeTag type; \ + /* \ + * Fields valid in all RTEs: \ + */ \ + Attr *alias; /* user-written alias clause, if any */ \ + Attr *eref; /* expanded reference names */ \ + bool inh; /* inheritance requested? */ \ + bool inFromCl; /* present in FROM clause */ \ + bool checkForRead; /* check rel for read access */ \ + bool checkForWrite; /* check rel for write access */ \ + Oid checkAsUser; /* if not zero, check access as this user */ \ + typedef struct RangeTblEntry { - NodeTag type; + RTE_COMMON_FIELDS +} RangeTblEntry; - /* - * Fields valid for a plain relation RTE (else NULL/zero): - */ +typedef struct RangeTblEntryRelation +{ + RTE_COMMON_FIELDS + /* Fields valid for a plain relation RTE (else NULL/zero): */ char *relname; /* real name of the relation */ Oid relid; /* OID of the relation */ +} RangeTblEntryRelation; - /* - * Fields valid for a subquery RTE (else NULL): - */ +typedef struct RangeTblEntrySubSelect +{ + RTE_COMMON_FIELDS + /* Fields valid for a subquery RTE (else NULL) */ Query *subquery; /* the sub-query */ - - /* - * Fields valid in all RTEs: - */ - Attr *alias; /* user-written alias clause, if any */ - Attr *eref; /* expanded reference names */ - bool inh; /* inheritance requested? */ - bool inFromCl; /* present in FROM clause */ - bool checkForRead; /* check rel for read access */ - bool checkForWrite; /* check rel for write access */ - Oid checkAsUser; /* if not zero, check access as this user */ -} RangeTblEntry; +} RangeTblEntrySubSelect; + +typedef struct RangeTblEntryPortal +{ + RTE_COMMON_FIELDS + /* fields valid for portal RTE */ + TupleDesc tupleDesc; /* tupleDesc of underlying portal */ + char *portal; /* portal's name */ +} RangeTblEntryPortal; /* * SortClause - Index: include/parser/parse_relation.h =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/include/parser/parse_relation.h,v retrieving revision 1.23 diff --unified -r1.23 parse_relation.h --- include/parser/parse_relation.h 2001/03/22 04:00:58 1.23 +++ include/parser/parse_relation.h 2001/06/30 20:28:12 @@ -36,6 +36,11 @@ Query *subquery, Attr *alias, bool inFromCl); +extern RangeTblEntry * addRangeTableEntryForPortal(ParseState *pstate, + TupleDesc tupleDesc, + char *portalname, + Attr *alias + ); extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToNameSpace); extern RangeTblEntry *addImplicitRTE(ParseState *pstate, char *relname); Index: include/parser/parsetree.h =================================================================== RCS file: /home/cvs/pgsql/pgsql/src/include/parser/parsetree.h,v retrieving revision 1.13 diff --unified -r1.13 parsetree.h --- include/parser/parsetree.h 2001/01/24 19:43:27 1.13 +++ include/parser/parsetree.h 2001/07/01 01:00:50 @@ -36,15 +36,8 @@ #define rt_store(rangetable_index, rangetable, rt) \ set_nth(rangetable, (rangetable_index)-1, rt) -/* - * getrelid - * - * Given the range index of a relation, return the corresponding - * relation OID. Note that InvalidOid will be returned if the - * RTE is for a sub-select rather than a relation. - */ -#define getrelid(rangeindex,rangetable) \ - (rt_fetch(rangeindex, rangetable)->relid) +/* getrelid is no longer a #define */ +extern Oid getrelid (int rangeindex, List * rangetable); /* * Given an RTE and an attribute number, return the appropriate