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)
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