@@ -279,6 +279,30 @@ CheckIndexCompatible(Oid oldId,
279
279
return ret ;
280
280
}
281
281
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
+
282
306
void
283
307
AlterIndex (Oid indexRelationId , IndexStmt * stmt )
284
308
{
@@ -292,14 +316,15 @@ AlterIndex(Oid indexRelationId, IndexStmt *stmt)
292
316
SPIPlanPtr plan ;
293
317
Portal portal ;
294
318
HeapTuple tuple ;
295
- HeapTuple updatedTuple ;
296
319
TupleTableSlot * slot ;
297
320
ItemPointer tupleid ;
298
321
IndexInfo * indexInfo ;
299
322
EState * estate ;
300
323
Oid namespaceId ;
301
- Relation pg_index ;
302
324
List * deparseCtx ;
325
+ char * oldIndexPredicate ;
326
+ char * newIndexPredicate ;
327
+ char * relationName ;
303
328
304
329
Assert (stmt -> whereClause );
305
330
CheckPredicate ((Expr * ) stmt -> whereClause );
@@ -314,8 +339,6 @@ AlterIndex(Oid indexRelationId, IndexStmt *stmt)
314
339
/* indexRelation = index_open(indexRelationId, AccessShareLock); */
315
340
namespaceId = RelationGetNamespace (indexRelation );
316
341
317
- pg_index = heap_open (IndexRelationId , RowExclusiveLock );
318
-
319
342
indexInfo = BuildIndexInfo (indexRelation );
320
343
Assert (indexInfo -> ii_Predicate );
321
344
Assert (!indexInfo -> ii_ExclusionOps );
@@ -327,75 +350,85 @@ AlterIndex(Oid indexRelationId, IndexStmt *stmt)
327
350
328
351
checkUnique = indexRelation -> rd_index -> indisunique ? UNIQUE_CHECK_YES : UNIQUE_CHECK_NO ;
329
352
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
-
345
353
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);
346
360
347
361
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
+ {
362
367
ereport (ERROR ,
363
368
(errcode (ERRCODE_INVALID_CURSOR_STATE ),
364
- errmsg ("Failed to open cursor for %s" , select )));
369
+ errmsg ("Failed to execute statement %s" , select )));
365
370
}
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 */
375
415
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 );
390
422
}
391
- SPI_cursor_close (portal );
392
423
SPI_finish ();
393
424
394
425
ExecDropSingleTupleTableSlot (slot );
395
426
FreeExecutorState (estate );
396
427
397
428
heap_close (heapRelation , NoLock );
398
- index_close (indexRelation , NoLock );
429
+ if (indexRelation ) {
430
+ index_close (indexRelation , NoLock );
431
+ }
399
432
}
400
433
401
434
/*
0 commit comments