Thanks for updating the patch.
>> It seems you allow to use IGNORE NULLS for all window functions. If
>> the case, you should explicitely stat that in the docs. Otherwise
>> users will be confused because;
>
> The latest version restricts it to lag, lead, first_value, last_value,
> and nth_value. We can extend it in a subsequent patch if there's
> demand?
The restriction is required by the SQL standard. So I don't think we
need to extend to other window functions.
>> I take a look at the patch and noticed that following functions have
>> no comments on what they are doing and what are the arguments. Please
>> look into other functions in nodeWindowAgg.c and add appropriate
>> comments to those functions.
>
> Latest version has more comments and should be in the standard coding style.
Still I see non standard coding stiles and indentations. See attached
patch for nodeWindowAgg.c, which is fixed by pgindent, for
example. (Other files may need fixing too).
>> I also notice that you have an array in memory which records non-null
>> row positions in a partition. The position is represented in int64,
>> which means 1 entry consumes 8 bytes. If my understanding is correct,
>> the array continues to grow up to the partition size. Also the array
>> is created for each window function (is it really necessary?). I worry
>> about this because it might consume excessive memory for big
>> partitions.
>
> It's an int64 because it stores the abs_pos/mark_pos which are int64.
> Keeping an array for each function is needed for the mark optimization
> to work correctly.
Ok.
Here are some comments regarding the patch:
(1) I noticed that ignorenulls_getfuncarginframe() does not take
account EXCLUSION frame options. The code path is in
WinGetFuncArgInFrame():
/*
* Account for exclusion option if one is active, but
advance only
* abs_pos not mark_pos. This prevents changes of the
current
* row's peer group from resulting in trying to fetch a
row before
* some previous mark position.
:
:
I guess ignorenulls_getfuncarginframe() was created by modifying
WinGetFuncArgInFrame() so I don't see the reason why
ignorenulls_getfuncarginframe() does not take account EXCLUSION frame
options.
(2) New member ignore_nulls are added to some structs. Its value is 0,
1 or -1. It's better to use a DEFINE for the value of ignore_nulls,
rather than 0, 1, or -1.
Best reagards,
--
Tatsuo Ishii
SRA OSS K.K.
English: http://www.sraoss.co.jp/index_en/
Japanese:http://www.sraoss.co.jp
diff --git a/src/backend/executor/nodeWindowAgg.c
b/src/backend/executor/nodeWindowAgg.c
index e1117857dc0..520e7e1bfcb 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -2624,7 +2624,10 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int
eflags)
elog(ERROR, "WindowFunc with winref %u assigned to
WindowAgg with winref %u",
wfunc->winref, node->winref);
- /* Look for a previous duplicate window function, which needs
the same ignore_nulls value */
+ /*
+ * Look for a previous duplicate window function, which needs
the same
+ * ignore_nulls value
+ */
for (i = 0; i <= wfuncno; i++)
{
if (equal(wfunc, perfunc[i].wfunc) &&
@@ -3379,8 +3382,8 @@ increment_nonnulls(WindowObject winobj, int64 pos)
winobj->nonnulls_size *= 2;
winobj->win_nonnulls =
repalloc_array(winobj->win_nonnulls,
- int64,
- winobj->nonnulls_size);
+ int64,
+ winobj->nonnulls_size);
}
winobj->win_nonnulls[winobj->nonnulls_len] = pos;
winobj->nonnulls_len++;
@@ -3394,7 +3397,8 @@ increment_nonnulls(WindowObject winobj, int64 pos)
static Datum
ignorenulls_getfuncarginpartition(WindowObject winobj, int argno,
int relpos,
int seektype, bool set_mark,
- bool *isnull,
bool *isout) {
+ bool *isnull,
bool *isout)
+{
WindowAggState *winstate;
ExprContext *econtext;
TupleTableSlot *slot;
@@ -3416,27 +3420,27 @@ ignorenulls_getfuncarginpartition(WindowObject winobj,
int argno,
switch (seektype)
{
- case WINDOW_SEEK_CURRENT:
- abs_pos = winstate->currentpos;
- break;
- case WINDOW_SEEK_HEAD:
- abs_pos = 0;
- break;
- case WINDOW_SEEK_TAIL:
- spool_tuples(winstate, -1);
- abs_pos = winstate->spooled_rows - 1;
- break;
- default:
- elog(ERROR, "unrecognized window seek type: %d", seektype);
- abs_pos = 0; /* keep compiler quiet */
- break;
+ case WINDOW_SEEK_CURRENT:
+ abs_pos = winstate->currentpos;
+ break;
+ case WINDOW_SEEK_HEAD:
+ abs_pos = 0;
+ break;
+ case WINDOW_SEEK_TAIL:
+ spool_tuples(winstate, -1);
+ abs_pos = winstate->spooled_rows - 1;
+ break;
+ default:
+ elog(ERROR, "unrecognized window seek type: %d",
seektype);
+ abs_pos = 0; /* keep compiler quiet */
+ break;
}
if (forward == -1)
goto check_partition;
/* if we're moving forward, store previous rows */
- for (i=0; i < winobj->nonnulls_len; ++i)
+ for (i = 0; i < winobj->nonnulls_len; ++i)
{
if (winobj->win_nonnulls[i] > abs_pos)
{
@@ -3448,7 +3452,7 @@ ignorenulls_getfuncarginpartition(WindowObject winobj,
int argno,
*isout = false;
window_gettupleslot(winobj, abs_pos, slot);
econtext->ecxt_outertuple = slot;
- return ExecEvalExpr((ExprState
*)list_nth(winobj->argstates, argno),
+ return ExecEvalExpr((ExprState *)
list_nth(winobj->argstates, argno),
econtext, isnull);
}
}
@@ -3465,13 +3469,13 @@ check_partition:
if (isout)
*isout = true;
*isnull = true;
- return (Datum)0;
+ return (Datum) 0;
}
if (isout)
*isout = false;
econtext->ecxt_outertuple = slot;
- datum = ExecEvalExpr((ExprState *)list_nth(winobj->argstates,
argno),
+ datum = ExecEvalExpr((ExprState *) list_nth(winobj->argstates,
argno),
econtext, isnull);
if (!*isnull)
@@ -3494,7 +3498,8 @@ check_partition:
static Datum
ignorenulls_getfuncarginframe(WindowObject winobj, int argno,
int relpos, int
seektype, bool set_mark,
- bool *isnull, bool
*isout) {
+ bool *isnull, bool
*isout)
+{
WindowAggState *winstate;
ExprContext *econtext;
TupleTableSlot *slot;
@@ -3511,7 +3516,7 @@ ignorenulls_getfuncarginframe(WindowObject winobj, int
argno,
winstate = winobj->winstate;
econtext = winstate->ss.ps.ps_ExprContext;
slot = winstate->temp_slot_1;
- datum = (Datum)0;
+ datum = (Datum) 0;
notnull_offset = 0;
notnull_relpos = abs(relpos);
@@ -3549,70 +3554,72 @@ ignorenulls_getfuncarginframe(WindowObject winobj, int
argno,
*/
for (i = 0; i < winobj->nonnulls_len; ++i)
{
- int inframe;
- if (winobj->win_nonnulls[i] < winobj->markpos)
- continue;
- if (!window_gettupleslot(winobj,
winobj->win_nonnulls[i], slot))
- continue;
+ int inframe;
- inframe = row_is_in_frame(winstate,
winobj->win_nonnulls[i], slot);
- if (inframe <= 0)
- {
- if (inframe == -1 && set_mark)
- WinSetMarkPosition(winobj,
winobj->win_nonnulls[i]);
- continue;
- }
+ if (winobj->win_nonnulls[i] < winobj->markpos)
+ continue;
+ if (!window_gettupleslot(winobj, winobj->win_nonnulls[i], slot))
+ continue;
- abs_pos = winobj->win_nonnulls[i] + 1;
- ++notnull_offset;
+ inframe = row_is_in_frame(winstate, winobj->win_nonnulls[i],
slot);
+ if (inframe <= 0)
+ {
+ if (inframe == -1 && set_mark)
+ WinSetMarkPosition(winobj,
winobj->win_nonnulls[i]);
+ continue;
+ }
- if (notnull_offset > notnull_relpos)
- {
- if (isout)
+ abs_pos = winobj->win_nonnulls[i] + 1;
+ ++notnull_offset;
+
+ if (notnull_offset > notnull_relpos)
+ {
+ if (isout)
*isout = false;
- econtext->ecxt_outertuple = slot;
- return ExecEvalExpr((ExprState
*)list_nth(winobj->argstates, argno),
-
econtext, isnull);
- }
+ econtext->ecxt_outertuple = slot;
+ return ExecEvalExpr((ExprState *)
list_nth(winobj->argstates, argno),
+ econtext,
isnull);
+ }
}
check_frame:
do
{
- int inframe;
- if (!window_gettupleslot(winobj, abs_pos, slot))
- goto out_of_frame;
+ int inframe;
- inframe = row_is_in_frame(winstate, abs_pos, slot);
- if (inframe == -1)
- goto out_of_frame;
- else if (inframe == 0)
- goto advance;
+ if (!window_gettupleslot(winobj, abs_pos, slot))
+ goto out_of_frame;
- gottuple = window_gettupleslot(winobj, abs_pos, slot);
+ inframe = row_is_in_frame(winstate, abs_pos, slot);
+ if (inframe == -1)
+ goto out_of_frame;
+ else if (inframe == 0)
+ goto advance;
- if (!gottuple)
- {
- if (isout)
- *isout = true;
- *isnull = true;
- return (Datum)0;
- }
+ gottuple = window_gettupleslot(winobj, abs_pos, slot);
+ if (!gottuple)
+ {
if (isout)
- *isout = false;
- econtext->ecxt_outertuple = slot;
- datum = ExecEvalExpr((ExprState
*)list_nth(winobj->argstates, argno),
- econtext,
isnull);
+ *isout = true;
+ *isnull = true;
+ return (Datum) 0;
+ }
- if (!*isnull)
- {
- ++notnull_offset;
- increment_nonnulls(winobj, abs_pos);
- }
+ if (isout)
+ *isout = false;
+ econtext->ecxt_outertuple = slot;
+ datum = ExecEvalExpr((ExprState *) list_nth(winobj->argstates,
argno),
+ econtext, isnull);
+
+ if (!*isnull)
+ {
+ ++notnull_offset;
+ increment_nonnulls(winobj, abs_pos);
+ }
advance:
- abs_pos += forward;
+ abs_pos += forward;
} while (notnull_offset <= notnull_relpos);
return datum;
@@ -3660,7 +3667,7 @@ WinGetFuncArgInPartition(WindowObject winobj, int argno,
if (winobj->ignore_nulls == 1 && relpos != 0)
return ignorenulls_getfuncarginpartition(winobj, argno, relpos,
seektype,
-
set_mark, isnull, isout);
+
set_mark, isnull, isout);
switch (seektype)
{
@@ -3752,7 +3759,7 @@ WinGetFuncArgInFrame(WindowObject winobj, int argno,
if (winobj->ignore_nulls == 1)
return ignorenulls_getfuncarginframe(winobj, argno, relpos,
seektype,
-
set_mark, isnull, isout);
+
set_mark, isnull, isout);
switch (seektype)
{