mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +03:00
pgindent run over code.
This commit is contained in:
@ -6,15 +6,15 @@
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This code provides support for a tee node, which allows
|
||||
* multiple parent in a megaplan.
|
||||
* This code provides support for a tee node, which allows
|
||||
* multiple parent in a megaplan.
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
* ExecTee
|
||||
* ExecInitTee
|
||||
* ExecEndTee
|
||||
*
|
||||
* $Id: nodeTee.c,v 1.1 1999/03/23 16:50:49 momjian Exp $
|
||||
* $Id: nodeTee.c,v 1.2 1999/05/25 16:08:50 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -46,12 +46,12 @@
|
||||
bool
|
||||
ExecInitTee(Tee *node, EState *currentEstate, Plan *parent)
|
||||
{
|
||||
TeeState *teeState;
|
||||
Plan *outerPlan;
|
||||
int len;
|
||||
TeeState *teeState;
|
||||
Plan *outerPlan;
|
||||
int len;
|
||||
Relation bufferRel;
|
||||
TupleDesc tupType;
|
||||
EState *estate;
|
||||
EState *estate;
|
||||
|
||||
/*
|
||||
* it is possible that the Tee has already been initialized since it
|
||||
@ -167,7 +167,7 @@ ExecInitTee(Tee *node, EState *currentEstate, Plan *parent)
|
||||
else
|
||||
bufferRel = heap_open(
|
||||
heap_create_with_catalog(teeState->tee_bufferRelname,
|
||||
tupType, RELKIND_RELATION, false));
|
||||
tupType, RELKIND_RELATION, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -176,7 +176,7 @@ ExecInitTee(Tee *node, EState *currentEstate, Plan *parent)
|
||||
newoid());
|
||||
bufferRel = heap_open(
|
||||
heap_create_with_catalog(teeState->tee_bufferRelname,
|
||||
tupType, RELKIND_RELATION, false));
|
||||
tupType, RELKIND_RELATION, false));
|
||||
}
|
||||
|
||||
teeState->tee_bufferRel = bufferRel;
|
||||
@ -339,6 +339,7 @@ ExecTee(Tee *node, Plan *parent)
|
||||
slot = ExecProcNode(childNode, (Plan *) node);
|
||||
if (!TupIsNull(slot))
|
||||
{
|
||||
|
||||
/*
|
||||
* heap_insert changes something...
|
||||
*/
|
||||
|
@ -5,7 +5,7 @@
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: execAmi.c,v 1.34 1999/05/10 00:45:05 momjian Exp $
|
||||
* $Id: execAmi.c,v 1.35 1999/05/25 16:08:34 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -24,7 +24,7 @@
|
||||
* ExecCreatR function to create temporary relations
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.50 1999/03/20 02:07:31 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.51 1999/05/25 16:08:37 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -66,7 +66,7 @@ bool execConstByVal;
|
||||
int execConstLen;
|
||||
|
||||
/* static functions decls */
|
||||
static Datum ExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull);
|
||||
static Datum ExecEvalAggref(Aggref * aggref, ExprContext *econtext, bool *isNull);
|
||||
static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext,
|
||||
bool *isNull, bool *isDone);
|
||||
static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull);
|
||||
@ -190,7 +190,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static Datum
|
||||
ExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull)
|
||||
ExecEvalAggref(Aggref * aggref, ExprContext *econtext, bool *isNull)
|
||||
{
|
||||
*isNull = econtext->ecxt_nulls[aggref->aggno];
|
||||
return econtext->ecxt_values[aggref->aggno];
|
||||
@ -232,7 +232,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||
int16 len;
|
||||
|
||||
/*
|
||||
* get the slot we want
|
||||
* get the slot we want
|
||||
*/
|
||||
switch (variable->varno)
|
||||
{
|
||||
@ -251,7 +251,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||
}
|
||||
|
||||
/*
|
||||
* extract tuple information from the slot
|
||||
* extract tuple information from the slot
|
||||
*/
|
||||
heapTuple = slot->val;
|
||||
tuple_type = slot->ttc_tupleDescriptor;
|
||||
@ -270,7 +270,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||
* the entire tuple, we give back a whole slot so that callers know
|
||||
* what the tuple looks like.
|
||||
*/
|
||||
if (attnum == InvalidAttrNumber)
|
||||
if (attnum == InvalidAttrNumber)
|
||||
{
|
||||
TupleTableSlot *tempSlot;
|
||||
TupleDesc td;
|
||||
@ -299,26 +299,25 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||
isNull); /* return: is attribute null? */
|
||||
|
||||
/*
|
||||
* return null if att is null
|
||||
* return null if att is null
|
||||
*/
|
||||
if (*isNull)
|
||||
return (Datum) NULL;
|
||||
|
||||
/*
|
||||
* get length and type information..
|
||||
* ??? what should we do about variable length attributes
|
||||
* - variable length attributes have their length stored
|
||||
* in the first 4 bytes of the memory pointed to by the
|
||||
* returned value.. If we can determine that the type
|
||||
* is a variable length type, we can do the right thing.
|
||||
* -cim 9/15/89
|
||||
* get length and type information.. ??? what should we do about
|
||||
* variable length attributes - variable length attributes have their
|
||||
* length stored in the first 4 bytes of the memory pointed to by the
|
||||
* returned value.. If we can determine that the type is a variable
|
||||
* length type, we can do the right thing. -cim 9/15/89
|
||||
*/
|
||||
if (attnum < 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* If this is a pseudo-att, we get the type and fake the length.
|
||||
* There ought to be a routine to return the real lengths, so
|
||||
* we'll mark this one ... XXX -mao
|
||||
* If this is a pseudo-att, we get the type and fake the length.
|
||||
* There ought to be a routine to return the real lengths, so
|
||||
* we'll mark this one ... XXX -mao
|
||||
*/
|
||||
len = heap_sysattrlen(attnum); /* XXX see -mao above */
|
||||
byval = heap_sysattrbyval(attnum); /* XXX see -mao above */
|
||||
@ -609,11 +608,11 @@ ExecEvalFuncArgs(FunctionCachePtr fcache,
|
||||
i = 0;
|
||||
foreach(arg, argList)
|
||||
{
|
||||
|
||||
/*
|
||||
* evaluate the expression, in general functions cannot take
|
||||
* sets as arguments but we make an exception in the case of
|
||||
* nested dot expressions. We have to watch out for this case
|
||||
* here.
|
||||
* evaluate the expression, in general functions cannot take sets
|
||||
* as arguments but we make an exception in the case of nested dot
|
||||
* expressions. We have to watch out for this case here.
|
||||
*/
|
||||
argV[i] = (Datum)
|
||||
ExecEvalExpr((Node *) lfirst(arg),
|
||||
@ -671,10 +670,10 @@ ExecMakeFunctionResult(Node *node,
|
||||
}
|
||||
|
||||
/*
|
||||
* arguments is a list of expressions to evaluate
|
||||
* before passing to the function manager.
|
||||
* We collect the results of evaluating the expressions
|
||||
* into a datum array (argV) and pass this array to arrayFmgr()
|
||||
* arguments is a list of expressions to evaluate before passing to
|
||||
* the function manager. We collect the results of evaluating the
|
||||
* expressions into a datum array (argV) and pass this array to
|
||||
* arrayFmgr()
|
||||
*/
|
||||
if (fcache->nargs != 0)
|
||||
{
|
||||
@ -743,8 +742,8 @@ ExecMakeFunctionResult(Node *node,
|
||||
}
|
||||
|
||||
/*
|
||||
* now return the value gotten by calling the function manager,
|
||||
* passing the function the evaluated parameter values.
|
||||
* now return the value gotten by calling the function manager,
|
||||
* passing the function the evaluated parameter values.
|
||||
*/
|
||||
if (fcache->language == SQLlanguageId)
|
||||
{
|
||||
@ -843,12 +842,12 @@ ExecEvalOper(Expr *opClause, ExprContext *econtext, bool *isNull)
|
||||
bool isDone;
|
||||
|
||||
/*
|
||||
* an opclause is a list (op args). (I think)
|
||||
* an opclause is a list (op args). (I think)
|
||||
*
|
||||
* we extract the oid of the function associated with
|
||||
* the op and then pass the work onto ExecMakeFunctionResult
|
||||
* which evaluates the arguments and returns the result of
|
||||
* calling the function on the evaluated arguments.
|
||||
* we extract the oid of the function associated with the op and then
|
||||
* pass the work onto ExecMakeFunctionResult which evaluates the
|
||||
* arguments and returns the result of calling the function on the
|
||||
* evaluated arguments.
|
||||
*/
|
||||
op = (Oper *) opClause->oper;
|
||||
argList = opClause->args;
|
||||
@ -865,8 +864,8 @@ ExecEvalOper(Expr *opClause, ExprContext *econtext, bool *isNull)
|
||||
}
|
||||
|
||||
/*
|
||||
* call ExecMakeFunctionResult() with a dummy isDone that we ignore.
|
||||
* We don't have operator whose arguments are sets.
|
||||
* call ExecMakeFunctionResult() with a dummy isDone that we ignore.
|
||||
* We don't have operator whose arguments are sets.
|
||||
*/
|
||||
return ExecMakeFunctionResult((Node *) op, argList, econtext, isNull, &isDone);
|
||||
}
|
||||
@ -887,14 +886,14 @@ ExecEvalFunc(Expr *funcClause,
|
||||
FunctionCachePtr fcache;
|
||||
|
||||
/*
|
||||
* an funcclause is a list (func args). (I think)
|
||||
* an funcclause is a list (func args). (I think)
|
||||
*
|
||||
* we extract the oid of the function associated with
|
||||
* the func node and then pass the work onto ExecMakeFunctionResult
|
||||
* which evaluates the arguments and returns the result of
|
||||
* calling the function on the evaluated arguments.
|
||||
* we extract the oid of the function associated with the func node and
|
||||
* then pass the work onto ExecMakeFunctionResult which evaluates the
|
||||
* arguments and returns the result of calling the function on the
|
||||
* evaluated arguments.
|
||||
*
|
||||
* this is nearly identical to the ExecEvalOper code.
|
||||
* this is nearly identical to the ExecEvalOper code.
|
||||
*/
|
||||
func = (Func *) funcClause->oper;
|
||||
argList = funcClause->args;
|
||||
@ -939,21 +938,21 @@ ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull)
|
||||
clause = lfirst(notclause->args);
|
||||
|
||||
/*
|
||||
* We don't iterate over sets in the quals, so pass in an isDone
|
||||
* flag, but ignore it.
|
||||
* We don't iterate over sets in the quals, so pass in an isDone flag,
|
||||
* but ignore it.
|
||||
*/
|
||||
expr_value = ExecEvalExpr(clause, econtext, isNull, &isDone);
|
||||
|
||||
/*
|
||||
* if the expression evaluates to null, then we just
|
||||
* cascade the null back to whoever called us.
|
||||
* if the expression evaluates to null, then we just cascade the null
|
||||
* back to whoever called us.
|
||||
*/
|
||||
if (*isNull)
|
||||
return expr_value;
|
||||
|
||||
/*
|
||||
* evaluation of 'not' is simple.. expr is false, then
|
||||
* return 'true' and vice versa.
|
||||
* evaluation of 'not' is simple.. expr is false, then return 'true'
|
||||
* and vice versa.
|
||||
*/
|
||||
if (DatumGetInt32(expr_value) == 0)
|
||||
return (Datum) true;
|
||||
@ -978,22 +977,19 @@ ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull)
|
||||
clauses = orExpr->args;
|
||||
|
||||
/*
|
||||
* we use three valued logic functions here...
|
||||
* we evaluate each of the clauses in turn,
|
||||
* as soon as one is true we return that
|
||||
* value. If none is true and none of the
|
||||
* clauses evaluate to NULL we return
|
||||
* the value of the last clause evaluated (which
|
||||
* should be false) with *isNull set to false else
|
||||
* if none is true and at least one clause evaluated
|
||||
* to NULL we set *isNull flag to true -
|
||||
* we use three valued logic functions here... we evaluate each of the
|
||||
* clauses in turn, as soon as one is true we return that value. If
|
||||
* none is true and none of the clauses evaluate to NULL we return
|
||||
* the value of the last clause evaluated (which should be false) with
|
||||
* *isNull set to false else if none is true and at least one clause
|
||||
* evaluated to NULL we set *isNull flag to true -
|
||||
*/
|
||||
foreach(clause, clauses)
|
||||
{
|
||||
|
||||
/*
|
||||
* We don't iterate over sets in the quals, so pass in an isDone
|
||||
* flag, but ignore it.
|
||||
* We don't iterate over sets in the quals, so pass in an isDone
|
||||
* flag, but ignore it.
|
||||
*/
|
||||
const_value = ExecEvalExpr((Node *) lfirst(clause),
|
||||
econtext,
|
||||
@ -1001,34 +997,32 @@ ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull)
|
||||
&isDone);
|
||||
|
||||
/*
|
||||
* if the expression evaluates to null, then we
|
||||
* remember it in the local IsNull flag, if none of the
|
||||
* clauses are true then we need to set *isNull
|
||||
* to true again.
|
||||
* if the expression evaluates to null, then we remember it in the
|
||||
* local IsNull flag, if none of the clauses are true then we need
|
||||
* to set *isNull to true again.
|
||||
*/
|
||||
if (*isNull)
|
||||
{
|
||||
IsNull = *isNull;
|
||||
|
||||
/*
|
||||
* Many functions don't (or can't!) check if an argument is NULL
|
||||
* or NOT_NULL and may return TRUE (1) with *isNull TRUE
|
||||
* (an_int4_column <> 1: int4ne returns TRUE for NULLs).
|
||||
* Not having time to fix the function manager I want to fix OR:
|
||||
* if we had 'x <> 1 OR x isnull' then when x is NULL
|
||||
* TRUE was returned by the 'x <> 1' clause ...
|
||||
* but ExecQualClause says that the qualification should *fail*
|
||||
* if isnull is TRUE for any value returned by ExecEvalExpr.
|
||||
* So, force this rule here:
|
||||
* if isnull is TRUE then the clause failed.
|
||||
* Note: nullvalue() & nonnullvalue() always sets isnull to FALSE for NULLs.
|
||||
* - vadim 09/22/97
|
||||
* Many functions don't (or can't!) check if an argument is
|
||||
* NULL or NOT_NULL and may return TRUE (1) with *isNull TRUE
|
||||
* (an_int4_column <> 1: int4ne returns TRUE for NULLs). Not
|
||||
* having time to fix the function manager I want to fix OR:
|
||||
* if we had 'x <> 1 OR x isnull' then when x is NULL TRUE was
|
||||
* returned by the 'x <> 1' clause ... but ExecQualClause says
|
||||
* that the qualification should *fail* if isnull is TRUE for
|
||||
* any value returned by ExecEvalExpr. So, force this rule
|
||||
* here: if isnull is TRUE then the clause failed. Note:
|
||||
* nullvalue() & nonnullvalue() always sets isnull to FALSE
|
||||
* for NULLs. - vadim 09/22/97
|
||||
*/
|
||||
const_value = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* if we have a true result, then we return it.
|
||||
* if we have a true result, then we return it.
|
||||
*/
|
||||
if (DatumGetInt32(const_value) != 0)
|
||||
return const_value;
|
||||
@ -1057,18 +1051,16 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
|
||||
clauses = andExpr->args;
|
||||
|
||||
/*
|
||||
* we evaluate each of the clauses in turn,
|
||||
* as soon as one is false we return that
|
||||
* value. If none are false or NULL then we return
|
||||
* the value of the last clause evaluated, which
|
||||
* should be true.
|
||||
* we evaluate each of the clauses in turn, as soon as one is false we
|
||||
* return that value. If none are false or NULL then we return the
|
||||
* value of the last clause evaluated, which should be true.
|
||||
*/
|
||||
foreach(clause, clauses)
|
||||
{
|
||||
|
||||
/*
|
||||
* We don't iterate over sets in the quals, so pass in an isDone
|
||||
* flag, but ignore it.
|
||||
* We don't iterate over sets in the quals, so pass in an isDone
|
||||
* flag, but ignore it.
|
||||
*/
|
||||
const_value = ExecEvalExpr((Node *) lfirst(clause),
|
||||
econtext,
|
||||
@ -1076,17 +1068,16 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
|
||||
&isDone);
|
||||
|
||||
/*
|
||||
* if the expression evaluates to null, then we
|
||||
* remember it in IsNull, if none of the clauses after
|
||||
* this evaluates to false we will have to set *isNull
|
||||
* to true again.
|
||||
* if the expression evaluates to null, then we remember it in
|
||||
* IsNull, if none of the clauses after this evaluates to false we
|
||||
* will have to set *isNull to true again.
|
||||
*/
|
||||
if (*isNull)
|
||||
IsNull = *isNull;
|
||||
|
||||
/*
|
||||
* if we have a false result, then we return it, since the
|
||||
* conjunction must be false.
|
||||
* if we have a false result, then we return it, since the
|
||||
* conjunction must be false.
|
||||
*/
|
||||
if (DatumGetInt32(const_value) == 0)
|
||||
return const_value;
|
||||
@ -1106,7 +1097,7 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static Datum
|
||||
ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
|
||||
ExecEvalCase(CaseExpr * caseExpr, ExprContext *econtext, bool *isNull)
|
||||
{
|
||||
List *clauses;
|
||||
List *clause;
|
||||
@ -1117,17 +1108,16 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
|
||||
clauses = caseExpr->args;
|
||||
|
||||
/*
|
||||
* we evaluate each of the WHEN clauses in turn,
|
||||
* as soon as one is true we return the corresponding
|
||||
* result. If none are true then we return the value
|
||||
* of the default clause, or NULL.
|
||||
* we evaluate each of the WHEN clauses in turn, as soon as one is
|
||||
* true we return the corresponding result. If none are true then we
|
||||
* return the value of the default clause, or NULL.
|
||||
*/
|
||||
foreach(clause, clauses)
|
||||
{
|
||||
|
||||
/*
|
||||
* We don't iterate over sets in the quals, so pass in an isDone
|
||||
* flag, but ignore it.
|
||||
* We don't iterate over sets in the quals, so pass in an isDone
|
||||
* flag, but ignore it.
|
||||
*/
|
||||
|
||||
wclause = lfirst(clause);
|
||||
@ -1137,8 +1127,8 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
|
||||
&isDone);
|
||||
|
||||
/*
|
||||
* if we have a true test, then we return the result,
|
||||
* since the case statement is satisfied.
|
||||
* if we have a true test, then we return the result, since the
|
||||
* case statement is satisfied.
|
||||
*/
|
||||
if (DatumGetInt32(const_value) != 0)
|
||||
{
|
||||
@ -1159,9 +1149,7 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext, bool *isNull)
|
||||
&isDone);
|
||||
}
|
||||
else
|
||||
{
|
||||
*isNull = true;
|
||||
}
|
||||
|
||||
return const_value;
|
||||
}
|
||||
@ -1204,8 +1192,8 @@ ExecEvalExpr(Node *expression,
|
||||
*isDone = true;
|
||||
|
||||
/*
|
||||
* here we dispatch the work to the appropriate type
|
||||
* of function given the type of our expression.
|
||||
* here we dispatch the work to the appropriate type of function given
|
||||
* the type of our expression.
|
||||
*/
|
||||
if (expression == NULL)
|
||||
{
|
||||
@ -1287,7 +1275,7 @@ ExecEvalExpr(Node *expression,
|
||||
}
|
||||
|
||||
return retDatum;
|
||||
} /* ExecEvalExpr() */
|
||||
} /* ExecEvalExpr() */
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@ -1325,16 +1313,15 @@ ExecQualClause(Node *clause, ExprContext *econtext)
|
||||
ExecEvalExpr(clause, econtext, &isNull, &isDone);
|
||||
|
||||
/*
|
||||
* this is interesting behaviour here. When a clause evaluates
|
||||
* to null, then we consider this as passing the qualification.
|
||||
* it seems kind of like, if the qual is NULL, then there's no
|
||||
* qual..
|
||||
* this is interesting behaviour here. When a clause evaluates to
|
||||
* null, then we consider this as passing the qualification. it seems
|
||||
* kind of like, if the qual is NULL, then there's no qual..
|
||||
*/
|
||||
if (isNull)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* remember, we return true when the qualification fails..
|
||||
* remember, we return true when the qualification fails..
|
||||
*/
|
||||
if (DatumGetInt32(expr_value) == 0)
|
||||
return true;
|
||||
@ -1356,7 +1343,7 @@ ExecQual(List *qual, ExprContext *econtext)
|
||||
bool result;
|
||||
|
||||
/*
|
||||
* debugging stuff
|
||||
* debugging stuff
|
||||
*/
|
||||
EV_printf("ExecQual: qual is ");
|
||||
EV_nodeDisplay(qual);
|
||||
@ -1365,18 +1352,18 @@ ExecQual(List *qual, ExprContext *econtext)
|
||||
IncrProcessed();
|
||||
|
||||
/*
|
||||
* return true immediately if no qual
|
||||
* return true immediately if no qual
|
||||
*/
|
||||
if (qual == NIL)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* a "qual" is a list of clauses. To evaluate the
|
||||
* qual, we evaluate each of the clauses in the list.
|
||||
* a "qual" is a list of clauses. To evaluate the qual, we evaluate
|
||||
* each of the clauses in the list.
|
||||
*
|
||||
* ExecQualClause returns true when we know the qualification
|
||||
* *failed* so we just pass each clause in qual to it until
|
||||
* we know the qual failed or there are no more clauses.
|
||||
* ExecQualClause returns true when we know the qualification *failed* so
|
||||
* we just pass each clause in qual to it until we know the qual
|
||||
* failed or there are no more clauses.
|
||||
*/
|
||||
result = false;
|
||||
|
||||
@ -1388,9 +1375,9 @@ ExecQual(List *qual, ExprContext *econtext)
|
||||
}
|
||||
|
||||
/*
|
||||
* if result is true, then it means a clause failed so we
|
||||
* return false. if result is false then it means no clause
|
||||
* failed so we return true.
|
||||
* if result is true, then it means a clause failed so we return
|
||||
* false. if result is false then it means no clause failed so we
|
||||
* return true.
|
||||
*/
|
||||
if (result == true)
|
||||
return false;
|
||||
@ -1447,48 +1434,46 @@ ExecTargetList(List *targetlist,
|
||||
bool isNull;
|
||||
|
||||
/*
|
||||
* debugging stuff
|
||||
* debugging stuff
|
||||
*/
|
||||
EV_printf("ExecTargetList: tl is ");
|
||||
EV_nodeDisplay(targetlist);
|
||||
EV_printf("\n");
|
||||
|
||||
/*
|
||||
* Return a dummy tuple if the targetlist is empty.
|
||||
* the dummy tuple is necessary to differentiate
|
||||
* between passing and failing the qualification.
|
||||
* Return a dummy tuple if the targetlist is empty. the dummy tuple is
|
||||
* necessary to differentiate between passing and failing the
|
||||
* qualification.
|
||||
*/
|
||||
if (targetlist == NIL)
|
||||
{
|
||||
|
||||
/*
|
||||
* I now think that the only time this makes
|
||||
* any sense is when we run a delete query. Then
|
||||
* we need to return something other than nil
|
||||
* so we know to delete the tuple associated
|
||||
* with the saved tupleid.. see what ExecutePlan
|
||||
* does with the returned tuple.. -cim 9/21/89
|
||||
* I now think that the only time this makes any sense is when we
|
||||
* run a delete query. Then we need to return something other
|
||||
* than nil so we know to delete the tuple associated with the
|
||||
* saved tupleid.. see what ExecutePlan does with the returned
|
||||
* tuple.. -cim 9/21/89
|
||||
*
|
||||
* It could also happen in queries like:
|
||||
* retrieve (foo.all) where bar.a = 3
|
||||
* It could also happen in queries like: retrieve (foo.all) where
|
||||
* bar.a = 3
|
||||
*
|
||||
* is this a new phenomenon? it might cause bogus behavior
|
||||
* if we try to free this tuple later!! I put a hook in
|
||||
* ExecProject to watch out for this case -mer 24 Aug 1992
|
||||
* is this a new phenomenon? it might cause bogus behavior if we try
|
||||
* to free this tuple later!! I put a hook in ExecProject to watch
|
||||
* out for this case -mer 24 Aug 1992
|
||||
*
|
||||
* We must return dummy tuple!!! Try
|
||||
* select t1.x from t1, t2 where t1.y = 1 and t2.y = 1
|
||||
* - t2 scan target list will be empty and so no one tuple
|
||||
* will be returned! But Mer was right - dummy tuple
|
||||
* must be palloced... - vadim 03/01/1999
|
||||
* We must return dummy tuple!!! Try select t1.x from t1, t2 where
|
||||
* t1.y = 1 and t2.y = 1 - t2 scan target list will be empty and
|
||||
* so no one tuple will be returned! But Mer was right - dummy
|
||||
* tuple must be palloced... - vadim 03/01/1999
|
||||
*/
|
||||
*isDone = true;
|
||||
return (HeapTuple) palloc(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate an array of char's to hold the "null" information
|
||||
* only if we have a really large targetlist. otherwise we use
|
||||
* the stack.
|
||||
* allocate an array of char's to hold the "null" information only if
|
||||
* we have a really large targetlist. otherwise we use the stack.
|
||||
*/
|
||||
if (nodomains > 64)
|
||||
{
|
||||
@ -1502,20 +1487,21 @@ ExecTargetList(List *targetlist,
|
||||
}
|
||||
|
||||
/*
|
||||
* evaluate all the expressions in the target list
|
||||
* evaluate all the expressions in the target list
|
||||
*/
|
||||
EV_printf("ExecTargetList: setting target list values\n");
|
||||
|
||||
*isDone = true;
|
||||
foreach(tl, targetlist)
|
||||
{
|
||||
|
||||
/*
|
||||
* remember, a target list is a list of lists:
|
||||
* remember, a target list is a list of lists:
|
||||
*
|
||||
* ((<resdom | fjoin> expr) (<resdom | fjoin> expr) ...)
|
||||
* ((<resdom | fjoin> expr) (<resdom | fjoin> expr) ...)
|
||||
*
|
||||
* tl is a pointer to successive cdr's of the targetlist
|
||||
* tle is a pointer to the target list entry in tl
|
||||
* tl is a pointer to successive cdr's of the targetlist tle is a
|
||||
* pointer to the target list entry in tl
|
||||
*/
|
||||
tle = lfirst(tl);
|
||||
|
||||
@ -1572,7 +1558,7 @@ ExecTargetList(List *targetlist,
|
||||
curNode < nNodes;
|
||||
curNode++, fjTlist = lnext(fjTlist))
|
||||
{
|
||||
#ifdef NOT_USED /* what is this?? */
|
||||
#ifdef NOT_USED /* what is this?? */
|
||||
Node *outernode = lfirst(fjTlist);
|
||||
|
||||
fjRes = (Resdom *) outernode->iterexpr;
|
||||
@ -1590,19 +1576,19 @@ ExecTargetList(List *targetlist,
|
||||
}
|
||||
|
||||
/*
|
||||
* form the new result tuple (in the "normal" context)
|
||||
* form the new result tuple (in the "normal" context)
|
||||
*/
|
||||
newTuple = (HeapTuple) heap_formtuple(targettype, values, null_head);
|
||||
|
||||
/*
|
||||
* free the nulls array if we allocated one..
|
||||
* free the nulls array if we allocated one..
|
||||
*/
|
||||
if (nodomains > 64)
|
||||
{
|
||||
pfree(null_head);
|
||||
pfree(fjIsNull);
|
||||
}
|
||||
|
||||
|
||||
return newTuple;
|
||||
}
|
||||
|
||||
@ -1631,13 +1617,13 @@ ExecProject(ProjectionInfo *projInfo, bool *isDone)
|
||||
HeapTuple newTuple;
|
||||
|
||||
/*
|
||||
* sanity checks
|
||||
* sanity checks
|
||||
*/
|
||||
if (projInfo == NULL)
|
||||
return (TupleTableSlot *) NULL;
|
||||
|
||||
/*
|
||||
* get the projection info we want
|
||||
* get the projection info we want
|
||||
*/
|
||||
slot = projInfo->pi_slot;
|
||||
targetlist = projInfo->pi_targetlist;
|
||||
@ -1648,7 +1634,7 @@ ExecProject(ProjectionInfo *projInfo, bool *isDone)
|
||||
econtext = projInfo->pi_exprContext;
|
||||
|
||||
/*
|
||||
* form a new (result) tuple
|
||||
* form a new (result) tuple
|
||||
*/
|
||||
newTuple = ExecTargetList(targetlist,
|
||||
len,
|
||||
@ -1658,11 +1644,10 @@ ExecProject(ProjectionInfo *projInfo, bool *isDone)
|
||||
isDone);
|
||||
|
||||
/*
|
||||
* store the tuple in the projection slot and return the slot.
|
||||
* store the tuple in the projection slot and return the slot.
|
||||
*
|
||||
* If there's no projection target list we don't want to pfree
|
||||
* the bogus tuple that ExecTargetList passes back to us.
|
||||
* -mer 24 Aug 1992
|
||||
* If there's no projection target list we don't want to pfree the bogus
|
||||
* tuple that ExecTargetList passes back to us. -mer 24 Aug 1992
|
||||
*/
|
||||
return (TupleTableSlot *)
|
||||
ExecStoreTuple(newTuple,/* tuple to store */
|
||||
@ -1670,4 +1655,3 @@ ExecProject(ProjectionInfo *projInfo, bool *isDone)
|
||||
InvalidBuffer, /* tuple has no buffer */
|
||||
true);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.24 1999/03/23 16:50:48 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.25 1999/05/25 16:08:39 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -467,6 +467,7 @@ ExecSetSlotPolicy(TupleTableSlot *slot, /* slot to change */
|
||||
|
||||
return old_shouldFree;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* --------------------------------
|
||||
@ -650,6 +651,7 @@ ExecInitMarkedTupleSlot(EState *estate, MergeJoinState *mergestate)
|
||||
INIT_SLOT_ALLOC;
|
||||
mergestate->mj_MarkedTupleSlot = (TupleTableSlot *) slot;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.44 1999/03/20 01:13:22 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.45 1999/05/25 16:08:39 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -402,7 +402,7 @@ ExecFreeExprContext(CommonState *commonstate)
|
||||
void
|
||||
ExecFreeTypeInfo(CommonState *commonstate)
|
||||
{
|
||||
TupleDesc tupDesc;
|
||||
TupleDesc tupDesc;
|
||||
|
||||
tupDesc = commonstate->cs_ResultTupleSlot->ttc_tupleDescriptor;
|
||||
if (tupDesc == NULL)
|
||||
@ -498,12 +498,12 @@ ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate)
|
||||
* Routines dealing with the structure 'attribute' which conatains
|
||||
* the type information about attributes in a tuple:
|
||||
*
|
||||
* ExecMakeTypeInfo(noType)
|
||||
* ExecMakeTypeInfo(noType)
|
||||
* returns pointer to array of 'noType' structure 'attribute'.
|
||||
* ExecSetTypeInfo(index, typeInfo, attNum, attLen)
|
||||
* ExecSetTypeInfo(index, typeInfo, attNum, attLen)
|
||||
* sets the element indexed by 'index' in typeInfo with
|
||||
* the values: attNum, attLen.
|
||||
* ExecFreeTypeInfo(typeInfo)
|
||||
* ExecFreeTypeInfo(typeInfo)
|
||||
* frees the structure 'typeInfo'.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
@ -677,7 +677,7 @@ ExecGetIndexKeyInfo(Form_pg_index indexTuple,
|
||||
*/
|
||||
numKeys = 0;
|
||||
for (i = 0; i < INDEX_MAX_KEYS &&
|
||||
indexTuple->indkey[i] != InvalidAttrNumber; i++)
|
||||
indexTuple->indkey[i] != InvalidAttrNumber; i++)
|
||||
numKeys++;
|
||||
|
||||
/* ----------------
|
||||
@ -711,7 +711,7 @@ ExecGetIndexKeyInfo(Form_pg_index indexTuple,
|
||||
*/
|
||||
CXT1_printf("ExecGetIndexKeyInfo: context is %d\n", CurrentMemoryContext);
|
||||
|
||||
attKeys = (AttrNumber *)palloc(numKeys * sizeof(AttrNumber));
|
||||
attKeys = (AttrNumber *) palloc(numKeys * sizeof(AttrNumber));
|
||||
|
||||
for (i = 0; i < numKeys; i++)
|
||||
attKeys[i] = indexTuple->indkey[i];
|
||||
@ -917,19 +917,20 @@ ExecOpenIndices(Oid resultRelationOid,
|
||||
if (indexDesc != NULL)
|
||||
{
|
||||
relationDescs[i++] = indexDesc;
|
||||
|
||||
/*
|
||||
* Hack for not btree and hash indices: they use relation level
|
||||
* exclusive locking on updation (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 lock in ExecCloseIndices.
|
||||
* Note, that hashes use page level locking - i.e. are not
|
||||
* deadlock-free, - let's them be on their way -:))
|
||||
* vadim 03-12-1998
|
||||
* Hack for not btree and hash indices: they use relation
|
||||
* level exclusive locking on updation (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
|
||||
* lock in ExecCloseIndices. Note, that hashes use page
|
||||
* level locking - i.e. are not deadlock-free, - let's
|
||||
* them be on their way -:)) vadim 03-12-1998
|
||||
*/
|
||||
if (indexDesc->rd_rel->relam != BTREE_AM_OID &&
|
||||
indexDesc->rd_rel->relam != HASH_AM_OID)
|
||||
if (indexDesc->rd_rel->relam != BTREE_AM_OID &&
|
||||
indexDesc->rd_rel->relam != HASH_AM_OID)
|
||||
LockRelation(indexDesc, AccessExclusiveLock);
|
||||
}
|
||||
}
|
||||
@ -1014,15 +1015,17 @@ ExecCloseIndices(RelationInfo *resultRelationInfo)
|
||||
{
|
||||
if (relationDescs[i] == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Notes in ExecOpenIndices.
|
||||
*/
|
||||
if (relationDescs[i]->rd_rel->relam != BTREE_AM_OID &&
|
||||
relationDescs[i]->rd_rel->relam != HASH_AM_OID)
|
||||
if (relationDescs[i]->rd_rel->relam != BTREE_AM_OID &&
|
||||
relationDescs[i]->rd_rel->relam != HASH_AM_OID)
|
||||
UnlockRelation(relationDescs[i], AccessExclusiveLock);
|
||||
|
||||
index_close(relationDescs[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX should free indexInfo array here too.
|
||||
*/
|
||||
@ -1210,7 +1213,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
|
||||
result = index_insert(relationDescs[i], /* index relation */
|
||||
datum, /* array of heaptuple Datums */
|
||||
nulls, /* info on nulls */
|
||||
&(heapTuple->t_self), /* tid of heap tuple */
|
||||
&(heapTuple->t_self), /* tid of heap tuple */
|
||||
heapRelation);
|
||||
|
||||
/* ----------------
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.25 1999/05/13 07:28:29 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.26 1999/05/25 16:08:39 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -107,9 +107,9 @@ init_execution_state(FunctionCachePtr fcache,
|
||||
preves = (execution_state *) NULL;
|
||||
|
||||
planTree_list = pg_parse_and_plan(fcache->src, fcache->argOidVect,
|
||||
nargs, &queryTree_list, None, FALSE);
|
||||
nargs, &queryTree_list, None, FALSE);
|
||||
|
||||
foreach (qtl_item, queryTree_list)
|
||||
foreach(qtl_item, queryTree_list)
|
||||
{
|
||||
Query *queryTree = lfirst(qtl_item);
|
||||
Plan *planTree = lfirst(planTree_list);
|
||||
@ -199,7 +199,7 @@ postquel_getnext(execution_state *es)
|
||||
|
||||
feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
|
||||
|
||||
return ExecutorRun(es->qd, es->estate, feature, (Node *)NULL, (Node *)NULL);
|
||||
return ExecutorRun(es->qd, es->estate, feature, (Node *) NULL, (Node *) NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -45,7 +45,7 @@ typedef struct AggFuncInfo
|
||||
FmgrInfo finalfn;
|
||||
} AggFuncInfo;
|
||||
|
||||
static Datum aggGetAttr(TupleTableSlot *tuple, Aggref *aggref, bool *isNull);
|
||||
static Datum aggGetAttr(TupleTableSlot *tuple, Aggref * aggref, bool *isNull);
|
||||
|
||||
|
||||
/* ---------------------------------------
|
||||
@ -121,7 +121,8 @@ ExecAgg(Agg *node)
|
||||
*/
|
||||
|
||||
/*
|
||||
* We loop retrieving groups until we find one matching node->plan.qual
|
||||
* We loop retrieving groups until we find one matching
|
||||
* node->plan.qual
|
||||
*/
|
||||
do
|
||||
{
|
||||
@ -133,7 +134,7 @@ ExecAgg(Agg *node)
|
||||
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
||||
|
||||
nagg = length(node->aggs);
|
||||
|
||||
|
||||
value1 = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_values;
|
||||
nulls = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_nulls;
|
||||
|
||||
@ -163,7 +164,7 @@ ExecAgg(Agg *node)
|
||||
finalfn_oid;
|
||||
|
||||
aggref->aggno = ++aggno;
|
||||
|
||||
|
||||
/* ---------------------
|
||||
* find transfer functions of all the aggregates and initialize
|
||||
* their initial values
|
||||
@ -172,7 +173,7 @@ ExecAgg(Agg *node)
|
||||
aggname = aggref->aggname;
|
||||
aggTuple = SearchSysCacheTuple(AGGNAME,
|
||||
PointerGetDatum(aggname),
|
||||
ObjectIdGetDatum(aggref->basetype),
|
||||
ObjectIdGetDatum(aggref->basetype),
|
||||
0, 0);
|
||||
if (!HeapTupleIsValid(aggTuple))
|
||||
elog(ERROR, "ExecAgg: cache lookup failed for aggregate \"%s\"(%s)",
|
||||
@ -195,9 +196,9 @@ ExecAgg(Agg *node)
|
||||
fmgr_info(xfn2_oid, &aggFuncInfo[aggno].xfn2);
|
||||
aggFuncInfo[aggno].xfn2_oid = xfn2_oid;
|
||||
value2[aggno] = (Datum) AggNameGetInitVal((char *) aggname,
|
||||
aggp->aggbasetype,
|
||||
2,
|
||||
&isNull2);
|
||||
aggp->aggbasetype,
|
||||
2,
|
||||
&isNull2);
|
||||
/* ------------------------------------------
|
||||
* If there is a second transition function, its initial
|
||||
* value must exist -- as it does not depend on data values,
|
||||
@ -213,9 +214,9 @@ ExecAgg(Agg *node)
|
||||
fmgr_info(xfn1_oid, &aggFuncInfo[aggno].xfn1);
|
||||
aggFuncInfo[aggno].xfn1_oid = xfn1_oid;
|
||||
value1[aggno] = (Datum) AggNameGetInitVal((char *) aggname,
|
||||
aggp->aggbasetype,
|
||||
1,
|
||||
&isNull1);
|
||||
aggp->aggbasetype,
|
||||
1,
|
||||
&isNull1);
|
||||
|
||||
/* ------------------------------------------
|
||||
* If the initial value for the first transition function
|
||||
@ -245,6 +246,7 @@ ExecAgg(Agg *node)
|
||||
outerslot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
if (TupIsNull(outerslot))
|
||||
{
|
||||
|
||||
/*
|
||||
* when the outerplan doesn't return a single tuple,
|
||||
* create a dummy heaptuple anyway because we still need
|
||||
@ -299,27 +301,29 @@ ExecAgg(Agg *node)
|
||||
{
|
||||
if (noInitValue[aggno])
|
||||
{
|
||||
|
||||
/*
|
||||
* value1 has not been initialized.
|
||||
* This is the first non-NULL input value.
|
||||
* We use it as the initial value for value1.
|
||||
* value1 has not been initialized. This is the
|
||||
* first non-NULL input value. We use it as the
|
||||
* initial value for value1.
|
||||
*
|
||||
* But we can't just use it straight, we have to
|
||||
* make a copy of it since the tuple from which it
|
||||
* came will be freed on the next iteration of the
|
||||
* But we can't just use it straight, we have to make
|
||||
* a copy of it since the tuple from which it came
|
||||
* will be freed on the next iteration of the
|
||||
* scan. This requires finding out how to copy
|
||||
* the Datum. We assume the datum is of the agg's
|
||||
* basetype, or at least binary compatible with it.
|
||||
* basetype, or at least binary compatible with
|
||||
* it.
|
||||
*/
|
||||
Type aggBaseType = typeidType(aggref->basetype);
|
||||
int attlen = typeLen(aggBaseType);
|
||||
bool byVal = typeByVal(aggBaseType);
|
||||
Type aggBaseType = typeidType(aggref->basetype);
|
||||
int attlen = typeLen(aggBaseType);
|
||||
bool byVal = typeByVal(aggBaseType);
|
||||
|
||||
if (byVal)
|
||||
value1[aggno] = newVal;
|
||||
else
|
||||
{
|
||||
if (attlen == -1) /* variable length */
|
||||
if (attlen == -1) /* variable length */
|
||||
attlen = VARSIZE((struct varlena *) newVal);
|
||||
value1[aggno] = (Datum) palloc(attlen);
|
||||
memcpy((char *) (value1[aggno]), (char *) newVal,
|
||||
@ -330,13 +334,14 @@ ExecAgg(Agg *node)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* apply the transition functions.
|
||||
*/
|
||||
args[0] = value1[aggno];
|
||||
args[1] = newVal;
|
||||
value1[aggno] = (Datum) fmgr_c(&aggfns->xfn1,
|
||||
(FmgrValues *) args, &isNull1);
|
||||
value1[aggno] = (Datum) fmgr_c(&aggfns->xfn1,
|
||||
(FmgrValues *) args, &isNull1);
|
||||
Assert(!isNull1);
|
||||
}
|
||||
}
|
||||
@ -344,8 +349,8 @@ ExecAgg(Agg *node)
|
||||
if (aggfns->xfn2.fn_addr != NULL)
|
||||
{
|
||||
args[0] = value2[aggno];
|
||||
value2[aggno] = (Datum) fmgr_c(&aggfns->xfn2,
|
||||
(FmgrValues *) args, &isNull2);
|
||||
value2[aggno] = (Datum) fmgr_c(&aggfns->xfn2,
|
||||
(FmgrValues *) args, &isNull2);
|
||||
Assert(!isNull2);
|
||||
}
|
||||
}
|
||||
@ -395,7 +400,7 @@ ExecAgg(Agg *node)
|
||||
else
|
||||
elog(NOTICE, "ExecAgg: no valid transition functions??");
|
||||
value1[aggno] = (Datum) fmgr_c(&aggfns->finalfn,
|
||||
(FmgrValues *) args, &(nulls[aggno]));
|
||||
(FmgrValues *) args, &(nulls[aggno]));
|
||||
}
|
||||
else if (aggfns->xfn1.fn_addr != NULL)
|
||||
{
|
||||
@ -441,10 +446,11 @@ ExecAgg(Agg *node)
|
||||
* As long as the retrieved group does not match the
|
||||
* qualifications it is ignored and the next group is fetched
|
||||
*/
|
||||
if(node->plan.qual != NULL)
|
||||
qual_result = ExecQual(fix_opids(node->plan.qual), econtext);
|
||||
else qual_result = false;
|
||||
|
||||
if (node->plan.qual != NULL)
|
||||
qual_result = ExecQual(fix_opids(node->plan.qual), econtext);
|
||||
else
|
||||
qual_result = false;
|
||||
|
||||
if (oneTuple)
|
||||
pfree(oneTuple);
|
||||
}
|
||||
@ -466,7 +472,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
AggState *aggstate;
|
||||
Plan *outerPlan;
|
||||
ExprContext *econtext;
|
||||
|
||||
|
||||
/*
|
||||
* assign the node's execution state
|
||||
*/
|
||||
@ -478,7 +484,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
aggstate = makeNode(AggState);
|
||||
node->aggstate = aggstate;
|
||||
aggstate->agg_done = FALSE;
|
||||
|
||||
|
||||
/*
|
||||
* assign node's base id and create expression context
|
||||
*/
|
||||
@ -494,7 +500,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
|
||||
|
||||
econtext = aggstate->csstate.cstate.cs_ExprContext;
|
||||
econtext->ecxt_values = (Datum *) palloc(sizeof(Datum) * length(node->aggs));
|
||||
econtext->ecxt_values = (Datum *) palloc(sizeof(Datum) * length(node->aggs));
|
||||
MemSet(econtext->ecxt_values, 0, sizeof(Datum) * length(node->aggs));
|
||||
econtext->ecxt_nulls = (char *) palloc(sizeof(char) * length(node->aggs));
|
||||
MemSet(econtext->ecxt_nulls, 0, sizeof(char) * length(node->aggs));
|
||||
@ -538,8 +544,8 @@ int
|
||||
ExecCountSlotsAgg(Agg *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan(node)) +
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
AGG_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
AGG_NSLOTS;
|
||||
}
|
||||
|
||||
/* ------------------------
|
||||
@ -576,7 +582,7 @@ ExecEndAgg(Agg *node)
|
||||
*/
|
||||
static Datum
|
||||
aggGetAttr(TupleTableSlot *slot,
|
||||
Aggref *aggref,
|
||||
Aggref * aggref,
|
||||
bool *isNull)
|
||||
{
|
||||
Datum result;
|
||||
@ -622,10 +628,11 @@ aggGetAttr(TupleTableSlot *slot,
|
||||
return (Datum) tempSlot;
|
||||
}
|
||||
|
||||
result = heap_getattr(heapTuple, /* tuple containing attribute */
|
||||
attnum, /* attribute number of desired attribute */
|
||||
tuple_type,/* tuple descriptor of tuple */
|
||||
isNull); /* return: is attribute null? */
|
||||
result = heap_getattr(heapTuple, /* tuple containing attribute */
|
||||
attnum, /* attribute number of desired
|
||||
* attribute */
|
||||
tuple_type, /* tuple descriptor of tuple */
|
||||
isNull); /* return: is attribute null? */
|
||||
|
||||
/* ----------------
|
||||
* return null if att is null
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.18 1999/02/21 03:48:40 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.19 1999/05/25 16:08:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -151,7 +151,7 @@ exec_append_initialize_next(Append *node)
|
||||
if (appendstate->as_junkFilter_list)
|
||||
{
|
||||
estate->es_junkFilter = (JunkFilter *) nth(whichplan,
|
||||
appendstate->as_junkFilter_list);
|
||||
appendstate->as_junkFilter_list);
|
||||
}
|
||||
if (appendstate->as_result_relation_info_list)
|
||||
{
|
||||
|
@ -13,7 +13,7 @@
|
||||
* columns. (ie. tuples from the same group are consecutive)
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.25 1999/02/13 23:15:21 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.26 1999/05/25 16:08:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -193,8 +193,8 @@ ExecGroupOneTuple(Group *node)
|
||||
grpstate->grp_done = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
grpstate->grp_firstTuple = firsttuple =
|
||||
heap_copytuple(outerslot->val);
|
||||
grpstate->grp_firstTuple = firsttuple =
|
||||
heap_copytuple(outerslot->val);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* $Id: nodeHash.c,v 1.35 1999/05/18 21:33:06 tgl Exp $
|
||||
* $Id: nodeHash.c,v 1.36 1999/05/25 16:08:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -80,7 +80,8 @@ ExecHash(Hash *node)
|
||||
*/
|
||||
for (i = 0; i < nbatch; i++)
|
||||
{
|
||||
File tfile = OpenTemporaryFile();
|
||||
File tfile = OpenTemporaryFile();
|
||||
|
||||
Assert(tfile >= 0);
|
||||
hashtable->innerBatchFile[i] = BufFileCreate(tfile);
|
||||
}
|
||||
@ -247,30 +248,33 @@ ExecHashTableCreate(Hash *node)
|
||||
int i;
|
||||
Portal myPortal;
|
||||
char myPortalName[64];
|
||||
MemoryContext oldcxt;
|
||||
MemoryContext oldcxt;
|
||||
|
||||
/* ----------------
|
||||
* Get information about the size of the relation to be hashed
|
||||
* (it's the "outer" subtree of this node, but the inner relation of
|
||||
* the hashjoin).
|
||||
* Caution: this is only the planner's estimates, and so
|
||||
* can't be trusted too far. Apply a healthy fudge factor.
|
||||
* Caution: this is only the planner's estimates, and so
|
||||
* can't be trusted too far. Apply a healthy fudge factor.
|
||||
* ----------------
|
||||
*/
|
||||
outerNode = outerPlan(node);
|
||||
ntuples = outerNode->plan_size;
|
||||
if (ntuples <= 0) /* force a plausible size if no info */
|
||||
ntuples = 1000;
|
||||
/* estimate tupsize based on footprint of tuple in hashtable...
|
||||
* but what about palloc overhead?
|
||||
|
||||
/*
|
||||
* estimate tupsize based on footprint of tuple in hashtable... but
|
||||
* what about palloc overhead?
|
||||
*/
|
||||
tupsize = MAXALIGN(outerNode->plan_width) +
|
||||
MAXALIGN(sizeof(HashJoinTupleData));
|
||||
inner_rel_bytes = (double) ntuples * tupsize * FUDGE_FAC;
|
||||
inner_rel_bytes = (double) ntuples *tupsize * FUDGE_FAC;
|
||||
|
||||
/*
|
||||
* Target hashtable size is SortMem kilobytes, but not less than
|
||||
* sqrt(estimated inner rel size), so as to avoid horrible performance.
|
||||
* sqrt(estimated inner rel size), so as to avoid horrible
|
||||
* performance.
|
||||
*/
|
||||
hash_table_bytes = sqrt(inner_rel_bytes);
|
||||
if (hash_table_bytes < (SortMem * 1024L))
|
||||
@ -278,17 +282,19 @@ ExecHashTableCreate(Hash *node)
|
||||
|
||||
/*
|
||||
* Count the number of hash buckets we want for the whole relation,
|
||||
* for an average bucket load of NTUP_PER_BUCKET (per virtual bucket!).
|
||||
* for an average bucket load of NTUP_PER_BUCKET (per virtual
|
||||
* bucket!).
|
||||
*/
|
||||
totalbuckets = (int) ceil((double) ntuples * FUDGE_FAC / NTUP_PER_BUCKET);
|
||||
|
||||
/*
|
||||
* Count the number of buckets we think will actually fit in the
|
||||
* target memory size, at a loading of NTUP_PER_BUCKET (physical buckets).
|
||||
* NOTE: FUDGE_FAC here determines the fraction of the hashtable space
|
||||
* reserved to allow for nonuniform distribution of hash values.
|
||||
* Perhaps this should be a different number from the other uses of
|
||||
* FUDGE_FAC, but since we have no real good way to pick either one...
|
||||
* target memory size, at a loading of NTUP_PER_BUCKET (physical
|
||||
* buckets). NOTE: FUDGE_FAC here determines the fraction of the
|
||||
* hashtable space reserved to allow for nonuniform distribution of
|
||||
* hash values. Perhaps this should be a different number from the
|
||||
* other uses of FUDGE_FAC, but since we have no real good way to pick
|
||||
* either one...
|
||||
*/
|
||||
bucketsize = NTUP_PER_BUCKET * tupsize;
|
||||
nbuckets = (int) (hash_table_bytes / (bucketsize * FUDGE_FAC));
|
||||
@ -297,21 +303,25 @@ ExecHashTableCreate(Hash *node)
|
||||
|
||||
if (totalbuckets <= nbuckets)
|
||||
{
|
||||
/* We have enough space, so no batching. In theory we could
|
||||
* even reduce nbuckets, but since that could lead to poor
|
||||
* behavior if estimated ntuples is much less than reality,
|
||||
* it seems better to make more buckets instead of fewer.
|
||||
|
||||
/*
|
||||
* We have enough space, so no batching. In theory we could even
|
||||
* reduce nbuckets, but since that could lead to poor behavior if
|
||||
* estimated ntuples is much less than reality, it seems better to
|
||||
* make more buckets instead of fewer.
|
||||
*/
|
||||
totalbuckets = nbuckets;
|
||||
nbatch = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Need to batch; compute how many batches we want to use.
|
||||
* Note that nbatch doesn't have to have anything to do with
|
||||
* the ratio totalbuckets/nbuckets; in fact, it is the number
|
||||
* of groups we will use for the part of the data that doesn't
|
||||
* fall into the first nbuckets hash buckets.
|
||||
|
||||
/*
|
||||
* Need to batch; compute how many batches we want to use. Note
|
||||
* that nbatch doesn't have to have anything to do with the ratio
|
||||
* totalbuckets/nbuckets; in fact, it is the number of groups we
|
||||
* will use for the part of the data that doesn't fall into the
|
||||
* first nbuckets hash buckets.
|
||||
*/
|
||||
nbatch = (int) ceil((inner_rel_bytes - hash_table_bytes) /
|
||||
hash_table_bytes);
|
||||
@ -319,16 +329,17 @@ ExecHashTableCreate(Hash *node)
|
||||
nbatch = 1;
|
||||
}
|
||||
|
||||
/* Now, totalbuckets is the number of (virtual) hashbuckets for the
|
||||
/*
|
||||
* Now, totalbuckets is the number of (virtual) hashbuckets for the
|
||||
* whole relation, and nbuckets is the number of physical hashbuckets
|
||||
* we will use in the first pass. Data falling into the first nbuckets
|
||||
* virtual hashbuckets gets handled in the first pass; everything else
|
||||
* gets divided into nbatch batches to be processed in additional
|
||||
* passes.
|
||||
* we will use in the first pass. Data falling into the first
|
||||
* nbuckets virtual hashbuckets gets handled in the first pass;
|
||||
* everything else gets divided into nbatch batches to be processed in
|
||||
* additional passes.
|
||||
*/
|
||||
#ifdef HJDEBUG
|
||||
printf("nbatch = %d, totalbuckets = %d, nbuckets = %d\n",
|
||||
nbatch, totalbuckets, nbuckets);
|
||||
printf("nbatch = %d, totalbuckets = %d, nbuckets = %d\n",
|
||||
nbatch, totalbuckets, nbuckets);
|
||||
#endif
|
||||
|
||||
/* ----------------
|
||||
@ -353,14 +364,16 @@ ExecHashTableCreate(Hash *node)
|
||||
* ----------------
|
||||
*/
|
||||
i = 0;
|
||||
do {
|
||||
do
|
||||
{
|
||||
i++;
|
||||
sprintf(myPortalName, "<hashtable %d>", i);
|
||||
myPortal = GetPortalByName(myPortalName);
|
||||
} while (PortalIsValid(myPortal));
|
||||
myPortal = CreatePortal(myPortalName);
|
||||
Assert(PortalIsValid(myPortal));
|
||||
hashtable->myPortal = (void*) myPortal; /* kluge for circular includes */
|
||||
hashtable->myPortal = (void *) myPortal; /* kluge for circular
|
||||
* includes */
|
||||
hashtable->hashCxt = (MemoryContext) PortalGetVariableMemory(myPortal);
|
||||
hashtable->batchCxt = (MemoryContext) PortalGetHeapMemory(myPortal);
|
||||
|
||||
@ -392,8 +405,9 @@ ExecHashTableCreate(Hash *node)
|
||||
/* The files will not be opened until later... */
|
||||
}
|
||||
|
||||
/* Prepare portal for the first-scan space allocations;
|
||||
* allocate the hashbucket array therein, and set each bucket "empty".
|
||||
/*
|
||||
* Prepare portal for the first-scan space allocations; allocate the
|
||||
* hashbucket array therein, and set each bucket "empty".
|
||||
*/
|
||||
MemoryContextSwitchTo(hashtable->batchCxt);
|
||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||
@ -405,9 +419,7 @@ ExecHashTableCreate(Hash *node)
|
||||
elog(ERROR, "Insufficient memory for hash table.");
|
||||
|
||||
for (i = 0; i < nbuckets; i++)
|
||||
{
|
||||
hashtable->buckets[i] = NULL;
|
||||
}
|
||||
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
|
||||
@ -436,7 +448,7 @@ ExecHashTableDestroy(HashJoinTable hashtable)
|
||||
|
||||
/* Destroy the portal to release all working memory */
|
||||
/* cast here is a kluge for circular includes... */
|
||||
PortalDestroy((Portal*) & hashtable->myPortal);
|
||||
PortalDestroy((Portal *) &hashtable->myPortal);
|
||||
|
||||
/* And drop the control block */
|
||||
pfree(hashtable);
|
||||
@ -468,15 +480,15 @@ ExecHashTableInsert(HashJoinTable hashtable,
|
||||
* put the tuple in hash table
|
||||
* ---------------
|
||||
*/
|
||||
HashJoinTuple hashTuple;
|
||||
int hashTupleSize;
|
||||
HashJoinTuple hashTuple;
|
||||
int hashTupleSize;
|
||||
|
||||
hashTupleSize = MAXALIGN(sizeof(*hashTuple)) + heapTuple->t_len;
|
||||
hashTuple = (HashJoinTuple) MemoryContextAlloc(hashtable->batchCxt,
|
||||
hashTupleSize);
|
||||
if (hashTuple == NULL)
|
||||
elog(ERROR, "Insufficient memory for hash table.");
|
||||
memcpy((char *) & hashTuple->htup,
|
||||
memcpy((char *) &hashTuple->htup,
|
||||
(char *) heapTuple,
|
||||
sizeof(hashTuple->htup));
|
||||
hashTuple->htup.t_data = (HeapTupleHeader)
|
||||
@ -493,8 +505,9 @@ ExecHashTableInsert(HashJoinTable hashtable,
|
||||
* put the tuple into a tmp file for other batches
|
||||
* -----------------
|
||||
*/
|
||||
int batchno = (hashtable->nbatch * (bucketno - hashtable->nbuckets)) /
|
||||
(hashtable->totalbuckets - hashtable->nbuckets);
|
||||
int batchno = (hashtable->nbatch * (bucketno - hashtable->nbuckets)) /
|
||||
(hashtable->totalbuckets - hashtable->nbuckets);
|
||||
|
||||
hashtable->innerBatchSize[batchno]++;
|
||||
ExecHashJoinSaveTuple(heapTuple,
|
||||
hashtable->innerBatchFile[batchno]);
|
||||
@ -563,26 +576,23 @@ ExecScanHashBucket(HashJoinState *hjstate,
|
||||
List *hjclauses,
|
||||
ExprContext *econtext)
|
||||
{
|
||||
HashJoinTable hashtable = hjstate->hj_HashTable;
|
||||
HashJoinTuple hashTuple = hjstate->hj_CurTuple;
|
||||
HashJoinTable hashtable = hjstate->hj_HashTable;
|
||||
HashJoinTuple hashTuple = hjstate->hj_CurTuple;
|
||||
|
||||
/* hj_CurTuple is NULL to start scanning a new bucket, or the address
|
||||
/*
|
||||
* hj_CurTuple is NULL to start scanning a new bucket, or the address
|
||||
* of the last tuple returned from the current bucket.
|
||||
*/
|
||||
if (hashTuple == NULL)
|
||||
{
|
||||
hashTuple = hashtable->buckets[hjstate->hj_CurBucketNo];
|
||||
}
|
||||
else
|
||||
{
|
||||
hashTuple = hashTuple->next;
|
||||
}
|
||||
|
||||
while (hashTuple != NULL)
|
||||
{
|
||||
HeapTuple heapTuple = & hashTuple->htup;
|
||||
HeapTuple heapTuple = &hashTuple->htup;
|
||||
TupleTableSlot *inntuple;
|
||||
bool qualResult;
|
||||
bool qualResult;
|
||||
|
||||
/* insert hashtable's tuple into exec slot so ExecQual sees it */
|
||||
inntuple = ExecStoreTuple(heapTuple, /* tuple to store */
|
||||
@ -618,28 +628,34 @@ ExecScanHashBucket(HashJoinState *hjstate,
|
||||
static int
|
||||
hashFunc(Datum key, int len, bool byVal)
|
||||
{
|
||||
unsigned int h = 0;
|
||||
unsigned char *k;
|
||||
unsigned int h = 0;
|
||||
unsigned char *k;
|
||||
|
||||
if (byVal)
|
||||
{
|
||||
|
||||
if (byVal) {
|
||||
/*
|
||||
* If it's a by-value data type, use the 'len' least significant bytes
|
||||
* of the Datum value. This should do the right thing on either
|
||||
* bigendian or littleendian hardware --- see the Datum access
|
||||
* macros in c.h.
|
||||
* If it's a by-value data type, use the 'len' least significant
|
||||
* bytes of the Datum value. This should do the right thing on
|
||||
* either bigendian or littleendian hardware --- see the Datum
|
||||
* access macros in c.h.
|
||||
*/
|
||||
while (len-- > 0) {
|
||||
while (len-- > 0)
|
||||
{
|
||||
h = (h * PRIME1) ^ (key & 0xFF);
|
||||
key >>= 8;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* If this is a variable length type, then 'k' points to a "struct
|
||||
* varlena" and len == -1. NOTE: VARSIZE returns the "real" data
|
||||
* length plus the sizeof the "vl_len" attribute of varlena (the
|
||||
* length information). 'k' points to the beginning of the varlena
|
||||
* struct, so we have to use "VARDATA" to find the beginning of the
|
||||
* "real" data.
|
||||
* struct, so we have to use "VARDATA" to find the beginning of
|
||||
* the "real" data.
|
||||
*/
|
||||
if (len == -1)
|
||||
{
|
||||
@ -647,9 +663,7 @@ hashFunc(Datum key, int len, bool byVal)
|
||||
k = (unsigned char *) VARDATA(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
k = (unsigned char *) key;
|
||||
}
|
||||
while (len-- > 0)
|
||||
h = (h * PRIME1) ^ (*k++);
|
||||
}
|
||||
@ -669,7 +683,7 @@ hashFunc(Datum key, int len, bool byVal)
|
||||
void
|
||||
ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
||||
{
|
||||
MemoryContext oldcxt;
|
||||
MemoryContext oldcxt;
|
||||
int nbuckets = hashtable->nbuckets;
|
||||
int i;
|
||||
|
||||
@ -682,13 +696,14 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
||||
StartPortalAllocMode(DefaultAllocMode, 0);
|
||||
|
||||
/*
|
||||
* We still use the same number of physical buckets as in the first pass.
|
||||
* (It could be different; but we already decided how many buckets would
|
||||
* be appropriate for the allowed memory, so stick with that number.)
|
||||
* We MUST set totalbuckets to equal nbuckets, because from now on
|
||||
* no tuples will go out to temp files; there are no more virtual buckets,
|
||||
* only real buckets. (This implies that tuples will go into different
|
||||
* bucket numbers than they did on the first pass, but that's OK.)
|
||||
* We still use the same number of physical buckets as in the first
|
||||
* pass. (It could be different; but we already decided how many
|
||||
* buckets would be appropriate for the allowed memory, so stick with
|
||||
* that number.) We MUST set totalbuckets to equal nbuckets, because
|
||||
* from now on no tuples will go out to temp files; there are no more
|
||||
* virtual buckets, only real buckets. (This implies that tuples will
|
||||
* go into different bucket numbers than they did on the first pass,
|
||||
* but that's OK.)
|
||||
*/
|
||||
hashtable->totalbuckets = nbuckets;
|
||||
|
||||
@ -700,9 +715,7 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
||||
elog(ERROR, "Insufficient memory for hash table.");
|
||||
|
||||
for (i = 0; i < nbuckets; i++)
|
||||
{
|
||||
hashtable->buckets[i] = NULL;
|
||||
}
|
||||
|
||||
MemoryContextSwitchTo(oldcxt);
|
||||
}
|
||||
@ -710,6 +723,7 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
||||
void
|
||||
ExecReScanHash(Hash *node, ExprContext *exprCtxt, Plan *parent)
|
||||
{
|
||||
|
||||
/*
|
||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||
* first ExecProcNode.
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.20 1999/05/18 21:33:06 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.21 1999/05/25 16:08:42 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -23,10 +23,10 @@
|
||||
#include "optimizer/clauses.h" /* for get_leftop */
|
||||
|
||||
static TupleTableSlot *ExecHashJoinOuterGetTuple(Plan *node, Plan *parent,
|
||||
HashJoinState *hjstate);
|
||||
HashJoinState *hjstate);
|
||||
static TupleTableSlot *ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
|
||||
BufFile *file,
|
||||
TupleTableSlot *tupleSlot);
|
||||
BufFile * file,
|
||||
TupleTableSlot *tupleSlot);
|
||||
static int ExecHashJoinGetBatch(int bucketno, HashJoinTable hashtable);
|
||||
static int ExecHashJoinNewBatch(HashJoinState *hjstate);
|
||||
|
||||
@ -132,7 +132,8 @@ ExecHashJoin(HashJoin *node)
|
||||
*/
|
||||
for (i = 0; i < hashtable->nbatch; i++)
|
||||
{
|
||||
File tfile = OpenTemporaryFile();
|
||||
File tfile = OpenTemporaryFile();
|
||||
|
||||
Assert(tfile >= 0);
|
||||
hashtable->outerBatchFile[i] = BufFileCreate(tfile);
|
||||
}
|
||||
@ -149,6 +150,7 @@ ExecHashJoin(HashJoin *node)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
||||
/*
|
||||
* if the current outer tuple is nil, get a new one
|
||||
*/
|
||||
@ -159,6 +161,7 @@ ExecHashJoin(HashJoin *node)
|
||||
hjstate);
|
||||
if (TupIsNull(outerTupleSlot))
|
||||
{
|
||||
|
||||
/*
|
||||
* when the last batch runs out, clean up and exit
|
||||
*/
|
||||
@ -168,8 +171,8 @@ ExecHashJoin(HashJoin *node)
|
||||
}
|
||||
|
||||
/*
|
||||
* now we have an outer tuple, find the corresponding bucket for
|
||||
* this tuple from the hash table
|
||||
* now we have an outer tuple, find the corresponding bucket
|
||||
* for this tuple from the hash table
|
||||
*/
|
||||
econtext->ecxt_outertuple = outerTupleSlot;
|
||||
hjstate->hj_CurBucketNo = ExecHashGetBucket(hashtable, econtext,
|
||||
@ -184,20 +187,23 @@ ExecHashJoin(HashJoin *node)
|
||||
*/
|
||||
if (hashtable->curbatch == 0)
|
||||
{
|
||||
int batch = ExecHashJoinGetBatch(hjstate->hj_CurBucketNo,
|
||||
hashtable);
|
||||
int batch = ExecHashJoinGetBatch(hjstate->hj_CurBucketNo,
|
||||
hashtable);
|
||||
|
||||
if (batch > 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* Need to postpone this outer tuple to a later batch.
|
||||
* Save it in the corresponding outer-batch file.
|
||||
*/
|
||||
int batchno = batch - 1;
|
||||
int batchno = batch - 1;
|
||||
|
||||
hashtable->outerBatchSize[batchno]++;
|
||||
ExecHashJoinSaveTuple(outerTupleSlot->val,
|
||||
hashtable->outerBatchFile[batchno]);
|
||||
hashtable->outerBatchFile[batchno]);
|
||||
ExecClearTuple(outerTupleSlot);
|
||||
continue; /* loop around for a new outer tuple */
|
||||
continue; /* loop around for a new outer tuple */
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -212,6 +218,7 @@ ExecHashJoin(HashJoin *node)
|
||||
econtext);
|
||||
if (curtuple == NULL)
|
||||
break; /* out of matches */
|
||||
|
||||
/*
|
||||
* we've got a match, but still need to test qpqual
|
||||
*/
|
||||
@ -427,32 +434,33 @@ ExecEndHashJoin(HashJoin *node)
|
||||
static TupleTableSlot *
|
||||
ExecHashJoinOuterGetTuple(Plan *node, Plan *parent, HashJoinState *hjstate)
|
||||
{
|
||||
HashJoinTable hashtable = hjstate->hj_HashTable;
|
||||
int curbatch = hashtable->curbatch;
|
||||
HashJoinTable hashtable = hjstate->hj_HashTable;
|
||||
int curbatch = hashtable->curbatch;
|
||||
TupleTableSlot *slot;
|
||||
|
||||
if (curbatch == 0)
|
||||
{ /* if it is the first pass */
|
||||
slot = ExecProcNode(node, parent);
|
||||
if (! TupIsNull(slot))
|
||||
if (!TupIsNull(slot))
|
||||
return slot;
|
||||
|
||||
/*
|
||||
* We have just reached the end of the first pass.
|
||||
* Try to switch to a saved batch.
|
||||
* We have just reached the end of the first pass. Try to switch
|
||||
* to a saved batch.
|
||||
*/
|
||||
curbatch = ExecHashJoinNewBatch(hjstate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to read from a temp file.
|
||||
* Loop allows us to advance to new batch as needed.
|
||||
* Try to read from a temp file. Loop allows us to advance to new
|
||||
* batch as needed.
|
||||
*/
|
||||
while (curbatch <= hashtable->nbatch)
|
||||
{
|
||||
slot = ExecHashJoinGetSavedTuple(hjstate,
|
||||
hashtable->outerBatchFile[curbatch-1],
|
||||
hashtable->outerBatchFile[curbatch - 1],
|
||||
hjstate->hj_OuterTupleSlot);
|
||||
if (! TupIsNull(slot))
|
||||
if (!TupIsNull(slot))
|
||||
return slot;
|
||||
curbatch = ExecHashJoinNewBatch(hjstate);
|
||||
}
|
||||
@ -470,12 +478,12 @@ ExecHashJoinOuterGetTuple(Plan *node, Plan *parent, HashJoinState *hjstate)
|
||||
|
||||
static TupleTableSlot *
|
||||
ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
|
||||
BufFile *file,
|
||||
BufFile * file,
|
||||
TupleTableSlot *tupleSlot)
|
||||
{
|
||||
HeapTupleData htup;
|
||||
size_t nread;
|
||||
HeapTuple heapTuple;
|
||||
HeapTupleData htup;
|
||||
size_t nread;
|
||||
HeapTuple heapTuple;
|
||||
|
||||
nread = BufFileRead(file, (void *) &htup, sizeof(HeapTupleData));
|
||||
if (nread == 0)
|
||||
@ -484,8 +492,8 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
|
||||
elog(ERROR, "Read from hashjoin temp file failed");
|
||||
heapTuple = palloc(HEAPTUPLESIZE + htup.t_len);
|
||||
memcpy((char *) heapTuple, (char *) &htup, sizeof(HeapTupleData));
|
||||
heapTuple->t_data = (HeapTupleHeader)
|
||||
((char *) heapTuple + HEAPTUPLESIZE);
|
||||
heapTuple->t_data = (HeapTupleHeader)
|
||||
((char *) heapTuple + HEAPTUPLESIZE);
|
||||
nread = BufFileRead(file, (void *) heapTuple->t_data, htup.t_len);
|
||||
if (nread != (size_t) htup.t_len)
|
||||
elog(ERROR, "Read from hashjoin temp file failed");
|
||||
@ -506,16 +514,17 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
|
||||
int newbatch = hashtable->curbatch + 1;
|
||||
long *innerBatchSize = hashtable->innerBatchSize;
|
||||
long *outerBatchSize = hashtable->outerBatchSize;
|
||||
BufFile *innerFile;
|
||||
BufFile *innerFile;
|
||||
TupleTableSlot *slot;
|
||||
ExprContext *econtext;
|
||||
Var *innerhashkey;
|
||||
|
||||
if (newbatch > 1)
|
||||
{
|
||||
|
||||
/*
|
||||
* We no longer need the previous outer batch file;
|
||||
* close it right away to free disk space.
|
||||
* We no longer need the previous outer batch file; close it right
|
||||
* away to free disk space.
|
||||
*/
|
||||
BufFileClose(hashtable->outerBatchFile[newbatch - 2]);
|
||||
hashtable->outerBatchFile[newbatch - 2] = NULL;
|
||||
@ -541,8 +550,8 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
|
||||
return newbatch; /* no more batches */
|
||||
|
||||
/*
|
||||
* Rewind inner and outer batch files for this batch,
|
||||
* so that we can start reading them.
|
||||
* Rewind inner and outer batch files for this batch, so that we can
|
||||
* start reading them.
|
||||
*/
|
||||
if (BufFileSeek(hashtable->outerBatchFile[newbatch - 1], 0L,
|
||||
SEEK_SET) != 0L)
|
||||
@ -571,7 +580,8 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
|
||||
}
|
||||
|
||||
/*
|
||||
* after we build the hash table, the inner batch file is no longer needed
|
||||
* after we build the hash table, the inner batch file is no longer
|
||||
* needed
|
||||
*/
|
||||
BufFileClose(innerFile);
|
||||
hashtable->innerBatchFile[newbatch - 1] = NULL;
|
||||
@ -615,9 +625,9 @@ ExecHashJoinGetBatch(int bucketno, HashJoinTable hashtable)
|
||||
|
||||
void
|
||||
ExecHashJoinSaveTuple(HeapTuple heapTuple,
|
||||
BufFile *file)
|
||||
BufFile * file)
|
||||
{
|
||||
size_t written;
|
||||
size_t written;
|
||||
|
||||
written = BufFileWrite(file, (void *) heapTuple, sizeof(HeapTupleData));
|
||||
if (written != sizeof(HeapTupleData))
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.35 1999/05/10 00:45:06 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.36 1999/05/25 16:08:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -91,13 +91,14 @@ IndexNext(IndexScan *node)
|
||||
IndexScanDesc scandesc;
|
||||
Relation heapRelation;
|
||||
RetrieveIndexResult result;
|
||||
HeapTuple tuple;
|
||||
HeapTuple tuple;
|
||||
TupleTableSlot *slot;
|
||||
Buffer buffer = InvalidBuffer;
|
||||
int numIndices;
|
||||
|
||||
bool bBackward;
|
||||
int indexNumber;
|
||||
bool bBackward;
|
||||
int indexNumber;
|
||||
|
||||
/* ----------------
|
||||
* extract necessary information from index scan node
|
||||
* ----------------
|
||||
@ -114,14 +115,14 @@ IndexNext(IndexScan *node)
|
||||
|
||||
/*
|
||||
* Check if we are evaluating PlanQual for tuple of this relation.
|
||||
* Additional checking is not good, but no other way for now.
|
||||
* We could introduce new nodes for this case and handle
|
||||
* IndexScan --> NewNode switching in Init/ReScan plan...
|
||||
* Additional checking is not good, but no other way for now. We could
|
||||
* introduce new nodes for this case and handle IndexScan --> NewNode
|
||||
* switching in Init/ReScan plan...
|
||||
*/
|
||||
if (estate->es_evTuple != NULL &&
|
||||
if (estate->es_evTuple != NULL &&
|
||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
||||
{
|
||||
int iptr;
|
||||
int iptr;
|
||||
|
||||
slot->ttc_buffer = InvalidBuffer;
|
||||
slot->ttc_shouldFree = false;
|
||||
@ -138,7 +139,7 @@ IndexNext(IndexScan *node)
|
||||
scanstate->cstate.cs_ExprContext))
|
||||
break;
|
||||
}
|
||||
if (iptr == numIndices) /* would not be returned by indices */
|
||||
if (iptr == numIndices) /* would not be returned by indices */
|
||||
slot->val = NULL;
|
||||
/* Flag for the next call that no more tuples */
|
||||
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
|
||||
@ -153,26 +154,26 @@ IndexNext(IndexScan *node)
|
||||
* appropriate heap tuple.. else return NULL.
|
||||
* ----------------
|
||||
*/
|
||||
bBackward = ScanDirectionIsBackward(direction);
|
||||
if (bBackward)
|
||||
{
|
||||
indexNumber = numIndices - indexstate->iss_IndexPtr - 1;
|
||||
if (indexNumber < 0)
|
||||
{
|
||||
indexNumber = 0;
|
||||
indexstate->iss_IndexPtr = numIndices - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((indexNumber = indexstate->iss_IndexPtr) < 0)
|
||||
{
|
||||
indexNumber = 0;
|
||||
indexstate->iss_IndexPtr = 0;
|
||||
}
|
||||
}
|
||||
while (indexNumber < numIndices)
|
||||
{
|
||||
bBackward = ScanDirectionIsBackward(direction);
|
||||
if (bBackward)
|
||||
{
|
||||
indexNumber = numIndices - indexstate->iss_IndexPtr - 1;
|
||||
if (indexNumber < 0)
|
||||
{
|
||||
indexNumber = 0;
|
||||
indexstate->iss_IndexPtr = numIndices - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((indexNumber = indexstate->iss_IndexPtr) < 0)
|
||||
{
|
||||
indexNumber = 0;
|
||||
indexstate->iss_IndexPtr = 0;
|
||||
}
|
||||
}
|
||||
while (indexNumber < numIndices)
|
||||
{
|
||||
scandesc = scanDescs[indexstate->iss_IndexPtr];
|
||||
while ((result = index_getnext(scandesc, direction)) != NULL)
|
||||
{
|
||||
@ -224,14 +225,14 @@ IndexNext(IndexScan *node)
|
||||
if (BufferIsValid(buffer))
|
||||
ReleaseBuffer(buffer);
|
||||
}
|
||||
if (indexNumber < numIndices)
|
||||
{
|
||||
indexNumber++;
|
||||
if (bBackward)
|
||||
indexstate->iss_IndexPtr--;
|
||||
else
|
||||
indexstate->iss_IndexPtr++;
|
||||
}
|
||||
if (indexNumber < numIndices)
|
||||
{
|
||||
indexNumber++;
|
||||
if (bBackward)
|
||||
indexstate->iss_IndexPtr--;
|
||||
else
|
||||
indexstate->iss_IndexPtr++;
|
||||
}
|
||||
}
|
||||
/* ----------------
|
||||
* if we get here it means the index scan failed so we
|
||||
@ -323,7 +324,7 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
indexstate->iss_IndexPtr = -1;
|
||||
|
||||
/* If this is re-scanning of PlanQual ... */
|
||||
if (estate->es_evTuple != NULL &&
|
||||
if (estate->es_evTuple != NULL &&
|
||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
||||
{
|
||||
estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
|
||||
@ -703,7 +704,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
run_keys = (n_keys <= 0) ? NULL :
|
||||
(int *) palloc(n_keys * sizeof(int));
|
||||
|
||||
CXT1_printf("ExecInitIndexScan: context is %d\n",CurrentMemoryContext);
|
||||
CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* for each opclause in the given qual,
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.21 1999/02/13 23:15:24 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.22 1999/05/25 16:08:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -116,7 +116,7 @@ ExecMaterial(Material *node)
|
||||
|
||||
if (TupIsNull(slot))
|
||||
break;
|
||||
|
||||
|
||||
/*
|
||||
* heap_insert changes something...
|
||||
*/
|
||||
@ -124,12 +124,12 @@ ExecMaterial(Material *node)
|
||||
heapTuple = heap_copytuple(slot->val);
|
||||
else
|
||||
heapTuple = slot->val;
|
||||
|
||||
|
||||
heap_insert(tempRelation, heapTuple);
|
||||
|
||||
if (slot->ttc_buffer != InvalidBuffer)
|
||||
pfree(heapTuple);
|
||||
|
||||
|
||||
ExecClearTuple(slot);
|
||||
}
|
||||
currentRelation = tempRelation;
|
||||
@ -360,8 +360,8 @@ ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
|
||||
return;
|
||||
|
||||
matstate->csstate.css_currentScanDesc = ExecReScanR(matstate->csstate.css_currentRelation,
|
||||
matstate->csstate.css_currentScanDesc,
|
||||
node->plan.state->es_direction, 0, NULL);
|
||||
matstate->csstate.css_currentScanDesc,
|
||||
node->plan.state->es_direction, 0, NULL);
|
||||
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.26 1999/05/10 00:45:07 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.27 1999/05/25 16:08:45 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -103,7 +103,7 @@ static bool MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
static List *
|
||||
MJFormSkipQual(List *qualList, char * replaceopname)
|
||||
MJFormSkipQual(List *qualList, char *replaceopname)
|
||||
{
|
||||
List *qualCopy;
|
||||
List *qualcdr;
|
||||
@ -148,14 +148,14 @@ MJFormSkipQual(List *qualList, char * replaceopname)
|
||||
* ----------------
|
||||
*/
|
||||
optup = get_operator_tuple(op->opno);
|
||||
if (!HeapTupleIsValid(optup)) /* shouldn't happen */
|
||||
if (!HeapTupleIsValid(optup)) /* shouldn't happen */
|
||||
elog(ERROR, "MJFormSkipQual: operator %u not found", op->opno);
|
||||
opform = (Form_pg_operator) GETSTRUCT(optup);
|
||||
oprleft = opform->oprleft;
|
||||
oprright = opform->oprright;
|
||||
|
||||
/* ----------------
|
||||
* Now look up the matching "<" or ">" operator. If there isn't one,
|
||||
* Now look up the matching "<" or ">" operator. If there isn't one,
|
||||
* whoever marked the "=" operator mergejoinable was a loser.
|
||||
* ----------------
|
||||
*/
|
||||
@ -166,7 +166,7 @@ MJFormSkipQual(List *qualList, char * replaceopname)
|
||||
CharGetDatum('b'));
|
||||
if (!HeapTupleIsValid(optup))
|
||||
elog(ERROR,
|
||||
"MJFormSkipQual: mergejoin operator %u has no matching %s op",
|
||||
"MJFormSkipQual: mergejoin operator %u has no matching %s op",
|
||||
op->opno, replaceopname);
|
||||
opform = (Form_pg_operator) GETSTRUCT(optup);
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
* SeqScan (emp.all)
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.10 1999/03/20 01:13:22 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.11 1999/05/25 16:08:46 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -263,8 +263,8 @@ ExecEndResult(Result *node)
|
||||
* is freed at end-transaction time. -cim 6/2/91
|
||||
* ----------------
|
||||
*/
|
||||
ExecFreeExprContext(&resstate->cstate); /* XXX - new for us - er1p */
|
||||
ExecFreeTypeInfo(&resstate->cstate); /* XXX - new for us - er1p */
|
||||
ExecFreeExprContext(&resstate->cstate); /* XXX - new for us - er1p */
|
||||
ExecFreeTypeInfo(&resstate->cstate); /* XXX - new for us - er1p */
|
||||
ExecFreeProjectionInfo(&resstate->cstate);
|
||||
|
||||
/* ----------------
|
||||
@ -278,7 +278,8 @@ ExecEndResult(Result *node)
|
||||
* ----------------
|
||||
*/
|
||||
ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
|
||||
pfree(resstate); node->resstate = NULL; /* XXX - new for us - er1p */
|
||||
pfree(resstate);
|
||||
node->resstate = NULL; /* XXX - new for us - er1p */
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.17 1999/02/13 23:15:26 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.18 1999/05/25 16:08:46 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -68,11 +68,11 @@ SeqNext(SeqScan *node)
|
||||
|
||||
/*
|
||||
* Check if we are evaluating PlanQual for tuple of this relation.
|
||||
* Additional checking is not good, but no other way for now.
|
||||
* We could introduce new nodes for this case and handle
|
||||
* SeqScan --> NewNode switching in Init/ReScan plan...
|
||||
* Additional checking is not good, but no other way for now. We could
|
||||
* introduce new nodes for this case and handle SeqScan --> NewNode
|
||||
* switching in Init/ReScan plan...
|
||||
*/
|
||||
if (estate->es_evTuple != NULL &&
|
||||
if (estate->es_evTuple != NULL &&
|
||||
estate->es_evTuple[node->scanrelid - 1] != NULL)
|
||||
{
|
||||
slot->ttc_buffer = InvalidBuffer;
|
||||
@ -83,10 +83,11 @@ SeqNext(SeqScan *node)
|
||||
return (slot);
|
||||
}
|
||||
slot->val = estate->es_evTuple[node->scanrelid - 1];
|
||||
|
||||
/*
|
||||
* Note that unlike IndexScan, SeqScan never use keys
|
||||
* in heap_beginscan (and this is very bad) - so, here
|
||||
* we have not check are keys ok or not.
|
||||
* Note that unlike IndexScan, SeqScan never use keys in
|
||||
* heap_beginscan (and this is very bad) - so, here we have not
|
||||
* check are keys ok or not.
|
||||
*/
|
||||
/* Flag for the next call that no more tuples */
|
||||
estate->es_evTupleNull[node->scanrelid - 1] = true;
|
||||
@ -401,10 +402,11 @@ ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
outerPlan = outerPlan((Plan *) node);
|
||||
ExecReScan(outerPlan, exprCtxt, parent);
|
||||
}
|
||||
else /* otherwise, we are scanning a relation */
|
||||
else
|
||||
/* otherwise, we are scanning a relation */
|
||||
{
|
||||
/* If this is re-scanning of PlanQual ... */
|
||||
if (estate->es_evTuple != NULL &&
|
||||
if (estate->es_evTuple != NULL &&
|
||||
estate->es_evTuple[node->scanrelid - 1] != NULL)
|
||||
{
|
||||
estate->es_evTupleNull[node->scanrelid - 1] = false;
|
||||
|
@ -58,15 +58,16 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
|
||||
ExecReScan(plan, (ExprContext *) NULL, plan);
|
||||
|
||||
/*
|
||||
* For all sublink types except EXPR_SUBLINK, the result type is boolean,
|
||||
* and we have a fairly clear idea of how to combine multiple subitems
|
||||
* and deal with NULL values or an empty subplan result.
|
||||
* For all sublink types except EXPR_SUBLINK, the result type is
|
||||
* boolean, and we have a fairly clear idea of how to combine multiple
|
||||
* subitems and deal with NULL values or an empty subplan result.
|
||||
*
|
||||
* For EXPR_SUBLINK, the result type is whatever the combining operator
|
||||
* returns. We have no way to deal with more than one column in the
|
||||
* subplan result --- hopefully the parser forbids that. More seriously,
|
||||
* it's unclear what to do with NULL values or an empty subplan result.
|
||||
* For now, we error out, but should something else happen?
|
||||
* subplan result --- hopefully the parser forbids that. More
|
||||
* seriously, it's unclear what to do with NULL values or an empty
|
||||
* subplan result. For now, we error out, but should something else
|
||||
* happen?
|
||||
*/
|
||||
|
||||
for (slot = ExecProcNode(plan, plan);
|
||||
@ -105,14 +106,14 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
|
||||
}
|
||||
if (subLinkType != EXPR_SUBLINK)
|
||||
{
|
||||
if ((! (bool) result && !(sublink->useor)) ||
|
||||
if ((!(bool) result && !(sublink->useor)) ||
|
||||
((bool) result && sublink->useor))
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (subLinkType == ALL_SUBLINK && ! (bool) result)
|
||||
if (subLinkType == ALL_SUBLINK && !(bool) result)
|
||||
break;
|
||||
if (subLinkType == ANY_SUBLINK && (bool) result)
|
||||
break;
|
||||
@ -120,7 +121,7 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
|
||||
|
||||
if (!found)
|
||||
{
|
||||
/* deal with empty subplan result. Note default result is 'false' */
|
||||
/* deal with empty subplan result. Note default result is 'false' */
|
||||
if (subLinkType == ALL_SUBLINK)
|
||||
result = (Datum) true;
|
||||
else if (subLinkType == EXPR_SUBLINK)
|
||||
|
@ -3,7 +3,7 @@
|
||||
* spi.c
|
||||
* Server Programming Interface
|
||||
*
|
||||
* $Id: spi.c,v 1.37 1999/05/13 07:28:30 tgl Exp $
|
||||
* $Id: spi.c,v 1.38 1999/05/25 16:08:48 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -19,9 +19,9 @@ static _SPI_connection *_SPI_current = NULL;
|
||||
static int _SPI_connected = -1;
|
||||
static int _SPI_curid = -1;
|
||||
|
||||
DLLIMPORT uint32 SPI_processed = 0;
|
||||
DLLIMPORT uint32 SPI_processed = 0;
|
||||
DLLIMPORT SPITupleTable *SPI_tuptable;
|
||||
DLLIMPORT int SPI_result;
|
||||
DLLIMPORT int SPI_result;
|
||||
|
||||
static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
|
||||
static int _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount);
|
||||
@ -49,8 +49,8 @@ extern void ShowUsage(void);
|
||||
int
|
||||
SPI_connect()
|
||||
{
|
||||
char pname[64];
|
||||
PortalVariableMemory pvmem;
|
||||
char pname[64];
|
||||
PortalVariableMemory pvmem;
|
||||
|
||||
/*
|
||||
* It's possible on startup and after commit/abort. In future we'll
|
||||
@ -345,8 +345,8 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
|
||||
mtuple = heap_formtuple(rel->rd_att, v, n);
|
||||
infomask = mtuple->t_data->t_infomask;
|
||||
memmove(&(mtuple->t_data->t_oid), &(tuple->t_data->t_oid),
|
||||
((char *) &(tuple->t_data->t_hoff) -
|
||||
(char *) &(tuple->t_data->t_oid)));
|
||||
((char *) &(tuple->t_data->t_hoff) -
|
||||
(char *) &(tuple->t_data->t_oid)));
|
||||
mtuple->t_data->t_infomask = infomask;
|
||||
mtuple->t_data->t_natts = numberOfAttributes;
|
||||
}
|
||||
@ -411,8 +411,8 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
|
||||
val = heap_getattr(tuple, fnumber, tupdesc, &isnull);
|
||||
if (isnull)
|
||||
return NULL;
|
||||
if (! getTypeOutAndElem((Oid) tupdesc->attrs[fnumber - 1]->atttypid,
|
||||
&foutoid, &typelem))
|
||||
if (!getTypeOutAndElem((Oid) tupdesc->attrs[fnumber - 1]->atttypid,
|
||||
&foutoid, &typelem))
|
||||
{
|
||||
SPI_result = SPI_ERROR_NOOUTFUNC;
|
||||
return NULL;
|
||||
@ -549,13 +549,13 @@ SPI_pfree(void *pointer)
|
||||
/* =================== private functions =================== */
|
||||
|
||||
/*
|
||||
* spi_printtup
|
||||
* spi_printtup
|
||||
* store tuple retrieved by Executor into SPITupleTable
|
||||
* of current SPI procedure
|
||||
*
|
||||
*/
|
||||
void
|
||||
spi_printtup(HeapTuple tuple, TupleDesc tupdesc, DestReceiver* self)
|
||||
spi_printtup(HeapTuple tuple, TupleDesc tupdesc, DestReceiver * self)
|
||||
{
|
||||
SPITupleTable *tuptable;
|
||||
MemoryContext oldcxt;
|
||||
@ -633,12 +633,13 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
||||
|
||||
_SPI_current->qtlist = queryTree_list;
|
||||
|
||||
foreach (queryTree_list_item, queryTree_list)
|
||||
foreach(queryTree_list_item, queryTree_list)
|
||||
{
|
||||
queryTree = (Query *) lfirst(queryTree_list_item);
|
||||
planTree = lfirst(planTree_list);
|
||||
planTree_list = lnext(planTree_list);
|
||||
islastquery = (planTree_list == NIL); /* assume lists are same len */
|
||||
islastquery = (planTree_list == NIL); /* assume lists are same
|
||||
* len */
|
||||
|
||||
if (queryTree->commandType == CMD_UTILITY)
|
||||
{
|
||||
@ -658,7 +659,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
|
||||
if (plan == NULL)
|
||||
{
|
||||
ProcessUtility(queryTree->utilityStmt, None);
|
||||
if (! islastquery)
|
||||
if (!islastquery)
|
||||
CommandCounterIncrement();
|
||||
else
|
||||
return res;
|
||||
@ -717,17 +718,18 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
|
||||
_SPI_current->tuptable = NULL;
|
||||
_SPI_current->qtlist = NULL;
|
||||
|
||||
foreach (queryTree_list_item, queryTree_list)
|
||||
foreach(queryTree_list_item, queryTree_list)
|
||||
{
|
||||
queryTree = (Query *) lfirst(queryTree_list_item);
|
||||
planTree = lfirst(planTree_list);
|
||||
planTree_list = lnext(planTree_list);
|
||||
islastquery = (planTree_list == NIL); /* assume lists are same len */
|
||||
islastquery = (planTree_list == NIL); /* assume lists are same
|
||||
* len */
|
||||
|
||||
if (queryTree->commandType == CMD_UTILITY)
|
||||
{
|
||||
ProcessUtility(queryTree->utilityStmt, None);
|
||||
if (! islastquery)
|
||||
if (!islastquery)
|
||||
CommandCounterIncrement();
|
||||
else
|
||||
return SPI_OK_UTILITY;
|
||||
@ -777,7 +779,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
||||
char *intoName = NULL;
|
||||
int res;
|
||||
Const tcount_const;
|
||||
Node *count = NULL;
|
||||
Node *count = NULL;
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
@ -833,18 +835,18 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
||||
* ----------------
|
||||
*/
|
||||
memset(&tcount_const, 0, sizeof(tcount_const));
|
||||
tcount_const.type = T_Const;
|
||||
tcount_const.consttype = INT4OID;
|
||||
tcount_const.constlen = sizeof(int4);
|
||||
tcount_const.constvalue = (Datum)tcount;
|
||||
tcount_const.constisnull = FALSE;
|
||||
tcount_const.constbyval = TRUE;
|
||||
tcount_const.constisset = FALSE;
|
||||
tcount_const.constiscast = FALSE;
|
||||
|
||||
count = (Node *)&tcount_const;
|
||||
tcount_const.type = T_Const;
|
||||
tcount_const.consttype = INT4OID;
|
||||
tcount_const.constlen = sizeof(int4);
|
||||
tcount_const.constvalue = (Datum) tcount;
|
||||
tcount_const.constisnull = FALSE;
|
||||
tcount_const.constbyval = TRUE;
|
||||
tcount_const.constisset = FALSE;
|
||||
tcount_const.constiscast = FALSE;
|
||||
|
||||
count = (Node *) &tcount_const;
|
||||
}
|
||||
|
||||
|
||||
if (state == NULL) /* plan preparation */
|
||||
return res;
|
||||
#ifdef SPI_EXECUTOR_STATS
|
||||
@ -922,7 +924,7 @@ _SPI_procmem()
|
||||
}
|
||||
|
||||
/*
|
||||
* _SPI_begin_call
|
||||
* _SPI_begin_call
|
||||
*
|
||||
*/
|
||||
static int
|
||||
|
Reference in New Issue
Block a user