* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.68 2003/05/05 00:44:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.69 2003/05/06 00:20:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static void printtup_setup(DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo);
+ const char *portalName, TupleDesc typeinfo, List *targetlist);
static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
static void printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
static void printtup_cleanup(DestReceiver *self);
static void
printtup_setup(DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo)
+ const char *portalName, TupleDesc typeinfo, List *targetlist)
{
DR_printtup *myState = (DR_printtup *) self;
* then we send back the tuple descriptor of the tuples.
*/
if (operation == CMD_SELECT && myState->sendDescrip)
- SendRowDescriptionMessage(typeinfo);
+ SendRowDescriptionMessage(typeinfo, targetlist);
/* ----------------
* We could set up the derived attr info at this time, but we postpone it
/*
* SendRowDescriptionMessage --- send a RowDescription message to the frontend
+ *
+ * Notes: the TupleDesc has typically been manufactured by ExecTypeFromTL()
+ * or some similar function; it does not contain a full set of fields.
+ * The targetlist will be NIL when executing a utility function that does
+ * not have a plan. If the targetlist isn't NIL then it is a Plan node's
+ * targetlist; it is up to us to ignore resjunk columns in it.
*/
void
-SendRowDescriptionMessage(TupleDesc typeinfo)
+SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist)
{
Form_pg_attribute *attrs = typeinfo->attrs;
int natts = typeinfo->natts;
/* column ID info appears in protocol 3.0 and up */
if (proto >= 3)
{
- /* XXX not yet implemented, send zeroes */
- pq_sendint(&buf, 0, 4);
- pq_sendint(&buf, 0, 2);
+ /* Do we have a non-resjunk tlist item? */
+ while (targetlist &&
+ ((TargetEntry *) lfirst(targetlist))->resdom->resjunk)
+ targetlist = lnext(targetlist);
+ if (targetlist)
+ {
+ Resdom *res = ((TargetEntry *) lfirst(targetlist))->resdom;
+
+ pq_sendint(&buf, res->resorigtbl, 4);
+ pq_sendint(&buf, res->resorigcol, 2);
+ targetlist = lnext(targetlist);
+ }
+ else
+ {
+ /* No info available, so send zeroes */
+ pq_sendint(&buf, 0, 4);
+ pq_sendint(&buf, 0, 2);
+ }
}
pq_sendint(&buf, (int) attrs[i]->atttypid,
sizeof(attrs[i]->atttypid));
*/
void
debugSetup(DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo)
+ const char *portalName, TupleDesc typeinfo, List *targetlist)
{
/*
* show the return type of the tuples
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.106 2003/04/24 21:16:42 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.107 2003/05/06 00:20:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
const char *outer_name, int outer_varno, Plan *outer_plan,
const char *inner_name, int inner_varno, Plan *inner_plan,
StringInfo str, int indent, ExplainState *es);
-static void show_sort_keys(List *tlist, int nkeys, const char *qlabel,
- StringInfo str, int indent, ExplainState *es);
+static void show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
+ const char *qlabel,
+ StringInfo str, int indent, ExplainState *es);
static Node *make_ors_ands_explicit(List *orclauses);
/*
ExplainState *es;
StringInfo str;
- /*
- * If we are not going to execute, suppress any SELECT INTO marker.
- * Without this, ExecutorStart will create the INTO target table,
- * which we don't want.
- */
- if (!stmt->analyze)
- queryDesc->parsetree->into = NULL;
-
gettimeofday(&starttime, NULL);
/* call ExecutorStart to prepare the plan for execution */
- ExecutorStart(queryDesc);
+ ExecutorStart(queryDesc, !stmt->analyze);
/* Execute the plan for statistics if asked for */
if (stmt->analyze)
str, indent, es);
break;
case T_Sort:
- show_sort_keys(plan->targetlist, ((Sort *) plan)->keycount,
+ show_sort_keys(plan->targetlist,
+ ((Sort *) plan)->numCols,
+ ((Sort *) plan)->sortColIdx,
"Sort Key",
str, indent, es);
break;
* Show the sort keys for a Sort node.
*/
static void
-show_sort_keys(List *tlist, int nkeys, const char *qlabel,
+show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
+ const char *qlabel,
StringInfo str, int indent, ExplainState *es)
{
List *context;
}
bms_free(varnos);
- for (keyno = 1; keyno <= nkeys; keyno++)
+ for (keyno = 0; keyno < nkeys; keyno++)
{
/* find key expression in tlist */
+ AttrNumber keyresno = keycols[keyno];
+
foreach(tl, tlist)
{
TargetEntry *target = (TargetEntry *) lfirst(tl);
- if (target->resdom->reskey == keyno)
+ if (target->resdom->resno == keyresno)
{
/* Deparse the expression, showing any top-level cast */
exprstr = deparse_expression((Node *) target->expr, context,
useprefix, true);
/* And add to str */
- if (keyno > 1)
+ if (keyno > 0)
appendStringInfo(str, ", ");
appendStringInfo(str, "%s", exprstr);
break;
}
}
if (tl == NIL)
- elog(ERROR, "show_sort_keys: no tlist entry for key %d", keyno);
+ elog(ERROR, "show_sort_keys: no tlist entry for key %d",
+ keyresno);
}
appendStringInfo(str, "\n");
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.206 2003/05/05 17:57:47 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.207 2003/05/06 00:20:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
} evalPlanQual;
/* decls for local routines only used within this module */
-static void InitPlan(QueryDesc *queryDesc);
+static void InitPlan(QueryDesc *queryDesc, bool explainOnly);
static void initResultRelInfo(ResultRelInfo *resultRelInfo,
Index resultRelationIndex,
List *rangeTable,
* field of the QueryDesc is filled in to describe the tuples that will be
* returned, and the internal fields (estate and planstate) are set up.
*
+ * If explainOnly is true, we are not actually intending to run the plan,
+ * only to set up for EXPLAIN; so skip unwanted side-effects.
+ *
* NB: the CurrentMemoryContext when this is called will become the parent
* of the per-query context used for this Executor invocation.
* ----------------------------------------------------------------
*/
void
-ExecutorStart(QueryDesc *queryDesc)
+ExecutorStart(QueryDesc *queryDesc, bool explainOnly)
{
EState *estate;
MemoryContext oldcontext;
Assert(queryDesc != NULL);
Assert(queryDesc->estate == NULL);
+ /*
+ * If the transaction is read-only, we need to check if any writes
+ * are planned to non-temporary tables.
+ */
+ if (!explainOnly)
+ ExecCheckXactReadOnly(queryDesc->parsetree, queryDesc->operation);
+
/*
* Build EState, switch into per-query memory context for startup.
*/
/*
* Initialize the plan state tree
*/
- InitPlan(queryDesc);
+ InitPlan(queryDesc, explainOnly);
MemoryContextSwitchTo(oldcontext);
}
operation = queryDesc->operation;
dest = queryDesc->dest;
- /*
- * If the transaction is read-only, we need to check if any writes
- * are planned to non-temporary tables. This is done here at this
- * rather late stage so that we can handle EXPLAIN vs. EXPLAIN
- * ANALYZE easily.
- */
- ExecCheckXactReadOnly(queryDesc->parsetree, operation);
-
/*
* startup tuple receiver
*/
estate->es_lastoid = InvalidOid;
destfunc = DestToFunction(dest);
- (*destfunc->setup) (destfunc, operation, queryDesc->portalName,
- queryDesc->tupDesc);
+ (*destfunc->setup) (destfunc, operation,
+ queryDesc->portalName,
+ queryDesc->tupDesc,
+ queryDesc->planstate->plan->targetlist);
/*
* run plan
* ----------------------------------------------------------------
*/
static void
-InitPlan(QueryDesc *queryDesc)
+InitPlan(QueryDesc *queryDesc, bool explainOnly)
{
CmdType operation = queryDesc->operation;
Query *parseTree = queryDesc->parsetree;
* If doing SELECT INTO, initialize the "into" relation. We must wait
* till now so we have the "clean" result tuple type to create the
* new table from.
+ *
+ * If EXPLAIN, skip creating the "into" relation.
*/
intoRelationDesc = (Relation) NULL;
- if (do_select_into)
+ if (do_select_into && !explainOnly)
{
char *intoName;
Oid namespaceId;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.63 2002/12/13 19:45:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.64 2003/05/06 00:20:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
tstate->destfunc = DestToFunction(dest);
(*tstate->destfunc->setup) (tstate->destfunc, (int) CMD_SELECT,
- NULL, tupdesc);
+ NULL, tupdesc, NIL);
return tstate;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.62 2002/12/15 16:17:46 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.63 2003/05/06 00:20:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* Utility commands don't need Executor. */
if (es->qd->operation != CMD_UTILITY)
- ExecutorStart(es->qd);
+ ExecutorStart(es->qd, false);
es->status = F_EXEC_RUN;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.43 2003/05/05 17:57:47 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.44 2003/05/06 00:20:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "executor/nodeSort.h"
#include "utils/tuplesort.h"
-/* ----------------------------------------------------------------
- * ExtractSortKeys
- *
- * Extract the sorting key information from the plan node.
- *
- * Returns two palloc'd arrays, one of sort operator OIDs and
- * one of attribute numbers.
- * ----------------------------------------------------------------
- */
-static void
-ExtractSortKeys(Sort *sortnode,
- Oid **sortOperators,
- AttrNumber **attNums)
-{
- List *targetList;
- int keycount;
- Oid *sortOps;
- AttrNumber *attNos;
- List *tl;
-
- /*
- * get information from the node
- */
- targetList = sortnode->plan.targetlist;
- keycount = sortnode->keycount;
-
- /*
- * first allocate space for results
- */
- if (keycount <= 0)
- elog(ERROR, "ExtractSortKeys: keycount <= 0");
- sortOps = (Oid *) palloc0(keycount * sizeof(Oid));
- *sortOperators = sortOps;
- attNos = (AttrNumber *) palloc0(keycount * sizeof(AttrNumber));
- *attNums = attNos;
-
- /*
- * extract info from the resdom nodes in the target list
- */
- foreach(tl, targetList)
- {
- TargetEntry *target = (TargetEntry *) lfirst(tl);
- Resdom *resdom = target->resdom;
- Index reskey = resdom->reskey;
-
- if (reskey > 0) /* ignore TLEs that are not sort keys */
- {
- Assert(reskey <= keycount);
- sortOps[reskey - 1] = resdom->reskeyop;
- attNos[reskey - 1] = resdom->resno;
- }
- }
-}
/* ----------------------------------------------------------------
* ExecSort
Sort *plannode = (Sort *) node->ss.ps.plan;
PlanState *outerNode;
TupleDesc tupDesc;
- Oid *sortOperators;
- AttrNumber *attNums;
SO1_printf("ExecSort: %s\n",
"sorting subplan");
outerNode = outerPlanState(node);
tupDesc = ExecGetResultType(outerNode);
- ExtractSortKeys(plannode, &sortOperators, &attNums);
-
- tuplesortstate = tuplesort_begin_heap(tupDesc, plannode->keycount,
- sortOperators, attNums,
+ tuplesortstate = tuplesort_begin_heap(tupDesc,
+ plannode->numCols,
+ plannode->sortOperators,
+ plannode->sortColIdx,
true /* randomAccess */ );
node->tuplesortstate = (void *) tuplesortstate;
- pfree(sortOperators);
- pfree(attNums);
-
/*
* Scan the subplan and feed all the tuples to tuplesort.
*/
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.94 2003/05/02 20:54:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.95 2003/05/06 00:20:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
void
spi_dest_setup(DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo)
+ const char *portalName, TupleDesc typeinfo, List *targetlist)
{
SPITupleTable *tuptable;
MemoryContext oldcxt;
ResetUsage();
#endif
- ExecutorStart(queryDesc);
+ ExecutorStart(queryDesc, false);
ExecutorRun(queryDesc, ForwardScanDirection, (long) tcount);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/tstoreReceiver.c,v 1.3 2003/05/02 20:54:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/tstoreReceiver.c,v 1.4 2003/05/06 00:20:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
static void
tstoreSetupReceiver(DestReceiver *self, int operation,
- const char *portalname, TupleDesc typeinfo)
+ const char *portalname,
+ TupleDesc typeinfo, List *targetlist)
{
TStoreState *myState = (TStoreState *) self;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.249 2003/05/02 20:54:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.250 2003/05/06 00:20:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
CopyPlanFields((Plan *) from, (Plan *) newnode);
- COPY_SCALAR_FIELD(keycount);
+ COPY_SCALAR_FIELD(numCols);
+ COPY_POINTER_FIELD(sortColIdx, from->numCols * sizeof(AttrNumber));
+ COPY_POINTER_FIELD(sortOperators, from->numCols * sizeof(Oid));
return newnode;
}
COPY_SCALAR_FIELD(restypmod);
COPY_STRING_FIELD(resname);
COPY_SCALAR_FIELD(ressortgroupref);
- COPY_SCALAR_FIELD(reskey);
- COPY_SCALAR_FIELD(reskeyop);
+ COPY_SCALAR_FIELD(resorigtbl);
+ COPY_SCALAR_FIELD(resorigcol);
COPY_SCALAR_FIELD(resjunk);
return newnode;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.192 2003/05/02 20:54:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.193 2003/05/06 00:20:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
COMPARE_SCALAR_FIELD(restypmod);
COMPARE_STRING_FIELD(resname);
COMPARE_SCALAR_FIELD(ressortgroupref);
- COMPARE_SCALAR_FIELD(reskey);
- COMPARE_SCALAR_FIELD(reskeyop);
+ COMPARE_SCALAR_FIELD(resorigtbl);
+ COMPARE_SCALAR_FIELD(resorigcol);
COMPARE_SCALAR_FIELD(resjunk);
return true;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.38 2003/02/10 04:44:45 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.39 2003/05/06 00:20:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
resdom->resname = resname;
/*
- * We always set the sorting/grouping fields to 0. If the caller
- * wants to change them he must do so explicitly. Few if any callers
- * should be doing that, so omitting these arguments reduces the
- * chance of error.
+ * We always set these fields to 0. If the caller wants to change them
+ * he must do so explicitly. Few callers do that, so omitting these
+ * arguments reduces the chance of error.
*/
resdom->ressortgroupref = 0;
- resdom->reskey = 0;
- resdom->reskeyop = InvalidOid;
+ resdom->resorigtbl = InvalidOid;
+ resdom->resorigcol = 0;
resdom->resjunk = resjunk;
+
return resdom;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.204 2003/05/02 20:54:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.205 2003/05/06 00:20:32 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
static void
_outGroup(StringInfo str, Group *node)
{
- WRITE_NODE_TYPE("GRP");
+ int i;
+
+ WRITE_NODE_TYPE("GROUP");
_outPlanInfo(str, (Plan *) node);
WRITE_INT_FIELD(numCols);
+
+ appendStringInfo(str, " :grpColIdx");
+ for (i = 0; i < node->numCols; i++)
+ appendStringInfo(str, " %d", node->grpColIdx[i]);
}
static void
static void
_outSort(StringInfo str, Sort *node)
{
+ int i;
+
WRITE_NODE_TYPE("SORT");
_outPlanInfo(str, (Plan *) node);
- WRITE_INT_FIELD(keycount);
+ WRITE_INT_FIELD(numCols);
+
+ appendStringInfo(str, " :sortColIdx");
+ for (i = 0; i < node->numCols; i++)
+ appendStringInfo(str, " %d", node->sortColIdx[i]);
+
+ appendStringInfo(str, " :sortOperators");
+ for (i = 0; i < node->numCols; i++)
+ appendStringInfo(str, " %u", node->sortOperators[i]);
}
static void
WRITE_INT_FIELD(restypmod);
WRITE_STRING_FIELD(resname);
WRITE_UINT_FIELD(ressortgroupref);
- WRITE_UINT_FIELD(reskey);
- WRITE_OID_FIELD(reskeyop);
+ WRITE_OID_FIELD(resorigtbl);
+ WRITE_INT_FIELD(resorigcol);
WRITE_BOOL_FIELD(resjunk);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.60 2003/01/22 19:26:35 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.61 2003/05/06 00:20:32 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
TargetEntry *tle = lfirst(tl);
printf("\t%d %s\t", tle->resdom->resno, tle->resdom->resname);
- if (tle->resdom->reskey != 0)
- printf("(%d):\t", tle->resdom->reskey);
+ if (tle->resdom->ressortgroupref != 0)
+ printf("(%u):\t", tle->resdom->ressortgroupref);
else
printf(" :\t");
print_expr((Node *) tle->expr, rtable);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.152 2003/05/02 20:54:34 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.153 2003/05/06 00:20:32 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
READ_INT_FIELD(restypmod);
READ_STRING_FIELD(resname);
READ_UINT_FIELD(ressortgroupref);
- READ_UINT_FIELD(reskey);
- READ_OID_FIELD(reskeyop);
+ READ_OID_FIELD(resorigtbl);
+ READ_INT_FIELD(resorigcol);
READ_BOOL_FIELD(resjunk);
READ_DONE();
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.138 2003/03/10 03:53:50 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.139 2003/05/06 00:20:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
List *mergeclauses,
Plan *lefttree, Plan *righttree,
JoinType jointype);
+static Sort *make_sort(Query *root, List *tlist, Plan *lefttree, int numCols,
+ AttrNumber *sortColIdx, Oid *sortOperators);
static Sort *make_sort_from_pathkeys(Query *root, Plan *lefttree,
Relids relids, List *pathkeys);
subplan->targetlist = newtlist;
}
- my_tlist = new_unsorted_tlist(subplan->targetlist);
+ my_tlist = copyObject(subplan->targetlist);
if (best_path->use_hash)
{
}
/*
- * To use make_sort directly, you must already have marked the tlist
- * with reskey and reskeyop information. The keys had better be
- * non-redundant, too (ie, there had better be tlist items marked with
- * each key number from 1 to keycount), or the executor will get confused!
+ * make_sort --- basic routine to build a Sort plan node
+ *
+ * Caller must have built the sortColIdx and sortOperators arrays already.
*/
-Sort *
-make_sort(Query *root, List *tlist, Plan *lefttree, int keycount)
+static Sort *
+make_sort(Query *root, List *tlist, Plan *lefttree, int numCols,
+ AttrNumber *sortColIdx, Oid *sortOperators)
{
Sort *node = makeNode(Sort);
Plan *plan = &node->plan;
plan->qual = NIL;
plan->lefttree = lefttree;
plan->righttree = NULL;
- node->keycount = keycount;
+ node->numCols = numCols;
+ node->sortColIdx = sortColIdx;
+ node->sortOperators = sortOperators;
return node;
}
+/*
+ * add_sort_column --- utility subroutine for building sort info arrays
+ *
+ * We need this routine because the same column might be selected more than
+ * once as a sort key column; if so, the extra mentions are redundant.
+ *
+ * Caller is assumed to have allocated the arrays large enough for the
+ * max possible number of columns. Return value is the new column count.
+ */
+static int
+add_sort_column(AttrNumber colIdx, Oid sortOp,
+ int numCols, AttrNumber *sortColIdx, Oid *sortOperators)
+{
+ int i;
+
+ for (i = 0; i < numCols; i++)
+ {
+ if (sortColIdx[i] == colIdx)
+ {
+ /* Already sorting by this col, so extra sort key is useless */
+ return numCols;
+ }
+ }
+
+ /* Add the column */
+ sortColIdx[numCols] = colIdx;
+ sortOperators[numCols] = sortOp;
+ return numCols + 1;
+}
+
/*
* make_sort_from_pathkeys
* Create sort plan to sort according to given pathkeys
* 'relids' is the set of relids represented by the input node
* 'pathkeys' is the list of pathkeys by which the result is to be sorted
*
- * We must convert the pathkey information into reskey and reskeyop fields
- * of resdom nodes in the sort plan's target list.
+ * We must convert the pathkey information into arrays of sort key column
+ * numbers and sort operator OIDs.
*
* If the pathkeys include expressions that aren't simple Vars, we will
* usually need to add resjunk items to the input plan's targetlist to
List *tlist = lefttree->targetlist;
List *sort_tlist;
List *i;
- int numsortkeys = 0;
+ int numsortkeys;
+ AttrNumber *sortColIdx;
+ Oid *sortOperators;
- /* Create a new target list for the sort, with sort keys set. */
- sort_tlist = new_unsorted_tlist(tlist);
+ /* We will need at most length(pathkeys) sort columns; possibly less */
+ numsortkeys = length(pathkeys);
+ sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
+ sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
+
+ numsortkeys = 0;
foreach(i, pathkeys)
{
/*
* We can sort by any one of the sort key items listed in this
* sublist. For now, we take the first one that corresponds to an
- * available Var in the sort_tlist. If there isn't any, use the
+ * available Var in the tlist. If there isn't any, use the
* first one that is an expression in the input's vars.
*
* XXX if we have a choice, is there any way of figuring out which
{
pathkey = lfirst(j);
Assert(IsA(pathkey, PathKeyItem));
- resdom = tlist_member(pathkey->key, sort_tlist);
+ resdom = tlist_member(pathkey->key, tlist);
if (resdom)
break;
}
*/
if (IsA(lefttree, Append))
{
- tlist = new_unsorted_tlist(tlist);
+ tlist = copyObject(tlist);
lefttree = (Plan *) make_result(tlist, NULL, lefttree);
}
/*
makeTargetEntry(resdom,
(Expr *) pathkey->key));
lefttree->targetlist = tlist; /* just in case NIL before */
- /*
- * Add one to sort node's tlist too. This will be identical
- * except we are going to set the sort key info in it.
- */
- resdom = makeResdom(length(sort_tlist) + 1,
- exprType(pathkey->key),
- exprTypmod(pathkey->key),
- NULL,
- true);
- sort_tlist = lappend(sort_tlist,
- makeTargetEntry(resdom,
- (Expr *) pathkey->key));
}
/*
- * The resdom might be already marked as a sort key, if the
+ * The column might already be selected as a sort key, if the
* pathkeys contain duplicate entries. (This can happen in
* scenarios where multiple mergejoinable clauses mention the same
- * var, for example.) In that case the current pathkey is
- * essentially a no-op, because only one value can be seen within
- * any subgroup where it would be consulted. We can ignore it.
+ * var, for example.) So enter it only once in the sort arrays.
*/
- if (resdom->reskey == 0)
- {
- /* OK, mark it as a sort key and set the sort operator */
- resdom->reskey = ++numsortkeys;
- resdom->reskeyop = pathkey->sortop;
- }
+ numsortkeys = add_sort_column(resdom->resno, pathkey->sortop,
+ numsortkeys, sortColIdx, sortOperators);
}
Assert(numsortkeys > 0);
- return make_sort(root, sort_tlist, lefttree, numsortkeys);
+ /* Give Sort node its own copy of the tlist (still necessary?) */
+ sort_tlist = copyObject(tlist);
+
+ return make_sort(root, sort_tlist, lefttree, numsortkeys,
+ sortColIdx, sortOperators);
}
/*
{
List *sort_tlist;
List *i;
- int keyno = 0;
+ int numsortkeys;
+ AttrNumber *sortColIdx;
+ Oid *sortOperators;
- /*
- * First make a copy of the tlist so that we don't corrupt the
- * original.
- */
- sort_tlist = new_unsorted_tlist(tlist);
+ /* We will need at most length(sortcls) sort columns; possibly less */
+ numsortkeys = length(sortcls);
+ sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
+ sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
+
+ numsortkeys = 0;
foreach(i, sortcls)
{
SortClause *sortcl = (SortClause *) lfirst(i);
- TargetEntry *tle = get_sortgroupclause_tle(sortcl, sort_tlist);
+ TargetEntry *tle = get_sortgroupclause_tle(sortcl, tlist);
Resdom *resdom = tle->resdom;
/*
* Check for the possibility of duplicate order-by clauses --- the
- * parser should have removed 'em, but the executor will get
- * terribly confused if any get through!
+ * parser should have removed 'em, but no point in sorting redundantly.
*/
- if (resdom->reskey == 0)
- {
- /* OK, insert the ordering info needed by the executor. */
- resdom->reskey = ++keyno;
- resdom->reskeyop = sortcl->sortop;
- }
+ numsortkeys = add_sort_column(resdom->resno, sortcl->sortop,
+ numsortkeys, sortColIdx, sortOperators);
}
- Assert(keyno > 0);
+ Assert(numsortkeys > 0);
+
+ /* Give Sort node its own copy of the tlist (still necessary?) */
+ sort_tlist = copyObject(tlist);
+
+ return make_sort(root, sort_tlist, lefttree, numsortkeys,
+ sortColIdx, sortOperators);
+}
+
+/*
+ * make_sort_from_groupcols
+ * Create sort plan to sort based on grouping columns
+ *
+ * 'groupcls' is the list of GroupClauses
+ * 'grpColIdx' gives the column numbers to use
+ *
+ * This might look like it could be merged with make_sort_from_sortclauses,
+ * but presently we *must* use the grpColIdx[] array to locate sort columns,
+ * because the child plan's tlist is not marked with ressortgroupref info
+ * appropriate to the grouping node. So, only the sortop is used from the
+ * GroupClause entries.
+ */
+Sort *
+make_sort_from_groupcols(Query *root,
+ List *groupcls,
+ AttrNumber *grpColIdx,
+ Plan *lefttree)
+{
+ List *sub_tlist = lefttree->targetlist;
+ List *sort_tlist;
+ int grpno = 0;
+ List *i;
+ int numsortkeys;
+ AttrNumber *sortColIdx;
+ Oid *sortOperators;
+
+ /* We will need at most length(groupcls) sort columns; possibly less */
+ numsortkeys = length(groupcls);
+ sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
+ sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
+
+ numsortkeys = 0;
+
+ foreach(i, groupcls)
+ {
+ GroupClause *grpcl = (GroupClause *) lfirst(i);
+ TargetEntry *tle = nth(grpColIdx[grpno] - 1, sub_tlist);
+ Resdom *resdom = tle->resdom;
+
+ /*
+ * Check for the possibility of duplicate group-by clauses --- the
+ * parser should have removed 'em, but no point in sorting redundantly.
+ */
+ numsortkeys = add_sort_column(resdom->resno, grpcl->sortop,
+ numsortkeys, sortColIdx, sortOperators);
+ grpno++;
+ }
+
+ Assert(numsortkeys > 0);
+
+ /* Give Sort node its own copy of the tlist (still necessary?) */
+ sort_tlist = copyObject(sub_tlist);
- return make_sort(root, sort_tlist, lefttree, keyno);
+ return make_sort(root, sort_tlist, lefttree, numsortkeys,
+ sortColIdx, sortOperators);
}
Material *
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.152 2003/03/13 16:58:35 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.153 2003/05/06 00:20:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
List *tlist,
List *sub_tlist,
AttrNumber *groupColIdx);
-static Plan *make_groupsortplan(Query *parse,
- List *groupClause,
- AttrNumber *grpColIdx,
- Plan *subplan);
static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
{
if (!pathkeys_contained_in(group_pathkeys, current_pathkeys))
{
- result_plan = make_groupsortplan(parse,
- parse->groupClause,
- groupColIdx,
- result_plan);
+ result_plan = (Plan *)
+ make_sort_from_groupcols(parse,
+ parse->groupClause,
+ groupColIdx,
+ result_plan);
current_pathkeys = group_pathkeys;
}
aggstrategy = AGG_SORTED;
*/
if (!pathkeys_contained_in(group_pathkeys, current_pathkeys))
{
- result_plan = make_groupsortplan(parse,
- parse->groupClause,
- groupColIdx,
- result_plan);
+ result_plan = (Plan *)
+ make_sort_from_groupcols(parse,
+ parse->groupClause,
+ groupColIdx,
+ result_plan);
current_pathkeys = group_pathkeys;
}
{
if (!pathkeys_contained_in(sort_pathkeys, current_pathkeys))
{
- result_plan = (Plan *) make_sort_from_sortclauses(parse,
- tlist,
- result_plan,
- parse->sortClause);
+ result_plan = (Plan *)
+ make_sort_from_sortclauses(parse,
+ tlist,
+ result_plan,
+ parse->sortClause);
current_pathkeys = sort_pathkeys;
}
}
}
}
-/*
- * make_groupsortplan
- * Add a Sort node to explicitly sort according to the GROUP BY clause.
- *
- * Note: the Sort node always just takes a copy of the subplan's tlist
- * plus ordering information. (This might seem inefficient if the
- * subplan contains complex GROUP BY expressions, but in fact Sort
- * does not evaluate its targetlist --- it only outputs the same
- * tuples in a new order. So the expressions we might be copying
- * are just dummies with no extra execution cost.)
- */
-static Plan *
-make_groupsortplan(Query *parse,
- List *groupClause,
- AttrNumber *grpColIdx,
- Plan *subplan)
-{
- List *sort_tlist = new_unsorted_tlist(subplan->targetlist);
- int grpno = 0;
- int keyno = 0;
- List *gl;
-
- foreach(gl, groupClause)
- {
- GroupClause *grpcl = (GroupClause *) lfirst(gl);
- TargetEntry *te = nth(grpColIdx[grpno] - 1, sort_tlist);
- Resdom *resdom = te->resdom;
-
- /*
- * Check for the possibility of duplicate group-by clauses ---
- * the parser should have removed 'em, but the Sort executor
- * will get terribly confused if any get through!
- */
- if (resdom->reskey == 0)
- {
- /* OK, insert the ordering info needed by the executor. */
- resdom->reskey = ++keyno;
- resdom->reskeyop = grpcl->sortop;
- }
- grpno++;
- }
-
- Assert(keyno > 0);
-
- return (Plan *) make_sort(parse, sort_tlist, subplan, keyno);
-}
-
/*
* postprocess_setop_tlist
* Fix up targetlist returned by plan_set_operations().
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.94 2003/04/29 22:13:09 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.95 2003/05/06 00:20:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
List *sortList;
- tlist = new_unsorted_tlist(tlist);
+ tlist = copyObject(tlist);
sortList = addAllTargetsToSortList(NIL, tlist);
plan = (Plan *) make_sort_from_sortclauses(parse, tlist,
plan, sortList);
* Sort the child results, then add a SetOp plan node to generate the
* correct output.
*/
- tlist = new_unsorted_tlist(tlist);
+ tlist = copyObject(tlist);
sortList = addAllTargetsToSortList(NIL, tlist);
plan = (Plan *) make_sort_from_sortclauses(parse, tlist, plan, sortList);
switch (op->op)
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.55 2003/02/15 20:12:40 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.56 2003/05/06 00:20:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* ---------- GENERAL target list routines ----------
*****************************************************************************/
-/*
- * new_unsorted_tlist
- * Creates a copy of a target list by creating new resdom nodes
- * without sort information.
- *
- * 'targetlist' is the target list to be copied.
- *
- * Returns the resulting target list.
- *
- */
-List *
-new_unsorted_tlist(List *targetlist)
-{
- List *new_targetlist = (List *) copyObject((Node *) targetlist);
- List *x;
-
- foreach(x, new_targetlist)
- {
- TargetEntry *tle = (TargetEntry *) lfirst(x);
-
- tle->resdom->reskey = 0;
- tle->resdom->reskeyop = (Oid) 0;
- }
- return new_targetlist;
-}
-
/*
* flatten_tlist
* Create a target list that only contains unique variables.
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.270 2003/05/05 00:44:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.271 2003/05/06 00:20:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if (stmt->intoColNames)
applyColumnNames(qry->targetList, stmt->intoColNames);
+ /* mark column origins */
+ markTargetListOrigins(pstate, qry->targetList);
+
/* transform WHERE */
qual = transformWhereClause(pstate, stmt->whereClause);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.100 2003/04/29 22:13:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.101 2003/05/06 00:20:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/builtins.h"
+static void markTargetListOrigin(ParseState *pstate, Resdom *res, Var *var);
static List *ExpandAllTables(ParseState *pstate);
static char *FigureColname(Node *node);
static int FigureColnameInternal(Node *node, char **name);
}
+/*
+ * markTargetListOrigins()
+ * Mark targetlist columns that are simple Vars with the source
+ * table's OID and column number.
+ *
+ * Currently, this is done only for SELECT targetlists, since we only
+ * need the info if we are going to send it to the frontend.
+ */
+void
+markTargetListOrigins(ParseState *pstate, List *targetlist)
+{
+ List *l;
+
+ foreach(l, targetlist)
+ {
+ TargetEntry *tle = (TargetEntry *) lfirst(l);
+
+ markTargetListOrigin(pstate, tle->resdom, (Var *) tle->expr);
+ }
+}
+
+/*
+ * markTargetListOrigin()
+ * If 'var' is a Var of a plain relation, mark 'res' with its origin
+ *
+ * This is split out so it can recurse for join references. Note that we
+ * do not drill down into views, but report the view as the column owner.
+ */
+static void
+markTargetListOrigin(ParseState *pstate, Resdom *res, Var *var)
+{
+ RangeTblEntry *rte;
+ AttrNumber attnum;
+
+ if (var == NULL || !IsA(var, Var))
+ return;
+ Assert(var->varno > 0 &&
+ (int) var->varno <= length(pstate->p_rtable));
+ rte = rt_fetch(var->varno, pstate->p_rtable);
+ attnum = var->varattno;
+
+ switch (rte->rtekind)
+ {
+ case RTE_RELATION:
+ /* It's a table or view, report it */
+ res->resorigtbl = rte->relid;
+ res->resorigcol = attnum;
+ break;
+ case RTE_SUBQUERY:
+ {
+ /* Subselect-in-FROM: copy up from the subselect */
+ List *subtl;
+
+ foreach(subtl, rte->subquery->targetList)
+ {
+ TargetEntry *subte = (TargetEntry *) lfirst(subtl);
+
+ if (subte->resdom->resjunk ||
+ subte->resdom->resno != attnum)
+ continue;
+ res->resorigtbl = subte->resdom->resorigtbl;
+ res->resorigcol = subte->resdom->resorigcol;
+ break;
+ }
+ /* falling off end of list shouldn't happen... */
+ if (subtl == NIL)
+ elog(ERROR, "Subquery %s does not have attribute %d",
+ rte->eref->aliasname, attnum);
+ }
+ break;
+ case RTE_JOIN:
+ {
+ /* Join RTE --- recursively inspect the alias variable */
+ Var *aliasvar;
+
+ Assert(attnum > 0 && attnum <= length(rte->joinaliasvars));
+ aliasvar = (Var *) nth(attnum - 1, rte->joinaliasvars);
+ markTargetListOrigin(pstate, res, aliasvar);
+ }
+ break;
+ case RTE_SPECIAL:
+ case RTE_FUNCTION:
+ /* not a simple relation, leave it unmarked */
+ break;
+ }
+}
+
+
/*
* updateTargetListEntry()
* This is used in INSERT and UPDATE statements only. It prepares a
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.55 2003/05/05 00:44:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.56 2003/05/06 00:20:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static void
donothingSetup(DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo)
+ const char *portalName, TupleDesc typeinfo, List *targetlist)
{
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.332 2003/05/05 00:44:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.333 2003/05/06 00:20:33 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
return; /* can't actually do anything... */
if (portal->tupDesc)
- SendRowDescriptionMessage(portal->tupDesc);
+ {
+ List *targetlist;
+
+ if (portal->strategy == PORTAL_ONE_SELECT)
+ targetlist = ((Plan *) lfirst(portal->planTrees))->targetlist;
+ else
+ targetlist = NIL;
+ SendRowDescriptionMessage(portal->tupDesc, targetlist);
+ }
else
pq_putemptymessage('n'); /* NoData */
}
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
- puts("$Revision: 1.332 $ $Date: 2003/05/05 00:44:56 $\n");
+ puts("$Revision: 1.333 $ $Date: 2003/05/06 00:20:33 $\n");
}
/*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.60 2003/05/02 20:54:35 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.61 2003/05/06 00:20:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Call ExecStart to prepare the plan for execution
*/
- ExecutorStart(queryDesc);
+ ExecutorStart(queryDesc, false);
/*
* Run the plan to completion.
/*
* Call ExecStart to prepare the plan for execution
*/
- ExecutorStart(queryDesc);
+ ExecutorStart(queryDesc, false);
/*
* This tells PortalCleanup to shut down the executor
*/
CommandDest dest)
{
DestReceiver *destfunc;
+ List *targetlist;
long current_tuple_count = 0;
destfunc = DestToFunction(dest);
- (*destfunc->setup) (destfunc, CMD_SELECT, portal->name, portal->tupDesc);
+
+ if (portal->strategy == PORTAL_ONE_SELECT)
+ targetlist = ((Plan *) lfirst(portal->planTrees))->targetlist;
+ else
+ targetlist = NIL;
+
+ (*destfunc->setup) (destfunc, CMD_SELECT, portal->name, portal->tupDesc,
+ targetlist);
if (direction == NoMovementScanDirection)
{
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: printtup.h,v 1.24 2003/05/05 00:44:56 tgl Exp $
+ * $Id: printtup.h,v 1.25 2003/05/06 00:20:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern DestReceiver *printtup_create_DR(bool isBinary, bool sendDescrip);
-extern void SendRowDescriptionMessage(TupleDesc typeinfo);
+extern void SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist);
extern void debugSetup(DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo);
+ const char *portalName, TupleDesc typeinfo, List *targetlist);
extern void debugtup(HeapTuple tuple, TupleDesc typeinfo,
DestReceiver *self);
/* XXX these are really in executor/spi.c */
extern void spi_dest_setup(DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo);
+ const char *portalName, TupleDesc typeinfo, List *targetlist);
extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc,
DestReceiver *self);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catversion.h,v 1.185 2003/05/02 20:54:35 tgl Exp $
+ * $Id: catversion.h,v 1.186 2003/05/06 00:20:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200305011
+#define CATALOG_VERSION_NO 200305051
#endif
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: executor.h,v 1.92 2003/05/05 17:57:47 tgl Exp $
+ * $Id: executor.h,v 1.93 2003/05/06 00:20:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* prototypes from functions in execMain.c
*/
-extern void ExecutorStart(QueryDesc *queryDesc);
+extern void ExecutorStart(QueryDesc *queryDesc, bool explainOnly);
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count);
extern void ExecutorEnd(QueryDesc *queryDesc);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: plannodes.h,v 1.64 2003/02/09 00:30:40 tgl Exp $
+ * $Id: plannodes.h,v 1.65 2003/05/06 00:20:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
typedef struct Sort
{
Plan plan;
- int keycount;
+ int numCols; /* number of sort-key columns */
+ AttrNumber *sortColIdx; /* their indexes in the target list */
+ Oid *sortOperators; /* OIDs of operators to sort them by */
} Sort;
/* ---------------
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: primnodes.h,v 1.81 2003/04/08 23:20:04 tgl Exp $
+ * $Id: primnodes.h,v 1.82 2003/05/06 00:20:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* Resdom (Result Domain)
*
* Notes:
- * ressortgroupref is the parse/plan-time representation of ORDER BY and
+ *
+ * resno will normally be equal to the item's position in a targetlist,
+ * but the code generally tries to avoid relying on that (eg, we avoid
+ * using "nth()" rather than a search to find an item by resno).
+ *
+ * resname will be null if no name can easily be assigned to the column.
+ * But it should never be null for user-visible columns (i.e., non-junk
+ * columns in a toplevel targetlist).
+ *
+ * ressortgroupref is used in the representation of ORDER BY and
* GROUP BY items. Targetlist entries with ressortgroupref=0 are not
* sort/group items. If ressortgroupref>0, then this item is an ORDER BY or
* GROUP BY value. No two entries in a targetlist may have the same nonzero
* ressortgroupref means a more significant sort key.) The order of the
* associated SortClause or GroupClause lists determine the semantics.
*
- * reskey and reskeyop are the execution-time representation of sorting.
- * reskey must be zero in any non-sort-key item. The reskey of sort key
- * targetlist items for a sort plan node is 1,2,...,n for the n sort keys.
- * The reskeyop of each such targetlist item is the sort operator's OID.
- * reskeyop will be zero in non-sort-key items.
+ * resorigtbl/resorigcol identify the source of the column, if it is a
+ * simple reference to a column of a base table (or view). If it is not
+ * a simple reference, these fields are zeroes.
*
- * Both reskey and reskeyop are typically zero during parse/plan stages.
- * The executor does not pay any attention to ressortgroupref.
+ * If resjunk is true then the column is a working column (such as a sort key)
+ * that should be removed from the final output of the query.
*--------------------
*/
typedef struct Resdom
{
NodeTag type;
- AttrNumber resno; /* attribute number */
+ AttrNumber resno; /* attribute number (1..N) */
Oid restype; /* type of the value */
int32 restypmod; /* type-specific modifier of the value */
- char *resname; /* name of the resdom (could be NULL) */
- Index ressortgroupref;
- /* nonzero if referenced by a sort/group clause */
- Index reskey; /* order of key in a sort (for those > 0) */
- Oid reskeyop; /* sort operator's Oid */
+ char *resname; /* name of the column (could be NULL) */
+ Index ressortgroupref; /* nonzero if referenced by a
+ * sort/group clause */
+ Oid resorigtbl; /* OID of column's source table */
+ AttrNumber resorigcol; /* column's number in source table */
bool resjunk; /* set to true to eliminate the attribute
* from final target list */
} Resdom;
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: planmain.h,v 1.69 2003/03/10 03:53:52 tgl Exp $
+ * $Id: planmain.h,v 1.70 2003/05/06 00:20:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual,
Index scanrelid, Plan *subplan);
extern Append *make_append(List *appendplans, bool isTarget, List *tlist);
-extern Sort *make_sort(Query *root, List *tlist,
- Plan *lefttree, int keycount);
extern Sort *make_sort_from_sortclauses(Query *root, List *tlist,
Plan *lefttree, List *sortcls);
+extern Sort *make_sort_from_groupcols(Query *root, List *groupcls,
+ AttrNumber *grpColIdx, Plan *lefttree);
extern Agg *make_agg(Query *root, List *tlist, List *qual,
AggStrategy aggstrategy,
int numGroupCols, AttrNumber *grpColIdx,
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: tlist.h,v 1.34 2003/02/15 20:12:41 tgl Exp $
+ * $Id: tlist.h,v 1.35 2003/05/06 00:20:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern void add_var_to_tlist(RelOptInfo *rel, Var *var);
extern TargetEntry *create_tl_element(Var *var, int resdomno);
-extern List *new_unsorted_tlist(List *targetlist);
extern List *flatten_tlist(List *tlist);
extern List *add_to_flat_tlist(List *tlist, List *vars);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_target.h,v 1.29 2003/02/13 05:53:46 momjian Exp $
+ * $Id: parse_target.h,v 1.30 2003/05/06 00:20:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern List *transformTargetList(ParseState *pstate, List *targetlist);
+extern void markTargetListOrigins(ParseState *pstate, List *targetlist);
extern TargetEntry *transformTargetEntry(ParseState *pstate,
Node *node, Node *expr,
char *colname, bool resjunk);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: dest.h,v 1.35 2003/05/05 00:44:56 tgl Exp $
+ * $Id: dest.h,v 1.36 2003/05/06 00:20:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
/* Called for each tuple to be output: */
void (*receiveTuple) (HeapTuple tuple, TupleDesc typeinfo,
- DestReceiver *self);
+ DestReceiver *self);
/* Initialization and teardown: */
void (*setup) (DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo);
+ const char *portalName,
+ TupleDesc typeinfo,
+ List *targetlist);
void (*cleanup) (DestReceiver *self);
/* Private fields might appear beyond this point... */
};