Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4d0e8a0

Browse files
committed
Fix various issues with ALTER TEXT SEARCH CONFIGURATION
This commit addresses a set of issues when changing token type mappingsin a text search configuration when using duplicated token names:- ADD MAPPING would fail on insertion because of a constraint failureafter inserting the same mapping.- ALTER MAPPING with an "overridden" configuration failed with "tuplealready updated by self" when the token mappings are removed.- DROP MAPPING failed with "tuple already updated by self", likepreviously, but in a different code path.The code is refactored so the token names (with their numbers) arehandled as a List with unique members rather than an array with numbers,ensuring that no duplicates mess up with the catalog inserts, updatesand deletes. The list is generated by getTokenTypes(), with the sameerror handling as previously while duplicated tokens are discarded fromthe list used to work on the catalogs.Regression tests are expanded to cover much more ground for the casesfixed by this commit, as there was no coverage for the code touched inthis commit. A bit more is done regarding the fact that a token namenot supported by a configuration's parser should result in an error evenif IF EXISTS is used in a DROP MAPPING clause. This is implied in thecode but there was no coverage for that, and it was very easy to miss.These issues exist since at least their introduction in core with140d4eb, so backpatch all the way down.Reported-by: Alexander LakhinAuthor: Tender Wang, Michael PaquierDiscussion:https://postgr.es/m/18310-1eb233c5908189c8@postgresql.orgBackpatch-through: 12
1 parent4c14225 commit4d0e8a0

File tree

4 files changed

+130
-30
lines changed

4 files changed

+130
-30
lines changed

‎src/backend/commands/tsearchcmds.c

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@
4848
#include"utils/rel.h"
4949
#include"utils/syscache.h"
5050

51+
/* Single entry of List returned by getTokenTypes() */
52+
typedefstruct
53+
{
54+
intnum;/* token type number */
55+
char*name;/* token type name */
56+
}TSTokenTypeItem;
5157

5258
staticvoidMakeConfigurationMapping(AlterTSConfigurationStmt*stmt,
5359
HeapTupletup,RelationrelMap);
@@ -1224,22 +1230,45 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
12241230
}
12251231

12261232
/*
1227-
*Translate a list oftoken typenames to an array oftoken type numbers
1233+
*Check whether atoken typename is a member ofa TSTokenTypeItem list.
12281234
*/
1229-
staticint*
1235+
staticbool
1236+
tstoken_list_member(char*token_name,List*tokens)
1237+
{
1238+
ListCell*c;
1239+
boolfound= false;
1240+
1241+
foreach(c,tokens)
1242+
{
1243+
TSTokenTypeItem*ts= (TSTokenTypeItem*)lfirst(c);
1244+
1245+
if (strcmp(token_name,ts->name)==0)
1246+
{
1247+
found= true;
1248+
break;
1249+
}
1250+
}
1251+
1252+
returnfound;
1253+
}
1254+
1255+
/*
1256+
* Translate a list of token type names to a list of unique TSTokenTypeItem.
1257+
*
1258+
* Duplicated entries list are removed from tokennames.
1259+
*/
1260+
staticList*
12301261
getTokenTypes(OidprsId,List*tokennames)
12311262
{
12321263
TSParserCacheEntry*prs=lookup_ts_parser_cache(prsId);
12331264
LexDescr*list;
1234-
int*res,
1235-
i,
1236-
ntoken;
1265+
List*result=NIL;
1266+
intntoken;
12371267
ListCell*tn;
12381268

12391269
ntoken=list_length(tokennames);
12401270
if (ntoken==0)
1241-
returnNULL;
1242-
res= (int*)palloc(sizeof(int)*ntoken);
1271+
returnNIL;
12431272

12441273
if (!OidIsValid(prs->lextypeOid))
12451274
elog(ERROR,"method lextype isn't defined for text search parser %u",
@@ -1249,19 +1278,26 @@ getTokenTypes(Oid prsId, List *tokennames)
12491278
list= (LexDescr*)DatumGetPointer(OidFunctionCall1(prs->lextypeOid,
12501279
(Datum)0));
12511280

1252-
i=0;
12531281
foreach(tn,tokennames)
12541282
{
12551283
Value*val= (Value*)lfirst(tn);
12561284
boolfound= false;
12571285
intj;
12581286

1287+
/* Skip if this token is already in the result */
1288+
if (tstoken_list_member(strVal(val),result))
1289+
continue;
1290+
12591291
j=0;
12601292
while (list&&list[j].lexid)
12611293
{
12621294
if (strcmp(strVal(val),list[j].alias)==0)
12631295
{
1264-
res[i]=list[j].lexid;
1296+
TSTokenTypeItem*ts= (TSTokenTypeItem*)palloc0(sizeof(TSTokenTypeItem));
1297+
1298+
ts->num=list[j].lexid;
1299+
ts->name=pstrdup(strVal(val));
1300+
result=lappend(result,ts);
12651301
found= true;
12661302
break;
12671303
}
@@ -1272,10 +1308,9 @@ getTokenTypes(Oid prsId, List *tokennames)
12721308
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
12731309
errmsg("token type \"%s\" does not exist",
12741310
strVal(val))));
1275-
i++;
12761311
}
12771312

1278-
returnres;
1313+
returnresult;
12791314
}
12801315

12811316
/*
@@ -1293,8 +1328,7 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
12931328
inti;
12941329
intj;
12951330
OidprsId;
1296-
int*tokens,
1297-
ntoken;
1331+
List*tokens=NIL;
12981332
Oid*dictIds;
12991333
intndict;
13001334
ListCell*c;
@@ -1304,23 +1338,24 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
13041338
prsId=tsform->cfgparser;
13051339

13061340
tokens=getTokenTypes(prsId,stmt->tokentype);
1307-
ntoken=list_length(stmt->tokentype);
13081341

13091342
if (stmt->override)
13101343
{
13111344
/*
13121345
* delete maps for tokens if they exist and command was ALTER
13131346
*/
1314-
for (i=0;i<ntoken;i++)
1347+
foreach(c,tokens)
13151348
{
1349+
TSTokenTypeItem*ts= (TSTokenTypeItem*)lfirst(c);
1350+
13161351
ScanKeyInit(&skey[0],
13171352
Anum_pg_ts_config_map_mapcfg,
13181353
BTEqualStrategyNumber,F_OIDEQ,
13191354
ObjectIdGetDatum(cfgId));
13201355
ScanKeyInit(&skey[1],
13211356
Anum_pg_ts_config_map_maptokentype,
13221357
BTEqualStrategyNumber,F_INT4EQ,
1323-
Int32GetDatum(tokens[i]));
1358+
Int32GetDatum(ts->num));
13241359

13251360
scan=systable_beginscan(relMap,TSConfigMapIndexId, true,
13261361
NULL,2,skey);
@@ -1375,9 +1410,11 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
13751410
{
13761411
booltokmatch= false;
13771412

1378-
for (j=0;j<ntoken;j++)
1413+
foreach(c,tokens)
13791414
{
1380-
if (cfgmap->maptokentype==tokens[j])
1415+
TSTokenTypeItem*ts= (TSTokenTypeItem*)lfirst(c);
1416+
1417+
if (cfgmap->maptokentype==ts->num)
13811418
{
13821419
tokmatch= true;
13831420
break;
@@ -1418,16 +1455,18 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
14181455
/*
14191456
* Insertion of new entries
14201457
*/
1421-
for (i=0;i<ntoken;i++)
1458+
foreach(c,tokens)
14221459
{
1460+
TSTokenTypeItem*ts= (TSTokenTypeItem*)lfirst(c);
1461+
14231462
for (j=0;j<ndict;j++)
14241463
{
14251464
Datumvalues[Natts_pg_ts_config_map];
14261465
boolnulls[Natts_pg_ts_config_map];
14271466

14281467
memset(nulls, false,sizeof(nulls));
14291468
values[Anum_pg_ts_config_map_mapcfg-1]=ObjectIdGetDatum(cfgId);
1430-
values[Anum_pg_ts_config_map_maptokentype-1]=Int32GetDatum(tokens[i]);
1469+
values[Anum_pg_ts_config_map_maptokentype-1]=Int32GetDatum(ts->num);
14311470
values[Anum_pg_ts_config_map_mapseqno-1]=Int32GetDatum(j+1);
14321471
values[Anum_pg_ts_config_map_mapdict-1]=ObjectIdGetDatum(dictIds[j]);
14331472

@@ -1454,9 +1493,8 @@ DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
14541493
ScanKeyDataskey[2];
14551494
SysScanDescscan;
14561495
HeapTuplemaptup;
1457-
inti;
14581496
OidprsId;
1459-
int*tokens;
1497+
List*tokens=NIL;
14601498
ListCell*c;
14611499

14621500
tsform= (Form_pg_ts_config)GETSTRUCT(tup);
@@ -1465,10 +1503,9 @@ DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
14651503

14661504
tokens=getTokenTypes(prsId,stmt->tokentype);
14671505

1468-
i=0;
1469-
foreach(c,stmt->tokentype)
1506+
foreach(c,tokens)
14701507
{
1471-
Value*val= (Value*)lfirst(c);
1508+
TSTokenTypeItem*ts= (TSTokenTypeItem*)lfirst(c);
14721509
boolfound= false;
14731510

14741511
ScanKeyInit(&skey[0],
@@ -1478,7 +1515,7 @@ DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
14781515
ScanKeyInit(&skey[1],
14791516
Anum_pg_ts_config_map_maptokentype,
14801517
BTEqualStrategyNumber,F_INT4EQ,
1481-
Int32GetDatum(tokens[i]));
1518+
Int32GetDatum(ts->num));
14821519

14831520
scan=systable_beginscan(relMap,TSConfigMapIndexId, true,
14841521
NULL,2,skey);
@@ -1498,17 +1535,15 @@ DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
14981535
ereport(ERROR,
14991536
(errcode(ERRCODE_UNDEFINED_OBJECT),
15001537
errmsg("mapping for token type \"%s\" does not exist",
1501-
strVal(val))));
1538+
ts->name)));
15021539
}
15031540
else
15041541
{
15051542
ereport(NOTICE,
15061543
(errmsg("mapping for token type \"%s\" does not exist, skipping",
1507-
strVal(val))));
1544+
ts->name)));
15081545
}
15091546
}
1510-
1511-
i++;
15121547
}
15131548

15141549
EventTriggerCollectAlterTSConfig(stmt,cfgId,NULL,0);

‎src/test/regress/expected/tsdicts.out

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,3 +687,37 @@ CREATE TEXT SEARCH DICTIONARY tsdict_case
687687
"AffFile" = ispell_sample
688688
);
689689
ERROR: unrecognized Ispell parameter: "DictFile"
690+
-- Test grammar for configurations
691+
CREATE TEXT SEARCH CONFIGURATION dummy_tst (COPY=english);
692+
-- Overriden mapping change with duplicated tokens.
693+
ALTER TEXT SEARCH CONFIGURATION dummy_tst
694+
ALTER MAPPING FOR word, word WITH ispell;
695+
-- Not a token supported by the configuration's parser, fails.
696+
ALTER TEXT SEARCH CONFIGURATION dummy_tst
697+
DROP MAPPING FOR not_a_token, not_a_token;
698+
ERROR: token type "not_a_token" does not exist
699+
-- Not a token supported by the configuration's parser, fails even
700+
-- with IF EXISTS.
701+
ALTER TEXT SEARCH CONFIGURATION dummy_tst
702+
DROP MAPPING IF EXISTS FOR not_a_token, not_a_token;
703+
ERROR: token type "not_a_token" does not exist
704+
-- Token supported by the configuration's parser, succeeds.
705+
ALTER TEXT SEARCH CONFIGURATION dummy_tst
706+
DROP MAPPING FOR word, word;
707+
-- No mapping for token supported by the configuration's parser, fails.
708+
ALTER TEXT SEARCH CONFIGURATION dummy_tst
709+
DROP MAPPING FOR word;
710+
ERROR: mapping for token type "word" does not exist
711+
-- Token supported by the configuration's parser, cannot be found,
712+
-- succeeds with IF EXISTS.
713+
ALTER TEXT SEARCH CONFIGURATION dummy_tst
714+
DROP MAPPING IF EXISTS FOR word, word;
715+
NOTICE: mapping for token type "word" does not exist, skipping
716+
-- Re-add mapping, with duplicated tokens supported by the parser.
717+
ALTER TEXT SEARCH CONFIGURATION dummy_tst
718+
ADD MAPPING FOR word, word WITH ispell;
719+
-- Not a token supported by the configuration's parser, fails.
720+
ALTER TEXT SEARCH CONFIGURATION dummy_tst
721+
ADD MAPPING FOR not_a_token WITH ispell;
722+
ERROR: token type "not_a_token" does not exist
723+
DROP TEXT SEARCH CONFIGURATION dummy_tst;

‎src/test/regress/sql/tsdicts.sql

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,33 @@ CREATE TEXT SEARCH DICTIONARY tsdict_case
251251
"DictFile"= ispell_sample,
252252
"AffFile"= ispell_sample
253253
);
254+
255+
-- Test grammar for configurations
256+
CREATETEXT SEARCH CONFIGURATION dummy_tst (COPY=english);
257+
-- Overriden mapping change with duplicated tokens.
258+
ALTERTEXT SEARCH CONFIGURATION dummy_tst
259+
ALTER MAPPING FOR word, word WITH ispell;
260+
-- Not a token supported by the configuration's parser, fails.
261+
ALTERTEXT SEARCH CONFIGURATION dummy_tst
262+
DROP MAPPING FOR not_a_token, not_a_token;
263+
-- Not a token supported by the configuration's parser, fails even
264+
-- with IF EXISTS.
265+
ALTERTEXT SEARCH CONFIGURATION dummy_tst
266+
DROP MAPPING IF EXISTS FOR not_a_token, not_a_token;
267+
-- Token supported by the configuration's parser, succeeds.
268+
ALTERTEXT SEARCH CONFIGURATION dummy_tst
269+
DROP MAPPING FOR word, word;
270+
-- No mapping for token supported by the configuration's parser, fails.
271+
ALTERTEXT SEARCH CONFIGURATION dummy_tst
272+
DROP MAPPING FOR word;
273+
-- Token supported by the configuration's parser, cannot be found,
274+
-- succeeds with IF EXISTS.
275+
ALTERTEXT SEARCH CONFIGURATION dummy_tst
276+
DROP MAPPING IF EXISTS FOR word, word;
277+
-- Re-add mapping, with duplicated tokens supported by the parser.
278+
ALTERTEXT SEARCH CONFIGURATION dummy_tst
279+
ADD MAPPING FOR word, word WITH ispell;
280+
-- Not a token supported by the configuration's parser, fails.
281+
ALTERTEXT SEARCH CONFIGURATION dummy_tst
282+
ADD MAPPING FOR not_a_token WITH ispell;
283+
DROPTEXT SEARCH CONFIGURATION dummy_tst;

‎src/tools/pgindent/typedefs.list

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2447,6 +2447,7 @@ TSQuerySign
24472447
TSReadPointer
24482448
TSTemplateInfo
24492449
TSTernaryValue
2450+
TSTokenTypeItem
24502451
TSTokenTypeStorage
24512452
TSVector
24522453
TSVectorBuildState

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp