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

Commitdde5b01

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 parent2acba01 commitdde5b01

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);
@@ -1151,22 +1157,45 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
11511157
}
11521158

11531159
/*
1154-
*Translate a list oftoken typenames to an array oftoken type numbers
1160+
*Check whether atoken typename is a member ofa TSTokenTypeItem list.
11551161
*/
1156-
staticint*
1162+
staticbool
1163+
tstoken_list_member(char*token_name,List*tokens)
1164+
{
1165+
ListCell*c;
1166+
boolfound= false;
1167+
1168+
foreach(c,tokens)
1169+
{
1170+
TSTokenTypeItem*ts= (TSTokenTypeItem*)lfirst(c);
1171+
1172+
if (strcmp(token_name,ts->name)==0)
1173+
{
1174+
found= true;
1175+
break;
1176+
}
1177+
}
1178+
1179+
returnfound;
1180+
}
1181+
1182+
/*
1183+
* Translate a list of token type names to a list of unique TSTokenTypeItem.
1184+
*
1185+
* Duplicated entries list are removed from tokennames.
1186+
*/
1187+
staticList*
11571188
getTokenTypes(OidprsId,List*tokennames)
11581189
{
11591190
TSParserCacheEntry*prs=lookup_ts_parser_cache(prsId);
11601191
LexDescr*list;
1161-
int*res,
1162-
i,
1163-
ntoken;
1192+
List*result=NIL;
1193+
intntoken;
11641194
ListCell*tn;
11651195

11661196
ntoken=list_length(tokennames);
11671197
if (ntoken==0)
1168-
returnNULL;
1169-
res= (int*)palloc(sizeof(int)*ntoken);
1198+
returnNIL;
11701199

11711200
if (!OidIsValid(prs->lextypeOid))
11721201
elog(ERROR,"method lextype isn't defined for text search parser %u",
@@ -1176,19 +1205,26 @@ getTokenTypes(Oid prsId, List *tokennames)
11761205
list= (LexDescr*)DatumGetPointer(OidFunctionCall1(prs->lextypeOid,
11771206
(Datum)0));
11781207

1179-
i=0;
11801208
foreach(tn,tokennames)
11811209
{
11821210
Value*val= (Value*)lfirst(tn);
11831211
boolfound= false;
11841212
intj;
11851213

1214+
/* Skip if this token is already in the result */
1215+
if (tstoken_list_member(strVal(val),result))
1216+
continue;
1217+
11861218
j=0;
11871219
while (list&&list[j].lexid)
11881220
{
11891221
if (strcmp(strVal(val),list[j].alias)==0)
11901222
{
1191-
res[i]=list[j].lexid;
1223+
TSTokenTypeItem*ts= (TSTokenTypeItem*)palloc0(sizeof(TSTokenTypeItem));
1224+
1225+
ts->num=list[j].lexid;
1226+
ts->name=pstrdup(strVal(val));
1227+
result=lappend(result,ts);
11921228
found= true;
11931229
break;
11941230
}
@@ -1199,10 +1235,9 @@ getTokenTypes(Oid prsId, List *tokennames)
11991235
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
12001236
errmsg("token type \"%s\" does not exist",
12011237
strVal(val))));
1202-
i++;
12031238
}
12041239

1205-
returnres;
1240+
returnresult;
12061241
}
12071242

12081243
/*
@@ -1220,8 +1255,7 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
12201255
inti;
12211256
intj;
12221257
OidprsId;
1223-
int*tokens,
1224-
ntoken;
1258+
List*tokens=NIL;
12251259
Oid*dictIds;
12261260
intndict;
12271261
ListCell*c;
@@ -1231,23 +1265,24 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
12311265
prsId=tsform->cfgparser;
12321266

12331267
tokens=getTokenTypes(prsId,stmt->tokentype);
1234-
ntoken=list_length(stmt->tokentype);
12351268

12361269
if (stmt->override)
12371270
{
12381271
/*
12391272
* delete maps for tokens if they exist and command was ALTER
12401273
*/
1241-
for (i=0;i<ntoken;i++)
1274+
foreach(c,tokens)
12421275
{
1276+
TSTokenTypeItem*ts= (TSTokenTypeItem*)lfirst(c);
1277+
12431278
ScanKeyInit(&skey[0],
12441279
Anum_pg_ts_config_map_mapcfg,
12451280
BTEqualStrategyNumber,F_OIDEQ,
12461281
ObjectIdGetDatum(cfgId));
12471282
ScanKeyInit(&skey[1],
12481283
Anum_pg_ts_config_map_maptokentype,
12491284
BTEqualStrategyNumber,F_INT4EQ,
1250-
Int32GetDatum(tokens[i]));
1285+
Int32GetDatum(ts->num));
12511286

12521287
scan=systable_beginscan(relMap,TSConfigMapIndexId, true,
12531288
NULL,2,skey);
@@ -1302,9 +1337,11 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
13021337
{
13031338
booltokmatch= false;
13041339

1305-
for (j=0;j<ntoken;j++)
1340+
foreach(c,tokens)
13061341
{
1307-
if (cfgmap->maptokentype==tokens[j])
1342+
TSTokenTypeItem*ts= (TSTokenTypeItem*)lfirst(c);
1343+
1344+
if (cfgmap->maptokentype==ts->num)
13081345
{
13091346
tokmatch= true;
13101347
break;
@@ -1345,16 +1382,18 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
13451382
/*
13461383
* Insertion of new entries
13471384
*/
1348-
for (i=0;i<ntoken;i++)
1385+
foreach(c,tokens)
13491386
{
1387+
TSTokenTypeItem*ts= (TSTokenTypeItem*)lfirst(c);
1388+
13501389
for (j=0;j<ndict;j++)
13511390
{
13521391
Datumvalues[Natts_pg_ts_config_map];
13531392
boolnulls[Natts_pg_ts_config_map];
13541393

13551394
memset(nulls, false,sizeof(nulls));
13561395
values[Anum_pg_ts_config_map_mapcfg-1]=ObjectIdGetDatum(cfgId);
1357-
values[Anum_pg_ts_config_map_maptokentype-1]=Int32GetDatum(tokens[i]);
1396+
values[Anum_pg_ts_config_map_maptokentype-1]=Int32GetDatum(ts->num);
13581397
values[Anum_pg_ts_config_map_mapseqno-1]=Int32GetDatum(j+1);
13591398
values[Anum_pg_ts_config_map_mapdict-1]=ObjectIdGetDatum(dictIds[j]);
13601399

@@ -1381,9 +1420,8 @@ DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
13811420
ScanKeyDataskey[2];
13821421
SysScanDescscan;
13831422
HeapTuplemaptup;
1384-
inti;
13851423
OidprsId;
1386-
int*tokens;
1424+
List*tokens=NIL;
13871425
ListCell*c;
13881426

13891427
tsform= (Form_pg_ts_config)GETSTRUCT(tup);
@@ -1392,10 +1430,9 @@ DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
13921430

13931431
tokens=getTokenTypes(prsId,stmt->tokentype);
13941432

1395-
i=0;
1396-
foreach(c,stmt->tokentype)
1433+
foreach(c,tokens)
13971434
{
1398-
Value*val= (Value*)lfirst(c);
1435+
TSTokenTypeItem*ts= (TSTokenTypeItem*)lfirst(c);
13991436
boolfound= false;
14001437

14011438
ScanKeyInit(&skey[0],
@@ -1405,7 +1442,7 @@ DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
14051442
ScanKeyInit(&skey[1],
14061443
Anum_pg_ts_config_map_maptokentype,
14071444
BTEqualStrategyNumber,F_INT4EQ,
1408-
Int32GetDatum(tokens[i]));
1445+
Int32GetDatum(ts->num));
14091446

14101447
scan=systable_beginscan(relMap,TSConfigMapIndexId, true,
14111448
NULL,2,skey);
@@ -1425,17 +1462,15 @@ DropConfigurationMapping(AlterTSConfigurationStmt *stmt,
14251462
ereport(ERROR,
14261463
(errcode(ERRCODE_UNDEFINED_OBJECT),
14271464
errmsg("mapping for token type \"%s\" does not exist",
1428-
strVal(val))));
1465+
ts->name)));
14291466
}
14301467
else
14311468
{
14321469
ereport(NOTICE,
14331470
(errmsg("mapping for token type \"%s\" does not exist, skipping",
1434-
strVal(val))));
1471+
ts->name)));
14351472
}
14361473
}
1437-
1438-
i++;
14391474
}
14401475

14411476
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
@@ -2594,6 +2594,7 @@ TSQuerySign
25942594
TSReadPointer
25952595
TSTemplateInfo
25962596
TSTernaryValue
2597+
TSTokenTypeItem
25972598
TSTokenTypeStorage
25982599
TSVector
25992600
TSVectorBuildState

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp