diff options
| -rw-r--r-- | src/backend/executor/nodeWindowAgg.c | 136 |
1 files changed, 98 insertions, 38 deletions
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index aa145d4e1a9..497eb25ea29 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -69,8 +69,10 @@ typedef struct WindowObjectData int readptr; /* tuplestore read pointer for this fn */ int64 markpos; /* row that markptr is positioned on */ int64 seekpos; /* row that readptr is positioned on */ - uint8 *notnull_info; /* not null info */ - int num_notnull_info; /* track size of the notnull_info array */ + uint8 **notnull_info; /* not null info for each func args */ + int64 *num_notnull_info; /* track size (number of tuples in + * partition) of the notnull_info array + * for each func args */ /* * Null treatment options. One of: NO_NULLTREATMENT, PARSER_IGNORE_NULLS, @@ -214,10 +216,14 @@ static Datum ignorenulls_getfuncarginframe(WindowObject winobj, int argno, static Datum gettuple_eval_partition(WindowObject winobj, int argno, int64 abs_pos, bool *isnull, bool *isout); -static void init_notnull_info(WindowObject winobj); -static void grow_notnull_info(WindowObject winobj, int64 pos); -static uint8 get_notnull_info(WindowObject winobj, int64 pos); -static void put_notnull_info(WindowObject winobj, int64 pos, bool isnull); +static void init_notnull_info(WindowObject winobj, + WindowStatePerFunc perfuncstate); +static void grow_notnull_info(WindowObject winobj, + int64 pos, int argno); +static uint8 get_notnull_info(WindowObject winobj, + int64 pos, int argno); +static void put_notnull_info(WindowObject winobj, + int64 pos, int argno, bool isnull); /* * Not null info bit array consists of 2-bit items @@ -1303,10 +1309,20 @@ begin_partition(WindowAggState *winstate) winobj->seekpos = -1; /* reset null map */ - if (winobj->ignore_nulls == IGNORE_NULLS) - memset(winobj->notnull_info, 0, - NN_POS_TO_BYTES( - perfuncstate->winobj->num_notnull_info)); + if (winobj->ignore_nulls == IGNORE_NULLS || + winobj->ignore_nulls == PARSER_IGNORE_NULLS) + { + int numargs = perfuncstate->numArguments; + + for (int j = 0; j < numargs; j++) + { + int n = winobj->num_notnull_info[j]; + + if (n > 0) + memset(winobj->notnull_info[j], 0, + NN_POS_TO_BYTES(n)); + } + } } } @@ -2734,7 +2750,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags) winobj->localmem = NULL; perfuncstate->winobj = winobj; winobj->ignore_nulls = wfunc->ignore_nulls; - init_notnull_info(winobj); + init_notnull_info(winobj, perfuncstate); /* It's a real window function, so set up to call it. */ fmgr_info_cxt(wfunc->winfnoid, &perfuncstate->flinfo, @@ -3387,7 +3403,7 @@ ignorenulls_getfuncarginframe(WindowObject winobj, int argno, if (isout) *isout = false; - v = get_notnull_info(winobj, abs_pos); + v = get_notnull_info(winobj, abs_pos, argno); if (v == NN_NULL) /* this row is known to be NULL */ goto advance; @@ -3405,7 +3421,7 @@ ignorenulls_getfuncarginframe(WindowObject winobj, int argno, notnull_offset++; /* record the row status */ - put_notnull_info(winobj, abs_pos, *isnull); + put_notnull_info(winobj, abs_pos, argno, *isnull); } else /* this row is known to be NOT NULL */ { @@ -3445,17 +3461,14 @@ out_of_frame: * Initialize non null map. */ static void -init_notnull_info(WindowObject winobj) +init_notnull_info(WindowObject winobj, WindowStatePerFunc perfuncstate) { -/* initial number of notnull info members */ -#define INIT_NOT_NULL_INFO_NUM 128 + int numargs = perfuncstate->numArguments; if (winobj->ignore_nulls == PARSER_IGNORE_NULLS) { - Size size = NN_POS_TO_BYTES(INIT_NOT_NULL_INFO_NUM); - - winobj->notnull_info = palloc0(size); - winobj->num_notnull_info = INIT_NOT_NULL_INFO_NUM; + winobj->notnull_info = palloc0(sizeof(uint8 *) * numargs); + winobj->num_notnull_info = palloc0(sizeof(int64) * numargs); } } @@ -3463,23 +3476,43 @@ init_notnull_info(WindowObject winobj) * grow_notnull_info * expand notnull_info if necessary. * pos: not null info position + * argno: argument number */ static void -grow_notnull_info(WindowObject winobj, int64 pos) +grow_notnull_info(WindowObject winobj, int64 pos, int argno) { - if (pos >= winobj->num_notnull_info) +/* initial number of notnull info members */ +#define INIT_NOT_NULL_INFO_NUM 128 + + if (pos >= winobj->num_notnull_info[argno]) { + /* We may be called in a short-lived context */ + MemoryContext oldcontext = MemoryContextSwitchTo + (winobj->winstate->ss.ps.ps_ExprContext->ecxt_per_query_memory); + for (;;) { - Size oldsize = NN_POS_TO_BYTES(winobj->num_notnull_info); - Size newsize = oldsize * 2; + Size oldsize = NN_POS_TO_BYTES + (winobj->num_notnull_info[argno]); + Size newsize; - winobj->notnull_info = - repalloc0(winobj->notnull_info, oldsize, newsize); - winobj->num_notnull_info = NN_BYTES_TO_POS(newsize); - if (winobj->num_notnull_info > pos) + if (oldsize == 0) /* memory has not been allocated yet for this + * arg */ + { + newsize = NN_POS_TO_BYTES(INIT_NOT_NULL_INFO_NUM); + winobj->notnull_info[argno] = palloc0(newsize); + } + else + { + newsize = oldsize * 2; + winobj->notnull_info[argno] = + repalloc0(winobj->notnull_info[argno], oldsize, newsize); + } + winobj->num_notnull_info[argno] = NN_BYTES_TO_POS(newsize); + if (winobj->num_notnull_info[argno] > pos) break; } + MemoryContextSwitchTo(oldcontext); } } @@ -3487,16 +3520,19 @@ grow_notnull_info(WindowObject winobj, int64 pos) * get_notnull_info * retrieve a map * pos: map position + * argno: argument number */ static uint8 -get_notnull_info(WindowObject winobj, int64 pos) +get_notnull_info(WindowObject winobj, int64 pos, int argno) { + uint8 *mbp; uint8 mb; int64 bpos; - grow_notnull_info(winobj, pos); + grow_notnull_info(winobj, pos, argno); bpos = NN_POS_TO_BYTES(pos); - mb = winobj->notnull_info[bpos]; + mbp = winobj->notnull_info[argno]; + mb = mbp[bpos]; return (mb >> (NN_SHIFT(pos))) & NN_MASK; } @@ -3504,22 +3540,26 @@ get_notnull_info(WindowObject winobj, int64 pos) * put_notnull_info * update map * pos: map position + * argno: argument number + * isnull: indicate NULL or NOT */ static void -put_notnull_info(WindowObject winobj, int64 pos, bool isnull) +put_notnull_info(WindowObject winobj, int64 pos, int argno, bool isnull) { + uint8 *mbp; uint8 mb; int64 bpos; uint8 val = isnull ? NN_NULL : NN_NOTNULL; int shift; - grow_notnull_info(winobj, pos); + grow_notnull_info(winobj, pos, argno); bpos = NN_POS_TO_BYTES(pos); - mb = winobj->notnull_info[bpos]; + mbp = winobj->notnull_info[argno]; + mb = mbp[bpos]; shift = NN_SHIFT(pos); mb &= ~(NN_MASK << shift); /* clear map */ mb |= (val << shift); /* update map */ - winobj->notnull_info[bpos] = mb; + mbp[bpos] = mb; } /*********************************************************************** @@ -3714,6 +3754,7 @@ WinGetFuncArgInPartition(WindowObject winobj, int argno, { WindowAggState *winstate; int64 abs_pos; + int64 mark_pos; Datum datum; bool null_treatment; int notnull_offset; @@ -3771,6 +3812,25 @@ WinGetFuncArgInPartition(WindowObject winobj, int argno, datum = 0; /* + * IGNORE NULLS + WINDOW_SEEK_CURRENT + relpos > 0 case, we would fetch + * beyond the current row + relpos to find out the target row. If we mark + * at abs_pos, next call to WinGetFuncArgInPartition or + * WinGetFuncArgInFrame (in case when a window function have multiple + * args) could fail with "cannot fetch row before WindowObject's mark + * position". So keep the mark position at currentpos. + */ + if (seektype == WINDOW_SEEK_CURRENT && relpos > 0) + mark_pos = winstate->currentpos; + else + + /* + * For other cases we have no idea what position of row callers would + * fetch next time. Also for relpos < 0 case (we go backward), we + * cannot set mark either. For those cases we always set mark at 0. + */ + mark_pos = 0; + + /* * Get the next nonnull value in the partition, moving forward or backward * until we find a value or reach the partition's end. We cache the * nullness status because we may repeat this process many times. @@ -3784,7 +3844,7 @@ WinGetFuncArgInPartition(WindowObject winobj, int argno, break; /* check NOT NULL cached info */ - nn_info = get_notnull_info(winobj, abs_pos); + nn_info = get_notnull_info(winobj, abs_pos, argno); if (nn_info == NN_NOTNULL) /* this row is known to be NOT NULL */ notnull_offset++; else if (nn_info == NN_NULL) /* this row is known to be NULL */ @@ -3805,7 +3865,7 @@ WinGetFuncArgInPartition(WindowObject winobj, int argno, if (!*isnull) notnull_offset++; /* record the row status */ - put_notnull_info(winobj, abs_pos, *isnull); + put_notnull_info(winobj, abs_pos, argno, *isnull); } } while (notnull_offset < notnull_relpos); @@ -3813,7 +3873,7 @@ WinGetFuncArgInPartition(WindowObject winobj, int argno, datum = gettuple_eval_partition(winobj, argno, abs_pos, isnull, &myisout); if (!myisout && set_mark) - WinSetMarkPosition(winobj, abs_pos); + WinSetMarkPosition(winobj, mark_pos); if (isout) *isout = myisout; |
