@@ -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+
282306void
283307AlterIndex (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