Attaching updated patch with a fix for an issue in window function.
I have also fixed naming convention of patch as last patch had incompatible name.
Note: 1. Pending: Investigation of test cases failures. Regards, Ankit
diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c index 4fcfd6df72..94ddccd23a 100644 --- a/contrib/amcheck/verify_heapam.c +++ b/contrib/amcheck/verify_heapam.c @@ -1574,14 +1574,40 @@ check_tuple(HeapCheckContext *ctx) static FullTransactionId FullTransactionIdFromXidAndCtx(TransactionId xid, const HeapCheckContext *ctx) { - uint32 epoch; + uint64 nextfxid_i; + int32 diff; + FullTransactionId fxid; + + Assert(TransactionIdIsNormal(ctx->next_xid)); + Assert(FullTransactionIdIsNormal(ctx->next_fxid)); + Assert(XidFromFullTransactionId(ctx->next_fxid) == ctx->next_xid); if (!TransactionIdIsNormal(xid)) return FullTransactionIdFromEpochAndXid(0, xid); - epoch = EpochFromFullTransactionId(ctx->next_fxid); - if (xid > ctx->next_xid) - epoch--; - return FullTransactionIdFromEpochAndXid(epoch, xid); + + nextfxid_i = U64FromFullTransactionId(ctx->next_fxid); + + /* compute the 32bit modulo difference */ + diff = (int32) (ctx->next_xid - xid); + + /* + * In cases of corruption we might see a 32bit xid that is before epoch + * 0. We can't represent that as a 64bit xid, due to 64bit xids being + * unsigned integers, without the modulo arithmetic of 32bit xid. There's + * no really nice way to deal with that, but it works ok enough to use + * FirstNormalFullTransactionId in that case, as a freshly initdb'd + * cluster already has a newer horizon. + */ + if (diff > 0 && (nextfxid_i - FirstNormalTransactionId) < (int64) diff) + { + Assert(EpochFromFullTransactionId(ctx->next_fxid) == 0); + fxid = FirstNormalFullTransactionId; + } + else + fxid = FullTransactionIdFromU64(nextfxid_i - diff); + + Assert(FullTransactionIdIsNormal(fxid)); + return fxid; } /* @@ -1597,8 +1623,8 @@ update_cached_xid_range(HeapCheckContext *ctx) LWLockRelease(XidGenLock); /* And compute alternate versions of the same */ - ctx->oldest_fxid = FullTransactionIdFromXidAndCtx(ctx->oldest_xid, ctx); ctx->next_xid = XidFromFullTransactionId(ctx->next_fxid); + ctx->oldest_fxid = FullTransactionIdFromXidAndCtx(ctx->oldest_xid, ctx); } /* diff --git a/contrib/pg_trgm/expected/pg_word_trgm.out b/contrib/pg_trgm/expected/pg_word_trgm.out index 936d489390..c66a67f30e 100644 --- a/contrib/pg_trgm/expected/pg_word_trgm.out +++ b/contrib/pg_trgm/expected/pg_word_trgm.out @@ -1044,3 +1044,9 @@ select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kaban Waikala | 0.3 (89 rows) +-- test unsatisfiable pattern +select * from test_trgm2 where t ~ '.*$x'; + t +--- +(0 rows) + diff --git a/contrib/pg_trgm/sql/pg_word_trgm.sql b/contrib/pg_trgm/sql/pg_word_trgm.sql index d9fa1c55e5..d2ada49133 100644 --- a/contrib/pg_trgm/sql/pg_word_trgm.sql +++ b/contrib/pg_trgm/sql/pg_word_trgm.sql @@ -43,3 +43,6 @@ select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t select t,word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <% t order by sml desc, t; select t,word_similarity('Baykal',t) as sml from test_trgm2 where t %> 'Baykal' order by sml desc, t; select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kabankala' order by sml desc, t; + +-- test unsatisfiable pattern +select * from test_trgm2 where t ~ '.*$x'; diff --git a/contrib/pg_trgm/trgm_regexp.c b/contrib/pg_trgm/trgm_regexp.c index 9a00564ae4..06cd3db67b 100644 --- a/contrib/pg_trgm/trgm_regexp.c +++ b/contrib/pg_trgm/trgm_regexp.c @@ -1947,9 +1947,7 @@ packGraph(TrgmNFA *trgmNFA, MemoryContext rcontext) arcsCount; HASH_SEQ_STATUS scan_status; TrgmState *state; - TrgmPackArcInfo *arcs, - *p1, - *p2; + TrgmPackArcInfo *arcs; TrgmPackedArc *packedArcs; TrgmPackedGraph *result; int i, @@ -2021,17 +2019,25 @@ packGraph(TrgmNFA *trgmNFA, MemoryContext rcontext) qsort(arcs, arcIndex, sizeof(TrgmPackArcInfo), packArcInfoCmp); /* We could have duplicates because states were merged. Remove them. */ - /* p1 is probe point, p2 is last known non-duplicate. */ - p2 = arcs; - for (p1 = arcs + 1; p1 < arcs + arcIndex; p1++) + if (arcIndex > 1) { - if (packArcInfoCmp(p1, p2) > 0) + /* p1 is probe point, p2 is last known non-duplicate. */ + TrgmPackArcInfo *p1, + *p2; + + p2 = arcs; + for (p1 = arcs + 1; p1 < arcs + arcIndex; p1++) { - p2++; - *p2 = *p1; + if (packArcInfoCmp(p1, p2) > 0) + { + p2++; + *p2 = *p1; + } } + arcsCount = (p2 - arcs) + 1; } - arcsCount = (p2 - arcs) + 1; + else + arcsCount = arcIndex; /* Create packed representation */ result = (TrgmPackedGraph *) diff --git a/meson.build b/meson.build index 2409cc2254..d4384f1bf6 100644 --- a/meson.build +++ b/meson.build @@ -1268,7 +1268,7 @@ if uuidopt != 'none' elif uuidopt == 'ossp' uuid = dependency('ossp-uuid', required: true) uuidfunc = 'uuid_export' - uuidheader = 'ossp/uuid.h' + uuidheader = 'uuid.h' else error('huh') endif diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index c695aa7525..7c07fb0684 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -155,13 +155,6 @@ typedef struct WindowStatePerAggData int64 transValueCount; /* number of currently-aggregated rows */ - Datum lastdatum; /* used for single-column DISTINCT */ - FmgrInfo equalfnOne; /* single-column comparisons*/ - Oid *eq_ops; - Oid *sort_ops; - - bool sort_in; - /* Data local to eval_windowaggregates() */ bool restart; /* need to restart this agg in this cycle? */ } WindowStatePerAggData; @@ -171,7 +164,7 @@ static void initialize_windowaggregate(WindowAggState *winstate, WindowStatePerAgg peraggstate); static void advance_windowaggregate(WindowAggState *winstate, WindowStatePerFunc perfuncstate, - WindowStatePerAgg peraggstate, Datum value, bool isNull); + WindowStatePerAgg peraggstate); static bool advance_windowaggregate_base(WindowAggState *winstate, WindowStatePerFunc perfuncstate, WindowStatePerAgg peraggstate); @@ -181,9 +174,6 @@ static void finalize_windowaggregate(WindowAggState *winstate, Datum *result, bool *isnull); static void eval_windowaggregates(WindowAggState *winstate); -static void process_ordered_aggregate_single(WindowAggState *winstate, - WindowStatePerFunc perfuncstate, - WindowStatePerAgg peraggstate); static void eval_windowfunction(WindowAggState *winstate, WindowStatePerFunc perfuncstate, Datum *result, bool *isnull); @@ -241,7 +231,6 @@ initialize_windowaggregate(WindowAggState *winstate, peraggstate->transValueIsNull = peraggstate->initValueIsNull; peraggstate->transValueCount = 0; peraggstate->resultValue = (Datum) 0; - peraggstate->lastdatum = (Datum) 0; peraggstate->resultValueIsNull = true; } @@ -252,21 +241,43 @@ initialize_windowaggregate(WindowAggState *winstate, static void advance_windowaggregate(WindowAggState *winstate, WindowStatePerFunc perfuncstate, - WindowStatePerAgg peraggstate, Datum value, bool isNull) + WindowStatePerAgg peraggstate) { LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); + WindowFuncExprState *wfuncstate = perfuncstate->wfuncstate; int numArguments = perfuncstate->numArguments; Datum newVal; + ListCell *arg; int i; MemoryContext oldContext; ExprContext *econtext = winstate->tmpcontext; + ExprState *filter = wfuncstate->aggfilter; oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); + /* Skip anything FILTERed out */ + if (filter) + { + bool isnull; + Datum res = ExecEvalExpr(filter, econtext, &isnull); + + if (isnull || !DatumGetBool(res)) + { + MemoryContextSwitchTo(oldContext); + return; + } + } + /* We start from 1, since the 0th arg will be the transition value */ + i = 1; + foreach(arg, wfuncstate->args) + { + ExprState *argstate = (ExprState *) lfirst(arg); - fcinfo->args[1].value = value; - fcinfo->args[1].isnull = isNull; + fcinfo->args[i].value = ExecEvalExpr(argstate, econtext, + &fcinfo->args[i].isnull); + i++; + } if (peraggstate->transfn.fn_strict) { @@ -575,10 +586,6 @@ finalize_windowaggregate(WindowAggState *winstate, oldContext = MemoryContextSwitchTo(winstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory); - /* Run transition function for distinct agg */ - if (perfuncstate->wfunc->aggdistinct) - process_ordered_aggregate_single(winstate, perfuncstate, peraggstate); - /* * Apply the agg's finalfn if one is provided, else return transValue. */ @@ -660,16 +667,6 @@ eval_windowaggregates(WindowAggState *winstate) TupleTableSlot *agg_row_slot; TupleTableSlot *temp_slot; - ExprState *filter; - bool isnull; - WindowFuncExprState *wfuncstate; - ListCell *arg; - Datum tuple; - ExprContext *aggecontext; - ListCell *lc; - Oid inputTypes[FUNC_MAX_ARGS]; - WindowStatePerFunc perfuncstate; - numaggs = winstate->numaggs; if (numaggs == 0) return; /* nothing to do */ @@ -897,22 +894,6 @@ eval_windowaggregates(WindowAggState *winstate) } } - perfuncstate = &winstate->perfunc[wfuncno]; - if (perfuncstate->wfunc->aggdistinct) - { - i = 0; - foreach(lc, perfuncstate->wfunc->args) - { - inputTypes[i++] = exprType((Node *) lfirst(lc)); - } - winstate->sortstates = - tuplesort_begin_datum(inputTypes[0], - peraggstate->sort_ops[0], - perfuncstate->wfunc->inputcollid, - true, - work_mem, NULL, TUPLESORT_NONE); - } - /* * Non-restarted aggregates now contain the rows between aggregatedbase * (i.e., frameheadpos) and aggregatedupto, while restarted aggregates @@ -947,8 +928,7 @@ eval_windowaggregates(WindowAggState *winstate) { if (!window_gettupleslot(agg_winobj, winstate->aggregatedupto, agg_row_slot)) - break; /* must be end of partition */ - + break; /* must be end of partition */ } /* @@ -956,16 +936,14 @@ eval_windowaggregates(WindowAggState *winstate) * current row is not in frame but there might be more in the frame. */ ret = row_is_in_frame(winstate, winstate->aggregatedupto, agg_row_slot); - if (ret < 0) break; - if (ret == 0) goto next_tuple; /* Set tuple context for evaluation of aggregate arguments */ winstate->tmpcontext->ecxt_outertuple = agg_row_slot; - + /* Accumulate row into the aggregates */ for (i = 0; i < numaggs; i++) { @@ -977,52 +955,9 @@ eval_windowaggregates(WindowAggState *winstate) continue; wfuncno = peraggstate->wfuncno; - perfuncstate = &winstate->perfunc[wfuncno]; - - aggecontext = winstate->tmpcontext; - - wfuncstate = perfuncstate->wfuncstate; - filter = wfuncstate->aggfilter; - - oldContext = MemoryContextSwitchTo(aggecontext->ecxt_per_tuple_memory); - /* Skip anything FILTERed out for aggregates */ - if (perfuncstate->plain_agg && wfuncstate->aggfilter) - { - Datum res = ExecEvalExpr(filter, aggecontext, &isnull); - - if (isnull || !DatumGetBool(res)) - { - MemoryContextSwitchTo(oldContext); - continue; - } - } - - - foreach(arg, wfuncstate->args) - { - - ExprState *argstate = (ExprState *) lfirst(arg); - tuple = ExecEvalExpr(argstate, aggecontext, &isnull); - - if (perfuncstate->wfunc->aggdistinct) - { - tuplesort_putdatum(winstate->sortstates, tuple, isnull); - peraggstate->sort_in = true; - } - else - { - advance_windowaggregate(winstate, &winstate->perfunc[wfuncno], - peraggstate, tuple, isnull); - } - - } - // Eg case of count(*), How can we this in better way? - if (wfuncstate->args == NIL) - { - advance_windowaggregate(winstate, &winstate->perfunc[wfuncno], - peraggstate, tuple, isnull); - } - MemoryContextSwitchTo(oldContext); + advance_windowaggregate(winstate, + &winstate->perfunc[wfuncno], + peraggstate); } next_tuple: @@ -1078,67 +1013,6 @@ next_tuple: } } - -static void -process_ordered_aggregate_single(WindowAggState *winstate, WindowStatePerFunc perfuncstate, - WindowStatePerAgg peraggstate) -{ - Datum newVal; - bool isNull; - MemoryContext workcontext = winstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory; - MemoryContext oldContext; - Datum oldVal = (Datum) 0; - bool oldIsNull = true; - bool haveOldVal = false; - - if (peraggstate->sort_in){ - tuplesort_performsort(winstate->sortstates); - - - while (tuplesort_getdatum(winstate->sortstates, - true, false, &newVal, &isNull, NULL)) - { - MemoryContextReset(workcontext); - oldContext = MemoryContextSwitchTo(workcontext); - - if (haveOldVal && DatumGetBool(FunctionCall2Coll(&peraggstate->equalfnOne, - perfuncstate->winCollation, - oldVal, newVal))) - { - MemoryContextSwitchTo(oldContext); - continue; - } - else - { - - advance_windowaggregate(winstate, perfuncstate, - peraggstate, newVal, isNull); - } - MemoryContextSwitchTo(oldContext); - - if (!peraggstate->resulttypeByVal) - { - if (!oldIsNull && false) - pfree(DatumGetPointer(oldVal)); - if (!isNull) - oldVal = datumCopy(newVal, true, - peraggstate->resulttypeLen); - } - else - oldVal = newVal; - - oldIsNull = isNull; - haveOldVal = true; - oldVal = newVal; - } - - } - tuplesort_end(winstate->sortstates); - peraggstate->sort_in = false; - -} - - /* * eval_windowfunction * @@ -3082,9 +2956,6 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, get_typlenbyval(aggtranstype, &peraggstate->transtypeLen, &peraggstate->transtypeByVal); - get_typlenbyval(wfunc->wintype, - &peraggstate->inputtypeLen, - &peraggstate->inputtypeByVal); /* * initval is potentially null, so don't try to access it as a struct @@ -3152,32 +3023,6 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc, else peraggstate->aggcontext = winstate->aggcontext; - /* Handle distinct operation in agg */ - if (wfunc->aggdistinct) - { - int numDistinctCols = list_length(wfunc->distinctargs); - peraggstate->eq_ops = palloc(numDistinctCols * sizeof(Oid)); - peraggstate->sort_ops = palloc(numDistinctCols * sizeof(Oid)); - winstate->sortstates = (Tuplesortstate *) - palloc0(sizeof(Tuplesortstate *) * 1); - - /* Initialize tuplesort to handle distinct operation */ - - i=0; - foreach(lc, wfunc->distinctargs) - { - peraggstate->eq_ops[i] = ((SortGroupClause *) lfirst(lc))->eqop; - peraggstate->sort_ops[i] = ((SortGroupClause *) lfirst(lc))->sortop; - i++; - } - fmgr_info(get_opcode(peraggstate->eq_ops[0]), &peraggstate->equalfnOne); - winstate->sortstates = tuplesort_begin_datum(inputTypes[0], - peraggstate->sort_ops[0], - wfunc->inputcollid, - true, - work_mem, NULL, TUPLESORT_NONE); - } - ReleaseSysCache(aggTuple); return peraggstate; diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 4a755d0604..76e25118f9 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -2445,8 +2445,6 @@ eval_const_expressions_mutator(Node *node, newexpr->winref = expr->winref; newexpr->winstar = expr->winstar; newexpr->winagg = expr->winagg; - newexpr->aggdistinct = expr->aggdistinct; - newexpr->distinctargs = expr->distinctargs; newexpr->location = expr->location; return (Node *) newexpr; diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index fb0262676b..4fbf80c271 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -1048,50 +1048,6 @@ transformWindowFuncCall(ParseState *pstate, WindowFunc *wfunc, } } - if (wfunc->aggdistinct){ - List *tlist = NIL; - List *torder = NIL; - List *tdistinct = NIL; - AttrNumber attno = 1; - ListCell *lc; - - foreach(lc, wfunc->args) - { - Expr *arg = (Expr *) lfirst(lc); - TargetEntry *tle; - - /* We don't bother to assign column names to the entries */ - tle = makeTargetEntry(arg, attno++, NULL, false); - tlist = lappend(tlist, tle); - } - torder = transformSortClause(pstate, - NIL, - &tlist, - EXPR_KIND_ORDER_BY, - true /* force SQL99 rules */ ); - - tdistinct = transformDistinctClause(pstate, &tlist, torder, true); - - foreach(lc, tdistinct) - { - SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc); - - if (!OidIsValid(sortcl->sortop)) - { - Node *expr = get_sortgroupclause_expr(sortcl, tlist); - - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("could not identify an ordering operator for type %s", - format_type_be(exprType(expr))), - errdetail("Aggregates with DISTINCT must be able to sort their inputs."), - parser_errposition(pstate, exprLocation(expr)))); - } - } - wfunc->distinctargs = tdistinct; - } - - pstate->p_hasWindowFuncs = true; } diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 89a443eac5..ca14f06308 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -835,7 +835,15 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, wfunc->winagg = (fdresult == FUNCDETAIL_AGGREGATE); wfunc->aggfilter = agg_filter; wfunc->location = location; - wfunc->aggdistinct = agg_distinct; + + /* + * agg_star is allowed for aggregate functions but distinct isn't + */ + if (agg_distinct) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("DISTINCT is not implemented for window functions"), + parser_errposition(pstate, location))); /* * Reject attempt to call a parameterless aggregate without (*) @@ -848,16 +856,6 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, NameListToString(funcname)), parser_errposition(pstate, location))); - /* - * Distinct is not implemented for aggregates with filter - */ - - if (agg_distinct && agg_filter) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("DISTINCT is not implemented for aggregate functions with FILTER"), - parser_errposition(pstate, location))); - /* * ordered aggs not allowed in windows yet */ diff --git a/src/bin/pg_amcheck/t/004_verify_heapam.pl b/src/bin/pg_amcheck/t/004_verify_heapam.pl index 215c30eaa8..e5ae7e6aad 100644 --- a/src/bin/pg_amcheck/t/004_verify_heapam.pl +++ b/src/bin/pg_amcheck/t/004_verify_heapam.pl @@ -217,17 +217,17 @@ my $rel = $node->safe_psql('postgres', my $relpath = "$pgdata/$rel"; # Insert data and freeze public.test -use constant ROWCOUNT => 16; +my $ROWCOUNT = 17; $node->safe_psql( 'postgres', qq( INSERT INTO public.test (a, b, c) - VALUES ( + SELECT x'DEADF9F9DEADF9F9'::bigint, 'abcdefg', repeat('w', 10000) - ); - VACUUM FREEZE public.test - )) for (1 .. ROWCOUNT); + FROM generate_series(1, $ROWCOUNT); + VACUUM FREEZE public.test;) +); my $relfrozenxid = $node->safe_psql('postgres', q(select relfrozenxid from pg_class where relname = 'test')); @@ -246,16 +246,13 @@ if ($datfrozenxid <= 3 || $datfrozenxid >= $relfrozenxid) } # Find where each of the tuples is located on the page. -my @lp_off; -for my $tup (0 .. ROWCOUNT - 1) -{ - push( - @lp_off, - $node->safe_psql( - 'postgres', qq( -select lp_off from heap_page_items(get_raw_page('test', 'main', 0)) - offset $tup limit 1))); -} +my @lp_off = split '\n', $node->safe_psql( + 'postgres', qq( + select lp_off from heap_page_items(get_raw_page('test', 'main', 0)) + where lp <= $ROWCOUNT + ) +); +is(scalar @lp_off, $ROWCOUNT, "acquired row offsets"); # Sanity check that our 'test' table on disk layout matches expectations. If # this is not so, we will have to skip the test until somebody updates the test @@ -267,7 +264,7 @@ open($file, '+<', $relpath) binmode $file; my $ENDIANNESS; -for (my $tupidx = 0; $tupidx < ROWCOUNT; $tupidx++) +for (my $tupidx = 0; $tupidx < $ROWCOUNT; $tupidx++) { my $offnum = $tupidx + 1; # offnum is 1-based, not zero-based my $offset = $lp_off[$tupidx]; @@ -345,7 +342,7 @@ open($file, '+<', $relpath) or BAIL_OUT("open failed: $!"); binmode $file; -for (my $tupidx = 0; $tupidx < ROWCOUNT; $tupidx++) +for (my $tupidx = 0; $tupidx < $ROWCOUNT; $tupidx++) { my $offnum = $tupidx + 1; # offnum is 1-based, not zero-based my $offset = $lp_off[$tupidx]; @@ -378,23 +375,24 @@ for (my $tupidx = 0; $tupidx < ROWCOUNT; $tupidx++) elsif ($offnum == 3) { # Corruptly set xmin < datfrozenxid, further back, noting circularity - # of xid comparison. For a new cluster with epoch = 0, the corrupt - # xmin will be interpreted as in the future - $tup->{t_xmin} = 4026531839; + # of xid comparison. + my $xmin = 4026531839; + $tup->{t_xmin} = $xmin; $tup->{t_infomask} &= ~HEAP_XMIN_COMMITTED; $tup->{t_infomask} &= ~HEAP_XMIN_INVALID; push @expected, - qr/${$header}xmin 4026531839 equals or exceeds next valid transaction ID 0:\d+/; + qr/${$header}xmin ${xmin} precedes oldest valid transaction ID 0:\d+/; } elsif ($offnum == 4) { # Corruptly set xmax < relminmxid; - $tup->{t_xmax} = 4026531839; + my $xmax = 4026531839; + $tup->{t_xmax} = $xmax; $tup->{t_infomask} &= ~HEAP_XMAX_INVALID; push @expected, - qr/${$header}xmax 4026531839 equals or exceeds next valid transaction ID 0:\d+/; + qr/${$header}xmax ${xmax} precedes oldest valid transaction ID 0:\d+/; } elsif ($offnum == 5) { @@ -502,7 +500,7 @@ for (my $tupidx = 0; $tupidx < ROWCOUNT; $tupidx++) push @expected, qr/${header}multitransaction ID 4 equals or exceeds next valid multitransaction ID 1/; } - elsif ($offnum == 15) # Last offnum must equal ROWCOUNT + elsif ($offnum == 15) { # Set both HEAP_XMAX_COMMITTED and HEAP_XMAX_IS_MULTI $tup->{t_infomask} |= HEAP_XMAX_COMMITTED; @@ -512,6 +510,17 @@ for (my $tupidx = 0; $tupidx < ROWCOUNT; $tupidx++) push @expected, qr/${header}multitransaction ID 4000000000 precedes relation minimum multitransaction ID threshold 1/; } + elsif ($offnum == 16) # Last offnum must equal ROWCOUNT + { + # Corruptly set xmin > next_xid to be in the future. + my $xmin = 123456; + $tup->{t_xmin} = $xmin; + $tup->{t_infomask} &= ~HEAP_XMIN_COMMITTED; + $tup->{t_infomask} &= ~HEAP_XMIN_INVALID; + + push @expected, + qr/${$header}xmin ${xmin} equals or exceeds next valid transaction ID 0:\d+/; + } write_tuple($file, $offset, $tup); } close($file) diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 4301db31d8..bc67cb9ed8 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -2529,7 +2529,6 @@ typedef struct WindowAggState * date for current row */ bool grouptail_valid; /* true if grouptailpos is known up to * date for current row */ - Tuplesortstate *sortstates; TupleTableSlot *first_part_slot; /* first tuple of current or next * partition */ diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index f5dd8f2d07..4220c63ab7 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -558,8 +558,6 @@ typedef struct WindowFunc /* true if argument list was really '*' */ bool winstar pg_node_attr(query_jumble_ignore); /* is function a simple aggregate? */ - bool aggdistinct; /* do we need distinct values for aggregation? */ - List *distinctargs; bool winagg pg_node_attr(query_jumble_ignore); /* token location, or -1 if unknown */ int location; diff --git a/src/test/regress/expected/window.out b/src/test/regress/expected/window.out index 04247ce4a3..747608e3c1 100644 --- a/src/test/regress/expected/window.out +++ b/src/test/regress/expected/window.out @@ -1775,22 +1775,6 @@ select first_value(salary) over(order by enroll_date range between unbounded pre 5000 | 4500 | 4200 | 01-01-2008 (10 rows) --- with DISTINCT in agg functionn -select depname, count(DISTINCT enroll_date) over (PARTITION BY depname) FROM empsalary; - depname | count ------------+------- - develop | 4 - develop | 4 - develop | 4 - develop | 4 - develop | 4 - personnel | 2 - personnel | 2 - sales | 3 - sales | 3 - sales | 3 -(10 rows) - -- RANGE offset PRECEDING/FOLLOWING with null values select x, y, first_value(y) over w, diff --git a/src/test/regress/sql/window.sql b/src/test/regress/sql/window.sql index a88d1d092c..1009b438de 100644 --- a/src/test/regress/sql/window.sql +++ b/src/test/regress/sql/window.sql @@ -434,9 +434,6 @@ select first_value(salary) over(order by enroll_date range between unbounded pre exclude current row), salary, enroll_date from empsalary; --- with DISTINCT in agg functionn -select depname, count(DISTINCT enroll_date) over (PARTITION BY depname) FROM empsalary; - -- RANGE offset PRECEDING/FOLLOWING with null values select x, y, first_value(y) over w,