Modify nodeAgg.c so that no rows are returned for a GROUP BY
with no input rows, per pghackers discussions around 7/22/99. Clean up a bunch of ugly coding while at it; remove redundant re-lookup of aggregate info at start of each new GROUP. Arrange to pfree intermediate values when they are pass-by-ref types, so that aggregates on pass-by-ref types no longer eat memory. This takes care of a couple of TODO items...
This commit is contained in:
parent
40f6524161
commit
be09bc9ff2
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.61 1999/09/26 02:28:15 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.62 1999/09/26 21:21:09 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -209,8 +209,8 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||||
static Datum
|
static Datum
|
||||||
ExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull)
|
ExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull)
|
||||||
{
|
{
|
||||||
*isNull = econtext->ecxt_nulls[aggref->aggno];
|
*isNull = econtext->ecxt_aggnulls[aggref->aggno];
|
||||||
return econtext->ecxt_values[aggref->aggno];
|
return econtext->ecxt_aggvalues[aggref->aggno];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
|
@ -244,7 +244,6 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||||
AttrNumber attnum;
|
AttrNumber attnum;
|
||||||
HeapTuple heapTuple;
|
HeapTuple heapTuple;
|
||||||
TupleDesc tuple_type;
|
TupleDesc tuple_type;
|
||||||
Buffer buffer;
|
|
||||||
bool byval;
|
bool byval;
|
||||||
int16 len;
|
int16 len;
|
||||||
|
|
||||||
|
@ -272,7 +271,6 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||||
*/
|
*/
|
||||||
heapTuple = slot->val;
|
heapTuple = slot->val;
|
||||||
tuple_type = slot->ttc_tupleDescriptor;
|
tuple_type = slot->ttc_tupleDescriptor;
|
||||||
buffer = slot->ttc_buffer;
|
|
||||||
|
|
||||||
attnum = variable->varattno;
|
attnum = variable->varattno;
|
||||||
|
|
||||||
|
@ -280,14 +278,14 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||||
Assert(attnum <= 0 ||
|
Assert(attnum <= 0 ||
|
||||||
(attnum - 1 <= tuple_type->natts - 1 &&
|
(attnum - 1 <= tuple_type->natts - 1 &&
|
||||||
tuple_type->attrs[attnum - 1] != NULL &&
|
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
|
* If the attribute number is invalid, then we are supposed to return
|
||||||
* the entire tuple, we give back a whole slot so that callers know
|
* the entire tuple, we give back a whole slot so that callers know
|
||||||
* what the tuple looks like.
|
* what the tuple looks like.
|
||||||
*/
|
*/
|
||||||
if (attnum == InvalidAttrNumber)
|
if (attnum == InvalidAttrNumber)
|
||||||
{
|
{
|
||||||
TupleTableSlot *tempSlot;
|
TupleTableSlot *tempSlot;
|
||||||
TupleDesc td;
|
TupleDesc td;
|
||||||
|
@ -301,7 +299,7 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||||
tempSlot->ttc_whichplan = -1;
|
tempSlot->ttc_whichplan = -1;
|
||||||
|
|
||||||
tup = heap_copytuple(heapTuple);
|
tup = heap_copytuple(heapTuple);
|
||||||
td = CreateTupleDescCopy(slot->ttc_tupleDescriptor);
|
td = CreateTupleDescCopy(tuple_type);
|
||||||
|
|
||||||
ExecSetSlotDescriptor(tempSlot, td);
|
ExecSetSlotDescriptor(tempSlot, td);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.48 1999/09/21 20:58:25 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.49 1999/09/26 21:21:15 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -540,22 +540,25 @@ float4div(float32 arg1, float32 arg2)
|
||||||
|
|
||||||
CheckFloat4Val(val);
|
CheckFloat4Val(val);
|
||||||
result = (float32) palloc(sizeof(float32data));
|
result = (float32) palloc(sizeof(float32data));
|
||||||
*result = *arg1 / *arg2;
|
*result = val;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
float32
|
float32
|
||||||
float4inc(float32 arg1)
|
float4inc(float32 arg1)
|
||||||
{
|
{
|
||||||
|
float32 result;
|
||||||
double val;
|
double val;
|
||||||
|
|
||||||
if (!arg1)
|
if (!arg1)
|
||||||
return (float32) NULL;
|
return (float32) NULL;
|
||||||
|
|
||||||
val = *arg1 + (float32data) 1.0;
|
val = *arg1 + (float32data) 1.0;
|
||||||
|
|
||||||
CheckFloat4Val(val);
|
CheckFloat4Val(val);
|
||||||
*arg1 = val;
|
result = (float32) palloc(sizeof(float32data));
|
||||||
return arg1;
|
*result = val;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -639,6 +642,7 @@ float8div(float64 arg1, float64 arg2)
|
||||||
float64
|
float64
|
||||||
float8inc(float64 arg1)
|
float8inc(float64 arg1)
|
||||||
{
|
{
|
||||||
|
float64 result;
|
||||||
double val;
|
double val;
|
||||||
|
|
||||||
if (!arg1)
|
if (!arg1)
|
||||||
|
@ -646,8 +650,9 @@ float8inc(float64 arg1)
|
||||||
|
|
||||||
val = *arg1 + (float64data) 1.0;
|
val = *arg1 + (float64data) 1.0;
|
||||||
CheckFloat8Val(val);
|
CheckFloat8Val(val);
|
||||||
*arg1 = val;
|
result = (float64) palloc(sizeof(float64data));
|
||||||
return arg1;
|
*result = val;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1388,7 +1393,7 @@ float48eq(float32 arg1, float64 arg2)
|
||||||
if (!arg1 || !arg2)
|
if (!arg1 || !arg2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return *arg1 == (float) *arg2;
|
return *arg1 == *arg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1397,7 +1402,7 @@ float48ne(float32 arg1, float64 arg2)
|
||||||
if (!arg1 || !arg2)
|
if (!arg1 || !arg2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return *arg1 != (float) *arg2;
|
return *arg1 != *arg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1406,7 +1411,7 @@ float48lt(float32 arg1, float64 arg2)
|
||||||
if (!arg1 || !arg2)
|
if (!arg1 || !arg2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return *arg1 < (float) *arg2;
|
return *arg1 < *arg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1415,7 +1420,7 @@ float48le(float32 arg1, float64 arg2)
|
||||||
if (!arg1 || !arg2)
|
if (!arg1 || !arg2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return *arg1 <= (float) *arg2;
|
return *arg1 <= *arg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1424,7 +1429,7 @@ float48gt(float32 arg1, float64 arg2)
|
||||||
if (!arg1 || !arg2)
|
if (!arg1 || !arg2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return *arg1 > (float) *arg2;
|
return *arg1 > *arg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1433,7 +1438,7 @@ float48ge(float32 arg1, float64 arg2)
|
||||||
if (!arg1 || !arg2)
|
if (!arg1 || !arg2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return *arg1 >= (float) *arg2;
|
return *arg1 >= *arg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1445,7 +1450,7 @@ float84eq(float64 arg1, float32 arg2)
|
||||||
if (!arg1 || !arg2)
|
if (!arg1 || !arg2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (float) *arg1 == *arg2;
|
return *arg1 == *arg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1454,7 +1459,7 @@ float84ne(float64 arg1, float32 arg2)
|
||||||
if (!arg1 || !arg2)
|
if (!arg1 || !arg2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (float) *arg1 != *arg2;
|
return *arg1 != *arg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1463,7 +1468,7 @@ float84lt(float64 arg1, float32 arg2)
|
||||||
if (!arg1 || !arg2)
|
if (!arg1 || !arg2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (float) *arg1 < *arg2;
|
return *arg1 < *arg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1472,7 +1477,7 @@ float84le(float64 arg1, float32 arg2)
|
||||||
if (!arg1 || !arg2)
|
if (!arg1 || !arg2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (float) *arg1 <= *arg2;
|
return *arg1 <= *arg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1481,7 +1486,7 @@ float84gt(float64 arg1, float32 arg2)
|
||||||
if (!arg1 || !arg2)
|
if (!arg1 || !arg2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (float) *arg1 > *arg2;
|
return *arg1 > *arg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1490,7 +1495,7 @@ float84ge(float64 arg1, float32 arg2)
|
||||||
if (!arg1 || !arg2)
|
if (!arg1 || !arg2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (float) *arg1 >= *arg2;
|
return *arg1 >= *arg2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========== PRIVATE ROUTINES ========== */
|
/* ========== PRIVATE ROUTINES ========== */
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 1994, Regents of the University of California
|
* Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: execnodes.h,v 1.35 1999/09/24 00:25:22 tgl Exp $
|
* $Id: execnodes.h,v 1.36 1999/09/26 21:21:04 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -88,8 +88,8 @@ typedef struct ExprContext
|
||||||
ParamListInfo ecxt_param_list_info;
|
ParamListInfo ecxt_param_list_info;
|
||||||
ParamExecData *ecxt_param_exec_vals; /* this is for subselects */
|
ParamExecData *ecxt_param_exec_vals; /* this is for subselects */
|
||||||
List *ecxt_range_table;
|
List *ecxt_range_table;
|
||||||
Datum *ecxt_values; /* precomputed values for aggreg */
|
Datum *ecxt_aggvalues; /* precomputed values for Aggref nodes */
|
||||||
char *ecxt_nulls; /* null flags for aggreg values */
|
bool *ecxt_aggnulls; /* null flags for Aggref nodes */
|
||||||
} ExprContext;
|
} ExprContext;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
|
@ -565,14 +565,20 @@ typedef struct MaterialState
|
||||||
/* ---------------------
|
/* ---------------------
|
||||||
* AggregateState information
|
* AggregateState information
|
||||||
*
|
*
|
||||||
* done indicated whether aggregate has been materialized
|
* Note: the associated ExprContext contains ecxt_aggvalues and ecxt_aggnulls
|
||||||
|
* arrays, which hold the computed agg values for the current input group
|
||||||
|
* during evaluation of an Agg node's output tuple(s).
|
||||||
* -------------------------
|
* -------------------------
|
||||||
*/
|
*/
|
||||||
|
typedef struct AggStatePerAggData *AggStatePerAgg; /* private in nodeAgg.c */
|
||||||
|
|
||||||
typedef struct AggState
|
typedef struct AggState
|
||||||
{
|
{
|
||||||
CommonScanState csstate; /* its first field is NodeTag */
|
CommonScanState csstate; /* its first field is NodeTag */
|
||||||
List *aggs; /* all Aggref nodes in targetlist & quals */
|
List *aggs; /* all Aggref nodes in targetlist & quals */
|
||||||
bool agg_done;
|
int numaggs; /* length of list (could be zero!) */
|
||||||
|
AggStatePerAgg peragg; /* per-Aggref working state */
|
||||||
|
bool agg_done; /* indicates completion of Agg scan */
|
||||||
} AggState;
|
} AggState;
|
||||||
|
|
||||||
/* ---------------------
|
/* ---------------------
|
||||||
|
|
Loading…
Reference in New Issue