Skip to content

Commit f8f994f

Browse files
committed
Add ALTER INDEX WHERE construction
1 parent 0bb319a commit f8f994f

File tree

12 files changed

+314
-83
lines changed

12 files changed

+314
-83
lines changed

src/backend/commands/indexcmds.c

Lines changed: 53 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "commands/tablespace.h"
3333
#include "mb/pg_wchar.h"
3434
#include "miscadmin.h"
35+
#include "funcapi.h"
3536
#include "nodes/nodeFuncs.h"
3637
#include "optimizer/clauses.h"
3738
#include "optimizer/planner.h"
@@ -50,6 +51,9 @@
5051
#include "utils/snapmgr.h"
5152
#include "utils/syscache.h"
5253
#include "utils/tqual.h"
54+
#include "utils/ruleutils.h"
55+
#include "executor/executor.h"
56+
#include "executor/spi.h"
5357

5458

5559
/* non-export function prototypes */
@@ -275,33 +279,40 @@ CheckIndexCompatible(Oid oldId,
275279
return ret;
276280
}
277281

278-
#if 0
279282
void
280-
AlterIndex(Oid relationId, IndexStmt *stmt, Oid indexRelationId)
283+
AlterIndex(Oid indexRelationId, IndexStmt *stmt)
281284
{
282285
char* select;
286+
Oid heapRelationId;
283287
IndexUniqueCheck checkUnique;
284-
bool satisfiesConstraint;
285288
Datum values[INDEX_MAX_KEYS];
286289
bool isnull[INDEX_MAX_KEYS];
287290
Relation heapRelation;
288291
Relation indexRelation;
289292
SPIPlanPtr plan;
290293
Portal portal;
291294
HeapTuple tuple;
292-
TupleDesc tupdesc;
295+
HeapTuple updatedTuple;
293296
TupleTableSlot *slot;
294297
ItemPointer tupleid;
295298
IndexInfo *indexInfo;
296299
EState *estate;
300+
Oid namespaceId;
301+
Relation pg_index;
302+
List* deparseCtx;
297303

298304
Assert(stmt->whereClause);
305+
CheckPredicate((Expr *) stmt->whereClause);
306+
307+
/* Open the target index relation */
308+
indexRelation = index_open(indexRelationId, RowExclusiveLock);
309+
namespaceId = RelationGetNamespace(indexRelation);
299310

300311
/* Open and lock the parent heap relation */
301-
heapRelation = heap_openrv(stmt->relation, ShareUpdateExclusiveLock);
312+
heapRelationId = IndexGetRelation(indexRelationId, false);
313+
heapRelation = heap_open(heapRelationId, ShareLock);
302314

303-
/* And the target index relation */
304-
indexRelation = index_open(indexRelationId, RowExclusiveLock);
315+
pg_index = heap_open(IndexRelationId, RowExclusiveLock);
305316

306317
indexInfo = BuildIndexInfo(indexRelation);
307318
Assert(indexInfo->ii_Predicate);
@@ -314,58 +325,40 @@ AlterIndex(Oid relationId, IndexStmt *stmt, Oid indexRelationId)
314325

315326
checkUnique = indexRelation->rd_index->indisunique ? UNIQUE_CHECK_YES : UNIQUE_CHECK_NO;
316327

317-
SPI_connect();
318-
select = psprintf("select * from %s where %s and not (%s)",
319-
quote_qualified_identifier(get_namespace_name(RelationGetNamespace(heapRelation)),
320-
get_rel_name(relationId)),
321-
nodeToString(indexInfo->ii_Predicate),
322-
nodeToString(stmt->whereClause)
323-
);
324-
plan = SPI_parepare(select, 0, NULL);
325-
if (plan == NULL) {
326-
ereport(ERROR,
327-
(errcode(ERRCODE_INVALID_CURSOR_STATE),
328-
errmsg("Failed to preapre statement ", select)));
329-
}
330-
portal = SPI_cursor_open(NULL, plan, NULL, NULL, true);
331-
if (portal == NULL) {
332-
ereport(ERROR,
333-
(errcode(ERRCODE_INVALID_CURSOR_STATE),
334-
errmsg("Failed to open cursor for ", select)));
335-
}
336-
while (true)
337-
{
338-
SPI_cursor_fetch(portal, true, 1);
339-
if (!SPI_processed) {
340-
break;
341-
}
342-
tuple = SPI_tuptable->vals[0];
343-
tupdesc = SPI_tuptable->tupdesc;
344-
slot = TupleDescGetSlot(tupdesc);
345-
tupleid = &tuple->t_datat->t_ctid;
328+
/* Update pg_index tuple */
329+
tuple = SearchSysCacheCopy1(INDEXRELID, ObjectIdGetDatum(indexRelationId));
330+
if (!HeapTupleIsValid(tuple))
331+
elog(ERROR, "cache lookup failed for index %u", indexRelationId);
346332

347-
/* delete tuple from index */
348-
}
349-
SPI_cursor_close(portal);
333+
Assert(Natts_pg_index <= INDEX_MAX_KEYS);
334+
heap_deform_tuple(tuple, RelationGetDescr(pg_index), values, isnull);
335+
values[Anum_pg_index_indpred - 1] = CStringGetTextDatum(nodeToString(stmt->whereClause));
336+
updatedTuple = heap_form_tuple(RelationGetDescr(pg_index), values, isnull);
337+
simple_heap_update(pg_index, &tuple->t_self, updatedTuple);
338+
CatalogUpdateIndexes(pg_index, updatedTuple);
339+
heap_freetuple(updatedTuple);
340+
heap_freetuple(tuple);
350341

342+
slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation));
351343

344+
SPI_connect();
345+
deparseCtx = deparse_context_for(RelationGetRelationName(heapRelation), heapRelationId);
352346
select = psprintf("select * from %s where %s and not (%s)",
353-
quote_qualified_identifier(get_namespace_name(RelationGetNamespace(heapRelation)),
354-
get_rel_name(relationId)),
355-
nodeToString(stmt->whereClause),
356-
nodeToString(indexInfo->ii_Predicate)
357-
);
358-
plan = SPI_parepare(select, 0, NULL);
347+
quote_qualified_identifier(get_namespace_name(namespaceId),
348+
get_rel_name(heapRelationId)),
349+
deparse_expression(stmt->whereClause, deparseCtx, false, false),
350+
deparse_expression((Node*)make_ands_explicit(indexInfo->ii_Predicate), deparseCtx, false, false));
351+
plan = SPI_prepare(select, 0, NULL);
359352
if (plan == NULL) {
360353
ereport(ERROR,
361354
(errcode(ERRCODE_INVALID_CURSOR_STATE),
362-
errmsg("Failed to preapre statement ", select)));
355+
errmsg("Failed to preapre statement %s", select)));
363356
}
364357
portal = SPI_cursor_open(NULL, plan, NULL, NULL, true);
365358
if (portal == NULL) {
366359
ereport(ERROR,
367360
(errcode(ERRCODE_INVALID_CURSOR_STATE),
368-
errmsg("Failed to open cursor for ", select)));
361+
errmsg("Failed to open cursor for %s", select)));
369362
}
370363
while (true)
371364
{
@@ -374,40 +367,34 @@ AlterIndex(Oid relationId, IndexStmt *stmt, Oid indexRelationId)
374367
break;
375368
}
376369
tuple = SPI_tuptable->vals[0];
377-
tupdesc = SPI_tuptable->tupdesc;
378-
slot = TupleDescGetSlot(tupdesc);
379-
tupleid = &tuple->t_datat->t_ctid;
370+
tupleid = &tuple->t_data->t_ctid;
371+
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
380372

381373
FormIndexDatum(indexInfo,
382374
slot,
383375
estate,
384376
values,
385377
isnull);
386-
satisfiesConstraint =
387-
index_insert(indexRelation, /* index relation */
388-
values, /* array of index Datums */
389-
isnull, /* null flags */
390-
tupleid, /* tid of heap tuple */
391-
heapRelation, /* heap relation */
392-
checkUnique); /* type of uniqueness check to do */
393-
394-
if (!satisfiesConstraint)
395-
{
396-
ereport(ERROR,
397-
(errcode(ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION),
398-
errmsg("Index constraint violation")));
399-
}
378+
index_insert(indexRelation, /* index relation */
379+
values, /* array of index Datums */
380+
isnull, /* null flags */
381+
tupleid, /* tid of heap tuple */
382+
heapRelation, /* heap relation */
383+
checkUnique); /* type of uniqueness check to do */
384+
400385
SPI_freetuple(tuple);
401386
SPI_freetuptable(SPI_tuptable);
402387
}
403388
SPI_cursor_close(portal);
404389
SPI_finish();
405390

406-
/* Close both the relations, but keep the locks */
391+
ExecDropSingleTupleTableSlot(slot);
392+
FreeExecutorState(estate);
393+
394+
heap_close(pg_index, NoLock);
407395
heap_close(heapRelation, NoLock);
408396
index_close(indexRelation, NoLock);
409397
}
410-
#endif
411398

412399
/*
413400
* DefineIndex

src/backend/nodes/copyfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3123,6 +3123,7 @@ _copyIndexStmt(const IndexStmt *from)
31233123
COPY_SCALAR_FIELD(transformed);
31243124
COPY_SCALAR_FIELD(concurrent);
31253125
COPY_SCALAR_FIELD(if_not_exists);
3126+
COPY_SCALAR_FIELD(is_alter);
31263127

31273128
return newnode;
31283129
}

src/backend/nodes/equalfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,7 @@ _equalIndexStmt(const IndexStmt *a, const IndexStmt *b)
12431243
COMPARE_SCALAR_FIELD(transformed);
12441244
COMPARE_SCALAR_FIELD(concurrent);
12451245
COMPARE_SCALAR_FIELD(if_not_exists);
1246+
COMPARE_SCALAR_FIELD(is_alter);
12461247

12471248
return true;
12481249
}

src/backend/nodes/outfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2184,6 +2184,7 @@ _outIndexStmt(StringInfo str, const IndexStmt *node)
21842184
WRITE_BOOL_FIELD(transformed);
21852185
WRITE_BOOL_FIELD(concurrent);
21862186
WRITE_BOOL_FIELD(if_not_exists);
2187+
WRITE_BOOL_FIELD(is_alter);
21872188
}
21882189

21892190
static void

src/backend/parser/gram.y

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,6 +1801,15 @@ AlterTableStmt:
18011801
n->nowait = $13;
18021802
$$ = (Node *)n;
18031803
}
1804+
| ALTER INDEX qualified_name WHERE a_expr
1805+
{
1806+
IndexStmt* n = makeNode(IndexStmt);
1807+
n->relation = $3;
1808+
n->whereClause = $5;
1809+
n->is_alter = true;
1810+
$$ = (Node *)n;
1811+
}
1812+
18041813
| ALTER INDEX qualified_name alter_table_cmds
18051814
{
18061815
AlterTableStmt *n = makeNode(AlterTableStmt);

src/backend/parser/parse_utilcmd.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,6 +2016,10 @@ transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
20162016
* to its fields without qualification. Caller is responsible for locking
20172017
* relation, but we still need to open it.
20182018
*/
2019+
if (stmt->is_alter)
2020+
{
2021+
relid = IndexGetRelation(relid, false);
2022+
}
20192023
rel = relation_open(relid, NoLock);
20202024
rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
20212025

src/backend/tcop/utility.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,22 +1257,29 @@ ProcessUtilitySlow(Node *parsetree,
12571257

12581258
/* ... and do it */
12591259
EventTriggerAlterTableStart(parsetree);
1260-
address =
1261-
DefineIndex(relid, /* OID of heap relation */
1262-
stmt,
1263-
InvalidOid, /* no predefined OID */
1264-
false, /* is_alter_table */
1265-
true, /* check_rights */
1266-
false, /* skip_build */
1267-
false); /* quiet */
1268-
1269-
/*
1270-
* Add the CREATE INDEX node itself to stash right away;
1271-
* if there were any commands stashed in the ALTER TABLE
1272-
* code, we need them to appear after this one.
1273-
*/
1274-
EventTriggerCollectSimpleCommand(address, secondaryObject,
1275-
parsetree);
1260+
if (stmt->is_alter)
1261+
{
1262+
AlterIndex(relid, stmt);
1263+
}
1264+
else
1265+
{
1266+
address =
1267+
DefineIndex(relid, /* OID of heap relation */
1268+
stmt,
1269+
InvalidOid, /* no predefined OID */
1270+
false, /* is_alter_table */
1271+
true, /* check_rights */
1272+
false, /* skip_build */
1273+
false); /* quiet */
1274+
1275+
/*
1276+
* Add the CREATE INDEX node itself to stash right away;
1277+
* if there were any commands stashed in the ALTER TABLE
1278+
* code, we need them to appear after this one.
1279+
*/
1280+
EventTriggerCollectSimpleCommand(address, secondaryObject,
1281+
parsetree);
1282+
}
12761283
commandCollected = true;
12771284
EventTriggerAlterTableEnd();
12781285
}

src/bin/insbench/core

9.32 MB
Binary file not shown.

0 commit comments

Comments
 (0)