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

Commit7cce159

Browse files
committed
Fix handling of expressions and predicates in REINDEX CONCURRENTLY
When copying the definition of an index rebuilt concurrently for the newentry, the index information was taken directly from the old index usingthe relation cache. In this case, predicates and expressions havesome post-processing to prepare things for the planner, which loses someinformation including the collations added in any of them.This inconsistency can cause issues when attempting for example a tablerewrite, and makes the new indexes rebuilt concurrently inconsistentwith the old entries.In order to fix the problem, fetch expressions and predicates directlyfrom the catalog of the old entry, and fill in IndexInfo for the newindex with that. This makes the process more consistent withDefineIndex(), and the code is refactored with the addition of a routineto create an IndexInfo node.Reported-by: Manuel RiggerAuthor: Michael PaquierDiscussion:https://postgr.es/m/CA+u7OA5Hp0ra235F3czPom_FyAd-3+XwSJmX95r1+sRPOJc9VQ@mail.gmail.comBackpatch-through: 12
1 parenta2a777d commit7cce159

File tree

6 files changed

+237
-42
lines changed

6 files changed

+237
-42
lines changed

‎src/backend/catalog/index.c

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,7 +1197,8 @@ Oid
11971197
index_concurrently_create_copy(RelationheapRelation,OidoldIndexId,constchar*newName)
11981198
{
11991199
RelationindexRelation;
1200-
IndexInfo*indexInfo;
1200+
IndexInfo*oldInfo,
1201+
*newInfo;
12011202
OidnewIndexId=InvalidOid;
12021203
HeapTupleindexTuple,
12031204
classTuple;
@@ -1208,11 +1209,22 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
12081209
int2vector*indcoloptions;
12091210
boolisnull;
12101211
List*indexColNames=NIL;
1212+
List*indexExprs=NIL;
1213+
List*indexPreds=NIL;
12111214

12121215
indexRelation=index_open(oldIndexId,RowExclusiveLock);
12131216

1214-
/* New index uses the same index information as old index */
1215-
indexInfo=BuildIndexInfo(indexRelation);
1217+
/* The new index needs some information from the old index */
1218+
oldInfo=BuildIndexInfo(indexRelation);
1219+
1220+
/*
1221+
* Concurrent build of an index with exclusion constraints is not
1222+
* supported.
1223+
*/
1224+
if (oldInfo->ii_ExclusionOps!=NULL)
1225+
ereport(ERROR,
1226+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1227+
errmsg("concurrent index creation for exclusion constraints is not supported")));
12161228

12171229
/* Get the array of class and column options IDs from index info */
12181230
indexTuple=SearchSysCache1(INDEXRELID,ObjectIdGetDatum(oldIndexId));
@@ -1236,14 +1248,64 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
12361248
Anum_pg_class_reloptions,&isnull);
12371249

12381250
/*
1239-
* Extract the list of column names to be used for the index creation.
1251+
* Fetch the list of expressions and predicates directly from the
1252+
* catalogs. This cannot rely on the information from IndexInfo of the
1253+
* old index as these have been flattened for the planner.
12401254
*/
1241-
for (inti=0;i<indexInfo->ii_NumIndexAttrs;i++)
1255+
if (oldInfo->ii_Expressions!=NIL)
1256+
{
1257+
DatumexprDatum;
1258+
char*exprString;
1259+
1260+
exprDatum=SysCacheGetAttr(INDEXRELID,indexTuple,
1261+
Anum_pg_index_indexprs,&isnull);
1262+
Assert(!isnull);
1263+
exprString=TextDatumGetCString(exprDatum);
1264+
indexExprs= (List*)stringToNode(exprString);
1265+
pfree(exprString);
1266+
}
1267+
if (oldInfo->ii_Predicate!=NIL)
1268+
{
1269+
DatumpredDatum;
1270+
char*predString;
1271+
1272+
predDatum=SysCacheGetAttr(INDEXRELID,indexTuple,
1273+
Anum_pg_index_indpred,&isnull);
1274+
Assert(!isnull);
1275+
predString=TextDatumGetCString(predDatum);
1276+
indexPreds= (List*)stringToNode(predString);
1277+
1278+
/* Also convert to implicit-AND format */
1279+
indexPreds=make_ands_implicit((Expr*)indexPreds);
1280+
pfree(predString);
1281+
}
1282+
1283+
/*
1284+
* Build the index information for the new index. Note that rebuild of
1285+
* indexes with exclusion constraints is not supported, hence there is no
1286+
* need to fill all the ii_Exclusion* fields.
1287+
*/
1288+
newInfo=makeIndexInfo(oldInfo->ii_NumIndexAttrs,
1289+
oldInfo->ii_NumIndexKeyAttrs,
1290+
oldInfo->ii_Am,
1291+
indexExprs,
1292+
indexPreds,
1293+
oldInfo->ii_Unique,
1294+
false,/* not ready for inserts */
1295+
true);
1296+
1297+
/*
1298+
* Extract the list of column names and the column numbers for the new
1299+
* index information. All this information will be used for the index
1300+
* creation.
1301+
*/
1302+
for (inti=0;i<oldInfo->ii_NumIndexAttrs;i++)
12421303
{
12431304
TupleDescindexTupDesc=RelationGetDescr(indexRelation);
12441305
Form_pg_attributeatt=TupleDescAttr(indexTupDesc,i);
12451306

12461307
indexColNames=lappend(indexColNames,NameStr(att->attname));
1308+
newInfo->ii_IndexAttrNumbers[i]=oldInfo->ii_IndexAttrNumbers[i];
12471309
}
12481310

12491311
/*
@@ -1259,7 +1321,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
12591321
InvalidOid,/* parentIndexRelid */
12601322
InvalidOid,/* parentConstraintId */
12611323
InvalidOid,/* relFileNode */
1262-
indexInfo,
1324+
newInfo,
12631325
indexColNames,
12641326
indexRelation->rd_rel->relam,
12651327
indexRelation->rd_rel->reltablespace,

‎src/backend/commands/indexcmds.c

Lines changed: 13 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -202,18 +202,8 @@ CheckIndexCompatible(Oid oldId,
202202
* contains only key attributes, thus we're filling ii_NumIndexAttrs and
203203
* ii_NumIndexKeyAttrs with same value.
204204
*/
205-
indexInfo=makeNode(IndexInfo);
206-
indexInfo->ii_NumIndexAttrs=numberOfAttributes;
207-
indexInfo->ii_NumIndexKeyAttrs=numberOfAttributes;
208-
indexInfo->ii_Expressions=NIL;
209-
indexInfo->ii_ExpressionsState=NIL;
210-
indexInfo->ii_PredicateState=NULL;
211-
indexInfo->ii_ExclusionOps=NULL;
212-
indexInfo->ii_ExclusionProcs=NULL;
213-
indexInfo->ii_ExclusionStrats=NULL;
214-
indexInfo->ii_Am=accessMethodId;
215-
indexInfo->ii_AmCache=NULL;
216-
indexInfo->ii_Context=CurrentMemoryContext;
205+
indexInfo=makeIndexInfo(numberOfAttributes,numberOfAttributes,
206+
accessMethodId,NIL,NIL, false, false, false);
217207
typeObjectId= (Oid*)palloc(numberOfAttributes*sizeof(Oid));
218208
collationObjectId= (Oid*)palloc(numberOfAttributes*sizeof(Oid));
219209
classObjectId= (Oid*)palloc(numberOfAttributes*sizeof(Oid));
@@ -780,27 +770,17 @@ DefineIndex(Oid relationId,
780770

781771
/*
782772
* Prepare arguments for index_create, primarily an IndexInfo structure.
783-
* Note that ii_Predicate must be in implicit-AND format.
784-
*/
785-
indexInfo=makeNode(IndexInfo);
786-
indexInfo->ii_NumIndexAttrs=numberOfAttributes;
787-
indexInfo->ii_NumIndexKeyAttrs=numberOfKeyAttributes;
788-
indexInfo->ii_Expressions=NIL;/* for now */
789-
indexInfo->ii_ExpressionsState=NIL;
790-
indexInfo->ii_Predicate=make_ands_implicit((Expr*)stmt->whereClause);
791-
indexInfo->ii_PredicateState=NULL;
792-
indexInfo->ii_ExclusionOps=NULL;
793-
indexInfo->ii_ExclusionProcs=NULL;
794-
indexInfo->ii_ExclusionStrats=NULL;
795-
indexInfo->ii_Unique=stmt->unique;
796-
/* In a concurrent build, mark it not-ready-for-inserts */
797-
indexInfo->ii_ReadyForInserts= !stmt->concurrent;
798-
indexInfo->ii_Concurrent=stmt->concurrent;
799-
indexInfo->ii_BrokenHotChain= false;
800-
indexInfo->ii_ParallelWorkers=0;
801-
indexInfo->ii_Am=accessMethodId;
802-
indexInfo->ii_AmCache=NULL;
803-
indexInfo->ii_Context=CurrentMemoryContext;
773+
* Note that predicates must be in implicit-AND format. In a concurrent
774+
* build, mark it not-ready-for-inserts.
775+
*/
776+
indexInfo=makeIndexInfo(numberOfAttributes,
777+
numberOfKeyAttributes,
778+
accessMethodId,
779+
NIL,/* expressions, NIL for now */
780+
make_ands_implicit((Expr*)stmt->whereClause),
781+
stmt->unique,
782+
!stmt->concurrent,
783+
stmt->concurrent);
804784

805785
typeObjectId= (Oid*)palloc(numberOfAttributes*sizeof(Oid));
806786
collationObjectId= (Oid*)palloc(numberOfAttributes*sizeof(Oid));

‎src/backend/nodes/makefuncs.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/*-------------------------------------------------------------------------
22
*
33
* makefuncs.c
4-
* creator functions forprimitive nodes. The functions here are for
5-
*themost frequently created nodes.
4+
* creator functions forvarious nodes. The functions here are for the
5+
* most frequently created nodes.
66
*
77
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
@@ -733,6 +733,54 @@ make_ands_implicit(Expr *clause)
733733
returnlist_make1(clause);
734734
}
735735

736+
/*
737+
* makeIndexInfo
738+
* create an IndexInfo node
739+
*/
740+
IndexInfo*
741+
makeIndexInfo(intnumattrs,intnumkeyattrs,Oidamoid,List*expressions,
742+
List*predicates,boolunique,boolisready,boolconcurrent)
743+
{
744+
IndexInfo*n=makeNode(IndexInfo);
745+
746+
n->ii_NumIndexAttrs=numattrs;
747+
n->ii_NumIndexKeyAttrs=numkeyattrs;
748+
Assert(n->ii_NumIndexKeyAttrs!=0);
749+
Assert(n->ii_NumIndexKeyAttrs <=n->ii_NumIndexAttrs);
750+
n->ii_Unique=unique;
751+
n->ii_ReadyForInserts=isready;
752+
n->ii_Concurrent=concurrent;
753+
754+
/* expressions */
755+
n->ii_Expressions=expressions;
756+
n->ii_ExpressionsState=NIL;
757+
758+
/* predicates */
759+
n->ii_Predicate=predicates;
760+
n->ii_PredicateState=NULL;
761+
762+
/* exclusion constraints */
763+
n->ii_ExclusionOps=NULL;
764+
n->ii_ExclusionProcs=NULL;
765+
n->ii_ExclusionStrats=NULL;
766+
767+
/* speculative inserts */
768+
n->ii_UniqueOps=NULL;
769+
n->ii_UniqueProcs=NULL;
770+
n->ii_UniqueStrats=NULL;
771+
772+
/* initialize index-build state to default */
773+
n->ii_BrokenHotChain= false;
774+
n->ii_ParallelWorkers=0;
775+
776+
/* set up for possible use by index AM */
777+
n->ii_Am=amoid;
778+
n->ii_AmCache=NULL;
779+
n->ii_Context=CurrentMemoryContext;
780+
781+
returnn;
782+
}
783+
736784
/*
737785
* makeGroupingSet
738786
*

‎src/include/nodes/makefuncs.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*-------------------------------------------------------------------------
22
*
33
* makefuncs.h
4-
* prototypes for the creator functions(for primitive nodes)
4+
* prototypes for the creator functionsof various nodes
55
*
66
*
77
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
@@ -14,6 +14,7 @@
1414
#ifndefMAKEFUNC_H
1515
#defineMAKEFUNC_H
1616

17+
#include"nodes/execnodes.h"
1718
#include"nodes/parsenodes.h"
1819

1920

@@ -92,6 +93,10 @@ extern Node *make_and_qual(Node *qual1, Node *qual2);
9293
externExpr*make_ands_explicit(List*andclauses);
9394
externList*make_ands_implicit(Expr*clause);
9495

96+
externIndexInfo*makeIndexInfo(intnumattrs,intnumkeyattrs,Oidamoid,
97+
List*expressions,List*predicates,
98+
boolunique,boolisready,boolconcurrent);
99+
95100
externDefElem*makeDefElem(char*name,Node*arg,intlocation);
96101
externDefElem*makeDefElemExtended(char*nameSpace,char*name,Node*arg,
97102
DefElemActiondefaction,intlocation);

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

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2170,6 +2170,78 @@ Indexes:
21702170
"concur_reindex_ind5" UNIQUE, btree (c1)
21712171

21722172
DROP TABLE concur_reindex_tab4;
2173+
-- Check handling of indexes with expressions and predicates. The
2174+
-- definitions of the rebuilt indexes should match the original
2175+
-- definitions.
2176+
CREATE TABLE concur_exprs_tab (c1 int , c2 boolean);
2177+
INSERT INTO concur_exprs_tab (c1, c2) VALUES (1369652450, FALSE),
2178+
(414515746, TRUE),
2179+
(897778963, FALSE);
2180+
CREATE UNIQUE INDEX concur_exprs_index_expr
2181+
ON concur_exprs_tab ((c1::text COLLATE "C"));
2182+
CREATE UNIQUE INDEX concur_exprs_index_pred ON concur_exprs_tab (c1)
2183+
WHERE (c1::text > 500000000::text COLLATE "C");
2184+
CREATE UNIQUE INDEX concur_exprs_index_pred_2
2185+
ON concur_exprs_tab ((1 / c1))
2186+
WHERE ('-H') >= (c2::TEXT) COLLATE "C";
2187+
SELECT pg_get_indexdef('concur_exprs_index_expr'::regclass);
2188+
pg_get_indexdef
2189+
---------------------------------------------------------------------------------------------------------------
2190+
CREATE UNIQUE INDEX concur_exprs_index_expr ON public.concur_exprs_tab USING btree (((c1)::text) COLLATE "C")
2191+
(1 row)
2192+
2193+
SELECT pg_get_indexdef('concur_exprs_index_pred'::regclass);
2194+
pg_get_indexdef
2195+
----------------------------------------------------------------------------------------------------------------------------------------------
2196+
CREATE UNIQUE INDEX concur_exprs_index_pred ON public.concur_exprs_tab USING btree (c1) WHERE ((c1)::text > ((500000000)::text COLLATE "C"))
2197+
(1 row)
2198+
2199+
SELECT pg_get_indexdef('concur_exprs_index_pred_2'::regclass);
2200+
pg_get_indexdef
2201+
--------------------------------------------------------------------------------------------------------------------------------------------------
2202+
CREATE UNIQUE INDEX concur_exprs_index_pred_2 ON public.concur_exprs_tab USING btree (((1 / c1))) WHERE ('-H'::text >= ((c2)::text COLLATE "C"))
2203+
(1 row)
2204+
2205+
REINDEX TABLE CONCURRENTLY concur_exprs_tab;
2206+
SELECT pg_get_indexdef('concur_exprs_index_expr'::regclass);
2207+
pg_get_indexdef
2208+
---------------------------------------------------------------------------------------------------------------
2209+
CREATE UNIQUE INDEX concur_exprs_index_expr ON public.concur_exprs_tab USING btree (((c1)::text) COLLATE "C")
2210+
(1 row)
2211+
2212+
SELECT pg_get_indexdef('concur_exprs_index_pred'::regclass);
2213+
pg_get_indexdef
2214+
----------------------------------------------------------------------------------------------------------------------------------------------
2215+
CREATE UNIQUE INDEX concur_exprs_index_pred ON public.concur_exprs_tab USING btree (c1) WHERE ((c1)::text > ((500000000)::text COLLATE "C"))
2216+
(1 row)
2217+
2218+
SELECT pg_get_indexdef('concur_exprs_index_pred_2'::regclass);
2219+
pg_get_indexdef
2220+
--------------------------------------------------------------------------------------------------------------------------------------------------
2221+
CREATE UNIQUE INDEX concur_exprs_index_pred_2 ON public.concur_exprs_tab USING btree (((1 / c1))) WHERE ('-H'::text >= ((c2)::text COLLATE "C"))
2222+
(1 row)
2223+
2224+
-- ALTER TABLE recreates the indexes, which should keep their collations.
2225+
ALTER TABLE concur_exprs_tab ALTER c2 TYPE TEXT;
2226+
SELECT pg_get_indexdef('concur_exprs_index_expr'::regclass);
2227+
pg_get_indexdef
2228+
---------------------------------------------------------------------------------------------------------------
2229+
CREATE UNIQUE INDEX concur_exprs_index_expr ON public.concur_exprs_tab USING btree (((c1)::text) COLLATE "C")
2230+
(1 row)
2231+
2232+
SELECT pg_get_indexdef('concur_exprs_index_pred'::regclass);
2233+
pg_get_indexdef
2234+
----------------------------------------------------------------------------------------------------------------------------------------------
2235+
CREATE UNIQUE INDEX concur_exprs_index_pred ON public.concur_exprs_tab USING btree (c1) WHERE ((c1)::text > ((500000000)::text COLLATE "C"))
2236+
(1 row)
2237+
2238+
SELECT pg_get_indexdef('concur_exprs_index_pred_2'::regclass);
2239+
pg_get_indexdef
2240+
------------------------------------------------------------------------------------------------------------------------------------------
2241+
CREATE UNIQUE INDEX concur_exprs_index_pred_2 ON public.concur_exprs_tab USING btree (((1 / c1))) WHERE ('-H'::text >= (c2 COLLATE "C"))
2242+
(1 row)
2243+
2244+
DROP TABLE concur_exprs_tab;
21732245
--
21742246
-- REINDEX SCHEMA
21752247
--

‎src/test/regress/sql/create_index.sql

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,34 @@ REINDEX INDEX CONCURRENTLY concur_reindex_ind5;
872872
\d concur_reindex_tab4
873873
DROPTABLE concur_reindex_tab4;
874874

875+
-- Check handling of indexes with expressions and predicates. The
876+
-- definitions of the rebuilt indexes should match the original
877+
-- definitions.
878+
CREATETABLEconcur_exprs_tab (c1int , c2boolean);
879+
INSERT INTO concur_exprs_tab (c1, c2)VALUES (1369652450, FALSE),
880+
(414515746, TRUE),
881+
(897778963, FALSE);
882+
CREATEUNIQUE INDEXconcur_exprs_index_expr
883+
ON concur_exprs_tab ((c1::text COLLATE"C"));
884+
CREATEUNIQUE INDEXconcur_exprs_index_predON concur_exprs_tab (c1)
885+
WHERE (c1::text>500000000::text COLLATE"C");
886+
CREATEUNIQUE INDEXconcur_exprs_index_pred_2
887+
ON concur_exprs_tab ((1/ c1))
888+
WHERE ('-H')>= (c2::TEXT) COLLATE"C";
889+
SELECT pg_get_indexdef('concur_exprs_index_expr'::regclass);
890+
SELECT pg_get_indexdef('concur_exprs_index_pred'::regclass);
891+
SELECT pg_get_indexdef('concur_exprs_index_pred_2'::regclass);
892+
REINDEX TABLE CONCURRENTLY concur_exprs_tab;
893+
SELECT pg_get_indexdef('concur_exprs_index_expr'::regclass);
894+
SELECT pg_get_indexdef('concur_exprs_index_pred'::regclass);
895+
SELECT pg_get_indexdef('concur_exprs_index_pred_2'::regclass);
896+
-- ALTER TABLE recreates the indexes, which should keep their collations.
897+
ALTERTABLE concur_exprs_tab ALTER c2 TYPETEXT;
898+
SELECT pg_get_indexdef('concur_exprs_index_expr'::regclass);
899+
SELECT pg_get_indexdef('concur_exprs_index_pred'::regclass);
900+
SELECT pg_get_indexdef('concur_exprs_index_pred_2'::regclass);
901+
DROPTABLE concur_exprs_tab;
902+
875903
--
876904
-- REINDEX SCHEMA
877905
--

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp