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

Commit6eb71ac

Browse files
committed
Make CheckIndexCompatible simpler and more bullet-proof.
This gives up the "don't rewrite the index" behavior in a couple ofrelatively unimportant cases, such as changing between an array typeand an unconstrained domain over that array type, in return formaking this code more future-proof.Noah Misch
1 parent8366c78 commit6eb71ac

File tree

3 files changed

+67
-55
lines changed

3 files changed

+67
-55
lines changed

‎src/backend/commands/indexcmds.c

Lines changed: 50 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include"catalog/pg_opclass.h"
2424
#include"catalog/pg_opfamily.h"
2525
#include"catalog/pg_tablespace.h"
26+
#include"catalog/pg_type.h"
2627
#include"commands/dbcommands.h"
2728
#include"commands/defrem.h"
2829
#include"commands/tablecmds.h"
@@ -52,6 +53,7 @@
5253
/* non-export function prototypes */
5354
staticvoidCheckPredicate(Expr*predicate);
5455
staticvoidComputeIndexAttrs(IndexInfo*indexInfo,
56+
Oid*typeOidP,
5557
Oid*collationOidP,
5658
Oid*classOidP,
5759
int16*colOptionP,
@@ -87,18 +89,17 @@ static void RangeVarCallbackForReindexIndex(const RangeVar *relation,
8789
* of columns and that if one has an expression column or predicate, both do.
8890
* Errors arising from the attribute list still apply.
8991
*
90-
* Most column type changes that can skip a table rewrite will not invalidate
91-
* indexes. For btree and hash indexes, we assume continued validity when
92-
* each column of an index would have the same operator family before and
93-
* after the change. Since we do not document a contract for GIN or GiST
94-
* operator families, we require an exact operator class match for them and
95-
* for any other access methods.
96-
*
97-
* DefineIndex always verifies that each exclusion operator shares an operator
98-
* family with its corresponding index operator class. For access methods
99-
* having no operator family contract, confirm that the old and new indexes
100-
* use the exact same exclusion operator. For btree and hash, there's nothing
101-
* more to check.
92+
* Most column type changes that can skip a table rewrite do not invalidate
93+
* indexes. We ackowledge this when all operator classes, collations and
94+
* exclusion operators match. Though we could further permit intra-opfamily
95+
* changes for btree and hash indexes, that adds subtle complexity with no
96+
* concrete benefit for core types.
97+
98+
* When a comparison or exclusion operator has a polymorphic input type, the
99+
* actual input types must also match. This defends against the possibility
100+
* that operators could vary behavior in response to get_fn_expr_argtype().
101+
* At present, this hazard is theoretical: check_exclusion_constraint() and
102+
* all core index access methods decline to set fn_expr for such calls.
102103
*
103104
* We do not yet implement a test to verify compatibility of expression
104105
* columns or predicates, so assume any such index is incompatible.
@@ -111,6 +112,7 @@ CheckIndexCompatible(Oid oldId,
111112
List*exclusionOpNames)
112113
{
113114
boolisconstraint;
115+
Oid*typeObjectId;
114116
Oid*collationObjectId;
115117
Oid*classObjectId;
116118
OidaccessMethodId;
@@ -123,10 +125,10 @@ CheckIndexCompatible(Oid oldId,
123125
intnumberOfAttributes;
124126
intold_natts;
125127
boolisnull;
126-
boolfamily_am;
127128
boolret= true;
128129
oidvector*old_indclass;
129130
oidvector*old_indcollation;
131+
Relationirel;
130132
inti;
131133
Datumd;
132134

@@ -168,10 +170,12 @@ CheckIndexCompatible(Oid oldId,
168170
indexInfo->ii_ExclusionOps=NULL;
169171
indexInfo->ii_ExclusionProcs=NULL;
170172
indexInfo->ii_ExclusionStrats=NULL;
173+
typeObjectId= (Oid*)palloc(numberOfAttributes*sizeof(Oid));
171174
collationObjectId= (Oid*)palloc(numberOfAttributes*sizeof(Oid));
172175
classObjectId= (Oid*)palloc(numberOfAttributes*sizeof(Oid));
173176
coloptions= (int16*)palloc(numberOfAttributes*sizeof(int16));
174-
ComputeIndexAttrs(indexInfo,collationObjectId,classObjectId,
177+
ComputeIndexAttrs(indexInfo,
178+
typeObjectId,collationObjectId,classObjectId,
175179
coloptions,attributeList,
176180
exclusionOpNames,relationId,
177181
accessMethodName,accessMethodId,
@@ -191,12 +195,7 @@ CheckIndexCompatible(Oid oldId,
191195
return false;
192196
}
193197

194-
/*
195-
* If the old and new operator class of any index column differ in
196-
* operator family or collation, regard the old index as incompatible.
197-
* For access methods other than btree and hash, a family match has no
198-
* defined meaning; require an exact operator class match.
199-
*/
198+
/* Any change in operator class or collation breaks compatibility. */
200199
old_natts= ((Form_pg_index)GETSTRUCT(tuple))->indnatts;
201200
Assert(old_natts==numberOfAttributes);
202201

@@ -208,52 +207,42 @@ CheckIndexCompatible(Oid oldId,
208207
Assert(!isnull);
209208
old_indclass= (oidvector*)DatumGetPointer(d);
210209

211-
family_am=accessMethodId==BTREE_AM_OID||accessMethodId==HASH_AM_OID;
212-
213-
for (i=0;i<old_natts;i++)
214-
{
215-
Oidold_class=old_indclass->values[i];
216-
Oidnew_class=classObjectId[i];
217-
218-
if (!(old_indcollation->values[i]==collationObjectId[i]
219-
&& (old_class==new_class
220-
|| (family_am&& (get_opclass_family(old_class)
221-
==get_opclass_family(new_class))))))
222-
{
223-
ret= false;
224-
break;
225-
}
226-
}
210+
ret= (memcmp(old_indclass->values,classObjectId,
211+
old_natts*sizeof(Oid))==0&&
212+
memcmp(old_indcollation->values,collationObjectId,
213+
old_natts*sizeof(Oid))==0);
227214

228215
ReleaseSysCache(tuple);
229216

230-
/*
231-
* For btree and hash, exclusion operators need only fall in the same
232-
* operator family; ComputeIndexAttrs already verified that much. If we
233-
* get this far, we know that the index operator family has not changed,
234-
* and we're done. For other access methods, require exact matches for
235-
* all exclusion operators.
236-
*/
237-
if (ret&&!family_am&&indexInfo->ii_ExclusionOps!=NULL)
217+
/* For polymorphic opcintype, column type changes break compatibility. */
218+
irel=index_open(oldId,AccessShareLock);/* caller probably has a lock */
219+
for (i=0;i<old_natts&&ret;i++)
220+
ret= (!IsPolymorphicType(get_opclass_input_type(classObjectId[i]))||
221+
irel->rd_att->attrs[i]->atttypid==typeObjectId[i]);
222+
223+
/* Any change in exclusion operator selections breaks compatibility. */
224+
if (ret&&indexInfo->ii_ExclusionOps!=NULL)
238225
{
239-
Relationirel;
240226
Oid*old_operators,*old_procs;
241227
uint16*old_strats;
242228

243-
/* Caller probably already holds a stronger lock. */
244-
irel=index_open(oldId,AccessShareLock);
245229
RelationGetExclusionInfo(irel,&old_operators,&old_procs,&old_strats);
230+
ret=memcmp(old_operators,indexInfo->ii_ExclusionOps,
231+
old_natts*sizeof(Oid))==0;
246232

247-
for (i=0;i<old_natts;i++)
248-
if (old_operators[i]!=indexInfo->ii_ExclusionOps[i])
249-
{
250-
ret= false;
251-
break;
252-
}
233+
/* Require an exact input type match for polymorphic operators. */
234+
for (i=0;i<old_natts&&ret;i++)
235+
{
236+
Oidleft,
237+
right;
253238

254-
index_close(irel,NoLock);
239+
op_input_types(indexInfo->ii_ExclusionOps[i],&left,&right);
240+
ret= (!(IsPolymorphicType(left)||IsPolymorphicType(right))||
241+
irel->rd_att->attrs[i]->atttypid==typeObjectId[i]);
242+
}
255243
}
256244

245+
index_close(irel,NoLock);
257246
returnret;
258247
}
259248

@@ -315,6 +304,7 @@ DefineIndex(RangeVar *heapRelation,
315304
boolquiet,
316305
boolconcurrent)
317306
{
307+
Oid*typeObjectId;
318308
Oid*collationObjectId;
319309
Oid*classObjectId;
320310
OidaccessMethodId;
@@ -550,10 +540,12 @@ DefineIndex(RangeVar *heapRelation,
550540
indexInfo->ii_Concurrent=concurrent;
551541
indexInfo->ii_BrokenHotChain= false;
552542

543+
typeObjectId= (Oid*)palloc(numberOfAttributes*sizeof(Oid));
553544
collationObjectId= (Oid*)palloc(numberOfAttributes*sizeof(Oid));
554545
classObjectId= (Oid*)palloc(numberOfAttributes*sizeof(Oid));
555546
coloptions= (int16*)palloc(numberOfAttributes*sizeof(int16));
556-
ComputeIndexAttrs(indexInfo,collationObjectId,classObjectId,
547+
ComputeIndexAttrs(indexInfo,
548+
typeObjectId,collationObjectId,classObjectId,
557549
coloptions,attributeList,
558550
exclusionOpNames,relationId,
559551
accessMethodName,accessMethodId,
@@ -980,6 +972,7 @@ CheckPredicate(Expr *predicate)
980972
*/
981973
staticvoid
982974
ComputeIndexAttrs(IndexInfo*indexInfo,
975+
Oid*typeOidP,
983976
Oid*collationOidP,
984977
Oid*classOidP,
985978
int16*colOptionP,
@@ -1108,6 +1101,8 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
11081101
}
11091102
}
11101103

1104+
typeOidP[attn]=atttype;
1105+
11111106
/*
11121107
* Apply collation override if any
11131108
*/

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,15 @@ where oid = 'test_storage'::regclass;
16651665
t
16661666
(1 row)
16671667

1668+
-- SET DATA TYPE without a rewrite
1669+
CREATE DOMAIN other_textarr AS text[];
1670+
CREATE TABLE norewrite_array(c text[] PRIMARY KEY);
1671+
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "norewrite_array_pkey" for table "norewrite_array"
1672+
SET client_min_messages = debug1;
1673+
ALTER TABLE norewrite_array ALTER c TYPE text[]; -- no work
1674+
ALTER TABLE norewrite_array ALTER c TYPE other_textarr; -- rebuild index
1675+
DEBUG: building index "norewrite_array_pkey" on table "norewrite_array"
1676+
RESET client_min_messages;
16681677
--
16691678
-- lock levels
16701679
--

‎src/test/regress/sql/alter_table.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,14 @@ select reltoastrelid <> 0 as has_toast_table
11971197
from pg_class
11981198
whereoid='test_storage'::regclass;
11991199

1200+
-- SET DATA TYPE without a rewrite
1201+
CREATEDOMAINother_textarrAStext[];
1202+
CREATETABLEnorewrite_array(ctext[]PRIMARY KEY);
1203+
SET client_min_messages= debug1;
1204+
ALTERTABLE norewrite_array ALTER c TYPEtext[];-- no work
1205+
ALTERTABLE norewrite_array ALTER c TYPE other_textarr;-- rebuild index
1206+
RESET client_min_messages;
1207+
12001208
--
12011209
-- lock levels
12021210
--

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp