mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
Ye-old pgindent run. Same 4-space tabs.
This commit is contained in:
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: execAmi.c,v 1.45 2000/01/26 05:56:21 momjian Exp $
|
||||
* $Id: execAmi.c,v 1.46 2000/04/12 17:15:07 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -235,9 +235,10 @@ ExecCloseR(Plan *node)
|
||||
heap_endscan(scanDesc);
|
||||
|
||||
/*
|
||||
* endscan released AccessShareLock acquired by beginscan. If we are
|
||||
* holding any stronger locks on the rel, they should be held till end of
|
||||
* xact. Therefore, we need only close the rel and not release locks.
|
||||
* endscan released AccessShareLock acquired by beginscan. If we are
|
||||
* holding any stronger locks on the rel, they should be held till end
|
||||
* of xact. Therefore, we need only close the rel and not release
|
||||
* locks.
|
||||
*/
|
||||
if (relation != NULL)
|
||||
heap_close(relation, NoLock);
|
||||
@ -423,7 +424,7 @@ ExecMarkPos(Plan *node)
|
||||
{
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
case T_SeqScan:
|
||||
case T_SeqScan:
|
||||
ExecSeqMarkPos((SeqScan *) node);
|
||||
break;
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.112 2000/04/07 07:24:47 vadim Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.113 2000/04/12 17:15:08 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -48,7 +48,7 @@
|
||||
|
||||
/* XXX no points for style */
|
||||
extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti,
|
||||
ItemPointer tid);
|
||||
ItemPointer tid);
|
||||
|
||||
/* decls for local routines only used within this module */
|
||||
static TupleDesc InitPlan(CmdType operation,
|
||||
@ -75,13 +75,14 @@ static void ExecReplace(TupleTableSlot *slot, ItemPointer tupleid,
|
||||
static TupleTableSlot *EvalPlanQualNext(EState *estate);
|
||||
static void EndEvalPlanQual(EState *estate);
|
||||
static void ExecCheckQueryPerms(CmdType operation, Query *parseTree,
|
||||
Plan *plan);
|
||||
Plan *plan);
|
||||
static void ExecCheckPlanPerms(Plan *plan, CmdType operation,
|
||||
int resultRelation, bool resultIsScanned);
|
||||
int resultRelation, bool resultIsScanned);
|
||||
static void ExecCheckRTPerms(List *rangeTable, CmdType operation,
|
||||
int resultRelation, bool resultIsScanned);
|
||||
int resultRelation, bool resultIsScanned);
|
||||
static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation,
|
||||
bool isResultRelation, bool resultIsScanned);
|
||||
bool isResultRelation, bool resultIsScanned);
|
||||
|
||||
/* end of local decls */
|
||||
|
||||
|
||||
@ -460,14 +461,14 @@ ExecCheckPlanPerms(Plan *plan, CmdType operation,
|
||||
|
||||
foreach(subp, plan->initPlan)
|
||||
{
|
||||
SubPlan *subplan = (SubPlan *) lfirst(subp);
|
||||
SubPlan *subplan = (SubPlan *) lfirst(subp);
|
||||
|
||||
ExecCheckRTPerms(subplan->rtable, CMD_SELECT, 0, false);
|
||||
ExecCheckPlanPerms(subplan->plan, CMD_SELECT, 0, false);
|
||||
}
|
||||
foreach(subp, plan->subPlan)
|
||||
{
|
||||
SubPlan *subplan = (SubPlan *) lfirst(subp);
|
||||
SubPlan *subplan = (SubPlan *) lfirst(subp);
|
||||
|
||||
ExecCheckRTPerms(subplan->rtable, CMD_SELECT, 0, false);
|
||||
ExecCheckPlanPerms(subplan->plan, CMD_SELECT, 0, false);
|
||||
@ -485,49 +486,51 @@ ExecCheckPlanPerms(Plan *plan, CmdType operation,
|
||||
switch (nodeTag(plan))
|
||||
{
|
||||
case T_Append:
|
||||
{
|
||||
Append *app = (Append *) plan;
|
||||
List *appendplans;
|
||||
|
||||
if (app->inheritrelid > 0)
|
||||
{
|
||||
/*
|
||||
* Append implements expansion of inheritance; all members
|
||||
* of inheritrtable list will be plugged into same RTE slot.
|
||||
* Therefore, they are either all result relations or none.
|
||||
*/
|
||||
List *rtable;
|
||||
Append *app = (Append *) plan;
|
||||
List *appendplans;
|
||||
|
||||
foreach(rtable, app->inheritrtable)
|
||||
if (app->inheritrelid > 0)
|
||||
{
|
||||
ExecCheckRTEPerms((RangeTblEntry *) lfirst(rtable),
|
||||
operation,
|
||||
(app->inheritrelid == resultRelation),
|
||||
resultIsScanned);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Append implements UNION, which must be a SELECT */
|
||||
List *rtables;
|
||||
|
||||
foreach(rtables, app->unionrtables)
|
||||
/*
|
||||
* Append implements expansion of inheritance; all
|
||||
* members of inheritrtable list will be plugged into
|
||||
* same RTE slot. Therefore, they are either all
|
||||
* result relations or none.
|
||||
*/
|
||||
List *rtable;
|
||||
|
||||
foreach(rtable, app->inheritrtable)
|
||||
{
|
||||
ExecCheckRTEPerms((RangeTblEntry *) lfirst(rtable),
|
||||
operation,
|
||||
(app->inheritrelid == resultRelation),
|
||||
resultIsScanned);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ExecCheckRTPerms((List *) lfirst(rtables),
|
||||
CMD_SELECT, 0, false);
|
||||
}
|
||||
}
|
||||
/* Append implements UNION, which must be a SELECT */
|
||||
List *rtables;
|
||||
|
||||
/* Check appended plans */
|
||||
foreach(appendplans, app->appendplans)
|
||||
{
|
||||
ExecCheckPlanPerms((Plan *) lfirst(appendplans),
|
||||
operation,
|
||||
resultRelation,
|
||||
resultIsScanned);
|
||||
foreach(rtables, app->unionrtables)
|
||||
{
|
||||
ExecCheckRTPerms((List *) lfirst(rtables),
|
||||
CMD_SELECT, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check appended plans */
|
||||
foreach(appendplans, app->appendplans)
|
||||
{
|
||||
ExecCheckPlanPerms((Plan *) lfirst(appendplans),
|
||||
operation,
|
||||
resultRelation,
|
||||
resultIsScanned);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -539,7 +542,7 @@ ExecCheckPlanPerms(Plan *plan, CmdType operation,
|
||||
* Check access permissions for all relations listed in a range table.
|
||||
*
|
||||
* If resultRelation is not 0, it is the RT index of the relation to be
|
||||
* treated as the result relation. All other relations are assumed to be
|
||||
* treated as the result relation. All other relations are assumed to be
|
||||
* read-only for the query.
|
||||
*/
|
||||
static void
|
||||
@ -576,10 +579,11 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation,
|
||||
|
||||
if (rte->skipAcl)
|
||||
{
|
||||
|
||||
/*
|
||||
* This happens if the access to this table is due to a view
|
||||
* query rewriting - the rewrite handler already checked the
|
||||
* permissions against the view owner, so we just skip this entry.
|
||||
* This happens if the access to this table is due to a view query
|
||||
* rewriting - the rewrite handler already checked the permissions
|
||||
* against the view owner, so we just skip this entry.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
@ -620,14 +624,12 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation,
|
||||
default:
|
||||
elog(ERROR, "ExecCheckRTEPerms: bogus operation %d",
|
||||
operation);
|
||||
aclcheck_result = ACLCHECK_OK; /* keep compiler quiet */
|
||||
aclcheck_result = ACLCHECK_OK; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aclcheck_result = CHECK(ACL_RD);
|
||||
}
|
||||
|
||||
if (aclcheck_result != ACLCHECK_OK)
|
||||
elog(ERROR, "%s: %s",
|
||||
@ -734,8 +736,9 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
/*
|
||||
* If there are indices on the result relation, open them and save
|
||||
* descriptors in the result relation info, so that we can add new
|
||||
* index entries for the tuples we add/update. We need not do this
|
||||
* for a DELETE, however, since deletion doesn't affect indexes.
|
||||
* index entries for the tuples we add/update. We need not do
|
||||
* this for a DELETE, however, since deletion doesn't affect
|
||||
* indexes.
|
||||
*/
|
||||
if (resultRelationDesc->rd_rel->relhasindex &&
|
||||
operation != CMD_DELETE)
|
||||
@ -805,10 +808,11 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
targetList = plan->targetlist;
|
||||
|
||||
/*
|
||||
* Now that we have the target list, initialize the junk filter if needed.
|
||||
* SELECT and INSERT queries need a filter if there are any junk attrs
|
||||
* in the tlist. UPDATE and DELETE always need one, since there's always
|
||||
* a junk 'ctid' attribute present --- no need to look first.
|
||||
* Now that we have the target list, initialize the junk filter if
|
||||
* needed. SELECT and INSERT queries need a filter if there are any
|
||||
* junk attrs in the tlist. UPDATE and DELETE always need one, since
|
||||
* there's always a junk 'ctid' attribute present --- no need to look
|
||||
* first.
|
||||
*/
|
||||
{
|
||||
bool junk_filter_needed = false;
|
||||
@ -948,8 +952,8 @@ EndPlan(Plan *plan, EState *estate)
|
||||
}
|
||||
|
||||
/*
|
||||
* close the result relations if necessary,
|
||||
* but hold locks on them until xact commit
|
||||
* close the result relations if necessary, but hold locks on them
|
||||
* until xact commit
|
||||
*/
|
||||
if (resultRelationInfo != NULL)
|
||||
{
|
||||
@ -1708,10 +1712,10 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
|
||||
|
||||
/*
|
||||
* NOTE: SQL92 specifies that a NULL result from a constraint
|
||||
* expression is not to be treated as a failure. Therefore,
|
||||
* tell ExecQual to return TRUE for NULL.
|
||||
* expression is not to be treated as a failure. Therefore, tell
|
||||
* ExecQual to return TRUE for NULL.
|
||||
*/
|
||||
if (! ExecQual(qual, econtext, true))
|
||||
if (!ExecQual(qual, econtext, true))
|
||||
return check[i].ccname;
|
||||
}
|
||||
|
||||
@ -1738,7 +1742,7 @@ ExecConstraints(char *caller, Relation rel, HeapTuple tuple, EState *estate)
|
||||
{
|
||||
if (rel->rd_att->attrs[attrChk - 1]->attnotnull && heap_attisnull(tuple, attrChk))
|
||||
elog(ERROR, "%s: Fail to add null value in not null attribute %s",
|
||||
caller, NameStr(rel->rd_att->attrs[attrChk - 1]->attname));
|
||||
caller, NameStr(rel->rd_att->attrs[attrChk - 1]->attname));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1791,7 +1795,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
||||
Assert(oldepq->rti != 0);
|
||||
/* stop execution */
|
||||
ExecEndNode(epq->plan, epq->plan);
|
||||
epqstate->es_tupleTable->next = 0;
|
||||
epqstate->es_tupleTable->next = 0;
|
||||
heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
|
||||
epqstate->es_evTuple[epq->rti - 1] = NULL;
|
||||
/* push current PQ to freePQ stack */
|
||||
@ -1861,7 +1865,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
||||
if (endNode)
|
||||
{
|
||||
ExecEndNode(epq->plan, epq->plan);
|
||||
epqstate->es_tupleTable->next = 0;
|
||||
epqstate->es_tupleTable->next = 0;
|
||||
}
|
||||
|
||||
/* free old RTE' tuple */
|
||||
@ -1949,10 +1953,10 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
||||
estate->es_evalPlanQual = (Pointer) epq;
|
||||
}
|
||||
else
|
||||
{
|
||||
epq->rti = 0; /* this is the first (oldest) */
|
||||
estate->es_useEvalPlan = false; /* PQ - mark as free and */
|
||||
return (NULL); /* continue Query execution */
|
||||
{
|
||||
epq->rti = 0; /* this is the first (oldest) */
|
||||
estate->es_useEvalPlan = false; /* PQ - mark as free and */
|
||||
return (NULL); /* continue Query execution */
|
||||
}
|
||||
}
|
||||
|
||||
@ -1961,7 +1965,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
||||
estate->es_origPlan->nParamExec * sizeof(ParamExecData));
|
||||
memset(epqstate->es_evTupleNull, false,
|
||||
length(estate->es_range_table) * sizeof(bool));
|
||||
Assert(epqstate->es_tupleTable->next == 0);
|
||||
Assert(epqstate->es_tupleTable->next == 0);
|
||||
ExecInitNode(epq->plan, epqstate, NULL);
|
||||
|
||||
/*
|
||||
@ -1992,16 +1996,16 @@ lpqnext:;
|
||||
if (TupIsNull(slot))
|
||||
{
|
||||
ExecEndNode(epq->plan, epq->plan);
|
||||
epqstate->es_tupleTable->next = 0;
|
||||
epqstate->es_tupleTable->next = 0;
|
||||
heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
|
||||
epqstate->es_evTuple[epq->rti - 1] = NULL;
|
||||
/* pop old PQ from the stack */
|
||||
oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
|
||||
if (oldepq == (evalPlanQual *) NULL)
|
||||
{
|
||||
epq->rti = 0; /* this is the first (oldest) */
|
||||
estate->es_useEvalPlan = false; /* PQ - mark as free and */
|
||||
return (NULL); /* continue Query execution */
|
||||
epq->rti = 0; /* this is the first (oldest) */
|
||||
estate->es_useEvalPlan = false; /* PQ - mark as free and */
|
||||
return (NULL); /* continue Query execution */
|
||||
}
|
||||
Assert(oldepq->rti != 0);
|
||||
/* push current PQ to freePQ stack */
|
||||
@ -2031,7 +2035,7 @@ EndEvalPlanQual(EState *estate)
|
||||
for (;;)
|
||||
{
|
||||
ExecEndNode(epq->plan, epq->plan);
|
||||
epqstate->es_tupleTable->next = 0;
|
||||
epqstate->es_tupleTable->next = 0;
|
||||
if (epqstate->es_evTuple[epq->rti - 1] != NULL)
|
||||
{
|
||||
heap_freetuple(epqstate->es_evTuple[epq->rti - 1]);
|
||||
@ -2041,8 +2045,8 @@ EndEvalPlanQual(EState *estate)
|
||||
oldepq = (evalPlanQual *) epqstate->es_evalPlanQual;
|
||||
if (oldepq == (evalPlanQual *) NULL)
|
||||
{
|
||||
epq->rti = 0; /* this is the first (oldest) */
|
||||
estate->es_useEvalPlan = false; /* PQ - mark as free */
|
||||
epq->rti = 0; /* this is the first (oldest) */
|
||||
estate->es_useEvalPlan = false; /* PQ - mark as free */
|
||||
break;
|
||||
}
|
||||
Assert(oldepq->rti != 0);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.68 2000/02/20 21:32:04 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.69 2000/04/12 17:15:08 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -108,12 +108,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Null refexpr indicates we are doing an INSERT into an array column.
|
||||
* For now, we just take the refassgnexpr (which the parser will have
|
||||
* ensured is an array value) and return it as-is, ignoring any
|
||||
* subscripts that may have been supplied in the INSERT column list.
|
||||
* This is a kluge, but it's not real clear what the semantics ought
|
||||
* to be...
|
||||
|
||||
/*
|
||||
* Null refexpr indicates we are doing an INSERT into an array
|
||||
* column. For now, we just take the refassgnexpr (which the
|
||||
* parser will have ensured is an array value) and return it
|
||||
* as-is, ignoring any subscripts that may have been supplied in
|
||||
* the INSERT column list. This is a kluge, but it's not real
|
||||
* clear what the semantics ought to be...
|
||||
*/
|
||||
array_scanner = NULL;
|
||||
}
|
||||
@ -153,16 +155,15 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||
lIndex = lower.indx;
|
||||
}
|
||||
else
|
||||
{
|
||||
lIndex = NULL;
|
||||
}
|
||||
|
||||
if (arrayRef->refassgnexpr != NULL)
|
||||
{
|
||||
Datum sourceData = ExecEvalExpr(arrayRef->refassgnexpr,
|
||||
econtext,
|
||||
isNull,
|
||||
&dummy);
|
||||
Datum sourceData = ExecEvalExpr(arrayRef->refassgnexpr,
|
||||
econtext,
|
||||
isNull,
|
||||
&dummy);
|
||||
|
||||
if (*isNull)
|
||||
return (Datum) NULL;
|
||||
|
||||
@ -209,7 +210,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||
static Datum
|
||||
ExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull)
|
||||
{
|
||||
if (econtext->ecxt_aggvalues == NULL) /* safety check */
|
||||
if (econtext->ecxt_aggvalues == NULL) /* safety check */
|
||||
elog(ERROR, "ExecEvalAggref: no aggregates in this expression context");
|
||||
|
||||
*isNull = econtext->ecxt_aggnulls[aggref->aggno];
|
||||
@ -281,7 +282,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||
Assert(attnum <= 0 ||
|
||||
(attnum - 1 <= tuple_type->natts - 1 &&
|
||||
tuple_type->attrs[attnum - 1] != NULL &&
|
||||
variable->vartype == tuple_type->attrs[attnum - 1]->atttypid));
|
||||
variable->vartype == tuple_type->attrs[attnum - 1]->atttypid));
|
||||
|
||||
/*
|
||||
* If the attribute number is invalid, then we are supposed to return
|
||||
@ -633,7 +634,7 @@ ExecEvalFuncArgs(FunctionCachePtr fcache,
|
||||
*/
|
||||
argV[i] = ExecEvalExpr((Node *) lfirst(arg),
|
||||
econtext,
|
||||
& nullVect[i],
|
||||
&nullVect[i],
|
||||
argIsDone);
|
||||
|
||||
if (!(*argIsDone))
|
||||
@ -779,9 +780,9 @@ ExecMakeFunctionResult(Node *node,
|
||||
result = postquel_function(funcNode, (char **) argV,
|
||||
isNull, isDone);
|
||||
|
||||
if (! *isDone)
|
||||
if (!*isDone)
|
||||
break; /* got a result from current argument */
|
||||
if (! fcache->hasSetArg)
|
||||
if (!fcache->hasSetArg)
|
||||
break; /* input not a set, so done */
|
||||
|
||||
/* OK, get the next argument... */
|
||||
@ -789,7 +790,11 @@ ExecMakeFunctionResult(Node *node,
|
||||
|
||||
if (argDone)
|
||||
{
|
||||
/* End of arguments, so reset the setArg flag and say "Done" */
|
||||
|
||||
/*
|
||||
* End of arguments, so reset the setArg flag and say
|
||||
* "Done"
|
||||
*/
|
||||
fcache->setArg = (char *) NULL;
|
||||
fcache->hasSetArg = false;
|
||||
*isDone = true;
|
||||
@ -797,7 +802,8 @@ ExecMakeFunctionResult(Node *node,
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we reach here, loop around to run the function on the
|
||||
/*
|
||||
* If we reach here, loop around to run the function on the
|
||||
* new argument.
|
||||
*/
|
||||
}
|
||||
@ -1003,20 +1009,22 @@ ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull)
|
||||
AnyNull = false;
|
||||
|
||||
/*
|
||||
* If any of the clauses is TRUE, the OR result is TRUE regardless
|
||||
* of the states of the rest of the clauses, so we can stop evaluating
|
||||
* If any of the clauses is TRUE, the OR result is TRUE regardless of
|
||||
* the states of the rest of the clauses, so we can stop evaluating
|
||||
* and return TRUE immediately. If none are TRUE and one or more is
|
||||
* NULL, we return NULL; otherwise we return FALSE. This makes sense
|
||||
* when you interpret NULL as "don't know": if we have a TRUE then the
|
||||
* OR is TRUE even if we aren't sure about some of the other inputs.
|
||||
* If all the known inputs are FALSE, but we have one or more "don't
|
||||
* knows", then we have to report that we "don't know" what the OR's
|
||||
* result should be --- perhaps one of the "don't knows" would have been
|
||||
* TRUE if we'd known its value. Only when all the inputs are known
|
||||
* to be FALSE can we state confidently that the OR's result is FALSE.
|
||||
* result should be --- perhaps one of the "don't knows" would have
|
||||
* been TRUE if we'd known its value. Only when all the inputs are
|
||||
* known to be FALSE can we state confidently that the OR's result is
|
||||
* FALSE.
|
||||
*/
|
||||
foreach(clause, clauses)
|
||||
{
|
||||
|
||||
/*
|
||||
* We don't iterate over sets in the quals, so pass in an isDone
|
||||
* flag, but ignore it.
|
||||
@ -1025,6 +1033,7 @@ ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull)
|
||||
econtext,
|
||||
isNull,
|
||||
&isDone);
|
||||
|
||||
/*
|
||||
* if we have a non-null true result, then return it.
|
||||
*/
|
||||
@ -1059,12 +1068,13 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
|
||||
* If any of the clauses is FALSE, the AND result is FALSE regardless
|
||||
* of the states of the rest of the clauses, so we can stop evaluating
|
||||
* and return FALSE immediately. If none are FALSE and one or more is
|
||||
* NULL, we return NULL; otherwise we return TRUE. This makes sense
|
||||
* NULL, we return NULL; otherwise we return TRUE. This makes sense
|
||||
* when you interpret NULL as "don't know", using the same sort of
|
||||
* reasoning as for OR, above.
|
||||
*/
|
||||
foreach(clause, clauses)
|
||||
{
|
||||
|
||||
/*
|
||||
* We don't iterate over sets in the quals, so pass in an isDone
|
||||
* flag, but ignore it.
|
||||
@ -1073,6 +1083,7 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
|
||||
econtext,
|
||||
isNull,
|
||||
&isDone);
|
||||
|
||||
/*
|
||||
* if we have a non-null false result, then return it.
|
||||
*/
|
||||
@ -1084,7 +1095,7 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
|
||||
|
||||
/* AnyNull is true if at least one clause evaluated to NULL */
|
||||
*isNull = AnyNull;
|
||||
return (Datum) (! AnyNull);
|
||||
return (Datum) (!AnyNull);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@ -1129,7 +1140,7 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
|
||||
* case statement is satisfied. A NULL result from the test is
|
||||
* not considered true.
|
||||
*/
|
||||
if (DatumGetInt32(clause_value) != 0 && ! *isNull)
|
||||
if (DatumGetInt32(clause_value) != 0 && !*isNull)
|
||||
{
|
||||
return ExecEvalExpr(wclause->result,
|
||||
econtext,
|
||||
@ -1258,7 +1269,7 @@ ExecEvalExpr(Node *expression,
|
||||
default:
|
||||
elog(ERROR, "ExecEvalExpr: unknown expression type %d",
|
||||
expr->opType);
|
||||
retDatum = 0; /* keep compiler quiet */
|
||||
retDatum = 0; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -1332,7 +1343,7 @@ ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
|
||||
IncrProcessed();
|
||||
|
||||
/*
|
||||
* Evaluate the qual conditions one at a time. If we find a FALSE
|
||||
* Evaluate the qual conditions one at a time. If we find a FALSE
|
||||
* result, we can stop evaluating and return FALSE --- the AND result
|
||||
* must be FALSE. Also, if we find a NULL result when resultForNull
|
||||
* is FALSE, we can stop and return FALSE --- the AND result must be
|
||||
@ -1353,14 +1364,15 @@ ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
|
||||
|
||||
/*
|
||||
* If there is a null clause, consider the qualification to fail.
|
||||
* XXX is this still correct for constraints? It probably shouldn't
|
||||
* happen at all ...
|
||||
* XXX is this still correct for constraints? It probably
|
||||
* shouldn't happen at all ...
|
||||
*/
|
||||
if (clause == NULL)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* pass isDone, but ignore it. We don't iterate over multiple returns
|
||||
* in the qualifications.
|
||||
* pass isDone, but ignore it. We don't iterate over multiple
|
||||
* returns in the qualifications.
|
||||
*/
|
||||
expr_value = ExecEvalExpr(clause, econtext, &isNull, &isDone);
|
||||
|
||||
@ -1429,7 +1441,8 @@ ExecTargetList(List *targetlist,
|
||||
HeapTuple newTuple;
|
||||
bool isNull;
|
||||
bool haveDoneIters;
|
||||
static struct tupleDesc NullTupleDesc; /* we assume this inits to zeroes */
|
||||
static struct tupleDesc NullTupleDesc; /* we assume this inits to
|
||||
* zeroes */
|
||||
|
||||
/*
|
||||
* debugging stuff
|
||||
@ -1512,7 +1525,8 @@ ExecTargetList(List *targetlist,
|
||||
if (itemIsDone[resind])
|
||||
haveDoneIters = true;
|
||||
else
|
||||
*isDone = false; /* we have undone Iters in the list */
|
||||
*isDone = false; /* we have undone Iters in the
|
||||
* list */
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1571,7 +1585,9 @@ ExecTargetList(List *targetlist,
|
||||
{
|
||||
if (*isDone)
|
||||
{
|
||||
/* all Iters are done, so return a null indicating tlist set
|
||||
|
||||
/*
|
||||
* all Iters are done, so return a null indicating tlist set
|
||||
* expansion is complete.
|
||||
*/
|
||||
newTuple = NULL;
|
||||
@ -1579,21 +1595,24 @@ ExecTargetList(List *targetlist,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have some done and some undone Iters. Restart the done ones
|
||||
* so that we can deliver a tuple (if possible).
|
||||
|
||||
/*
|
||||
* We have some done and some undone Iters. Restart the done
|
||||
* ones so that we can deliver a tuple (if possible).
|
||||
*
|
||||
* XXX this code is a crock, because it only works for Iters at
|
||||
* the top level of tlist expressions, and doesn't even work right
|
||||
* for them: you should get all possible combinations of Iter
|
||||
* results, but you won't unless the numbers of values returned by
|
||||
* each are relatively prime. Should have a mechanism more like
|
||||
* aggregate functions, where we make a list of all Iters
|
||||
* contained in the tlist and cycle through their values in a
|
||||
* methodical fashion. To do someday; can't get excited about
|
||||
* fixing a Berkeley feature that's not in SQL92. (The only
|
||||
* reason we're doing this much is that we have to be sure all
|
||||
* the Iters are run to completion, or their subplan executors
|
||||
* will have unreleased resources, e.g. pinned buffers...)
|
||||
* the top level of tlist expressions, and doesn't even work
|
||||
* right for them: you should get all possible combinations of
|
||||
* Iter results, but you won't unless the numbers of values
|
||||
* returned by each are relatively prime. Should have a
|
||||
* mechanism more like aggregate functions, where we make a
|
||||
* list of all Iters contained in the tlist and cycle through
|
||||
* their values in a methodical fashion. To do someday; can't
|
||||
* get excited about fixing a Berkeley feature that's not in
|
||||
* SQL92. (The only reason we're doing this much is that we
|
||||
* have to be sure all the Iters are run to completion, or
|
||||
* their subplan executors will have unreleased resources,
|
||||
* e.g. pinned buffers...)
|
||||
*/
|
||||
foreach(tl, targetlist)
|
||||
{
|
||||
@ -1605,16 +1624,18 @@ ExecTargetList(List *targetlist,
|
||||
resdom = tle->resdom;
|
||||
resind = resdom->resno - 1;
|
||||
|
||||
if (IsA(expr, Iter) && itemIsDone[resind])
|
||||
if (IsA(expr, Iter) &&itemIsDone[resind])
|
||||
{
|
||||
constvalue = (Datum) ExecEvalExpr(expr,
|
||||
econtext,
|
||||
&isNull,
|
||||
&itemIsDone[resind]);
|
||||
&itemIsDone[resind]);
|
||||
if (itemIsDone[resind])
|
||||
{
|
||||
/* Oh dear, this Iter is returning an empty set.
|
||||
* Guess we can't make a tuple after all.
|
||||
|
||||
/*
|
||||
* Oh dear, this Iter is returning an empty
|
||||
* set. Guess we can't make a tuple after all.
|
||||
*/
|
||||
*isDone = true;
|
||||
newTuple = NULL;
|
||||
@ -1639,6 +1660,7 @@ ExecTargetList(List *targetlist,
|
||||
newTuple = (HeapTuple) heap_formtuple(targettype, values, null_head);
|
||||
|
||||
exit:
|
||||
|
||||
/*
|
||||
* free the status arrays if we palloc'd them
|
||||
*/
|
||||
|
@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.36 2000/01/27 18:11:27 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.37 2000/04/12 17:15:08 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -188,8 +188,8 @@ ExecCreateTupleTable(int initialSize) /* initial number of slots in
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
ExecDropTupleTable(TupleTable table, /* tuple table */
|
||||
bool shouldFree) /* true if we should free slot
|
||||
ExecDropTupleTable(TupleTable table, /* tuple table */
|
||||
bool shouldFree) /* true if we should free slot
|
||||
* contents */
|
||||
{
|
||||
int next; /* next available slot */
|
||||
@ -262,7 +262,7 @@ TupleTableSlot * /* return: the slot allocated in the tuple
|
||||
ExecAllocTableSlot(TupleTable table)
|
||||
{
|
||||
int slotnum; /* new slot number */
|
||||
TupleTableSlot* slot;
|
||||
TupleTableSlot *slot;
|
||||
|
||||
/* ----------------
|
||||
* sanity checks
|
||||
@ -335,8 +335,8 @@ ExecAllocTableSlot(TupleTable table)
|
||||
*
|
||||
* tuple: tuple to store
|
||||
* slot: slot to store it in
|
||||
* buffer: disk buffer if tuple is in a disk page, else InvalidBuffer
|
||||
* shouldFree: true if ExecClearTuple should pfree() the tuple
|
||||
* buffer: disk buffer if tuple is in a disk page, else InvalidBuffer
|
||||
* shouldFree: true if ExecClearTuple should pfree() the tuple
|
||||
* when done with it
|
||||
*
|
||||
* If 'buffer' is not InvalidBuffer, the tuple table code acquires a pin
|
||||
@ -350,7 +350,7 @@ ExecAllocTableSlot(TupleTable table)
|
||||
* Another case where it is 'false' is when the referenced tuple is held
|
||||
* in a tuple table slot belonging to a lower-level executor Proc node.
|
||||
* In this case the lower-level slot retains ownership and responsibility
|
||||
* for eventually releasing the tuple. When this method is used, we must
|
||||
* for eventually releasing the tuple. When this method is used, we must
|
||||
* be certain that the upper-level Proc node will lose interest in the tuple
|
||||
* sooner than the lower-level one does! If you're not certain, copy the
|
||||
* lower-level tuple with heap_copytuple and let the upper-level table
|
||||
@ -385,7 +385,8 @@ ExecStoreTuple(HeapTuple tuple,
|
||||
slot->ttc_buffer = buffer;
|
||||
slot->ttc_shouldFree = shouldFree;
|
||||
|
||||
/* If tuple is on a disk page, keep the page pinned as long as we hold
|
||||
/*
|
||||
* If tuple is on a disk page, keep the page pinned as long as we hold
|
||||
* a pointer into it.
|
||||
*/
|
||||
if (BufferIsValid(buffer))
|
||||
@ -426,7 +427,7 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
|
||||
|
||||
slot->val = (HeapTuple) NULL;
|
||||
|
||||
slot->ttc_shouldFree = true; /* probably useless code... */
|
||||
slot->ttc_shouldFree = true;/* probably useless code... */
|
||||
|
||||
/* ----------------
|
||||
* Drop the pin on the referenced buffer, if there is one.
|
||||
@ -776,6 +777,7 @@ NodeGetResultTupleSlot(Plan *node)
|
||||
case T_TidScan:
|
||||
{
|
||||
CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate;
|
||||
|
||||
slot = scanstate->cstate.cs_ResultTupleSlot;
|
||||
}
|
||||
break;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.54 2000/02/18 09:29:57 inoue Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.55 2000/04/12 17:15:08 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -776,7 +776,7 @@ ExecOpenIndices(Oid resultRelationOid,
|
||||
if (!RelationGetForm(resultRelationInfo->ri_RelationDesc)->relhasindex)
|
||||
return;
|
||||
if (IsIgnoringSystemIndexes() &&
|
||||
IsSystemRelationName(RelationGetRelationName(resultRelationInfo->ri_RelationDesc)))
|
||||
IsSystemRelationName(RelationGetRelationName(resultRelationInfo->ri_RelationDesc)))
|
||||
return;
|
||||
/* ----------------
|
||||
* open pg_index
|
||||
@ -923,8 +923,8 @@ ExecOpenIndices(Oid resultRelationOid,
|
||||
|
||||
/*
|
||||
* Hack for not btree and hash indices: they use relation
|
||||
* level exclusive locking on update (i.e. - they are
|
||||
* not ready for MVCC) and so we have to exclusively lock
|
||||
* level exclusive locking on update (i.e. - they are not
|
||||
* ready for MVCC) and so we have to exclusively lock
|
||||
* indices here to prevent deadlocks if we will scan them
|
||||
* - index_beginscan places AccessShareLock, indices
|
||||
* update methods don't use locks at all. We release this
|
||||
@ -1186,7 +1186,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
|
||||
econtext->ecxt_scantuple = slot;
|
||||
|
||||
/* Skip this index-update if the predicate isn't satisfied */
|
||||
if (! ExecQual((List *) predicate, econtext, false))
|
||||
if (!ExecQual((List *) predicate, econtext, false))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.32 2000/04/04 21:44:39 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.33 2000/04/12 17:15:09 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -150,6 +150,7 @@ init_execution_state(FunctionCachePtr fcache,
|
||||
static TupleDesc
|
||||
postquel_start(execution_state *es)
|
||||
{
|
||||
|
||||
/*
|
||||
* Do nothing for utility commands. (create, destroy...) DZ -
|
||||
* 30-8-1996
|
||||
@ -166,9 +167,9 @@ postquel_getnext(execution_state *es)
|
||||
|
||||
if (es->qd->operation == CMD_UTILITY)
|
||||
{
|
||||
|
||||
/*
|
||||
* Process a utility command. (create, destroy...) DZ -
|
||||
* 30-8-1996
|
||||
* Process a utility command. (create, destroy...) DZ - 30-8-1996
|
||||
*/
|
||||
ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest);
|
||||
if (!LAST_POSTQUEL_COMMAND(es))
|
||||
@ -184,6 +185,7 @@ postquel_getnext(execution_state *es)
|
||||
static void
|
||||
postquel_end(execution_state *es)
|
||||
{
|
||||
|
||||
/*
|
||||
* Do nothing for utility commands. (create, destroy...) DZ -
|
||||
* 30-8-1996
|
||||
|
@ -15,7 +15,7 @@
|
||||
* value1 = finalfunc(value1, value2)
|
||||
*
|
||||
* If initcond1 is NULL then the first non-NULL input_value is
|
||||
* assigned directly to value1. sfunc1 isn't applied until value1
|
||||
* assigned directly to value1. sfunc1 isn't applied until value1
|
||||
* is non-NULL.
|
||||
*
|
||||
* sfunc1 is never applied when the current tuple's input_value is NULL.
|
||||
@ -24,7 +24,7 @@
|
||||
* (usenulls was formerly used for COUNT(*), but is no longer needed for
|
||||
* that purpose; as of 10/1999 the support for usenulls is dead code.
|
||||
* I have not removed it because it seems like a potentially useful
|
||||
* feature for user-defined aggregates. We'd just need to add a
|
||||
* feature for user-defined aggregates. We'd just need to add a
|
||||
* flag column to pg_aggregate and a parameter to CREATE AGGREGATE...)
|
||||
*
|
||||
*
|
||||
@ -32,7 +32,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.62 2000/01/26 05:56:22 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.63 2000/04/12 17:15:09 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -56,6 +56,7 @@
|
||||
*/
|
||||
typedef struct AggStatePerAggData
|
||||
{
|
||||
|
||||
/*
|
||||
* These values are set up during ExecInitAgg() and do not change
|
||||
* thereafter:
|
||||
@ -68,6 +69,7 @@ typedef struct AggStatePerAggData
|
||||
Oid xfn1_oid;
|
||||
Oid xfn2_oid;
|
||||
Oid finalfn_oid;
|
||||
|
||||
/*
|
||||
* fmgr lookup data for transfer functions --- only valid when
|
||||
* corresponding oid is not InvalidOid
|
||||
@ -75,18 +77,21 @@ typedef struct AggStatePerAggData
|
||||
FmgrInfo xfn1;
|
||||
FmgrInfo xfn2;
|
||||
FmgrInfo finalfn;
|
||||
|
||||
/*
|
||||
* Type of input data and Oid of sort operator to use for it;
|
||||
* only set/used when aggregate has DISTINCT flag. (These are not
|
||||
* used directly by nodeAgg, but must be passed to the Tuplesort object.)
|
||||
* Type of input data and Oid of sort operator to use for it; only
|
||||
* set/used when aggregate has DISTINCT flag. (These are not used
|
||||
* directly by nodeAgg, but must be passed to the Tuplesort object.)
|
||||
*/
|
||||
Oid inputType;
|
||||
Oid sortOperator;
|
||||
|
||||
/*
|
||||
* fmgr lookup data for input type's equality operator --- only set/used
|
||||
* when aggregate has DISTINCT flag.
|
||||
* fmgr lookup data for input type's equality operator --- only
|
||||
* set/used when aggregate has DISTINCT flag.
|
||||
*/
|
||||
FmgrInfo equalfn;
|
||||
|
||||
/*
|
||||
* initial values from pg_aggregate entry
|
||||
*/
|
||||
@ -94,6 +99,7 @@ typedef struct AggStatePerAggData
|
||||
Datum initValue2; /* for transtype2 */
|
||||
bool initValue1IsNull,
|
||||
initValue2IsNull;
|
||||
|
||||
/*
|
||||
* We need the len and byval info for the agg's input and transition
|
||||
* data types in order to know how to copy/delete values.
|
||||
@ -106,14 +112,14 @@ typedef struct AggStatePerAggData
|
||||
transtype2ByVal;
|
||||
|
||||
/*
|
||||
* These values are working state that is initialized at the start
|
||||
* of an input tuple group and updated for each input tuple.
|
||||
* These values are working state that is initialized at the start of
|
||||
* an input tuple group and updated for each input tuple.
|
||||
*
|
||||
* For a simple (non DISTINCT) aggregate, we just feed the input values
|
||||
* straight to the transition functions. If it's DISTINCT, we pass the
|
||||
* input values into a Tuplesort object; then at completion of the input
|
||||
* tuple group, we scan the sorted values, eliminate duplicates, and run
|
||||
* the transition functions on the rest.
|
||||
* straight to the transition functions. If it's DISTINCT, we pass
|
||||
* the input values into a Tuplesort object; then at completion of the
|
||||
* input tuple group, we scan the sorted values, eliminate duplicates,
|
||||
* and run the transition functions on the rest.
|
||||
*/
|
||||
|
||||
Tuplesortstate *sortstate; /* sort object, if a DISTINCT agg */
|
||||
@ -123,20 +129,22 @@ typedef struct AggStatePerAggData
|
||||
bool value1IsNull,
|
||||
value2IsNull;
|
||||
bool noInitValue; /* true if value1 not set yet */
|
||||
|
||||
/*
|
||||
* Note: right now, noInitValue always has the same value as value1IsNull.
|
||||
* But we should keep them separate because once the fmgr interface is
|
||||
* fixed, we'll need to distinguish a null returned by transfn1 from
|
||||
* a null we haven't yet replaced with an input value.
|
||||
* Note: right now, noInitValue always has the same value as
|
||||
* value1IsNull. But we should keep them separate because once the
|
||||
* fmgr interface is fixed, we'll need to distinguish a null returned
|
||||
* by transfn1 from a null we haven't yet replaced with an input
|
||||
* value.
|
||||
*/
|
||||
} AggStatePerAggData;
|
||||
|
||||
|
||||
static void initialize_aggregate (AggStatePerAgg peraggstate);
|
||||
static void advance_transition_functions (AggStatePerAgg peraggstate,
|
||||
Datum newVal, bool isNull);
|
||||
static void finalize_aggregate (AggStatePerAgg peraggstate,
|
||||
Datum *resultVal, bool *resultIsNull);
|
||||
static void initialize_aggregate(AggStatePerAgg peraggstate);
|
||||
static void advance_transition_functions(AggStatePerAgg peraggstate,
|
||||
Datum newVal, bool isNull);
|
||||
static void finalize_aggregate(AggStatePerAgg peraggstate,
|
||||
Datum *resultVal, bool *resultIsNull);
|
||||
static Datum copyDatum(Datum val, int typLen, bool typByVal);
|
||||
|
||||
|
||||
@ -144,17 +152,19 @@ static Datum copyDatum(Datum val, int typLen, bool typByVal);
|
||||
* Initialize one aggregate for a new set of input values.
|
||||
*/
|
||||
static void
|
||||
initialize_aggregate (AggStatePerAgg peraggstate)
|
||||
initialize_aggregate(AggStatePerAgg peraggstate)
|
||||
{
|
||||
Aggref *aggref = peraggstate->aggref;
|
||||
Aggref *aggref = peraggstate->aggref;
|
||||
|
||||
/*
|
||||
* Start a fresh sort operation for each DISTINCT aggregate.
|
||||
*/
|
||||
if (aggref->aggdistinct)
|
||||
{
|
||||
/* In case of rescan, maybe there could be an uncompleted
|
||||
* sort operation? Clean it up if so.
|
||||
|
||||
/*
|
||||
* In case of rescan, maybe there could be an uncompleted sort
|
||||
* operation? Clean it up if so.
|
||||
*/
|
||||
if (peraggstate->sortstate)
|
||||
tuplesort_end(peraggstate->sortstate);
|
||||
@ -169,8 +179,8 @@ initialize_aggregate (AggStatePerAgg peraggstate)
|
||||
* (Re)set value1 and value2 to their initial values.
|
||||
*/
|
||||
if (OidIsValid(peraggstate->xfn1_oid) &&
|
||||
! peraggstate->initValue1IsNull)
|
||||
peraggstate->value1 = copyDatum(peraggstate->initValue1,
|
||||
!peraggstate->initValue1IsNull)
|
||||
peraggstate->value1 = copyDatum(peraggstate->initValue1,
|
||||
peraggstate->transtype1Len,
|
||||
peraggstate->transtype1ByVal);
|
||||
else
|
||||
@ -178,8 +188,8 @@ initialize_aggregate (AggStatePerAgg peraggstate)
|
||||
peraggstate->value1IsNull = peraggstate->initValue1IsNull;
|
||||
|
||||
if (OidIsValid(peraggstate->xfn2_oid) &&
|
||||
! peraggstate->initValue2IsNull)
|
||||
peraggstate->value2 = copyDatum(peraggstate->initValue2,
|
||||
!peraggstate->initValue2IsNull)
|
||||
peraggstate->value2 = copyDatum(peraggstate->initValue2,
|
||||
peraggstate->transtype2Len,
|
||||
peraggstate->transtype2ByVal);
|
||||
else
|
||||
@ -205,8 +215,8 @@ initialize_aggregate (AggStatePerAgg peraggstate)
|
||||
* out before reaching here.
|
||||
*/
|
||||
static void
|
||||
advance_transition_functions (AggStatePerAgg peraggstate,
|
||||
Datum newVal, bool isNull)
|
||||
advance_transition_functions(AggStatePerAgg peraggstate,
|
||||
Datum newVal, bool isNull)
|
||||
{
|
||||
Datum args[2];
|
||||
|
||||
@ -214,6 +224,7 @@ advance_transition_functions (AggStatePerAgg peraggstate,
|
||||
{
|
||||
if (peraggstate->noInitValue)
|
||||
{
|
||||
|
||||
/*
|
||||
* value1 has not been initialized. This is the first non-NULL
|
||||
* input value. We use it as the initial value for value1.
|
||||
@ -238,7 +249,7 @@ advance_transition_functions (AggStatePerAgg peraggstate,
|
||||
newVal = (Datum) fmgr_c(&peraggstate->xfn1,
|
||||
(FmgrValues *) args,
|
||||
&isNull);
|
||||
if (! peraggstate->transtype1ByVal)
|
||||
if (!peraggstate->transtype1ByVal)
|
||||
pfree(peraggstate->value1);
|
||||
peraggstate->value1 = newVal;
|
||||
}
|
||||
@ -252,7 +263,7 @@ advance_transition_functions (AggStatePerAgg peraggstate,
|
||||
newVal = (Datum) fmgr_c(&peraggstate->xfn2,
|
||||
(FmgrValues *) args,
|
||||
&isNull);
|
||||
if (! peraggstate->transtype2ByVal)
|
||||
if (!peraggstate->transtype2ByVal)
|
||||
pfree(peraggstate->value2);
|
||||
peraggstate->value2 = newVal;
|
||||
}
|
||||
@ -262,17 +273,18 @@ advance_transition_functions (AggStatePerAgg peraggstate,
|
||||
* Compute the final value of one aggregate.
|
||||
*/
|
||||
static void
|
||||
finalize_aggregate (AggStatePerAgg peraggstate,
|
||||
Datum *resultVal, bool *resultIsNull)
|
||||
finalize_aggregate(AggStatePerAgg peraggstate,
|
||||
Datum *resultVal, bool *resultIsNull)
|
||||
{
|
||||
Aggref *aggref = peraggstate->aggref;
|
||||
char *args[2];
|
||||
|
||||
/*
|
||||
* If it's a DISTINCT aggregate, all we've done so far is to stuff the
|
||||
* input values into the sort object. Complete the sort, then run
|
||||
* the transition functions on the non-duplicate values. Note that
|
||||
* DISTINCT always suppresses nulls, per SQL spec, regardless of usenulls.
|
||||
* input values into the sort object. Complete the sort, then run the
|
||||
* transition functions on the non-duplicate values. Note that
|
||||
* DISTINCT always suppresses nulls, per SQL spec, regardless of
|
||||
* usenulls.
|
||||
*/
|
||||
if (aggref->aggdistinct)
|
||||
{
|
||||
@ -289,41 +301,41 @@ finalize_aggregate (AggStatePerAgg peraggstate,
|
||||
continue;
|
||||
if (haveOldVal)
|
||||
{
|
||||
Datum equal;
|
||||
Datum equal;
|
||||
|
||||
equal = (Datum) (*fmgr_faddr(&peraggstate->equalfn)) (oldVal,
|
||||
newVal);
|
||||
newVal);
|
||||
if (DatumGetInt32(equal) != 0)
|
||||
{
|
||||
if (! peraggstate->inputtypeByVal)
|
||||
if (!peraggstate->inputtypeByVal)
|
||||
pfree(DatumGetPointer(newVal));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
advance_transition_functions(peraggstate, newVal, false);
|
||||
if (haveOldVal && ! peraggstate->inputtypeByVal)
|
||||
if (haveOldVal && !peraggstate->inputtypeByVal)
|
||||
pfree(DatumGetPointer(oldVal));
|
||||
oldVal = newVal;
|
||||
haveOldVal = true;
|
||||
}
|
||||
if (haveOldVal && ! peraggstate->inputtypeByVal)
|
||||
if (haveOldVal && !peraggstate->inputtypeByVal)
|
||||
pfree(DatumGetPointer(oldVal));
|
||||
tuplesort_end(peraggstate->sortstate);
|
||||
peraggstate->sortstate = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now apply the agg's finalfn, or substitute the appropriate transition
|
||||
* value if there is no finalfn.
|
||||
* Now apply the agg's finalfn, or substitute the appropriate
|
||||
* transition value if there is no finalfn.
|
||||
*
|
||||
* XXX For now, only apply finalfn if we got at least one
|
||||
* non-null input value. This prevents zero divide in AVG().
|
||||
* If we had cleaner handling of null inputs/results in functions,
|
||||
* we could probably take out this hack and define the result
|
||||
* for no inputs as whatever finalfn returns for null input.
|
||||
* XXX For now, only apply finalfn if we got at least one non-null input
|
||||
* value. This prevents zero divide in AVG(). If we had cleaner
|
||||
* handling of null inputs/results in functions, we could probably
|
||||
* take out this hack and define the result for no inputs as whatever
|
||||
* finalfn returns for null input.
|
||||
*/
|
||||
if (OidIsValid(peraggstate->finalfn_oid) &&
|
||||
! peraggstate->noInitValue)
|
||||
!peraggstate->noInitValue)
|
||||
{
|
||||
if (peraggstate->finalfn.fn_nargs > 1)
|
||||
{
|
||||
@ -361,17 +373,17 @@ finalize_aggregate (AggStatePerAgg peraggstate,
|
||||
elog(ERROR, "ExecAgg: no valid transition functions??");
|
||||
|
||||
/*
|
||||
* Release any per-group working storage, unless we're passing
|
||||
* it back as the result of the aggregate.
|
||||
* Release any per-group working storage, unless we're passing it back
|
||||
* as the result of the aggregate.
|
||||
*/
|
||||
if (OidIsValid(peraggstate->xfn1_oid) &&
|
||||
! peraggstate->value1IsNull &&
|
||||
! peraggstate->transtype1ByVal)
|
||||
!peraggstate->value1IsNull &&
|
||||
!peraggstate->transtype1ByVal)
|
||||
pfree(peraggstate->value1);
|
||||
|
||||
|
||||
if (OidIsValid(peraggstate->xfn2_oid) &&
|
||||
! peraggstate->value2IsNull &&
|
||||
! peraggstate->transtype2ByVal)
|
||||
!peraggstate->value2IsNull &&
|
||||
!peraggstate->transtype2ByVal)
|
||||
pfree(peraggstate->value2);
|
||||
}
|
||||
|
||||
@ -383,8 +395,8 @@ finalize_aggregate (AggStatePerAgg peraggstate,
|
||||
* the appropriate attribute for each aggregate function use (Aggref
|
||||
* node) appearing in the targetlist or qual of the node. The number
|
||||
* of tuples to aggregate over depends on whether a GROUP BY clause is
|
||||
* present. We can produce an aggregate result row per group, or just
|
||||
* one for the whole query. The value of each aggregate is stored in
|
||||
* present. We can produce an aggregate result row per group, or just
|
||||
* one for the whole query. The value of each aggregate is stored in
|
||||
* the expression context to be used when ExecProject evaluates the
|
||||
* result tuple.
|
||||
*
|
||||
@ -403,7 +415,7 @@ ExecAgg(Agg *node)
|
||||
ProjectionInfo *projInfo;
|
||||
Datum *aggvalues;
|
||||
bool *aggnulls;
|
||||
AggStatePerAgg peragg;
|
||||
AggStatePerAgg peragg;
|
||||
TupleTableSlot *resultSlot;
|
||||
HeapTuple inputTuple;
|
||||
int aggno;
|
||||
@ -437,7 +449,7 @@ ExecAgg(Agg *node)
|
||||
*/
|
||||
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
|
||||
{
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
|
||||
initialize_aggregate(peraggstate);
|
||||
}
|
||||
@ -459,9 +471,9 @@ ExecAgg(Agg *node)
|
||||
|
||||
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
|
||||
{
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
Aggref *aggref = peraggstate->aggref;
|
||||
Datum newVal;
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
Aggref *aggref = peraggstate->aggref;
|
||||
Datum newVal;
|
||||
|
||||
newVal = ExecEvalExpr(aggref->target, econtext,
|
||||
&isNull, &isDone);
|
||||
@ -479,37 +491,37 @@ ExecAgg(Agg *node)
|
||||
|
||||
/*
|
||||
* Keep a copy of the first input tuple for the projection.
|
||||
* (We only need one since only the GROUP BY columns in it
|
||||
* can be referenced, and these will be the same for all
|
||||
* tuples aggregated over.)
|
||||
* (We only need one since only the GROUP BY columns in it can
|
||||
* be referenced, and these will be the same for all tuples
|
||||
* aggregated over.)
|
||||
*/
|
||||
if (!inputTuple)
|
||||
inputTuple = heap_copytuple(outerslot->val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Done scanning input tuple group.
|
||||
* Finalize each aggregate calculation.
|
||||
* Done scanning input tuple group. Finalize each aggregate
|
||||
* calculation.
|
||||
*/
|
||||
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
|
||||
{
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
|
||||
finalize_aggregate(peraggstate,
|
||||
& aggvalues[aggno], & aggnulls[aggno]);
|
||||
&aggvalues[aggno], &aggnulls[aggno]);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the outerPlan is a Group node, we will reach here after each
|
||||
* group. We are not done unless the Group node is done (a little
|
||||
* ugliness here while we reach into the Group's state to find out).
|
||||
* Furthermore, when grouping we return nothing at all unless we
|
||||
* had some input tuple(s). By the nature of Group, there are
|
||||
* no empty groups, so if we get here with no input the whole scan
|
||||
* is empty.
|
||||
* ugliness here while we reach into the Group's state to find
|
||||
* out). Furthermore, when grouping we return nothing at all
|
||||
* unless we had some input tuple(s). By the nature of Group,
|
||||
* there are no empty groups, so if we get here with no input the
|
||||
* whole scan is empty.
|
||||
*
|
||||
* If the outerPlan isn't a Group, we are done when we get here,
|
||||
* and we will emit a (single) tuple even if there were no input
|
||||
* If the outerPlan isn't a Group, we are done when we get here, and
|
||||
* we will emit a (single) tuple even if there were no input
|
||||
* tuples.
|
||||
*/
|
||||
if (IsA(outerPlan, Group))
|
||||
@ -523,17 +535,18 @@ ExecAgg(Agg *node)
|
||||
else
|
||||
{
|
||||
aggstate->agg_done = true;
|
||||
|
||||
/*
|
||||
* If inputtuple==NULL (ie, the outerPlan didn't return anything),
|
||||
* create a dummy all-nulls input tuple for use by execProject.
|
||||
* 99.44% of the time this is a waste of cycles, because
|
||||
* ordinarily the projected output tuple's targetlist cannot
|
||||
* contain any direct (non-aggregated) references to input
|
||||
* columns, so the dummy tuple will not be referenced. However
|
||||
* there are special cases where this isn't so --- in particular
|
||||
* an UPDATE involving an aggregate will have a targetlist
|
||||
* reference to ctid. We need to return a null for ctid in that
|
||||
* situation, not coredump.
|
||||
* If inputtuple==NULL (ie, the outerPlan didn't return
|
||||
* anything), create a dummy all-nulls input tuple for use by
|
||||
* execProject. 99.44% of the time this is a waste of cycles,
|
||||
* because ordinarily the projected output tuple's targetlist
|
||||
* cannot contain any direct (non-aggregated) references to
|
||||
* input columns, so the dummy tuple will not be referenced.
|
||||
* However there are special cases where this isn't so --- in
|
||||
* particular an UPDATE involving an aggregate will have a
|
||||
* targetlist reference to ctid. We need to return a null for
|
||||
* ctid in that situation, not coredump.
|
||||
*
|
||||
* The values returned for the aggregates will be the initial
|
||||
* values of the transition functions.
|
||||
@ -550,7 +563,7 @@ ExecAgg(Agg *node)
|
||||
/* watch out for null input tuples, though... */
|
||||
if (tupType && tupValue)
|
||||
{
|
||||
null_array = (char *) palloc(sizeof(char)*tupType->natts);
|
||||
null_array = (char *) palloc(sizeof(char) * tupType->natts);
|
||||
for (attnum = 0; attnum < tupType->natts; attnum++)
|
||||
null_array[attnum] = 'n';
|
||||
inputTuple = heap_formtuple(tupType, tupValue, null_array);
|
||||
@ -571,17 +584,17 @@ ExecAgg(Agg *node)
|
||||
|
||||
/*
|
||||
* Form a projection tuple using the aggregate results and the
|
||||
* representative input tuple. Store it in the result tuple slot.
|
||||
* representative input tuple. Store it in the result tuple slot.
|
||||
*/
|
||||
resultSlot = ExecProject(projInfo, &isDone);
|
||||
|
||||
/*
|
||||
* If the completed tuple does not match the qualifications,
|
||||
* it is ignored and we loop back to try to process another group.
|
||||
* If the completed tuple does not match the qualifications, it is
|
||||
* ignored and we loop back to try to process another group.
|
||||
* Otherwise, return the tuple.
|
||||
*/
|
||||
}
|
||||
while (! ExecQual(node->plan.qual, econtext, false));
|
||||
while (!ExecQual(node->plan.qual, econtext, false));
|
||||
|
||||
return resultSlot;
|
||||
}
|
||||
@ -596,13 +609,13 @@ ExecAgg(Agg *node)
|
||||
bool
|
||||
ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
{
|
||||
AggState *aggstate;
|
||||
AggStatePerAgg peragg;
|
||||
Plan *outerPlan;
|
||||
ExprContext *econtext;
|
||||
int numaggs,
|
||||
aggno;
|
||||
List *alist;
|
||||
AggState *aggstate;
|
||||
AggStatePerAgg peragg;
|
||||
Plan *outerPlan;
|
||||
ExprContext *econtext;
|
||||
int numaggs,
|
||||
aggno;
|
||||
List *alist;
|
||||
|
||||
/*
|
||||
* assign the node's execution state
|
||||
@ -620,21 +633,23 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
* find aggregates in targetlist and quals
|
||||
*
|
||||
* Note: pull_agg_clauses also checks that no aggs contain other agg
|
||||
* calls in their arguments. This would make no sense under SQL semantics
|
||||
* anyway (and it's forbidden by the spec). Because that is true, we
|
||||
* don't need to worry about evaluating the aggs in any particular order.
|
||||
* calls in their arguments. This would make no sense under SQL
|
||||
* semantics anyway (and it's forbidden by the spec). Because that is
|
||||
* true, we don't need to worry about evaluating the aggs in any
|
||||
* particular order.
|
||||
*/
|
||||
aggstate->aggs = nconc(pull_agg_clause((Node *) node->plan.targetlist),
|
||||
pull_agg_clause((Node *) node->plan.qual));
|
||||
aggstate->numaggs = numaggs = length(aggstate->aggs);
|
||||
if (numaggs <= 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* This used to be treated as an error, but we can't do that anymore
|
||||
* because constant-expression simplification could optimize away
|
||||
* all of the Aggrefs in the targetlist and qual. So, just make a
|
||||
* debug note, and force numaggs positive so that palloc()s below
|
||||
* don't choke.
|
||||
* This used to be treated as an error, but we can't do that
|
||||
* anymore because constant-expression simplification could
|
||||
* optimize away all of the Aggrefs in the targetlist and qual.
|
||||
* So, just make a debug note, and force numaggs positive so that
|
||||
* palloc()s below don't choke.
|
||||
*/
|
||||
elog(DEBUG, "ExecInitAgg: could not find any aggregate functions");
|
||||
numaggs = 1;
|
||||
@ -655,8 +670,8 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
|
||||
|
||||
/*
|
||||
* Set up aggregate-result storage in the expr context,
|
||||
* and also allocate my private per-agg working storage
|
||||
* Set up aggregate-result storage in the expr context, and also
|
||||
* allocate my private per-agg working storage
|
||||
*/
|
||||
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
||||
econtext->ecxt_aggvalues = (Datum *) palloc(sizeof(Datum) * numaggs);
|
||||
@ -693,15 +708,15 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
aggno = -1;
|
||||
foreach(alist, aggstate->aggs)
|
||||
{
|
||||
Aggref *aggref = (Aggref *) lfirst(alist);
|
||||
AggStatePerAgg peraggstate = &peragg[++aggno];
|
||||
char *aggname = aggref->aggname;
|
||||
HeapTuple aggTuple;
|
||||
Aggref *aggref = (Aggref *) lfirst(alist);
|
||||
AggStatePerAgg peraggstate = &peragg[++aggno];
|
||||
char *aggname = aggref->aggname;
|
||||
HeapTuple aggTuple;
|
||||
Form_pg_aggregate aggform;
|
||||
Type typeInfo;
|
||||
Oid xfn1_oid,
|
||||
xfn2_oid,
|
||||
finalfn_oid;
|
||||
Type typeInfo;
|
||||
Oid xfn1_oid,
|
||||
xfn2_oid,
|
||||
finalfn_oid;
|
||||
|
||||
/* Mark Aggref node with its associated index in the result array */
|
||||
aggref->aggno = aggno;
|
||||
@ -762,9 +777,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
}
|
||||
|
||||
if (OidIsValid(finalfn_oid))
|
||||
{
|
||||
fmgr_info(finalfn_oid, &peraggstate->finalfn);
|
||||
}
|
||||
|
||||
if (aggref->aggdistinct)
|
||||
{
|
||||
@ -848,7 +861,7 @@ copyDatum(Datum val, int typLen, bool typByVal)
|
||||
return val;
|
||||
else
|
||||
{
|
||||
char *newVal;
|
||||
char *newVal;
|
||||
|
||||
if (typLen == -1) /* variable length type? */
|
||||
typLen = VARSIZE((struct varlena *) DatumGetPointer(val));
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.29 2000/01/26 05:56:22 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.30 2000/04/12 17:15:09 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -251,9 +251,9 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
|
||||
|
||||
foreach(rtentryP, rtable)
|
||||
{
|
||||
RangeTblEntry *rtentry = lfirst(rtentryP);
|
||||
Oid reloid;
|
||||
RelationInfo *rri;
|
||||
RangeTblEntry *rtentry = lfirst(rtentryP);
|
||||
Oid reloid;
|
||||
RelationInfo *rri;
|
||||
|
||||
reloid = rtentry->relid;
|
||||
rri = makeNode(RelationInfo);
|
||||
@ -304,6 +304,7 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
|
||||
{
|
||||
JunkFilter *j = ExecInitJunkFilter(initNode->targetlist,
|
||||
ExecGetTupType(initNode));
|
||||
|
||||
junkList = lappend(junkList, j);
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* locate group boundaries.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.33 2000/01/27 18:11:27 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.34 2000/04/12 17:15:09 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -97,8 +97,9 @@ ExecGroupEveryTuple(Group *node)
|
||||
{
|
||||
grpstate->grp_useFirstTuple = FALSE;
|
||||
|
||||
/* note we rely on subplan to hold ownership of the tuple
|
||||
* for as long as we need it; we don't copy it.
|
||||
/*
|
||||
* note we rely on subplan to hold ownership of the tuple for as
|
||||
* long as we need it; we don't copy it.
|
||||
*/
|
||||
ExecStoreTuple(grpstate->grp_firstTuple,
|
||||
grpstate->csstate.css_ScanTupleSlot,
|
||||
@ -122,17 +123,20 @@ ExecGroupEveryTuple(Group *node)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Compare with first tuple and see if this tuple is of the
|
||||
* same group.
|
||||
*/
|
||||
if (! execTuplesMatch(firsttuple, outerTuple,
|
||||
tupdesc,
|
||||
node->numCols, node->grpColIdx,
|
||||
grpstate->eqfunctions))
|
||||
if (!execTuplesMatch(firsttuple, outerTuple,
|
||||
tupdesc,
|
||||
node->numCols, node->grpColIdx,
|
||||
grpstate->eqfunctions))
|
||||
{
|
||||
|
||||
/*
|
||||
* No; save the tuple to return it next time, and return NULL
|
||||
* No; save the tuple to return it next time, and return
|
||||
* NULL
|
||||
*/
|
||||
grpstate->grp_useFirstTuple = TRUE;
|
||||
heap_freetuple(firsttuple);
|
||||
@ -142,8 +146,9 @@ ExecGroupEveryTuple(Group *node)
|
||||
}
|
||||
}
|
||||
|
||||
/* note we rely on subplan to hold ownership of the tuple
|
||||
* for as long as we need it; we don't copy it.
|
||||
/*
|
||||
* note we rely on subplan to hold ownership of the tuple for as
|
||||
* long as we need it; we don't copy it.
|
||||
*/
|
||||
ExecStoreTuple(outerTuple,
|
||||
grpstate->csstate.css_ScanTupleSlot,
|
||||
@ -227,13 +232,13 @@ ExecGroupOneTuple(Group *node)
|
||||
outerTuple = outerslot->val;
|
||||
|
||||
/*
|
||||
* Compare with first tuple and see if this tuple is of the
|
||||
* same group.
|
||||
* Compare with first tuple and see if this tuple is of the same
|
||||
* group.
|
||||
*/
|
||||
if (! execTuplesMatch(firsttuple, outerTuple,
|
||||
tupdesc,
|
||||
node->numCols, node->grpColIdx,
|
||||
grpstate->eqfunctions))
|
||||
if (!execTuplesMatch(firsttuple, outerTuple,
|
||||
tupdesc,
|
||||
node->numCols, node->grpColIdx,
|
||||
grpstate->eqfunctions))
|
||||
break;
|
||||
}
|
||||
|
||||
@ -244,8 +249,9 @@ ExecGroupOneTuple(Group *node)
|
||||
*/
|
||||
projInfo = grpstate->csstate.cstate.cs_ProjInfo;
|
||||
|
||||
/* note we rely on subplan to hold ownership of the tuple
|
||||
* for as long as we need it; we don't copy it.
|
||||
/*
|
||||
* note we rely on subplan to hold ownership of the tuple for as long
|
||||
* as we need it; we don't copy it.
|
||||
*/
|
||||
ExecStoreTuple(firsttuple,
|
||||
grpstate->csstate.css_ScanTupleSlot,
|
||||
@ -418,7 +424,7 @@ execTuplesMatch(HeapTuple tuple1,
|
||||
* start comparing at the last field (least significant sort key).
|
||||
* That's the most likely to be different...
|
||||
*/
|
||||
for (i = numCols; --i >= 0; )
|
||||
for (i = numCols; --i >= 0;)
|
||||
{
|
||||
AttrNumber att = matchColIdx[i];
|
||||
Datum attr1,
|
||||
@ -445,7 +451,7 @@ execTuplesMatch(HeapTuple tuple1,
|
||||
|
||||
/* Apply the type-specific equality function */
|
||||
|
||||
equal = (Datum) (*fmgr_faddr(& eqfunctions[i])) (attr1, attr2);
|
||||
equal = (Datum) (*fmgr_faddr(&eqfunctions[i])) (attr1, attr2);
|
||||
|
||||
if (DatumGetInt32(equal) == 0)
|
||||
return FALSE;
|
||||
@ -459,7 +465,7 @@ execTuplesMatch(HeapTuple tuple1,
|
||||
* Look up the equality functions needed for execTuplesMatch.
|
||||
* The result is a palloc'd array.
|
||||
*/
|
||||
FmgrInfo *
|
||||
FmgrInfo *
|
||||
execTuplesMatchPrepare(TupleDesc tupdesc,
|
||||
int numCols,
|
||||
AttrNumber *matchColIdx)
|
||||
@ -481,7 +487,7 @@ execTuplesMatchPrepare(TupleDesc tupdesc,
|
||||
typeidTypeName(typid));
|
||||
}
|
||||
pgopform = (Form_pg_operator) GETSTRUCT(eq_operator);
|
||||
fmgr_info(pgopform->oprcode, & eqfunctions[i]);
|
||||
fmgr_info(pgopform->oprcode, &eqfunctions[i]);
|
||||
}
|
||||
|
||||
return eqfunctions;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.48 2000/04/07 00:30:41 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.49 2000/04/12 17:15:09 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -106,7 +106,7 @@ IndexNext(IndexScan *node)
|
||||
direction = BackwardScanDirection;
|
||||
else if (ScanDirectionIsBackward(direction))
|
||||
direction = ForwardScanDirection;
|
||||
}
|
||||
}
|
||||
snapshot = estate->es_snapshot;
|
||||
scanstate = node->scan.scanstate;
|
||||
indexstate = node->indxstate;
|
||||
@ -195,11 +195,11 @@ IndexNext(IndexScan *node)
|
||||
List *qual;
|
||||
|
||||
/*
|
||||
* store the scanned tuple in the scan tuple slot of
|
||||
* the scan state. Eventually we will only do this and not
|
||||
* return a tuple. Note: we pass 'false' because tuples
|
||||
* returned by amgetnext are pointers onto disk pages and
|
||||
* must not be pfree()'d.
|
||||
* store the scanned tuple in the scan tuple slot of the
|
||||
* scan state. Eventually we will only do this and not
|
||||
* return a tuple. Note: we pass 'false' because tuples
|
||||
* returned by amgetnext are pointers onto disk pages and
|
||||
* must not be pfree()'d.
|
||||
*/
|
||||
ExecStoreTuple(tuple, /* tuple to store */
|
||||
slot, /* slot to store in */
|
||||
@ -208,16 +208,17 @@ IndexNext(IndexScan *node)
|
||||
|
||||
/*
|
||||
* At this point we have an extra pin on the buffer,
|
||||
* because ExecStoreTuple incremented the pin count.
|
||||
* Drop our local pin.
|
||||
* because ExecStoreTuple incremented the pin count. Drop
|
||||
* our local pin.
|
||||
*/
|
||||
ReleaseBuffer(buffer);
|
||||
|
||||
/*
|
||||
* We must check to see if the current tuple was already
|
||||
* matched by an earlier index, so we don't double-report it.
|
||||
* We do this by passing the tuple through ExecQual and
|
||||
* checking for failure with all previous qualifications.
|
||||
* matched by an earlier index, so we don't double-report
|
||||
* it. We do this by passing the tuple through ExecQual
|
||||
* and checking for failure with all previous
|
||||
* qualifications.
|
||||
*/
|
||||
scanstate->cstate.cs_ExprContext->ecxt_scantuple = slot;
|
||||
qual = node->indxqualorig;
|
||||
@ -234,7 +235,7 @@ IndexNext(IndexScan *node)
|
||||
qual = lnext(qual);
|
||||
}
|
||||
if (!prev_matches)
|
||||
return slot; /* OK to return tuple */
|
||||
return slot;/* OK to return tuple */
|
||||
/* Duplicate tuple, so drop it and loop back for another */
|
||||
ExecClearTuple(slot);
|
||||
}
|
||||
@ -380,13 +381,14 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
scanexpr = (run_keys[j] == RIGHT_OP) ?
|
||||
(Node *) get_rightop(clause) :
|
||||
(Node *) get_leftop(clause);
|
||||
|
||||
/*
|
||||
* pass in isDone but ignore it. We don't iterate in
|
||||
* quals
|
||||
*/
|
||||
scanvalue = (Datum)
|
||||
ExecEvalExpr(scanexpr,
|
||||
node->scan.scanstate->cstate.cs_ExprContext,
|
||||
node->scan.scanstate->cstate.cs_ExprContext,
|
||||
&isNull, &isDone);
|
||||
scan_keys[j].sk_argument = scanvalue;
|
||||
if (isNull)
|
||||
@ -750,7 +752,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
clause = nth(j, qual);
|
||||
|
||||
op = (Oper *) clause->oper;
|
||||
if (!IsA(clause, Expr) || !IsA(op, Oper))
|
||||
if (!IsA(clause, Expr) ||!IsA(op, Oper))
|
||||
elog(ERROR, "ExecInitIndexScan: indxqual not an opclause!");
|
||||
|
||||
opid = op->opid;
|
||||
@ -801,7 +803,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
|
||||
Assert(leftop != NULL);
|
||||
|
||||
if (IsA(leftop, Var) && var_is_rel((Var *) leftop))
|
||||
if (IsA(leftop, Var) &&var_is_rel((Var *) leftop))
|
||||
{
|
||||
/* ----------------
|
||||
* if the leftop is a "rel-var", then it means
|
||||
@ -884,7 +886,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
|
||||
Assert(rightop != NULL);
|
||||
|
||||
if (IsA(rightop, Var) && var_is_rel((Var *) rightop))
|
||||
if (IsA(rightop, Var) &&var_is_rel((Var *) rightop))
|
||||
{
|
||||
/* ----------------
|
||||
* here we make sure only one op identifies the
|
||||
@ -1049,10 +1051,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
¤tRelation, /* return: rel desc */
|
||||
(Pointer *) ¤tScanDesc); /* return: scan desc */
|
||||
|
||||
if (!RelationGetForm(currentRelation)->relhasindex)
|
||||
{
|
||||
elog(ERROR, "indexes of the relation %u was inactivated", reloid);
|
||||
}
|
||||
if (!RelationGetForm(currentRelation)->relhasindex)
|
||||
elog(ERROR, "indexes of the relation %u was inactivated", reloid);
|
||||
scanstate->css_currentRelation = currentRelation;
|
||||
scanstate->css_currentScanDesc = currentScanDesc;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.25 2000/01/26 05:56:23 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.26 2000/04/12 17:15:09 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -126,7 +126,7 @@ ExecSort(Sort *node)
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
if (! sortstate->sort_Done)
|
||||
if (!sortstate->sort_Done)
|
||||
{
|
||||
Plan *outerNode;
|
||||
TupleDesc tupDesc;
|
||||
@ -156,7 +156,7 @@ ExecSort(Sort *node)
|
||||
sortkeys = (ScanKey) sortstate->sort_Keys;
|
||||
|
||||
tuplesortstate = tuplesort_begin_heap(tupDesc, keycount, sortkeys,
|
||||
true /* randomAccess */);
|
||||
true /* randomAccess */ );
|
||||
|
||||
sortstate->tuplesortstate = (void *) tuplesortstate;
|
||||
|
||||
@ -371,7 +371,7 @@ ExecSortMarkPos(Sort *node)
|
||||
* if we haven't sorted yet, just return
|
||||
* ----------------
|
||||
*/
|
||||
if (! sortstate->sort_Done)
|
||||
if (!sortstate->sort_Done)
|
||||
return;
|
||||
|
||||
tuplesort_markpos((Tuplesortstate *) sortstate->tuplesortstate);
|
||||
@ -392,7 +392,7 @@ ExecSortRestrPos(Sort *node)
|
||||
* if we haven't sorted yet, just return.
|
||||
* ----------------
|
||||
*/
|
||||
if (! sortstate->sort_Done)
|
||||
if (!sortstate->sort_Done)
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
@ -412,14 +412,14 @@ ExecReScanSort(Sort *node, ExprContext *exprCtxt, Plan *parent)
|
||||
* not NULL then it will be re-scanned by ExecProcNode, else - no
|
||||
* reason to re-scan it at all.
|
||||
*/
|
||||
if (! sortstate->sort_Done)
|
||||
if (!sortstate->sort_Done)
|
||||
return;
|
||||
|
||||
ExecClearTuple(sortstate->csstate.cstate.cs_ResultTupleSlot);
|
||||
|
||||
/*
|
||||
* If subnode is to be rescanned then we forget previous sort
|
||||
* results; we have to re-read the subplan and re-sort.
|
||||
* If subnode is to be rescanned then we forget previous sort results;
|
||||
* we have to re-read the subplan and re-sort.
|
||||
*
|
||||
* Otherwise we can just rewind and rescan the sorted output.
|
||||
*/
|
||||
@ -430,7 +430,5 @@ ExecReScanSort(Sort *node, ExprContext *exprCtxt, Plan *parent)
|
||||
sortstate->tuplesortstate = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
tuplesort_rescan((Tuplesortstate *) sortstate->tuplesortstate);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.24 2000/03/23 07:32:58 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.25 2000/04/12 17:15:10 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -67,20 +67,20 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
||||
ExecReScan(plan, (ExprContext *) NULL, plan);
|
||||
|
||||
/*
|
||||
* For all sublink types except EXPR_SUBLINK, the result is boolean
|
||||
* as are the results of the combining operators. We combine results
|
||||
* For all sublink types except EXPR_SUBLINK, the result is boolean as
|
||||
* are the results of the combining operators. We combine results
|
||||
* within a tuple (if there are multiple columns) using OR semantics
|
||||
* if "useor" is true, AND semantics if not. We then combine results
|
||||
* across tuples (if the subplan produces more than one) using OR
|
||||
* semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
|
||||
* (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.)
|
||||
* NULL results from the combining operators are handled according to
|
||||
* the usual SQL semantics for OR and AND. The result for no input
|
||||
* the usual SQL semantics for OR and AND. The result for no input
|
||||
* tuples is FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
|
||||
* MULTIEXPR_SUBLINK.
|
||||
*
|
||||
* For EXPR_SUBLINK we require the subplan to produce no more than one
|
||||
* tuple, else an error is raised. If zero tuples are produced, we
|
||||
* tuple, else an error is raised. If zero tuples are produced, we
|
||||
* return NULL. Assuming we get a tuple, we just return its first
|
||||
* column (there can be only one non-junk column in this case).
|
||||
*/
|
||||
@ -106,13 +106,14 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
||||
if (found)
|
||||
elog(ERROR, "More than one tuple returned by a subselect used as an expression.");
|
||||
found = true;
|
||||
|
||||
/*
|
||||
* We need to copy the subplan's tuple in case the result is of
|
||||
* pass-by-ref type --- our return value will point into this
|
||||
* copied tuple! Can't use the subplan's instance of the tuple
|
||||
* since it won't still be valid after next ExecProcNode() call.
|
||||
* node->curTuple keeps track of the copied tuple for eventual
|
||||
* freeing.
|
||||
* We need to copy the subplan's tuple in case the result is
|
||||
* of pass-by-ref type --- our return value will point into
|
||||
* this copied tuple! Can't use the subplan's instance of the
|
||||
* tuple since it won't still be valid after next
|
||||
* ExecProcNode() call. node->curTuple keeps track of the
|
||||
* copied tuple for eventual freeing.
|
||||
*/
|
||||
tup = heap_copytuple(tup);
|
||||
if (node->curTuple)
|
||||
@ -129,7 +130,8 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
||||
|
||||
found = true;
|
||||
|
||||
/* For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
|
||||
/*
|
||||
* For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
|
||||
* operators for columns of tuple.
|
||||
*/
|
||||
foreach(lst, sublink->oper)
|
||||
@ -140,14 +142,14 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
||||
bool expnull;
|
||||
|
||||
/*
|
||||
* The righthand side of the expression should be either a Const
|
||||
* or a function call or RelabelType node taking a Const as arg
|
||||
* (these nodes represent run-time type coercions inserted by
|
||||
* the parser to get to the input type needed by the operator).
|
||||
* Find the Const node and insert the actual righthand-side value
|
||||
* into it.
|
||||
* The righthand side of the expression should be either a
|
||||
* Const or a function call or RelabelType node taking a Const
|
||||
* as arg (these nodes represent run-time type coercions
|
||||
* inserted by the parser to get to the input type needed by
|
||||
* the operator). Find the Const node and insert the actual
|
||||
* righthand-side value into it.
|
||||
*/
|
||||
if (! IsA(con, Const))
|
||||
if (!IsA(con, Const))
|
||||
{
|
||||
switch (con->type)
|
||||
{
|
||||
@ -161,16 +163,18 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
||||
/* will fail below */
|
||||
break;
|
||||
}
|
||||
if (! IsA(con, Const))
|
||||
if (!IsA(con, Const))
|
||||
elog(ERROR, "ExecSubPlan: failed to find placeholder for subplan result");
|
||||
}
|
||||
con->constvalue = heap_getattr(tup, col, tdesc,
|
||||
&(con->constisnull));
|
||||
|
||||
/*
|
||||
* Now we can eval the combining operator for this column.
|
||||
*/
|
||||
expresult = ExecEvalExpr((Node *) expr, econtext, &expnull,
|
||||
(bool *) NULL);
|
||||
|
||||
/*
|
||||
* Combine the result into the row result as appropriate.
|
||||
*/
|
||||
@ -240,14 +244,16 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
||||
|
||||
if (!found)
|
||||
{
|
||||
/* deal with empty subplan result. result/isNull were previously
|
||||
|
||||
/*
|
||||
* deal with empty subplan result. result/isNull were previously
|
||||
* initialized correctly for all sublink types except EXPR and
|
||||
* MULTIEXPR; for those, return NULL.
|
||||
*/
|
||||
if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK)
|
||||
{
|
||||
result = (Datum) false;
|
||||
*isNull = true;
|
||||
result = (Datum) false;
|
||||
*isNull = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,9 +360,9 @@ ExecSetParamPlan(SubPlan *node)
|
||||
|
||||
/*
|
||||
* We need to copy the subplan's tuple in case any of the params
|
||||
* are pass-by-ref type --- the pointers stored in the param structs
|
||||
* will point at this copied tuple! node->curTuple keeps track
|
||||
* of the copied tuple for eventual freeing.
|
||||
* are pass-by-ref type --- the pointers stored in the param
|
||||
* structs will point at this copied tuple! node->curTuple keeps
|
||||
* track of the copied tuple for eventual freeing.
|
||||
*/
|
||||
tup = heap_copytuple(tup);
|
||||
if (node->curTuple)
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.5 2000/04/07 00:30:41 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.6 2000/04/12 17:15:10 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -32,21 +32,21 @@
|
||||
#include "access/heapam.h"
|
||||
#include "parser/parsetree.h"
|
||||
|
||||
static int TidListCreate(List *, ExprContext *, ItemPointer *);
|
||||
static int TidListCreate(List *, ExprContext *, ItemPointer *);
|
||||
static TupleTableSlot *TidNext(TidScan *node);
|
||||
|
||||
static int
|
||||
TidListCreate(List *evalList, ExprContext *econtext, ItemPointer *tidList)
|
||||
{
|
||||
List *lst;
|
||||
ItemPointer itemptr;
|
||||
List *lst;
|
||||
ItemPointer itemptr;
|
||||
bool isNull;
|
||||
int numTids = 0;
|
||||
int numTids = 0;
|
||||
|
||||
foreach (lst, evalList)
|
||||
foreach(lst, evalList)
|
||||
{
|
||||
itemptr = (ItemPointer)ExecEvalExpr(lfirst(lst), econtext,
|
||||
&isNull, (bool *)0);
|
||||
itemptr = (ItemPointer) ExecEvalExpr(lfirst(lst), econtext,
|
||||
&isNull, (bool *) 0);
|
||||
if (itemptr && ItemPointerIsValid(itemptr))
|
||||
{
|
||||
tidList[numTids] = itemptr;
|
||||
@ -67,20 +67,21 @@ TidListCreate(List *evalList, ExprContext *econtext, ItemPointer *tidList)
|
||||
static TupleTableSlot *
|
||||
TidNext(TidScan *node)
|
||||
{
|
||||
EState *estate;
|
||||
EState *estate;
|
||||
CommonScanState *scanstate;
|
||||
TidScanState *tidstate;
|
||||
ScanDirection direction;
|
||||
TidScanState *tidstate;
|
||||
ScanDirection direction;
|
||||
Snapshot snapshot;
|
||||
Relation heapRelation;
|
||||
HeapTuple tuple;
|
||||
TupleTableSlot *slot;
|
||||
TupleTableSlot *slot;
|
||||
Buffer buffer = InvalidBuffer;
|
||||
int numTids;
|
||||
int numTids;
|
||||
|
||||
bool bBackward;
|
||||
int tidNumber;
|
||||
ItemPointer *tidList, itemptr;
|
||||
int tidNumber;
|
||||
ItemPointer *tidList,
|
||||
itemptr;
|
||||
|
||||
/* ----------------
|
||||
* extract necessary information from tid scan node
|
||||
@ -108,7 +109,7 @@ TidNext(TidScan *node)
|
||||
ExecClearTuple(slot);
|
||||
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
|
||||
return slot; /* return empty slot */
|
||||
|
||||
|
||||
/* probably ought to use ExecStoreTuple here... */
|
||||
slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
|
||||
slot->ttc_shouldFree = false;
|
||||
@ -159,7 +160,7 @@ TidNext(TidScan *node)
|
||||
if (tuple->t_data != NULL)
|
||||
{
|
||||
bool prev_matches = false;
|
||||
int prev_tid;
|
||||
int prev_tid;
|
||||
|
||||
/* ----------------
|
||||
* store the scanned tuple in the scan tuple slot of
|
||||
@ -169,23 +170,23 @@ TidNext(TidScan *node)
|
||||
* were not created with palloc() and so should not be pfree()'d.
|
||||
* ----------------
|
||||
*/
|
||||
ExecStoreTuple(tuple, /* tuple to store */
|
||||
slot, /* slot to store in */
|
||||
buffer, /* buffer associated with tuple */
|
||||
false); /* don't pfree */
|
||||
ExecStoreTuple(tuple, /* tuple to store */
|
||||
slot,/* slot to store in */
|
||||
buffer, /* buffer associated with tuple */
|
||||
false); /* don't pfree */
|
||||
|
||||
/*
|
||||
* At this point we have an extra pin on the buffer,
|
||||
* because ExecStoreTuple incremented the pin count.
|
||||
* Drop our local pin.
|
||||
*/
|
||||
ReleaseBuffer(buffer);
|
||||
* At this point we have an extra pin on the buffer, because
|
||||
* ExecStoreTuple incremented the pin count. Drop our local
|
||||
* pin.
|
||||
*/
|
||||
ReleaseBuffer(buffer);
|
||||
|
||||
/*
|
||||
* We must check to see if the current tuple would have
|
||||
* been matched by an earlier tid, so we don't double
|
||||
* report it. We do this by passing the tuple through
|
||||
* ExecQual and look for failure with all previous
|
||||
* qualifications.
|
||||
* We must check to see if the current tuple would have been
|
||||
* matched by an earlier tid, so we don't double report it. We
|
||||
* do this by passing the tuple through ExecQual and look for
|
||||
* failure with all previous qualifications.
|
||||
*/
|
||||
for (prev_tid = 0; prev_tid < tidstate->tss_TidPtr;
|
||||
prev_tid++)
|
||||
@ -209,7 +210,7 @@ TidNext(TidScan *node)
|
||||
else
|
||||
tidstate->tss_TidPtr++;
|
||||
if (slot_is_valid)
|
||||
return slot;
|
||||
return slot;
|
||||
}
|
||||
/* ----------------
|
||||
* if we get here it means the tid scan failed so we
|
||||
@ -255,9 +256,9 @@ ExecTidScan(TidScan *node)
|
||||
void
|
||||
ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
{
|
||||
EState *estate;
|
||||
TidScanState *tidstate;
|
||||
ItemPointer *tidList;
|
||||
EState *estate;
|
||||
TidScanState *tidstate;
|
||||
ItemPointer *tidList;
|
||||
|
||||
tidstate = node->tidstate;
|
||||
estate = node->scan.plan.state;
|
||||
@ -278,7 +279,7 @@ ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
}
|
||||
|
||||
tidstate->tss_NumTids = TidListCreate(node->tideval,
|
||||
node->scan.scanstate->cstate.cs_ExprContext,
|
||||
node->scan.scanstate->cstate.cs_ExprContext,
|
||||
tidList);
|
||||
|
||||
/* ----------------
|
||||
@ -299,7 +300,7 @@ void
|
||||
ExecEndTidScan(TidScan *node)
|
||||
{
|
||||
CommonScanState *scanstate;
|
||||
TidScanState *tidstate;
|
||||
TidScanState *tidstate;
|
||||
|
||||
scanstate = node->scan.scanstate;
|
||||
tidstate = node->tidstate;
|
||||
@ -385,18 +386,18 @@ ExecTidRestrPos(TidScan *node)
|
||||
bool
|
||||
ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
||||
{
|
||||
TidScanState *tidstate;
|
||||
TidScanState *tidstate;
|
||||
CommonScanState *scanstate;
|
||||
ItemPointer *tidList;
|
||||
int numTids;
|
||||
int tidPtr;
|
||||
List *rangeTable;
|
||||
RangeTblEntry *rtentry;
|
||||
Oid relid;
|
||||
Oid reloid;
|
||||
ItemPointer *tidList;
|
||||
int numTids;
|
||||
int tidPtr;
|
||||
List *rangeTable;
|
||||
RangeTblEntry *rtentry;
|
||||
Oid relid;
|
||||
Oid reloid;
|
||||
|
||||
Relation currentRelation;
|
||||
int baseid;
|
||||
int baseid;
|
||||
|
||||
List *execParam = NULL;
|
||||
|
||||
@ -473,7 +474,7 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
||||
* get the tid node information
|
||||
* ----------------
|
||||
*/
|
||||
tidList = (ItemPointer *)palloc(length(node->tideval) * sizeof(ItemPointer));
|
||||
tidList = (ItemPointer *) palloc(length(node->tideval) * sizeof(ItemPointer));
|
||||
numTids = 0;
|
||||
if (!node->needRescan)
|
||||
numTids = TidListCreate(node->tideval, scanstate->cstate.cs_ExprContext, tidList);
|
||||
@ -502,8 +503,8 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
||||
reloid = rtentry->relid;
|
||||
|
||||
currentRelation = heap_open(reloid, AccessShareLock);
|
||||
if (currentRelation == NULL)
|
||||
elog(ERROR, "ExecInitTidScan heap_open failed.");
|
||||
if (currentRelation == NULL)
|
||||
elog(ERROR, "ExecInitTidScan heap_open failed.");
|
||||
scanstate->css_currentRelation = currentRelation;
|
||||
scanstate->css_currentScanDesc = 0;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.27 2000/01/27 18:11:27 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.28 2000/04/12 17:15:10 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -55,7 +55,7 @@ ExecUnique(Unique *node)
|
||||
uniquestate = node->uniquestate;
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
resultTupleSlot = uniquestate->cstate.cs_ResultTupleSlot;
|
||||
tupDesc = ExecGetResultType(& uniquestate->cstate);
|
||||
tupDesc = ExecGetResultType(&uniquestate->cstate);
|
||||
|
||||
/* ----------------
|
||||
* now loop, returning only non-duplicate tuples.
|
||||
@ -86,16 +86,16 @@ ExecUnique(Unique *node)
|
||||
* another new tuple from the subplan.
|
||||
* ----------------
|
||||
*/
|
||||
if (! execTuplesMatch(slot->val, uniquestate->priorTuple,
|
||||
tupDesc,
|
||||
node->numCols, node->uniqColIdx,
|
||||
uniquestate->eqfunctions))
|
||||
if (!execTuplesMatch(slot->val, uniquestate->priorTuple,
|
||||
tupDesc,
|
||||
node->numCols, node->uniqColIdx,
|
||||
uniquestate->eqfunctions))
|
||||
break;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* We have a new tuple different from the previous saved tuple (if any).
|
||||
* Save it and return it. Note that we make two copies of the tuple:
|
||||
* Save it and return it. Note that we make two copies of the tuple:
|
||||
* one to keep for our own future comparisons, and one to return to the
|
||||
* caller. We need to copy the tuple returned by the subplan to avoid
|
||||
* holding buffer refcounts, and we need our own copy because the caller
|
||||
@ -151,14 +151,14 @@ ExecInitUnique(Unique *node, EState *estate, Plan *parent)
|
||||
* they never call ExecQual or ExecTargetList.
|
||||
* ----------------
|
||||
*/
|
||||
ExecAssignNodeBaseInfo(estate, & uniquestate->cstate, parent);
|
||||
ExecAssignNodeBaseInfo(estate, &uniquestate->cstate, parent);
|
||||
|
||||
#define UNIQUE_NSLOTS 1
|
||||
/* ------------
|
||||
* Tuple table initialization
|
||||
* ------------
|
||||
*/
|
||||
ExecInitResultTupleSlot(estate, & uniquestate->cstate);
|
||||
ExecInitResultTupleSlot(estate, &uniquestate->cstate);
|
||||
|
||||
/* ----------------
|
||||
* then initialize outer plan
|
||||
@ -172,14 +172,14 @@ ExecInitUnique(Unique *node, EState *estate, Plan *parent)
|
||||
* projection info for this node appropriately
|
||||
* ----------------
|
||||
*/
|
||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, & uniquestate->cstate);
|
||||
ExecAssignResultTypeFromOuterPlan((Plan *) node, &uniquestate->cstate);
|
||||
uniquestate->cstate.cs_ProjInfo = NULL;
|
||||
|
||||
/*
|
||||
* Precompute fmgr lookup data for inner loop
|
||||
*/
|
||||
uniquestate->eqfunctions =
|
||||
execTuplesMatchPrepare(ExecGetResultType(& uniquestate->cstate),
|
||||
execTuplesMatchPrepare(ExecGetResultType(&uniquestate->cstate),
|
||||
node->numCols,
|
||||
node->uniqColIdx);
|
||||
|
||||
|
Reference in New Issue
Block a user