From e4c50b789b31b33989bcd53142fa6d53a491d010 Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Wed, 20 Dec 2017 18:49:52 +0300 Subject: [PATCH 01/21] Make shared_ispell compile for PostgreSQL master --- Makefile | 4 +++- src/shared_ispell.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index cf91b65..363eea6 100644 --- a/Makefile +++ b/Makefile @@ -21,4 +21,6 @@ include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk endif -installcheck:; +# Disabled because these tests require "shared_preload_libraries=shared_ispell", +# which typical installcheck users do not have (e.g. buildfarm clients). +installcheck: REGRESS= diff --git a/src/shared_ispell.c b/src/shared_ispell.c index 126dd72..61ac39c 100644 --- a/src/shared_ispell.c +++ b/src/shared_ispell.c @@ -166,7 +166,7 @@ _PG_fini(void) static void ispell_shmem_startup() { - bool found = FALSE; + bool found = false; char *segment; if (prev_shmem_startup_hook) From 62df307cf780db3b68f33eab2d72394644998679 Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Thu, 25 Jan 2018 14:48:03 +0300 Subject: [PATCH 02/21] Issue #1. Fix mention about USE_PGXS --- .gitignore | 3 +++ README.md | 17 +++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8a9a6c9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.so +results diff --git a/README.md b/README.md index b6d359e..d78c5aa 100644 --- a/README.md +++ b/README.md @@ -16,18 +16,23 @@ dictionary, this may save you a lot of resources. Install ------- -Installing the extension is quite simple, especially if you're on 9.1. -In that case all you need to do is this: - $ make install +Before build and install `shared_ispell` you should ensure following: + +* PostgreSQL version is 9.6 or 10. + +Installing the extension is quite simple. In that case all you need to do is this: + + $ git clone git@github.com:postgrespro/shared_ispell.git + $ cd shared_ispell + $ make USE_PGXS=1 + $ make USE_PGXS=1 install and then (after connecting to the database) db=# CREATE EXTENSION shared_ispell; -If you're on pre-9.1 version, you'll have to do the second part manually -by running the SQL script (shared_ispell--x.y.sql) in the database. If -needed, replace MODULE_PATHNAME by $libdir. +> **Important:** Don't forget to set the `PG_CONFIG` variable in case you want to test `shared_ispell` on a custom build of PostgreSQL. Read more [here](https://wiki.postgresql.org/wiki/Building_and_Installing_PostgreSQL_Extension_Modules). Config From bdcadfeea8459caabf616248889b16596473b5eb Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Tue, 15 May 2018 16:49:39 +0300 Subject: [PATCH 03/21] Teodor Sigaev Fix segmentation fault. init_shared_dict() copied dictFile into info->affixFile and info->stopFile. --- expected/shared_ispell.out | 6 +++ sql/shared_ispell.sql | 3 +- src/shared_ispell.c | 100 ++++++++++++++++++++++++------------- src/shared_ispell.h | 6 ++- 4 files changed, 77 insertions(+), 38 deletions(-) diff --git a/expected/shared_ispell.out b/expected/shared_ispell.out index 68e59c9..9998cb9 100644 --- a/expected/shared_ispell.out +++ b/expected/shared_ispell.out @@ -211,3 +211,9 @@ SELECT ts_lexize('shared_hunspell', 'skies'); {sky} (1 row) +SELECT ts_lexize('shared_hunspell', 'skies'); + ts_lexize +----------- + {sky} +(1 row) + diff --git a/sql/shared_ispell.sql b/sql/shared_ispell.sql index e791399..0a4af97 100644 --- a/sql/shared_ispell.sql +++ b/sql/shared_ispell.sql @@ -53,4 +53,5 @@ SELECT stop_name, words FROM shared_ispell_stoplists(); SELECT shared_ispell_reset(); SELECT ts_lexize('shared_ispell', 'skies'); -SELECT ts_lexize('shared_hunspell', 'skies'); \ No newline at end of file +SELECT ts_lexize('shared_hunspell', 'skies'); +SELECT ts_lexize('shared_hunspell', 'skies'); diff --git a/src/shared_ispell.c b/src/shared_ispell.c index 61ac39c..5c59d7b 100644 --- a/src/shared_ispell.c +++ b/src/shared_ispell.c @@ -20,33 +20,33 @@ * ===== shared segment init (postmaster startup) ===== * * _PG_init - * -> ispell_shmem_startup (registered as a hook) + * -> ispell_shmem_startup (registered as a hook) * * ===== dictionary init (backend) ===== * * dispell_init - * -> init_shared_dict - * -> get_shared_dict - * -> NIStartBuild - * -> NIImportDictionary - * -> NIImportAffixes - * -> NISortDictionary - * -> NISortAffixes - * -> NIFinishBuild - * -> sizeIspellDict - * -> copyIspellDict - * -> copySPNode - * -> get_shared_stop_list - * -> readstoplist - * -> copyStopList + * -> init_shared_dict + * -> get_shared_dict + * -> NIStartBuild + * -> NIImportDictionary + * -> NIImportAffixes + * -> NISortDictionary + * -> NISortAffixes + * -> NIFinishBuild + * -> sizeIspellDict + * -> copyIspellDict + * -> copySPNode + * -> get_shared_stop_list + * -> readstoplist + * -> copyStopList * * ===== dictionary reinit after reset (backend) ===== * * dispell_lexize - * -> timestamp of lookup < last reset - * -> init_shared_dict - * (see dispell_init above) - * -> SharedNINormalizeWord + * -> timestamp of lookup < last reset + * -> init_shared_dict + * (see dispell_init above) + * -> SharedNINormalizeWord */ #include "postgres.h" @@ -166,7 +166,7 @@ _PG_fini(void) static void ispell_shmem_startup() { - bool found = false; + bool found = FALSE; char *segment; if (prev_shmem_startup_hook) @@ -185,6 +185,12 @@ ispell_shmem_startup() /* Was the shared memory segment already initialized? */ if (!found) { + if (segment == NULL) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Cannot acquire %d kB of shared memory", + max_ispell_mem_size_kb))); + } memset(segment, 0, max_ispell_mem_size()); #if PG_VERSION_NUM >= 90600 @@ -288,13 +294,9 @@ static void init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile) { int size; - SharedIspellDict *shdict = NULL; SharedStopList *shstop = NULL; - IspellDict *dict; - StopList stoplist; - /* DICTIONARY + AFFIXES */ /* TODO This should probably check that the filenames are not NULL, and maybe that @@ -313,6 +315,8 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile) /* load the dictionary (word list) if not yet defined */ if (shdict == NULL) { + IspellDict *dict; + dict = (IspellDict *) palloc0(sizeof(IspellDict)); NIStartBuild(dict); @@ -383,6 +387,8 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile) /* load the stopwords if not yet defined */ if (shstop == NULL) { + StopList stoplist; + readstoplist(stopFile, &stoplist, lowerstr); size = sizeStopList(&stoplist, stopFile); @@ -407,11 +413,14 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile) info->lookup = GetCurrentTimestamp(); memcpy(info->dictFile, dictFile, strlen(dictFile) + 1); - memcpy(info->affixFile, dictFile, strlen(affFile)+ 1); + memcpy(info->affixFile, affFile, strlen(affFile) + 1); if (stopFile != NULL) - memcpy(info->stopFile, dictFile, strlen(stopFile) + 1); + memcpy(info->stopFile, stopFile, strlen(stopFile) + 1); else memset(info->stopFile, 0, sizeof(info->stopFile)); + + /* save current context as long-lived */ + info->saveCntx = CurrentMemoryContext; } Datum dispell_init(PG_FUNCTION_ARGS); @@ -498,6 +507,9 @@ dispell_mem_used(PG_FUNCTION_ARGS) * The StopWords parameter is optional, the two other are required. * * If any of the filenames are incorrect, the call to init_shared_dict will fail. + * + * Do not call it directly - it saves current memory context as long-lived + * context. */ Datum dispell_init(PG_FUNCTION_ARGS) @@ -586,7 +598,7 @@ dispell_lexize(PG_FUNCTION_ARGS) char *txt; TSLexeme *res; TSLexeme *ptr, - *cptr; + *cptr; if (len <= 0) PG_RETURN_POINTER(NULL); @@ -599,11 +611,27 @@ dispell_lexize(PG_FUNCTION_ARGS) /* do we need to reinit the dictionary? was the dict reset since the lookup */ if (timestamp_cmp_internal(info->lookup, segment_info->lastReset) < 0) { + DictInfo saveInfo = *info; + MemoryContext ctx; + /* relock in exclusive mode */ LWLockRelease(segment_info->lock); LWLockAcquire(segment_info->lock, LW_EXCLUSIVE); - init_shared_dict(info, info->dictFile, info->affixFile, info->stopFile); + /* + * info is allocated in info->saveCntx, so that's why we use a copy of + * info here + */ + + MemoryContextResetAndDeleteChildren(saveInfo.saveCntx); + ctx = MemoryContextSwitchTo(saveInfo.saveCntx); + + info = palloc0(sizeof(*info)); + + init_shared_dict(info, saveInfo.dictFile, + saveInfo.affixFile, saveInfo.stopFile); + + MemoryContextSwitchTo(ctx); } res = NINormalizeWord(&(info->dict), txt); @@ -697,13 +725,13 @@ copySPNode(SPNode *node) SPNode *copy = NULL; if (node == NULL) - return NULL; + return NULL; copy = (SPNode *) shalloc(offsetof(SPNode, data) + sizeof(SPNodeData) * node->length); memcpy(copy, node, offsetof(SPNode, data) + sizeof(SPNodeData) * node->length); for (i = 0; i < node->length; i++) - copy->data[i].node = copySPNode(node->data[i].node); + copy->data[i].node = copySPNode(node->data[i].node); return copy; } @@ -715,7 +743,7 @@ sizeSPNode(SPNode *node) int size = 0; if (node == NULL) - return 0; + return 0; size = MAXALIGN(offsetof(SPNode, data) + sizeof(SPNodeData) * node->length); @@ -815,7 +843,7 @@ sizeIspellDict(IspellDict *dict, char *dictFile, char *affixFile) /* copy affix data */ size += MAXALIGN(sizeof(char *) * dict->nAffixData); for (i = 0; i < dict->nAffixData; i++) - size += MAXALIGN(sizeof(char) * strlen(dict->AffixData[i]) + 1); + size += MAXALIGN(sizeof(char) * strlen(dict->AffixData[i]) + 1); return size; } @@ -842,10 +870,10 @@ dispell_list_dicts(PG_FUNCTION_ARGS) /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("function returning record called in context " - "that cannot accept type record"))); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("function returning record called in context " + "that cannot accept type record"))); /* * generate attribute metadata needed later to produce tuples from raw diff --git a/src/shared_ispell.h b/src/shared_ispell.h index 92de330..2039ffe 100644 --- a/src/shared_ispell.h +++ b/src/shared_ispell.h @@ -2,6 +2,7 @@ #define __SHARED_ISPELL_H__ #include "storage/lwlock.h" +#include "utils/memutils.h" #include "utils/timestamp.h" #include "tsearch/dicts/spell.h" #include "tsearch/ts_public.h" @@ -66,6 +67,9 @@ typedef struct DictInfo SharedIspellDict *shdict; IspellDict dict; SharedStopList *shstop; + + /* MemoryContext of dict local content */ + MemoryContext saveCntx; } DictInfo; -#endif \ No newline at end of file +#endif From 38b259fd278cb6fb8836ea52e731941a80220f6a Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Wed, 16 May 2018 12:37:57 +0300 Subject: [PATCH 04/21] Style fixes, revert unnecessary ereport() and FALSE --- src/shared_ispell.c | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/shared_ispell.c b/src/shared_ispell.c index 5c59d7b..ca1fed7 100644 --- a/src/shared_ispell.c +++ b/src/shared_ispell.c @@ -166,7 +166,7 @@ _PG_fini(void) static void ispell_shmem_startup() { - bool found = FALSE; + bool found = false; char *segment; if (prev_shmem_startup_hook) @@ -177,27 +177,19 @@ ispell_shmem_startup() */ LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); - segment = ShmemInitStruct(SEGMENT_NAME, - max_ispell_mem_size(), - &found); + segment = ShmemInitStruct(SEGMENT_NAME, max_ispell_mem_size(), &found); segment_info = (SegmentInfo *) segment; /* Was the shared memory segment already initialized? */ if (!found) { - if (segment == NULL) { - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("Cannot acquire %d kB of shared memory", - max_ispell_mem_size_kb))); - } memset(segment, 0, max_ispell_mem_size()); - #if PG_VERSION_NUM >= 90600 +#if PG_VERSION_NUM >= 90600 segment_info->lock = &(GetNamedLWLockTranche("shared_ispell"))->lock; - #else +#else segment_info->lock = LWLockAssign(); - #endif +#endif segment_info->firstfree = segment + MAXALIGN(sizeof(SegmentInfo)); segment_info->available = max_ispell_mem_size() - (int)(segment_info->firstfree - segment); @@ -293,9 +285,9 @@ clean_dict_affix(IspellDict *dict) static void init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile) { - int size; + int size; SharedIspellDict *shdict = NULL; - SharedStopList *shstop = NULL; + SharedStopList *shstop = NULL; /* DICTIONARY + AFFIXES */ @@ -315,7 +307,7 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile) /* load the dictionary (word list) if not yet defined */ if (shdict == NULL) { - IspellDict *dict; + IspellDict *dict; dict = (IspellDict *) palloc0(sizeof(IspellDict)); @@ -337,11 +329,13 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile) */ if (info->dict.useFlagAliases) { - int i; + int i; + dict->useFlagAliases = true; dict->lenAffixData = info->dict.lenAffixData; dict->nAffixData = info->dict.nAffixData; dict->AffixData = (char **) palloc0(dict->nAffixData * sizeof(char *)); + for (i = 0; i < dict->nAffixData; i++) { dict->AffixData[i] = palloc0(strlen(info->dict.AffixData[i]) + 1); @@ -721,8 +715,8 @@ shstrcpy(char *str) static SPNode * copySPNode(SPNode *node) { - int i; - SPNode *copy = NULL; + int i; + SPNode *copy = NULL; if (node == NULL) return NULL; @@ -739,8 +733,8 @@ copySPNode(SPNode *node) static int sizeSPNode(SPNode *node) { - int i; - int size = 0; + int i; + int size = 0; if (node == NULL) return 0; @@ -852,9 +846,9 @@ sizeIspellDict(IspellDict *dict, char *dictFile, char *affixFile) Datum dispell_list_dicts(PG_FUNCTION_ARGS) { - FuncCallContext *funcctx; - TupleDesc tupdesc; - SharedIspellDict *dict; + FuncCallContext *funcctx; + TupleDesc tupdesc; + SharedIspellDict *dict; /* init on the first call */ if (SRF_IS_FIRSTCALL()) From fa70830b4fc7f7942015d3d2dddccae719dc6160 Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Wed, 16 May 2018 12:47:34 +0300 Subject: [PATCH 05/21] Do not palloc0() DictInfo, MemSet() it --- src/shared_ispell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared_ispell.c b/src/shared_ispell.c index ca1fed7..61d21e3 100644 --- a/src/shared_ispell.c +++ b/src/shared_ispell.c @@ -620,7 +620,7 @@ dispell_lexize(PG_FUNCTION_ARGS) MemoryContextResetAndDeleteChildren(saveInfo.saveCntx); ctx = MemoryContextSwitchTo(saveInfo.saveCntx); - info = palloc0(sizeof(*info)); + MemSet(info, 0, sizeof(*info)); init_shared_dict(info, saveInfo.dictFile, saveInfo.affixFile, saveInfo.stopFile); From 8b55719f90f11d3a95f7700795bd3b5c6dc165e3 Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Wed, 16 May 2018 15:33:04 +0300 Subject: [PATCH 06/21] fa70830 isn't correct. Fix the bug by creating child context of entry->dictCtx. --- Makefile | 2 +- src/shared_ispell.c | 30 +++++++++++++++++++----------- src/shared_ispell.h | 2 +- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 363eea6..dbb4136 100644 --- a/Makefile +++ b/Makefile @@ -23,4 +23,4 @@ endif # Disabled because these tests require "shared_preload_libraries=shared_ispell", # which typical installcheck users do not have (e.g. buildfarm clients). -installcheck: REGRESS= +#installcheck: REGRESS= diff --git a/src/shared_ispell.c b/src/shared_ispell.c index 61d21e3..7803759 100644 --- a/src/shared_ispell.c +++ b/src/shared_ispell.c @@ -283,11 +283,15 @@ clean_dict_affix(IspellDict *dict) * of the shared memory (using SegmentInfo->lock). */ static void -init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile) +init_shared_dict(DictInfo *info, MemoryContext infoCntx, + char *dictFile, char *affFile, char *stopFile) { int size; SharedIspellDict *shdict = NULL; SharedStopList *shstop = NULL; + MemoryContext oldctx; + + oldctx = MemoryContextSwitchTo(infoCntx); /* DICTIONARY + AFFIXES */ @@ -413,8 +417,9 @@ init_shared_dict(DictInfo *info, char *dictFile, char *affFile, char *stopFile) else memset(info->stopFile, 0, sizeof(info->stopFile)); + MemoryContextSwitchTo(oldctx); /* save current context as long-lived */ - info->saveCntx = CurrentMemoryContext; + info->infoCntx = infoCntx; } Datum dispell_init(PG_FUNCTION_ARGS); @@ -576,7 +581,15 @@ dispell_init(PG_FUNCTION_ARGS) /* search if the dictionary is already initialized */ LWLockAcquire(segment_info->lock, LW_EXCLUSIVE); - init_shared_dict(info, dictFile, affFile, stopFile); + /* + * Current context is a long lived context. Create child context to store + * DictInfo internal data. + */ + info->infoCntx = AllocSetContextCreate(CurrentMemoryContext, + "shared_ispell context", + ALLOCSET_DEFAULT_SIZES); + + init_shared_dict(info, info->infoCntx, dictFile, affFile, stopFile); LWLockRelease(segment_info->lock); @@ -605,8 +618,7 @@ dispell_lexize(PG_FUNCTION_ARGS) /* do we need to reinit the dictionary? was the dict reset since the lookup */ if (timestamp_cmp_internal(info->lookup, segment_info->lastReset) < 0) { - DictInfo saveInfo = *info; - MemoryContext ctx; + DictInfo saveInfo = *info; /* relock in exclusive mode */ LWLockRelease(segment_info->lock); @@ -617,15 +629,11 @@ dispell_lexize(PG_FUNCTION_ARGS) * info here */ - MemoryContextResetAndDeleteChildren(saveInfo.saveCntx); - ctx = MemoryContextSwitchTo(saveInfo.saveCntx); - + MemoryContextResetAndDeleteChildren(saveInfo.infoCntx); MemSet(info, 0, sizeof(*info)); - init_shared_dict(info, saveInfo.dictFile, + init_shared_dict(info, saveInfo.infoCntx, saveInfo.dictFile, saveInfo.affixFile, saveInfo.stopFile); - - MemoryContextSwitchTo(ctx); } res = NINormalizeWord(&(info->dict), txt); diff --git a/src/shared_ispell.h b/src/shared_ispell.h index 2039ffe..ca4d014 100644 --- a/src/shared_ispell.h +++ b/src/shared_ispell.h @@ -69,7 +69,7 @@ typedef struct DictInfo SharedStopList *shstop; /* MemoryContext of dict local content */ - MemoryContext saveCntx; + MemoryContext infoCntx; } DictInfo; #endif From 6431b333b5ff72080e92502e0e5d8959b4317d1a Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Wed, 16 May 2018 15:36:14 +0300 Subject: [PATCH 07/21] Revert Makefile accidental changes --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dbb4136..363eea6 100644 --- a/Makefile +++ b/Makefile @@ -23,4 +23,4 @@ endif # Disabled because these tests require "shared_preload_libraries=shared_ispell", # which typical installcheck users do not have (e.g. buildfarm clients). -#installcheck: REGRESS= +installcheck: REGRESS= From 1afd1a5dec75d9e710e5d8b2390f7470909ae45e Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Fri, 18 May 2018 11:19:41 +0300 Subject: [PATCH 08/21] Code style fixes --- src/shared_ispell.c | 49 +++++++++++++++++++++------------------------ src/shared_ispell.h | 6 +++--- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/shared_ispell.c b/src/shared_ispell.c index 7803759..ec459e8 100644 --- a/src/shared_ispell.c +++ b/src/shared_ispell.c @@ -94,7 +94,7 @@ static int sizeStopList(StopList *list, char *stopFile); static Size max_ispell_mem_size() { - return (Size)max_ispell_mem_size_kb * 1024L; + return (Size) max_ispell_mem_size_kb * 1024L; } /* @@ -134,11 +134,11 @@ _PG_init(void) */ RequestAddinShmemSpace(max_ispell_mem_size()); - #if PG_VERSION_NUM >= 90600 +#if PG_VERSION_NUM >= 90600 RequestNamedLWLockTranche("shared_ispell", 1); - #else +#else RequestAddinLWLocks(1); - #endif +#endif /* Install hooks. */ prev_shmem_startup_hook = shmem_startup_hook; @@ -166,8 +166,8 @@ _PG_fini(void) static void ispell_shmem_startup() { - bool found = false; - char *segment; + bool found = false; + char *segment; if (prev_shmem_startup_hook) prev_shmem_startup_hook(); @@ -191,8 +191,8 @@ ispell_shmem_startup() segment_info->lock = LWLockAssign(); #endif segment_info->firstfree = segment + MAXALIGN(sizeof(SegmentInfo)); - segment_info->available = max_ispell_mem_size() - - (int)(segment_info->firstfree - segment); + segment_info->available = max_ispell_mem_size() - + (int) (segment_info->firstfree - segment); segment_info->lastReset = GetCurrentTimestamp(); } @@ -311,7 +311,7 @@ init_shared_dict(DictInfo *info, MemoryContext infoCntx, /* load the dictionary (word list) if not yet defined */ if (shdict == NULL) { - IspellDict *dict; + IspellDict *dict; dict = (IspellDict *) palloc0(sizeof(IspellDict)); @@ -422,14 +422,6 @@ init_shared_dict(DictInfo *info, MemoryContext infoCntx, info->infoCntx = infoCntx; } -Datum dispell_init(PG_FUNCTION_ARGS); -Datum dispell_lexize(PG_FUNCTION_ARGS); -Datum dispell_reset(PG_FUNCTION_ARGS); -Datum dispell_mem_available(PG_FUNCTION_ARGS); -Datum dispell_mem_used(PG_FUNCTION_ARGS); -Datum dispell_list_dicts(PG_FUNCTION_ARGS); -Datum dispell_list_stoplists(PG_FUNCTION_ARGS); - PG_FUNCTION_INFO_V1(dispell_init); PG_FUNCTION_INFO_V1(dispell_lexize); PG_FUNCTION_INFO_V1(dispell_reset); @@ -453,7 +445,8 @@ dispell_reset(PG_FUNCTION_ARGS) segment_info->shstop = NULL; segment_info->lastReset = GetCurrentTimestamp(); segment_info->firstfree = ((char*) segment_info) + MAXALIGN(sizeof(SegmentInfo)); - segment_info->available = max_ispell_mem_size() - (int)(segment_info->firstfree - (char*) segment_info); + segment_info->available = max_ispell_mem_size() - + (int) (segment_info->firstfree - (char*) segment_info); memset(segment_info->firstfree, 0, segment_info->available); @@ -479,12 +472,14 @@ dispell_mem_available(PG_FUNCTION_ARGS) } /* - * Returns amount of 'occupied space' in the shared segment (used by current dictionaries). + * Returns amount of 'occupied space' in the shared segment (used by current + * dictionaries). */ Datum dispell_mem_used(PG_FUNCTION_ARGS) { - int result = 0; + int result = 0; + LWLockAcquire(segment_info->lock, LW_SHARED); result = max_ispell_mem_size() - segment_info->available; @@ -679,7 +674,8 @@ dispell_lexize(PG_FUNCTION_ARGS) static char * shalloc(int bytes) { - char *result; + char *result; + bytes = MAXALIGN(bytes); /* This shouldn't really happen, as the init_shared_dict checks the size @@ -706,8 +702,10 @@ shalloc(int bytes) static char * shstrcpy(char *str) { - char *tmp = shalloc(strlen(str) + 1); + char *tmp = shalloc(strlen(str) + 1); + memcpy(tmp, str, strlen(str) + 1); + return tmp; } @@ -801,8 +799,7 @@ sizeStopList(StopList *list, char *stopFile) static SharedIspellDict * copyIspellDict(IspellDict *dict, char *dictFile, char *affixFile, int size, int words) { - int i; - + int i; SharedIspellDict *copy = (SharedIspellDict *) shalloc(sizeof(SharedIspellDict)); copy->dictFile = shalloc(strlen(dictFile) + 1); @@ -834,8 +831,8 @@ copyIspellDict(IspellDict *dict, char *dictFile, char *affixFile, int size, int static int sizeIspellDict(IspellDict *dict, char *dictFile, char *affixFile) { - int i; - int size = MAXALIGN(sizeof(SharedIspellDict)); + int i; + int size = MAXALIGN(sizeof(SharedIspellDict)); size += MAXALIGN(strlen(dictFile) + 1); size += MAXALIGN(strlen(affixFile) + 1); diff --git a/src/shared_ispell.h b/src/shared_ispell.h index ca4d014..2cfb422 100644 --- a/src/shared_ispell.h +++ b/src/shared_ispell.h @@ -42,9 +42,9 @@ typedef struct SharedStopList typedef struct SegmentInfo { LWLockId lock; - char *firstfree; /* first free address (always maxaligned) */ - size_t available; /* free space remaining at firstfree */ - Timestamp lastReset; /* last reset of the dictionary */ + char *firstfree; /* first free address (always maxaligned) */ + size_t available; /* free space remaining at firstfree */ + Timestamp lastReset; /* last reset of the dictionary */ /* the shared segment (info and data) */ SharedIspellDict *shdict; From 0ad59c2dfc1a52fe61b137f666fd378b19811c3a Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Wed, 23 May 2018 11:41:56 +0300 Subject: [PATCH 09/21] Enable installcheck --- Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Makefile b/Makefile index 363eea6..6ff9e12 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,3 @@ include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk endif -# Disabled because these tests require "shared_preload_libraries=shared_ispell", -# which typical installcheck users do not have (e.g. buildfarm clients). -installcheck: REGRESS= From d7a1e85f540b3d9e408290dbe39d8d3ceaa8e165 Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Tue, 29 May 2018 15:11:27 +0300 Subject: [PATCH 10/21] Copy flagMode into shared dictionary structure. Issue https://github.com/postgrespro/hunspell_dicts/issues/3#issuecomment-392709311 --- src/shared_ispell.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shared_ispell.c b/src/shared_ispell.c index ec459e8..9192f56 100644 --- a/src/shared_ispell.c +++ b/src/shared_ispell.c @@ -318,6 +318,7 @@ init_shared_dict(DictInfo *info, MemoryContext infoCntx, NIStartBuild(dict); NIImportDictionary(dict, get_tsearch_config_filename(dictFile, "dict")); + dict->flagMode = info->dict.flagMode; dict->usecompound = info->dict.usecompound; dict->nCompoundAffixFlag = dict->mCompoundAffixFlag = @@ -816,6 +817,8 @@ copyIspellDict(IspellDict *dict, char *dictFile, char *affixFile, int size, int for (i = 0; i < copy->dict.nAffixData; i++) copy->dict.AffixData[i] = shstrcpy(dict->AffixData[i]); + copy->dict.flagMode = dict->flagMode; + copy->nbytes = size; copy->nwords = words; From e6d908dc28464b441b15037b46fccf47bfc10378 Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Tue, 7 Aug 2018 18:30:42 +0300 Subject: [PATCH 11/21] Add and dirs into .gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8a9a6c9..b87b714 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.o *.so -results +/log/ +/results/ +/tmp_check/ From 49da9567c4b31587b03e173febad7fd02503dcf6 Mon Sep 17 00:00:00 2001 From: Marina Polyakova Date: Fri, 5 Oct 2018 12:18:48 +0300 Subject: [PATCH 12/21] PGPRO-2033: a try to fix the use of dispell_reset in shared_ispell on Windows The shared_ispell dictionary is loaded into memory if the timestamp of its last lookup is less than the timestamp of the reset of the shared dictionary memory. These timestamps used the function gettimeofday() which is not for Win32 high precision timing purposes. Therefore sometimes the timestamp of the last dictinary lookup and the timestamp of the reset of the shared dictionary memory are equal and the function ts_lexize returns NULL (from buildfarm). To avoid this use the structure instr_time and its macros/functions with portable high-precision interval timing for the same purpose. --- src/shared_ispell.c | 9 +++++---- src/shared_ispell.h | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/shared_ispell.c b/src/shared_ispell.c index 9192f56..cbf78ae 100644 --- a/src/shared_ispell.c +++ b/src/shared_ispell.c @@ -194,7 +194,7 @@ ispell_shmem_startup() segment_info->available = max_ispell_mem_size() - (int) (segment_info->firstfree - segment); - segment_info->lastReset = GetCurrentTimestamp(); + INSTR_TIME_SET_CURRENT(segment_info->lastReset); } LWLockRelease(AddinShmemInitLock); @@ -409,7 +409,7 @@ init_shared_dict(DictInfo *info, MemoryContext infoCntx, info->shdict = shdict; info->shstop = shstop; - info->lookup = GetCurrentTimestamp(); + INSTR_TIME_SET_CURRENT(info->lookup); memcpy(info->dictFile, dictFile, strlen(dictFile) + 1); memcpy(info->affixFile, affFile, strlen(affFile) + 1); @@ -444,7 +444,7 @@ dispell_reset(PG_FUNCTION_ARGS) segment_info->shdict = NULL; segment_info->shstop = NULL; - segment_info->lastReset = GetCurrentTimestamp(); + INSTR_TIME_SET_CURRENT(segment_info->lastReset); segment_info->firstfree = ((char*) segment_info) + MAXALIGN(sizeof(SegmentInfo)); segment_info->available = max_ispell_mem_size() - (int) (segment_info->firstfree - (char*) segment_info); @@ -612,7 +612,8 @@ dispell_lexize(PG_FUNCTION_ARGS) LWLockAcquire(segment_info->lock, LW_SHARED); /* do we need to reinit the dictionary? was the dict reset since the lookup */ - if (timestamp_cmp_internal(info->lookup, segment_info->lastReset) < 0) + if (INSTR_TIME_GET_MICROSEC(info->lookup) < + INSTR_TIME_GET_MICROSEC(segment_info->lastReset)) { DictInfo saveInfo = *info; diff --git a/src/shared_ispell.h b/src/shared_ispell.h index 2cfb422..cbba198 100644 --- a/src/shared_ispell.h +++ b/src/shared_ispell.h @@ -44,7 +44,7 @@ typedef struct SegmentInfo LWLockId lock; char *firstfree; /* first free address (always maxaligned) */ size_t available; /* free space remaining at firstfree */ - Timestamp lastReset; /* last reset of the dictionary */ + instr_time lastReset; /* last reset of the dictionary */ /* the shared segment (info and data) */ SharedIspellDict *shdict; @@ -54,7 +54,7 @@ typedef struct SegmentInfo /* used to keep track of dictionary in each backend */ typedef struct DictInfo { - Timestamp lookup; + instr_time lookup; char dictFile[MAXLEN]; char affixFile[MAXLEN]; From bfa1978652c9e9e2d971e6e1119571e0db129b2f Mon Sep 17 00:00:00 2001 From: Arthur Zakirov Date: Fri, 2 Nov 2018 15:18:37 +0300 Subject: [PATCH 13/21] Update copyrights and license --- LICENSE | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/LICENSE b/LICENSE index 417dcbb..54e49a5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,25 +1,19 @@ -Copyright 2012, Tomas Vondra (tv@fuzzy.cz). All rights reserved. +Copyright (c) 2016-2018, Postgres Professional +Portions Copyright 2012, Tomas Vondra (tv@fuzzy.cz). All rights reserved. -Redistribution and use in source and binary forms, with or without modification, are -permitted provided that the following conditions are met: +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement +is hereby granted, provided that the above copyright notice and this +paragraph and the following two paragraphs appear in all copies. - 1. Redistributions of source code must retain the above copyright notice, this list of - conditions and the following disclaimer. +IN NO EVENT SHALL POSTGRES PROFESSIONAL BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS +DOCUMENTATION, EVEN IF POSTGRES PROFESSIONAL HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. - 2. Redistributions in binary form must reproduce the above copyright notice, this list - of conditions and the following disclaimer in the documentation and/or other materials - provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY TOMAS VONDRA ''AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOMAS VONDRA OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those of the -authors and should not be interpreted as representing official policies, either expressed -or implied, of Tomas Vondra. \ No newline at end of file +POSTGRES PROFESSIONAL SPECIFICALLY DISCLAIMS ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND POSTGRES PROFESSIONAL HAS NO OBLIGATIONS TO +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. From f0e83041ebfc5435babb1c2d60c7d6646a7dcfc8 Mon Sep 17 00:00:00 2001 From: Daria Lepikhova Date: Mon, 9 Nov 2020 15:03:50 +0500 Subject: [PATCH 14/21] Fixed security CVE_2020_14350. Added tests --- Makefile | 2 +- expected/security.out | 40 +++++++++++++++++++++++++++++++++++++ shared_ispell--1.1.0.sql | 14 ++++++------- sql/security.sql | 43 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 expected/security.out create mode 100644 sql/security.sql diff --git a/Makefile b/Makefile index 6ff9e12..15d3187 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ OBJS = src/shared_ispell.o EXTENSION = shared_ispell DATA = shared_ispell--1.1.0.sql -REGRESS = shared_ispell +REGRESS = security shared_ispell EXTRA_REGRESS_OPTS=--temp-config=$(top_srcdir)/$(subdir)/postgresql.conf diff --git a/expected/security.out b/expected/security.out new file mode 100644 index 0000000..d6522bd --- /dev/null +++ b/expected/security.out @@ -0,0 +1,40 @@ +create type si_dicts_result as (dict_name VARCHAR, affix_name VARCHAR, words INT, affixes INT, bytes INT); +create function shared_ispell_dicts( OUT dict_name VARCHAR, OUT affix_name VARCHAR, OUT words INT, OUT affixes INT, OUT bytes INT) +returns SETOF record as $$ +declare + qString varchar(4000); + rec si_dicts_result; +begin + qString := 'select * from shared_ispell_dicts()'; + for rec in execute qString loop + return NEXT; + end loop; + return; +end +$$ language plpgsql; +create extension shared_ispell; +ERROR: function "shared_ispell_dicts" already exists with same argument types +drop extension if exists shared_ispell; +NOTICE: extension "shared_ispell" does not exist, skipping +drop type si_dicts_result; +drop function shared_ispell_dicts; +create type si_stoplists_result as (stop_name VARCHAR, words INT, bytes INT); +create function shared_ispell_stoplists(OUT stop_name VARCHAR, OUT words INT, OUT bytes INT) +returns SETOF record as $$ +declare + rec si_stoplists_result; + qString varchar(4000); +begin + qString := 'select * from shared_ispell_stoplists()'; + for rec in execute qString loop + return NEXT; + end loop; + return; +end +$$ language plpgsql; +create extension shared_ispell; +ERROR: function "shared_ispell_stoplists" already exists with same argument types +drop extension if exists shared_ispell; +NOTICE: extension "shared_ispell" does not exist, skipping +drop type si_stoplists_result; +drop function shared_ispell_stoplists; diff --git a/shared_ispell--1.1.0.sql b/shared_ispell--1.1.0.sql index 07c3ac3..7f638ab 100644 --- a/shared_ispell--1.1.0.sql +++ b/shared_ispell--1.1.0.sql @@ -1,34 +1,34 @@ -CREATE OR REPLACE FUNCTION shared_ispell_init(internal) +CREATE FUNCTION shared_ispell_init(internal) RETURNS internal AS 'MODULE_PATHNAME', 'dispell_init' LANGUAGE C IMMUTABLE; -CREATE OR REPLACE FUNCTION shared_ispell_lexize(internal,internal,internal,internal) +CREATE FUNCTION shared_ispell_lexize(internal,internal,internal,internal) RETURNS internal AS 'MODULE_PATHNAME', 'dispell_lexize' LANGUAGE C IMMUTABLE; -CREATE OR REPLACE FUNCTION shared_ispell_reset() +CREATE FUNCTION shared_ispell_reset() RETURNS void AS 'MODULE_PATHNAME', 'dispell_reset' LANGUAGE C IMMUTABLE; -CREATE OR REPLACE FUNCTION shared_ispell_mem_used() +CREATE FUNCTION shared_ispell_mem_used() RETURNS integer AS 'MODULE_PATHNAME', 'dispell_mem_used' LANGUAGE C IMMUTABLE; -CREATE OR REPLACE FUNCTION shared_ispell_mem_available() +CREATE FUNCTION shared_ispell_mem_available() RETURNS integer AS 'MODULE_PATHNAME', 'dispell_mem_available' LANGUAGE C IMMUTABLE; -CREATE OR REPLACE FUNCTION shared_ispell_dicts( OUT dict_name VARCHAR, OUT affix_name VARCHAR, OUT words INT, OUT affixes INT, OUT bytes INT) +CREATE FUNCTION shared_ispell_dicts( OUT dict_name VARCHAR, OUT affix_name VARCHAR, OUT words INT, OUT affixes INT, OUT bytes INT) RETURNS SETOF record AS 'MODULE_PATHNAME', 'dispell_list_dicts' LANGUAGE C IMMUTABLE; -CREATE OR REPLACE FUNCTION shared_ispell_stoplists( OUT stop_name VARCHAR, OUT words INT, OUT bytes INT) +CREATE FUNCTION shared_ispell_stoplists( OUT stop_name VARCHAR, OUT words INT, OUT bytes INT) RETURNS SETOF record AS 'MODULE_PATHNAME', 'dispell_list_stoplists' LANGUAGE C IMMUTABLE; diff --git a/sql/security.sql b/sql/security.sql new file mode 100644 index 0000000..c29b1a5 --- /dev/null +++ b/sql/security.sql @@ -0,0 +1,43 @@ +create type si_dicts_result as (dict_name VARCHAR, affix_name VARCHAR, words INT, affixes INT, bytes INT); + +create function shared_ispell_dicts( OUT dict_name VARCHAR, OUT affix_name VARCHAR, OUT words INT, OUT affixes INT, OUT bytes INT) +returns SETOF record as $$ +declare + qString varchar(4000); + rec si_dicts_result; +begin + qString := 'select * from shared_ispell_dicts()'; + for rec in execute qString loop + return NEXT; + end loop; + return; +end +$$ language plpgsql; + +create extension shared_ispell; + +drop extension if exists shared_ispell; +drop type si_dicts_result; +drop function shared_ispell_dicts; + +create type si_stoplists_result as (stop_name VARCHAR, words INT, bytes INT); + +create function shared_ispell_stoplists(OUT stop_name VARCHAR, OUT words INT, OUT bytes INT) +returns SETOF record as $$ +declare + rec si_stoplists_result; + qString varchar(4000); +begin + qString := 'select * from shared_ispell_stoplists()'; + for rec in execute qString loop + return NEXT; + end loop; + return; +end +$$ language plpgsql; + +create extension shared_ispell; + +drop extension if exists shared_ispell; +drop type si_stoplists_result; +drop function shared_ispell_stoplists; From 8f061f79b6619bce620bfcf8d0df92b17595e3fd Mon Sep 17 00:00:00 2001 From: Daria Lepikhova Date: Wed, 11 Nov 2020 08:54:48 +0500 Subject: [PATCH 15/21] Fixed test for 9.6 --- expected/security.out | 4 ++-- sql/security.sql | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/expected/security.out b/expected/security.out index d6522bd..6f73aa1 100644 --- a/expected/security.out +++ b/expected/security.out @@ -17,7 +17,7 @@ ERROR: function "shared_ispell_dicts" already exists with same argument types drop extension if exists shared_ispell; NOTICE: extension "shared_ispell" does not exist, skipping drop type si_dicts_result; -drop function shared_ispell_dicts; +drop function shared_ispell_dicts(); create type si_stoplists_result as (stop_name VARCHAR, words INT, bytes INT); create function shared_ispell_stoplists(OUT stop_name VARCHAR, OUT words INT, OUT bytes INT) returns SETOF record as $$ @@ -37,4 +37,4 @@ ERROR: function "shared_ispell_stoplists" already exists with same argument typ drop extension if exists shared_ispell; NOTICE: extension "shared_ispell" does not exist, skipping drop type si_stoplists_result; -drop function shared_ispell_stoplists; +drop function shared_ispell_stoplists(); diff --git a/sql/security.sql b/sql/security.sql index c29b1a5..33a09e1 100644 --- a/sql/security.sql +++ b/sql/security.sql @@ -18,7 +18,7 @@ create extension shared_ispell; drop extension if exists shared_ispell; drop type si_dicts_result; -drop function shared_ispell_dicts; +drop function shared_ispell_dicts(); create type si_stoplists_result as (stop_name VARCHAR, words INT, bytes INT); @@ -40,4 +40,4 @@ create extension shared_ispell; drop extension if exists shared_ispell; drop type si_stoplists_result; -drop function shared_ispell_stoplists; +drop function shared_ispell_stoplists(); From be086277d4fde7fbb5830cecdcfb127732931f5f Mon Sep 17 00:00:00 2001 From: Ivan Panchenko Date: Fri, 23 Apr 2021 07:22:29 +0300 Subject: [PATCH 16/21] Updated PostgreSQL version info --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d78c5aa..9f9b6d8 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Install Before build and install `shared_ispell` you should ensure following: -* PostgreSQL version is 9.6 or 10. +* PostgreSQL version is 9.6 or later. Installing the extension is quite simple. In that case all you need to do is this: From 64b5868f0e831cb07e46fe02a81db7edd16b9b57 Mon Sep 17 00:00:00 2001 From: Anton Voloshin Date: Wed, 20 Jul 2022 12:28:46 +0300 Subject: [PATCH 17/21] adapt shared_ispell for upcoming PostgreSQL 15 1. Only call RequestAddinShmemSpace and RequestNamedLWLockTranche from within our implementation of shmem_request_hook (as required after commit 4f2400cb3 in PostgreSQL 15). 2. While we are here, remove _PG_fini, as it is now officially dead after commit ab02d702e in PostgreSQL 15. --- src/shared_ispell.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/shared_ispell.c b/src/shared_ispell.c index cbf78ae..04587fd 100644 --- a/src/shared_ispell.c +++ b/src/shared_ispell.c @@ -66,12 +66,11 @@ PG_MODULE_MAGIC; void _PG_init(void); -void _PG_fini(void); /* Memory for dictionaries in kbytes */ static int max_ispell_mem_size_kb; -/* Saved hook values in case of unload */ +/* Saved hook value for proper chaining */ static shmem_startup_hook_type prev_shmem_startup_hook = NULL; /* These are used to allocate data within shared segment */ @@ -97,6 +96,11 @@ max_ispell_mem_size() return (Size) max_ispell_mem_size_kb * 1024L; } +#if (PG_VERSION_NUM >= 150000) +static shmem_request_hook_type prev_shmem_request_hook = NULL; +static void shared_ispell_shmem_request(void); +#endif + /* * Module load callback */ @@ -127,17 +131,17 @@ _PG_init(void) EmitWarningsOnPlaceholders("shared_ispell"); - /* - * Request additional shared resources. (These are no-ops if we're not in - * the postmaster process.) We'll allocate or attach to the shared - * resources in ispell_shmem_startup(). - */ +#if PG_VERSION_NUM >= 150000 + prev_shmem_request_hook = shmem_request_hook; + shmem_request_hook = shared_ispell_shmem_request; +#else RequestAddinShmemSpace(max_ispell_mem_size()); #if PG_VERSION_NUM >= 90600 RequestNamedLWLockTranche("shared_ispell", 1); #else RequestAddinLWLocks(1); +#endif #endif /* Install hooks. */ @@ -145,15 +149,15 @@ _PG_init(void) shmem_startup_hook = ispell_shmem_startup; } - -/* - * Module unload callback - */ -void -_PG_fini(void) +static void +shared_ispell_shmem_request(void) { - /* Uninstall hooks. */ - shmem_startup_hook = prev_shmem_startup_hook; + if (prev_shmem_request_hook) + prev_shmem_request_hook(); + + RequestAddinShmemSpace(max_ispell_mem_size()); + + RequestNamedLWLockTranche("shared_ispell", 1); } /* From 8b3f4d463ea00618ca6e73a354b9293f711a0331 Mon Sep 17 00:00:00 2001 From: Yura Sokolov Date: Mon, 8 Aug 2022 12:37:31 +0300 Subject: [PATCH 18/21] fix compilation on pre-15 --- src/shared_ispell.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shared_ispell.c b/src/shared_ispell.c index 04587fd..95a8b9d 100644 --- a/src/shared_ispell.c +++ b/src/shared_ispell.c @@ -149,6 +149,7 @@ _PG_init(void) shmem_startup_hook = ispell_shmem_startup; } +#if PG_VERSION_NUM >= 150000 static void shared_ispell_shmem_request(void) { @@ -159,6 +160,7 @@ shared_ispell_shmem_request(void) RequestNamedLWLockTranche("shared_ispell", 1); } +#endif /* * Probably the most important part of the startup - initializes the From 39ecfe635327ecad41504ea31495f9965e9671b3 Mon Sep 17 00:00:00 2001 From: Marina Polyakova Date: Fri, 18 Nov 2022 08:27:38 +0300 Subject: [PATCH 19/21] Fix build due to new changes in PostgreSQL 16 --- src/shared_ispell.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared_ispell.c b/src/shared_ispell.c index 95a8b9d..4fac4fb 100644 --- a/src/shared_ispell.c +++ b/src/shared_ispell.c @@ -59,6 +59,7 @@ #include "access/htup_details.h" #include "funcapi.h" #include "utils/builtins.h" +#include "utils/guc.h" #include "shared_ispell.h" #include "tsearch/dicts/spell.h" From b580a8256f87b8fdf3406eeac465a7d1f82235c2 Mon Sep 17 00:00:00 2001 From: Marina Polyakova Date: Wed, 24 Jan 2024 10:15:55 +0300 Subject: [PATCH 20/21] Retire MemoryContextResetAndDeleteChildren() macro. Caused by the following commits in PostgreSQL: - eaa5808e8ec4e82ce1a87103a6b6f687666e4e4c (PostgreSQL 9.5) Redefine MemoryContextReset() as deleting, not resetting, child contexts. - 6a72c42fd5af7ada49584694f543eb06dddb4a87 (PostgreSQL 17) Retire MemoryContextResetAndDeleteChildren() macro. --- src/shared_ispell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared_ispell.c b/src/shared_ispell.c index 4fac4fb..37243e2 100644 --- a/src/shared_ispell.c +++ b/src/shared_ispell.c @@ -633,7 +633,7 @@ dispell_lexize(PG_FUNCTION_ARGS) * info here */ - MemoryContextResetAndDeleteChildren(saveInfo.infoCntx); + MemoryContextReset(saveInfo.infoCntx); MemSet(info, 0, sizeof(*info)); init_shared_dict(info, saveInfo.infoCntx, saveInfo.dictFile, From 4a9dce8c7d6806ee7c01dfbf5fdd8fe7a05a3083 Mon Sep 17 00:00:00 2001 From: Zharkov Roman Date: Tue, 21 Jan 2025 16:54:13 +0300 Subject: [PATCH 21/21] Add meson.build file to support building from the contrib source tree. --- meson.build | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 meson.build diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..0f07821 --- /dev/null +++ b/meson.build @@ -0,0 +1,39 @@ +# Copyright (c) 2025, Postgres Professional + +# Does not support the PGXS infrastructure at this time. Please, compile as part +# of the contrib source tree. + +shared_ispell_sources = files( + 'src' / 'shared_ispell.c' +) + +if host_system == 'windows' + shared_ispell_sources += rc_lib_gen.process(win32ver_rc, extra_args: [ + '--NAME', 'shared_ispell', + '--FILEDESC', 'shared_ispell - provides a shared ispell dictionary, i.e. a dictionary that\'s stored in shared segment.',]) +endif + +shared_ispell = shared_module('shared_ispell', + shared_ispell_sources, + kwargs: contrib_mod_args, +) +contrib_targets += shared_ispell + +install_data( + 'shared_ispell.control', + 'shared_ispell--1.1.0.sql', + kwargs: contrib_data_args, +) + +tests += { + 'name': 'shared_ispell', + 'sd': meson.current_source_dir(), + 'bd': meson.current_build_dir(), + 'regress': { + 'sql': [ + 'security', + 'shared_ispell', + ], + 'regress_args': ['--temp-config', files('postgresql.conf')], + }, +}