diff -Nru postgresql-rum-1.3.11/debian/changelog postgresql-rum-1.3.13/debian/changelog --- postgresql-rum-1.3.11/debian/changelog 2022-06-14 14:15:08.000000000 +0000 +++ postgresql-rum-1.3.13/debian/changelog 2022-10-24 14:27:17.000000000 +0000 @@ -1,3 +1,10 @@ +postgresql-rum (1.3.13-1) unstable; urgency=medium + + * New upstream version 1.3.13. + * debian/watch: Look at GitHub tags instead of releases. + + -- Christoph Berg Mon, 24 Oct 2022 16:27:17 +0200 + postgresql-rum (1.3.11-1) unstable; urgency=medium * New upstream version. diff -Nru postgresql-rum-1.3.11/debian/control postgresql-rum-1.3.13/debian/control --- postgresql-rum-1.3.11/debian/control 2021-10-26 12:06:36.000000000 +0000 +++ postgresql-rum-1.3.13/debian/control 2022-10-24 14:27:17.000000000 +0000 @@ -13,9 +13,9 @@ Vcs-Browser: https://salsa.debian.org/postgresql/postgresql-rum Vcs-Git: https://salsa.debian.org/postgresql/postgresql-rum.git -Package: postgresql-14-rum +Package: postgresql-15-rum Architecture: any -Depends: postgresql-14, ${misc:Depends}, ${shlibs:Depends} +Depends: postgresql-15, ${misc:Depends}, ${shlibs:Depends} Description: PostgreSQL RUM access method This PostgreSQL extension provides the RUM access method, an inverted index with additional information in posting lists. diff -Nru postgresql-rum-1.3.11/debian/watch postgresql-rum-1.3.13/debian/watch --- postgresql-rum-1.3.11/debian/watch 2018-11-09 13:08:49.000000000 +0000 +++ postgresql-rum-1.3.13/debian/watch 2022-10-24 14:27:17.000000000 +0000 @@ -1,2 +1,2 @@ version=4 -https://github.com/postgrespro/rum/releases .*/([0-9].*).tar.gz +https://github.com/postgrespro/rum/tags .*/([0-9].*).tar.gz diff -Nru postgresql-rum-1.3.11/README.md postgresql-rum-1.3.13/README.md --- postgresql-rum-1.3.11/README.md 2022-05-27 10:48:17.000000000 +0000 +++ postgresql-rum-1.3.13/README.md 2022-09-19 11:42:21.000000000 +0000 @@ -8,38 +8,38 @@ ## Introduction -The **rum** module provides access method to work with `RUM` index. It is based -on the `GIN` access methods code. +The **rum** module provides an access method to work with a `RUM` index. It is based +on the `GIN` access method's code. -`GIN` index allows to perform fast full text search using `tsvector` and -`tsquery` types. But full text search with GIN index has several problems: +A `GIN` index allows performing fast full-text search using `tsvector` and +`tsquery` types. But full-text search with a GIN index has several problems: -- Slow ranking. It is need position information about lexems to ranking. `GIN` -index doesn't store positions of lexems. So after index scan we need additional -heap scan to retrieve lexems positions. -- Slow phrase search with `GIN` index. This problem relates with previous -problem. It is need position information to perform phrase search. -- Slow ordering by timestamp. `GIN` index can't store some related information -in index with lexemes. So it is necessary to perform additional heap scan. +- Slow ranking. It needs positional information about lexemes to do ranking. A `GIN` +index doesn't store positions of lexemes. So after index scanning, we need an +additional heap scan to retrieve lexeme positions. +- Slow phrase search with a `GIN` index. This problem relates to the previous +problem. It needs positional information to perform phrase search. +- Slow ordering by timestamp. A `GIN` index can't store some related information +in the index with lexemes. So it is necessary to perform an additional heap scan. -`RUM` solves this problems by storing additional information in posting tree. +`RUM` solves these problems by storing additional information in a posting tree. For example, positional information of lexemes or timestamps. You can get an -idea of `RUM` by the following picture: +idea of `RUM` with the following diagram: ![How RUM stores additional information](img/gin_rum.png) -Drawback of `RUM` is that it has slower build and insert time than `GIN`. -It is because we need to store additional information besides keys and because -`RUM` uses generic WAL records. +A drawback of `RUM` is that it has slower build and insert times than `GIN`. +This is because we need to store additional information besides keys and because +`RUM` uses generic Write-Ahead Log (WAL) records. ## License -This module available under the [license](LICENSE) similar to +This module is available under the [license](LICENSE) similar to [PostgreSQL](http://www.postgresql.org/about/licence/). ## Installation -Before build and install **rum** you should ensure following: +Before building and installing **rum**, you should ensure following are installed: * PostgreSQL version is 9.6+. @@ -62,7 +62,7 @@ ## Common operators and functions -**rum** module provides next operators. +The **rum** module provides next operators. | Operator | Returns | Description | -------------------- | ------- | ---------------------------------------------- @@ -71,19 +71,19 @@ | timestamp <=| timestamp | float8 | Returns distance only for left timestamps. | timestamp |=> timestamp | float8 | Returns distance only for right timestamps. -Last three operations also works for types timestamptz, int2, int4, int8, float4, float8, +The last three operations also work for types timestamptz, int2, int4, int8, float4, float8, money and oid. ## Operator classes -**rum** provides next operator classes. +**rum** provides the following operator classes. ### rum_tsvector_ops For type: `tsvector` -This operator class stores `tsvector` lexemes with positional information. Supports -ordering by `<=>` operator and prefix search. There is the example. +This operator class stores `tsvector` lexemes with positional information. It supports +ordering by the `<=>` operator and prefix search. See the example below. Let us assume we have the table: @@ -140,8 +140,8 @@ For type: `tsvector` -This operator class stores hash of `tsvector` lexemes with positional information. -Supports ordering by `<=>` operator. But **doesn't** support prefix search. +This operator class stores a hash of `tsvector` lexemes with positional information. +It supports ordering by the `<=>` operator. It **doesn't** support prefix search. ### rum_TYPE_ops @@ -153,17 +153,18 @@ `<=>`, `<=|` and `|=>` for int2, int4, int8, float4, float8, money, oid, timestamp and timestamptz types. -Supports ordering by `<=>`, `<=|` and `|=>` operators. Can be used with +This operator supports ordering by the `<=>`, `<=|` and `|=>` operators. It can be used with `rum_tsvector_addon_ops`, `rum_tsvector_hash_addon_ops' and `rum_anyarray_addon_ops` operator classes. ### rum_tsvector_addon_ops For type: `tsvector` -This operator class stores `tsvector` lexems with any supported by module -field. There is the example. +This operator class stores `tsvector` lexemes with any supported by module +field. See the example below. Let us assume we have the table: + ```sql CREATE TABLE tsts (id int, t tsvector, d timestamp); @@ -202,16 +203,16 @@ For type: `tsvector` -This operator class stores hash of `tsvector` lexems with any supported by module +This operator class stores a hash of `tsvector` lexemes with any supported by module field. -**Doesn't** support prefix search. +It **doesn't** support prefix search. ### rum_tsquery_ops For type: `tsquery` -Stores branches of query tree in additional information. For example we have the table: +It stores branches of query tree in additional information. For example, we have the table: ```sql CREATE TABLE query (q tsquery, tag text); @@ -240,8 +241,8 @@ For type: `anyarray` This operator class stores `anyarray` elements with length of the array. -Supports operators `&&`, `@>`, `<@`, `=`, `%` operators. Supports ordering by `<=>` operator. -For example we have the table: +It supports operators `&&`, `@>`, `<@`, `=`, `%` operators. It also supports ordering by `<=>` operator. +For example, we have the table: ```sql CREATE TABLE test_array (i int2[]); diff -Nru postgresql-rum-1.3.11/src/disable_core_macro.h postgresql-rum-1.3.13/src/disable_core_macro.h --- postgresql-rum-1.3.11/src/disable_core_macro.h 2022-05-27 10:48:17.000000000 +0000 +++ postgresql-rum-1.3.13/src/disable_core_macro.h 2022-09-19 11:42:21.000000000 +0000 @@ -16,9 +16,18 @@ #undef TRACE_POSTGRESQL_SORT_START #undef TRACE_POSTGRESQL_SORT_DONE +#if PG_VERSION_NUM >= 110000 #define TRACE_POSTGRESQL_SORT_START(arg1, arg2, arg3, arg4, arg5, arg6) \ do {} while(0) +#else +#define TRACE_POSTGRESQL_SORT_START(arg1, arg2, arg3, arg4, arg5) \ + do {} while(0) +#endif + + #define TRACE_POSTGRESQL_SORT_DONE(arg1, arg2) \ do {} while(0) + + #endif /* __DISABLE_CORE_MACRO_H__ */ diff -Nru postgresql-rum-1.3.11/src/rumsort.c postgresql-rum-1.3.13/src/rumsort.c --- postgresql-rum-1.3.11/src/rumsort.c 2022-05-27 10:48:17.000000000 +0000 +++ postgresql-rum-1.3.13/src/rumsort.c 2022-09-19 11:42:21.000000000 +0000 @@ -27,7 +27,12 @@ #include "rum.h" /* RumItem */ -#if PG_VERSION_NUM >= 150000 +#if PG_VERSION_NUM >= 160000 +/* + * After allocating a public interface for Tuplesortstate, no need to include + * source code from pg-core. + */ +#elif PG_VERSION_NUM >= 150000 #include "tuplesort15.c" #elif PG_VERSION_NUM >= 140000 #include "tuplesort14.c" @@ -44,29 +49,92 @@ #endif /* - * We need extra field in a state structure but we should not modify struct RumTuplesortstate - * which is inherited from Tuplesortstate core function. + * In case of using custom compare function we should store function pointer in + * sort stare in order to use it later. + */ + +#if PG_VERSION_NUM >= 160000 +/* + * After allocating a public interface for Tuplesortstate we may use + * TuplesortPublic->arg filed to store pointer to the compare function. + */ + +/* GUC variables */ +#ifdef TRACE_SORT +extern PGDLLIMPORT bool trace_sort; +#endif + +/* All memory management should be inside Tuplesortstate module. */ +#define USEMEM(state,amt) do {} while(0) + +#else /* PG_VERSION_NUM >= 160000 */ +/* + * We need extra field in a state structure but we should not modify struct + * RumTuplesortstate which is inherited from Tuplesortstate core function. */ typedef struct RumTuplesortstateExt { RumTuplesortstate ts; FmgrInfo *cmp; } RumTuplesortstateExt; +#endif /* PG_VERSION_NUM < 160000 */ -static int compare_rum_itempointer(ItemPointerData p1, ItemPointerData p2); static int comparetup_rum(const SortTuple *a, const SortTuple *b, - RumTuplesortstate * state, bool compareItemPointer); + RumTuplesortstate *state, bool compareItemPointer); static int comparetup_rum_true(const SortTuple *a, const SortTuple *b, - RumTuplesortstate * state); + RumTuplesortstate *state); static int comparetup_rum_false(const SortTuple *a, const SortTuple *b, - RumTuplesortstate * state); + RumTuplesortstate *state); static int comparetup_rumitem(const SortTuple *a, const SortTuple *b, - RumTuplesortstate * state); -static void copytup_rum(RumTuplesortstate * state, SortTuple *stup, void *tup); -static void copytup_rumitem(RumTuplesortstate * state, SortTuple *stup, void *tup); -static void *rum_tuplesort_getrum_internal(RumTuplesortstate * state, bool forward, bool *should_free); + RumTuplesortstate *state); +static void copytup_rum(RumTuplesortstate *state, SortTuple *stup, void *tup); +static void copytup_rumitem(RumTuplesortstate *state, SortTuple *stup, + void *tup); +static void *rum_tuplesort_getrum_internal(RumTuplesortstate *state, + bool forward, bool *should_free); -static int +/* + * Tuplesortstate handling should be done through this macro. + */ +#if PG_VERSION_NUM >= 160000 +# define TSS_GET(state) TuplesortstateGetPublic((state)) +#else +# define TSS_GET(state) (state) +#endif + +/* + * Logical tape handling should be done through this macro. + */ +#if PG_VERSION_NUM >= 150000 +#define LT_TYPE LogicalTape * +#define LT_ARG tape +#define TAPE(state, LT_ARG) LT_ARG +#else +#define LT_TYPE int +#define LT_ARG tapenum +#define TAPE(state, LT_ARG) state->tapeset, LT_ARG +#endif + +/* + * Just for convenience and uniformity. + */ +#if PG_VERSION_NUM >= 110000 +#define tuplesort_begin_common(x,y) tuplesort_begin_common((x), NULL, (y)) +#endif + +/* + * Trace log wrapper. + */ +#ifdef TRACE_SORT +# define LOG_SORT(...) \ + if (trace_sort) \ + ereport(LOG, errmsg_internal(__VA_ARGS__)) +#else +# define LOG_SORT(...) \ + {} +#endif + +static inline int compare_rum_itempointer(ItemPointerData p1, ItemPointerData p2) { if (p1.ip_blkid.bi_hi < p2.ip_blkid.bi_hi) @@ -88,7 +156,8 @@ } static int -comparetup_rum(const SortTuple *a, const SortTuple *b, RumTuplesortstate * state, bool compareItemPointer) +comparetup_rum(const SortTuple *a, const SortTuple *b, + RumTuplesortstate *state, bool compareItemPointer) { RumSortItem *i1, *i2; @@ -104,7 +173,7 @@ i1 = (RumSortItem *) a->tuple; i2 = (RumSortItem *) b->tuple; - for (i = 1; i < state->nKeys; i++) + for (i = 1; i < TSS_GET(state)->nKeys; i++) { if (i1->data[i] < i2->data[i]) return -1; @@ -122,28 +191,43 @@ } static int -comparetup_rum_true(const SortTuple *a, const SortTuple *b, RumTuplesortstate * state) +comparetup_rum_true(const SortTuple *a, const SortTuple *b, + RumTuplesortstate *state) { return comparetup_rum(a, b, state, true); } static int -comparetup_rum_false(const SortTuple *a, const SortTuple *b, RumTuplesortstate * state) +comparetup_rum_false(const SortTuple *a, const SortTuple *b, + RumTuplesortstate *state) { return comparetup_rum(a, b, state, false); } +static inline FmgrInfo * +comparetup_rumitem_custom_fun(RumTuplesortstate *state) +{ +#if PG_VERSION_NUM >= 160000 + return (FmgrInfo *) TSS_GET(state)->arg; +#else + return ((RumTuplesortstateExt *) state)->cmp; +#endif +} + static int -comparetup_rumitem(const SortTuple *a, const SortTuple *b, RumTuplesortstate * state) +comparetup_rumitem(const SortTuple *a, const SortTuple *b, + RumTuplesortstate *state) { - RumItem *i1, - *i2; + RumItem *i1, + *i2; + FmgrInfo *cmp; /* Extract RumItem from RumScanItem */ i1 = (RumItem *) a->tuple; i2 = (RumItem *) b->tuple; - if (((RumTuplesortstateExt *) state)->cmp) + cmp = comparetup_rumitem_custom_fun(state); + if (cmp != NULL) { if (i1->addInfoIsNull || i2->addInfoIsNull) { @@ -155,7 +239,7 @@ { int r; - r = DatumGetInt32(FunctionCall2(((RumTuplesortstateExt *) state)->cmp, + r = DatumGetInt32(FunctionCall2(cmp, i1->addInfo, i2->addInfo)); @@ -171,18 +255,19 @@ } static void -copytup_rum(RumTuplesortstate * state, SortTuple *stup, void *tup) +copytup_rum(RumTuplesortstate *state, SortTuple *stup, void *tup) { RumSortItem *item = (RumSortItem *) tup; + int nKeys = TSS_GET(state)->nKeys; - stup->datum1 = Float8GetDatum(state->nKeys > 0 ? item->data[0] : 0); + stup->datum1 = Float8GetDatum(nKeys > 0 ? item->data[0] : 0); stup->isnull1 = false; stup->tuple = tup; USEMEM(state, GetMemoryChunkSpace(tup)); } static void -copytup_rumitem(RumTuplesortstate * state, SortTuple *stup, void *tup) +copytup_rumitem(RumTuplesortstate *state, SortTuple *stup, void *tup) { stup->isnull1 = true; stup->tuple = palloc(sizeof(RumScanItem)); @@ -190,61 +275,64 @@ USEMEM(state, GetMemoryChunkSpace(stup->tuple)); } -#if PG_VERSION_NUM >= 150000 -#define LT_TYPE LogicalTape * -#define LT_ARG tape -#define TAPE(state, LT_ARG) LT_ARG -#else -#define LT_TYPE int -#define LT_ARG tapenum -#define TAPE(state, LT_ARG) state->tapeset, LT_ARG -#endif +static void readtup_rum(RumTuplesortstate *state, SortTuple *stup, + LT_TYPE LT_ARG, unsigned int len); + +static void readtup_rumitem(RumTuplesortstate *state, SortTuple *stup, + LT_TYPE LT_ARG, unsigned int len); static Size -rum_item_size(RumTuplesortstate * state) +rum_item_size(RumTuplesortstate *state) { - if (state->copytup == copytup_rum) - return RumSortItemSize(state->nKeys); - else if (state->copytup == copytup_rumitem) + if (TSS_GET(state)->readtup == readtup_rum) + return RumSortItemSize(TSS_GET(state)->nKeys); + else if (TSS_GET(state)->readtup == readtup_rumitem) return sizeof(RumScanItem); - else - elog (FATAL, "Unknown RUM state"); + + elog (FATAL, "Unknown RUM state"); + return 0; /* keep compiler quiet */ } static void -writetup_rum_internal(RumTuplesortstate * state, LT_TYPE LT_ARG, SortTuple *stup) +writetup_rum_internal(RumTuplesortstate *state, LT_TYPE LT_ARG, + SortTuple *stup) { void *item = stup->tuple; size_t size = rum_item_size(state); unsigned int writtenlen = size + sizeof(unsigned int); + bool randomAccess; LogicalTapeWrite(TAPE(state, LT_ARG), (void *) &writtenlen, sizeof(writtenlen)); LogicalTapeWrite(TAPE(state, LT_ARG), (void *) item, size); -#if PG_VERSION_NUM >= 150000 - if (state->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */ -#else - if (state->randomAccess) /* need trailing length word? */ -#endif - LogicalTapeWrite(TAPE(state, LT_ARG), - (void *) &writtenlen, sizeof(writtenlen)); + + randomAccess = +# if PG_VERSION_NUM >= 150000 + (TSS_GET(state)->sortopt & TUPLESORT_RANDOMACCESS) != 0; +# else + TSS_GET(state)->randomAccess; +# endif + + if (randomAccess) + LogicalTapeWrite(TAPE(TSS_GET(state), LT_ARG), (void *) &writtenlen, + sizeof(writtenlen)); } static void -writetup_rum(RumTuplesortstate * state, LT_TYPE LT_ARG, SortTuple *stup) +writetup_rum(RumTuplesortstate *state, LT_TYPE LT_ARG, SortTuple *stup) { writetup_rum_internal(state, LT_ARG, stup); } static void -writetup_rumitem(RumTuplesortstate * state, LT_TYPE LT_ARG, SortTuple *stup) +writetup_rumitem(RumTuplesortstate *state, LT_TYPE LT_ARG, SortTuple *stup) { writetup_rum_internal(state, LT_ARG, stup); } static void -readtup_rum_internal(RumTuplesortstate * state, SortTuple *stup, +readtup_rum_internal(RumTuplesortstate *state, SortTuple *stup, LT_TYPE LT_ARG, unsigned int len, bool is_item) { unsigned int tuplen = len - sizeof(unsigned int); @@ -254,43 +342,43 @@ Assert(tuplen == size); USEMEM(state, GetMemoryChunkSpace(item)); + #if PG_VERSION_NUM >= 150000 LogicalTapeReadExact(LT_ARG, item, size); #else - LogicalTapeReadExact(state->tapeset, LT_ARG, item, size); + LogicalTapeReadExact(TSS_GET(state)->tapeset, LT_ARG, item, size); #endif stup->tuple = item; stup->isnull1 = is_item; if (!is_item) - stup->datum1 = Float8GetDatum(state->nKeys > 0 ? ((RumSortItem *) item)->data[0] : 0); + stup->datum1 = Float8GetDatum(TSS_GET(state)->nKeys > 0 ? + ((RumSortItem *) item)->data[0] : 0); #if PG_VERSION_NUM >= 150000 - if (state->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing length word? */ + if (TSS_GET(state)->sortopt & TUPLESORT_RANDOMACCESS) /* need trailing + * length word? */ LogicalTapeReadExact(LT_ARG, &tuplen, sizeof(tuplen)); #else - if (state->randomAccess) - LogicalTapeReadExact(state->tapeset, LT_ARG, &tuplen, sizeof(tuplen)); + if (TSS_GET(state)->randomAccess) + LogicalTapeReadExact(TSS_GET(state)->tapeset, LT_ARG, &tuplen, + sizeof(tuplen)); #endif } static void -readtup_rum(RumTuplesortstate * state, SortTuple *stup, - LT_TYPE LT_ARG, unsigned int len) +readtup_rum(RumTuplesortstate *state, SortTuple *stup, LT_TYPE LT_ARG, + unsigned int len) { readtup_rum_internal(state, stup, LT_ARG, len, false); } static void -readtup_rumitem(RumTuplesortstate * state, SortTuple *stup, - LT_TYPE LT_ARG, unsigned int len) +readtup_rumitem(RumTuplesortstate *state, SortTuple *stup, LT_TYPE LT_ARG, + unsigned int len) { readtup_rum_internal(state, stup, LT_ARG, len, true); } -#if PG_VERSION_NUM >= 110000 -#define tuplesort_begin_common(x,y) tuplesort_begin_common((x), NULL, (y)) -#endif - RumTuplesortstate * rum_tuplesort_begin_rum(int workMem, int nKeys, bool randomAccess, bool compareItemPointer) @@ -305,21 +393,16 @@ #endif MemoryContext oldcontext; - oldcontext = MemoryContextSwitchTo(state->sortcontext); + oldcontext = MemoryContextSwitchTo(TSS_GET(state)->sortcontext); -#ifdef TRACE_SORT - if (trace_sort) - elog(LOG, - "begin rum sort: nKeys = %d, workMem = %d, randomAccess = %c", + LOG_SORT("begin rum sort: nKeys = %d, workMem = %d, randomAccess = %c", nKeys, workMem, randomAccess ? 't' : 'f'); -#endif - - state->nKeys = nKeys; - state->comparetup = compareItemPointer ? comparetup_rum_true : comparetup_rum_false; - state->copytup = copytup_rum; - state->writetup = writetup_rum; - state->readtup = readtup_rum; + TSS_GET(state)->nKeys = nKeys; + TSS_GET(state)->comparetup = compareItemPointer ? comparetup_rum_true : + comparetup_rum_false; + TSS_GET(state)->writetup = writetup_rum; + TSS_GET(state)->readtup = readtup_rum; MemoryContextSwitchTo(oldcontext); @@ -329,26 +412,38 @@ RumTuplesortstate * rum_tuplesort_begin_rumitem(int workMem, FmgrInfo *cmp) { +#if PG_VERSION_NUM >= 160000 + RumTuplesortstate *state = tuplesort_begin_common(workMem, false); + MemoryContext oldcontext; + + oldcontext = MemoryContextSwitchTo(TSS_GET(state)->sortcontext); + + LOG_SORT("begin rumitem sort: workMem = %d", workMem); + + TSS_GET(state)->comparetup = comparetup_rumitem; + TSS_GET(state)->writetup = writetup_rumitem; + TSS_GET(state)->readtup = readtup_rumitem; + TSS_GET(state)->arg = cmp; + + MemoryContextSwitchTo(oldcontext); + + return state; +#else RumTuplesortstate *state = tuplesort_begin_common(workMem, false); RumTuplesortstateExt *rs; MemoryContext oldcontext; - oldcontext = MemoryContextSwitchTo(state->sortcontext); + oldcontext = MemoryContextSwitchTo(TSS_GET(state)->sortcontext); /* Allocate extended state in the same context as state */ rs = palloc(sizeof(*rs)); -#ifdef TRACE_SORT - if (trace_sort) - elog(LOG, - "begin rumitem sort: workMem = %d", workMem); -#endif + LOG_SORT("begin rumitem sort: workMem = %d", workMem); rs->cmp = cmp; - state->comparetup = comparetup_rumitem; - state->copytup = copytup_rumitem; - state->writetup = writetup_rumitem; - state->readtup = readtup_rumitem; + TSS_GET(state)->comparetup = comparetup_rumitem; + TSS_GET(state)->writetup = writetup_rumitem; + TSS_GET(state)->readtup = readtup_rumitem; memcpy(&rs->ts, state, sizeof(RumTuplesortstate)); pfree(state); /* just to be sure *state isn't used anywhere * else */ @@ -356,6 +451,7 @@ MemoryContextSwitchTo(oldcontext); return (RumTuplesortstate *) rs; +#endif } /* @@ -368,9 +464,9 @@ * pointers afterwards! */ void -rum_tuplesort_end(RumTuplesortstate * state) +rum_tuplesort_end(RumTuplesortstate *state) { -#if PG_VERSION_NUM >= 130000 +#if PG_VERSION_NUM < 160000 && PG_VERSION_NUM >= 130000 tuplesort_free(state); #else tuplesort_end(state); @@ -382,39 +478,67 @@ * RumSortItem. */ MemoryContext -rum_tuplesort_get_memorycontext(RumTuplesortstate * state) +rum_tuplesort_get_memorycontext(RumTuplesortstate *state) { - return state->sortcontext; + return TSS_GET(state)->sortcontext; } void rum_tuplesort_putrum(RumTuplesortstate *state, RumSortItem *item) { - tuplesort_puttupleslot(state, (TupleTableSlot *) item); + MemoryContext oldcontext; + SortTuple stup; + + oldcontext = MemoryContextSwitchTo(rum_tuplesort_get_memorycontext(state)); + copytup_rum(state, &stup, item); + +#if PG_VERSION_NUM >= 160000 + tuplesort_puttuple_common(state, &stup, false); +#else + puttuple_common(state, &stup); +#endif + + MemoryContextSwitchTo(oldcontext); } void rum_tuplesort_putrumitem(RumTuplesortstate *state, RumScanItem *item) { - tuplesort_puttupleslot(state, (TupleTableSlot *) item); + MemoryContext oldcontext; + SortTuple stup; + + oldcontext = MemoryContextSwitchTo(rum_tuplesort_get_memorycontext(state)); + copytup_rumitem(state, &stup, item); + +#if PG_VERSION_NUM >= 160000 + tuplesort_puttuple_common(state, &stup, false); +#else + puttuple_common(state, &stup); +#endif + + MemoryContextSwitchTo(oldcontext); } void -rum_tuplesort_performsort(RumTuplesortstate * state) +rum_tuplesort_performsort(RumTuplesortstate *state) { tuplesort_performsort(state); } /* - * Internal routine to fetch the next index tuple in either forward or back direction. - * Returns NULL if no more tuples. Returned tuple belongs to tuplesort memory context. Caller may not rely on tuple remaining valid after any further manipulation of tuplesort. + * Internal routine to fetch the next index tuple in either forward or back + * direction. Returns NULL if no more tuples. Returned tuple belongs to + * tuplesort memory context. Caller may not rely on tuple remaining valid after + * any further manipulation of tuplesort. + * * If *should_free is set, the caller must pfree stup.tuple when done with it. * - * NOTE: in PG 10 and newer tuple is always allocated tuple in tuplesort context and - * should not be freed by caller. + * NOTE: in PG 10 and newer tuple is always allocated tuple in tuplesort context + * and should not be freed by caller. */ static void * -rum_tuplesort_getrum_internal(RumTuplesortstate * state, bool forward, bool *should_free) +rum_tuplesort_getrum_internal(RumTuplesortstate *state, bool forward, + bool *should_free) { #if PG_VERSION_NUM >= 100000 *should_free = false; @@ -425,13 +549,16 @@ } RumSortItem * -rum_tuplesort_getrum(RumTuplesortstate * state, bool forward, bool *should_free) +rum_tuplesort_getrum(RumTuplesortstate *state, bool forward, bool *should_free) { - return (RumSortItem *) rum_tuplesort_getrum_internal(state, forward, should_free); + return (RumSortItem *) rum_tuplesort_getrum_internal(state, forward, + should_free); } RumScanItem * -rum_tuplesort_getrumitem(RumTuplesortstate * state, bool forward, bool *should_free) +rum_tuplesort_getrumitem(RumTuplesortstate *state, bool forward, + bool *should_free) { - return (RumScanItem *) rum_tuplesort_getrum_internal(state, forward, should_free); + return (RumScanItem *) rum_tuplesort_getrum_internal(state, forward, + should_free); } diff -Nru postgresql-rum-1.3.11/src/rumutil.c postgresql-rum-1.3.13/src/rumutil.c --- postgresql-rum-1.3.11/src/rumutil.c 2022-05-27 10:48:17.000000000 +0000 +++ postgresql-rum-1.3.13/src/rumutil.c 2022-09-19 11:42:21.000000000 +0000 @@ -129,9 +129,6 @@ #if PG_VERSION_NUM >= 100000 amroutine->amcanparallel = false; #endif -#if PG_VERSION_NUM >= 150000 - amroutine->amhotblocking = true; -#endif amroutine->amkeytype = InvalidOid; amroutine->ambuild = rumbuild; diff -Nru postgresql-rum-1.3.11/src/tuplesort15.c postgresql-rum-1.3.13/src/tuplesort15.c --- postgresql-rum-1.3.11/src/tuplesort15.c 2022-05-27 10:48:17.000000000 +0000 +++ postgresql-rum-1.3.13/src/tuplesort15.c 2022-09-19 11:42:21.000000000 +0000 @@ -471,7 +471,7 @@ /* These are specific to the index_btree subcase: */ bool enforceUnique; /* complain if we find duplicate tuples */ - bool uniqueNullsNotDistinct; /* unique constraint null treatment */ + bool uniqueNullsNotDistinct; /* unique constraint null treatment */ /* These are specific to the index_hash subcase: */ uint32 high_mask; /* masks for sortable part of hash code */ @@ -708,8 +708,8 @@ return compare; /* - * No need to waste effort calling the tiebreak function when there are - * no other keys to sort on. + * No need to waste effort calling the tiebreak function when there are no + * other keys to sort on. */ if (state->onlyKey != NULL) return 0; @@ -717,6 +717,7 @@ return state->comparetup(a, b, state); } +#if SIZEOF_DATUM >= 8 /* Used if first key's comparator is ssup_datum_signed_compare */ static pg_attribute_always_inline int qsort_tuple_signed_compare(SortTuple *a, SortTuple *b, Tuplesortstate *state) @@ -731,14 +732,15 @@ return compare; /* - * No need to waste effort calling the tiebreak function when there are - * no other keys to sort on. + * No need to waste effort calling the tiebreak function when there are no + * other keys to sort on. */ if (state->onlyKey != NULL) return 0; return state->comparetup(a, b, state); } +#endif /* Used if first key's comparator is ssup_datum_int32_compare */ static pg_attribute_always_inline int @@ -747,15 +749,15 @@ int compare; compare = ApplyInt32SortComparator(a->datum1, a->isnull1, - b->datum1, b->isnull1, - &state->sortKeys[0]); + b->datum1, b->isnull1, + &state->sortKeys[0]); if (compare != 0) return compare; /* - * No need to waste effort calling the tiebreak function when there are - * no other keys to sort on. + * No need to waste effort calling the tiebreak function when there are no + * other keys to sort on. */ if (state->onlyKey != NULL) return 0; @@ -781,6 +783,7 @@ #define ST_DEFINE #include "lib/sort_template.h" +#if SIZEOF_DATUM >= 8 #define ST_SORT qsort_tuple_signed #define ST_ELEMENT_TYPE SortTuple #define ST_COMPARE(a, b, state) qsort_tuple_signed_compare(a, b, state) @@ -789,6 +792,7 @@ #define ST_SCOPE static #define ST_DEFINE #include "lib/sort_template.h" +#endif #define ST_SORT qsort_tuple_int32 #define ST_ELEMENT_TYPE SortTuple @@ -3662,23 +3666,22 @@ { if (state->sortKeys[0].comparator == ssup_datum_unsigned_cmp) { - elog(DEBUG1, "qsort_tuple_unsigned"); qsort_tuple_unsigned(state->memtuples, state->memtupcount, state); return; } +#if SIZEOF_DATUM >= 8 else if (state->sortKeys[0].comparator == ssup_datum_signed_cmp) { - elog(DEBUG1, "qsort_tuple_signed"); qsort_tuple_signed(state->memtuples, state->memtupcount, state); return; } +#endif else if (state->sortKeys[0].comparator == ssup_datum_int32_cmp) { - elog(DEBUG1, "qsort_tuple_int32"); qsort_tuple_int32(state->memtuples, state->memtupcount, state); @@ -3689,13 +3692,11 @@ /* Can we use the single-key sort function? */ if (state->onlyKey != NULL) { - elog(DEBUG1, "qsort_ssup"); qsort_ssup(state->memtuples, state->memtupcount, state->onlyKey); } else { - elog(DEBUG1, "qsort_tuple"); qsort_tuple(state->memtuples, state->memtupcount, state->comparetup, @@ -4907,16 +4908,12 @@ return 0; } +#if SIZEOF_DATUM >= 8 int ssup_datum_signed_cmp(Datum x, Datum y, SortSupport ssup) { -#if SIZEOF_DATUM == 8 - int64 xx = (int64) x; - int64 yy = (int64) y; -#else - int32 xx = (int32) x; - int32 yy = (int32) y; -#endif + int64 xx = DatumGetInt64(x); + int64 yy = DatumGetInt64(y); if (xx < yy) return -1; @@ -4925,12 +4922,13 @@ else return 0; } +#endif int ssup_datum_int32_cmp(Datum x, Datum y, SortSupport ssup) { - int32 xx = (int32) x; - int32 yy = (int32) y; + int32 xx = DatumGetInt32(x); + int32 yy = DatumGetInt32(y); if (xx < yy) return -1; diff -Nru postgresql-rum-1.3.11/.travis.yml postgresql-rum-1.3.13/.travis.yml --- postgresql-rum-1.3.11/.travis.yml 2022-05-27 10:48:17.000000000 +0000 +++ postgresql-rum-1.3.13/.travis.yml 2022-09-19 11:42:21.000000000 +0000 @@ -1,4 +1,6 @@ -sudo: required +os: linux + +dist: bionic language: c @@ -21,6 +23,8 @@ on_failure: always env: + - PG_VERSION=15beta1 + - PG_VERSION=15beta1 LEVEL=hardcore - PG_VERSION=14 - PG_VERSION=14 LEVEL=hardcore - PG_VERSION=13