From 1a6c6b0265b9cff4ca38baa672dd825e2ab7bde1 Mon Sep 17 00:00:00 2001
From: Ewan Young <kdbase.hack@gmail.com>
Date: Tue, 25 Aug 2026 02:51:54 +0800
Subject: [PATCH v1 2/2] Drop the per-entry copy of the flag mode in
 CompoundAffixFlags

Each CompoundAffixFlag carried its own copy of the dictionary's flag
mode, which decides whether the union holds a string or an integer.  The
comment on the field explained why: cmpcmdflag() needs the mode, and at
the time there was no bsearch() variant that could be passed a context
pointer.  bsearch_arg() has existed since bfa2cee7841, so the copies can
go away and the mode can be taken from the dictionary itself, where it
belongs.  Since every entry necessarily agreed with Conf->flagMode once
the flags are converted in one place, the copies were pure redundancy,
and the Assert() that checked they agreed can go as well.

No functional change.  sizeof(CompoundAffixFlag) is unchanged, the struct
is used only while a dictionary is being built, and it is private to
spell.c and its header.
---
 src/backend/tsearch/spell.c       | 22 +++++++++-------------
 src/include/tsearch/dicts/spell.h |  6 ++----
 2 files changed, 11 insertions(+), 17 deletions(-)

diff --git a/src/backend/tsearch/spell.c b/src/backend/tsearch/spell.c
index 0e2b4f91390..3a922dfa22b 100644
--- a/src/backend/tsearch/spell.c
+++ b/src/backend/tsearch/spell.c
@@ -208,14 +208,13 @@ cmpspellaffix(const void *s1, const void *s2)
 }
 
 static int
-cmpcmdflag(const void *f1, const void *f2)
+cmpcmdflag(const void *f1, const void *f2, void *arg)
 {
 	const CompoundAffixFlag *fv1 = f1;
 	const CompoundAffixFlag *fv2 = f2;
+	FlagMode	flagMode = *(const FlagMode *) arg;
 
-	Assert(fv1->flagMode == fv2->flagMode);
-
-	if (fv1->flagMode == FM_NUM)
+	if (flagMode == FM_NUM)
 	{
 		if (fv1->flag.i == fv2->flag.i)
 			return 0;
@@ -1071,7 +1070,6 @@ setCompoundAffixFlagValue(IspellDict *Conf, CompoundAffixFlag *entry,
 	else
 		entry->flag.s = cpstrdup(Conf, s);
 
-	entry->flagMode = Conf->flagMode;
 	entry->value = val;
 }
 
@@ -1135,7 +1133,7 @@ addCompoundAffixFlagValue(IspellDict *Conf, const char *s, uint32 val)
 	 * how flags are spelled may appear anywhere in the affix file, including
 	 * after the compound flags themselves, so the final representation cannot
 	 * be chosen until the whole file has been read.  See
-	 * finalizeCompoundAffixFlags(), which fills in flagMode as well.
+	 * finalizeCompoundAffixFlags().
 	 *
 	 * The interim copy goes in the short-lived build context, since the final
 	 * representation may well not be a string at all.
@@ -1173,8 +1171,6 @@ finalizeCompoundAffixFlags(IspellDict *Conf)
 			entry->flag.i = parseNumericAffixFlag(entry->flag.s);
 		else
 			entry->flag.s = cpstrdup(Conf, entry->flag.s);
-
-		entry->flagMode = Conf->flagMode;
 	}
 }
 
@@ -1201,9 +1197,9 @@ getCompoundAffixFlagValue(IspellDict *Conf, const char *s)
 		setCompoundAffixFlagValue(Conf, &key, sflag, 0);
 
 		found = (CompoundAffixFlag *)
-			bsearch(&key, Conf->CompoundAffixFlags,
-					Conf->nCompoundAffixFlag, sizeof(CompoundAffixFlag),
-					cmpcmdflag);
+			bsearch_arg(&key, Conf->CompoundAffixFlags,
+						Conf->nCompoundAffixFlag, sizeof(CompoundAffixFlag),
+						cmpcmdflag, &Conf->flagMode);
 		if (found != NULL)
 			flag |= found->value;
 	}
@@ -1358,8 +1354,8 @@ NIImportOOAffixes(IspellDict *Conf, const char *filename)
 	finalizeCompoundAffixFlags(Conf);
 
 	if (Conf->nCompoundAffixFlag > 1)
-		qsort(Conf->CompoundAffixFlags, Conf->nCompoundAffixFlag,
-			  sizeof(CompoundAffixFlag), cmpcmdflag);
+		qsort_arg(Conf->CompoundAffixFlags, Conf->nCompoundAffixFlag,
+				  sizeof(CompoundAffixFlag), cmpcmdflag, &Conf->flagMode);
 
 	if (!tsearch_readline_begin(&trst, filename))
 		ereport(ERROR,
diff --git a/src/include/tsearch/dicts/spell.h b/src/include/tsearch/dicts/spell.h
index 038b4384fb4..92ae1f35c59 100644
--- a/src/include/tsearch/dicts/spell.h
+++ b/src/include/tsearch/dicts/spell.h
@@ -169,13 +169,11 @@ typedef struct CompoundAffixFlag
 {
 	union
 	{
-		/* Flag name if flagMode is FM_CHAR or FM_LONG */
+		/* Flag name if the dictionary's flagMode is FM_CHAR or FM_LONG */
 		const char *s;
-		/* Flag name if flagMode is FM_NUM */
+		/* Flag name if the dictionary's flagMode is FM_NUM */
 		uint32		i;
 	}			flag;
-	/* we don't have a bsearch_arg version, so, copy FlagMode */
-	FlagMode	flagMode;
 	uint32		value;
 } CompoundAffixFlag;
 
-- 
2.47.3

