Skip to content

Commit 137c068

Browse files
committed
Support more restricted predicate in ALTER INDEX clause
1 parent ce6c567 commit 137c068

File tree

1 file changed

+92
-59
lines changed

1 file changed

+92
-59
lines changed

src/backend/commands/indexcmds.c

Lines changed: 92 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,30 @@ CheckIndexCompatible(Oid oldId,
279279
return ret;
280280
}
281281

282+
static void
283+
UpdateIndex(Oid indexRelationId, Node* whereClause)
284+
{
285+
Datum values[Natts_pg_index];
286+
bool isnull[Natts_pg_index];
287+
HeapTuple oldTuple;
288+
HeapTuple newTuple;
289+
Relation pg_index;
290+
291+
pg_index = heap_open(IndexRelationId, RowExclusiveLock);
292+
oldTuple = SearchSysCacheCopy1(INDEXRELID, ObjectIdGetDatum(indexRelationId));
293+
if (!HeapTupleIsValid(oldTuple))
294+
elog(ERROR, "cache lookup failed for index %u", indexRelationId);
295+
296+
heap_deform_tuple(oldTuple, RelationGetDescr(pg_index), values, isnull);
297+
values[Anum_pg_index_indpred - 1] = CStringGetTextDatum(nodeToString(whereClause));
298+
newTuple = heap_form_tuple(RelationGetDescr(pg_index), values, isnull);
299+
simple_heap_update(pg_index, &oldTuple->t_self, newTuple);
300+
CatalogUpdateIndexes(pg_index, newTuple);
301+
heap_freetuple(newTuple);
302+
heap_freetuple(oldTuple);
303+
heap_close(pg_index, NoLock);
304+
}
305+
282306
void
283307
AlterIndex(Oid indexRelationId, IndexStmt *stmt)
284308
{
@@ -292,14 +316,15 @@ AlterIndex(Oid indexRelationId, IndexStmt *stmt)
292316
SPIPlanPtr plan;
293317
Portal portal;
294318
HeapTuple tuple;
295-
HeapTuple updatedTuple;
296319
TupleTableSlot *slot;
297320
ItemPointer tupleid;
298321
IndexInfo *indexInfo;
299322
EState *estate;
300323
Oid namespaceId;
301-
Relation pg_index;
302324
List* deparseCtx;
325+
char* oldIndexPredicate;
326+
char* newIndexPredicate;
327+
char* relationName;
303328

304329
Assert(stmt->whereClause);
305330
CheckPredicate((Expr *) stmt->whereClause);
@@ -314,8 +339,6 @@ AlterIndex(Oid indexRelationId, IndexStmt *stmt)
314339
/* indexRelation = index_open(indexRelationId, AccessShareLock); */
315340
namespaceId = RelationGetNamespace(indexRelation);
316341

317-
pg_index = heap_open(IndexRelationId, RowExclusiveLock);
318-
319342
indexInfo = BuildIndexInfo(indexRelation);
320343
Assert(indexInfo->ii_Predicate);
321344
Assert(!indexInfo->ii_ExclusionOps);
@@ -327,75 +350,85 @@ AlterIndex(Oid indexRelationId, IndexStmt *stmt)
327350

328351
checkUnique = indexRelation->rd_index->indisunique ? UNIQUE_CHECK_YES : UNIQUE_CHECK_NO;
329352

330-
/* Update pg_index tuple */
331-
tuple = SearchSysCacheCopy1(INDEXRELID, ObjectIdGetDatum(indexRelationId));
332-
if (!HeapTupleIsValid(tuple))
333-
elog(ERROR, "cache lookup failed for index %u", indexRelationId);
334-
335-
Assert(Natts_pg_index <= INDEX_MAX_KEYS);
336-
heap_deform_tuple(tuple, RelationGetDescr(pg_index), values, isnull);
337-
values[Anum_pg_index_indpred - 1] = CStringGetTextDatum(nodeToString(stmt->whereClause));
338-
updatedTuple = heap_form_tuple(RelationGetDescr(pg_index), values, isnull);
339-
simple_heap_update(pg_index, &tuple->t_self, updatedTuple);
340-
CatalogUpdateIndexes(pg_index, updatedTuple);
341-
heap_freetuple(updatedTuple);
342-
heap_freetuple(tuple);
343-
heap_close(pg_index, NoLock);
344-
345353
slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
354+
355+
deparseCtx = deparse_context_for(RelationGetRelationName(heapRelation), heapRelationId);
356+
relationName = quote_qualified_identifier(get_namespace_name(namespaceId),
357+
get_rel_name(heapRelationId)),
358+
newIndexPredicate = deparse_expression(stmt->whereClause, deparseCtx, false, false);
359+
oldIndexPredicate = deparse_expression((Node*)make_ands_explicit(indexInfo->ii_Predicate), deparseCtx, false, false);
346360

347361
SPI_connect();
348-
deparseCtx = deparse_context_for(RelationGetRelationName(heapRelation), heapRelationId);
349-
select = psprintf("select * from %s where %s and not (%s)",
350-
quote_qualified_identifier(get_namespace_name(namespaceId),
351-
get_rel_name(heapRelationId)),
352-
deparse_expression(stmt->whereClause, deparseCtx, false, false),
353-
deparse_expression((Node*)make_ands_explicit(indexInfo->ii_Predicate), deparseCtx, false, false));
354-
plan = SPI_prepare(select, 0, NULL);
355-
if (plan == NULL) {
356-
ereport(ERROR,
357-
(errcode(ERRCODE_INVALID_CURSOR_STATE),
358-
errmsg("Failed to preapre statement %s", select)));
359-
}
360-
portal = SPI_cursor_open(NULL, plan, NULL, NULL, true);
361-
if (portal == NULL) {
362+
363+
select = psprintf("select * from %s where %s and not (%s) limit 1",
364+
relationName, oldIndexPredicate, newIndexPredicate);
365+
if (SPI_execute(select, true, 1) != SPI_OK_SELECT)
366+
{
362367
ereport(ERROR,
363368
(errcode(ERRCODE_INVALID_CURSOR_STATE),
364-
errmsg("Failed to open cursor for %s", select)));
369+
errmsg("Failed to execute statement %s", select)));
365370
}
366-
while (true)
367-
{
368-
SPI_cursor_fetch(portal, true, 1);
369-
if (!SPI_processed) {
370-
break;
371-
}
372-
tuple = SPI_tuptable->vals[0];
373-
tupleid = &tuple->t_data->t_ctid;
374-
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
371+
if (SPI_processed) {
372+
/* There is no way in Postgres to exclude records from index, so we have to completelty rebuild index in this case */
373+
bool relpersistence = indexRelation->rd_rel->relpersistence;
374+
index_close(indexRelation, NoLock);
375+
indexRelation->rd_indpred = make_ands_implicit((Expr *) stmt->whereClause);
376+
indexRelation = NULL;
377+
UpdateIndex(indexRelationId, stmt->whereClause);
378+
reindex_index(indexRelationId, false, relpersistence, 0);
379+
} else {
380+
select = psprintf("select * from %s where %s and not (%s)",
381+
relationName, newIndexPredicate, oldIndexPredicate);
382+
plan = SPI_prepare(select, 0, NULL);
383+
if (plan == NULL) {
384+
ereport(ERROR,
385+
(errcode(ERRCODE_INVALID_CURSOR_STATE),
386+
errmsg("Failed to preapre statement %s", select)));
387+
}
388+
portal = SPI_cursor_open(NULL, plan, NULL, NULL, true);
389+
if (portal == NULL) {
390+
ereport(ERROR,
391+
(errcode(ERRCODE_INVALID_CURSOR_STATE),
392+
errmsg("Failed to open cursor for %s", select)));
393+
}
394+
while (true)
395+
{
396+
SPI_cursor_fetch(portal, true, 1);
397+
if (!SPI_processed) {
398+
break;
399+
}
400+
tuple = SPI_tuptable->vals[0];
401+
tupleid = &tuple->t_data->t_ctid;
402+
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
403+
404+
FormIndexDatum(indexInfo,
405+
slot,
406+
estate,
407+
values,
408+
isnull);
409+
index_insert(indexRelation, /* index relation */
410+
values, /* array of index Datums */
411+
isnull, /* null flags */
412+
tupleid, /* tid of heap tuple */
413+
heapRelation, /* heap relation */
414+
checkUnique); /* type of uniqueness check to do */
375415

376-
FormIndexDatum(indexInfo,
377-
slot,
378-
estate,
379-
values,
380-
isnull);
381-
index_insert(indexRelation, /* index relation */
382-
values, /* array of index Datums */
383-
isnull, /* null flags */
384-
tupleid, /* tid of heap tuple */
385-
heapRelation, /* heap relation */
386-
checkUnique); /* type of uniqueness check to do */
387-
388-
SPI_freetuple(tuple);
389-
SPI_freetuptable(SPI_tuptable);
416+
SPI_freetuple(tuple);
417+
SPI_freetuptable(SPI_tuptable);
418+
}
419+
SPI_cursor_close(portal);
420+
421+
UpdateIndex(indexRelationId, stmt->whereClause);
390422
}
391-
SPI_cursor_close(portal);
392423
SPI_finish();
393424

394425
ExecDropSingleTupleTableSlot(slot);
395426
FreeExecutorState(estate);
396427

397428
heap_close(heapRelation, NoLock);
398-
index_close(indexRelation, NoLock);
429+
if (indexRelation) {
430+
index_close(indexRelation, NoLock);
431+
}
399432
}
400433

401434
/*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy