@@ -284,6 +284,30 @@ CheckIndexCompatible(Oid oldId,
284284 return ret ;
285285}
286286
287+ static void
288+ UpdateIndex (Oid indexRelationId , Node * whereClause )
289+ {
290+ Datum values [Natts_pg_index ];
291+ bool isnull [Natts_pg_index ];
292+ HeapTuple oldTuple ;
293+ HeapTuple newTuple ;
294+ Relation pg_index ;
295+
296+ pg_index = heap_open (IndexRelationId , RowExclusiveLock );
297+ oldTuple = SearchSysCacheCopy1 (INDEXRELID , ObjectIdGetDatum (indexRelationId ));
298+ if (!HeapTupleIsValid (oldTuple ))
299+ elog (ERROR , "cache lookup failed for index %u" , indexRelationId );
300+
301+ heap_deform_tuple (oldTuple , RelationGetDescr (pg_index ), values , isnull );
302+ values [Anum_pg_index_indpred - 1 ] = CStringGetTextDatum (nodeToString (whereClause ));
303+ newTuple = heap_form_tuple (RelationGetDescr (pg_index ), values , isnull );
304+ simple_heap_update (pg_index , & oldTuple -> t_self , newTuple );
305+ CatalogUpdateIndexes (pg_index , newTuple );
306+ heap_freetuple (newTuple );
307+ heap_freetuple (oldTuple );
308+ heap_close (pg_index , NoLock );
309+ }
310+
287311void
288312AlterIndex (Oid indexRelationId , IndexStmt * stmt )
289313{
@@ -297,14 +321,15 @@ AlterIndex(Oid indexRelationId, IndexStmt *stmt)
297321 SPIPlanPtr plan ;
298322 Portal portal ;
299323 HeapTuple tuple ;
300- HeapTuple updatedTuple ;
301324 TupleTableSlot * slot ;
302325 ItemPointer tupleid ;
303326 IndexInfo * indexInfo ;
304327 EState * estate ;
305328 Oid namespaceId ;
306- Relation pg_index ;
307329 List * deparseCtx ;
330+ char * oldIndexPredicate ;
331+ char * newIndexPredicate ;
332+ char * relationName ;
308333
309334 Assert (stmt -> whereClause );
310335 CheckPredicate ((Expr * ) stmt -> whereClause );
@@ -319,8 +344,6 @@ AlterIndex(Oid indexRelationId, IndexStmt *stmt)
319344 /* indexRelation = index_open(indexRelationId, AccessShareLock); */
320345 namespaceId = RelationGetNamespace (indexRelation );
321346
322- pg_index = heap_open (IndexRelationId , RowExclusiveLock );
323-
324347 indexInfo = BuildIndexInfo (indexRelation );
325348 Assert (indexInfo -> ii_Predicate );
326349 Assert (!indexInfo -> ii_ExclusionOps );
@@ -332,75 +355,85 @@ AlterIndex(Oid indexRelationId, IndexStmt *stmt)
332355
333356 checkUnique = indexRelation -> rd_index -> indisunique ? UNIQUE_CHECK_YES : UNIQUE_CHECK_NO ;
334357
335- /* Update pg_index tuple */
336- tuple = SearchSysCacheCopy1 (INDEXRELID , ObjectIdGetDatum (indexRelationId ));
337- if (!HeapTupleIsValid (tuple ))
338- elog (ERROR , "cache lookup failed for index %u" , indexRelationId );
339-
340- Assert (Natts_pg_index <= INDEX_MAX_KEYS );
341- heap_deform_tuple (tuple , RelationGetDescr (pg_index ), values , isnull );
342- values [Anum_pg_index_indpred - 1 ] = CStringGetTextDatum (nodeToString (stmt -> whereClause ));
343- updatedTuple = heap_form_tuple (RelationGetDescr (pg_index ), values , isnull );
344- simple_heap_update (pg_index , & tuple -> t_self , updatedTuple );
345- CatalogUpdateIndexes (pg_index , updatedTuple );
346- heap_freetuple (updatedTuple );
347- heap_freetuple (tuple );
348- heap_close (pg_index , NoLock );
349-
350358 slot = MakeSingleTupleTableSlot (RelationGetDescr (heapRelation ));
359+
360+ deparseCtx = deparse_context_for (RelationGetRelationName (heapRelation ), heapRelationId );
361+ relationName = quote_qualified_identifier (get_namespace_name (namespaceId ),
362+ get_rel_name (heapRelationId )),
363+ newIndexPredicate = deparse_expression (stmt -> whereClause , deparseCtx , false, false);
364+ oldIndexPredicate = deparse_expression ((Node * )make_ands_explicit (indexInfo -> ii_Predicate ), deparseCtx , false, false);
351365
352366 SPI_connect ();
353- deparseCtx = deparse_context_for (RelationGetRelationName (heapRelation ), heapRelationId );
354- select = psprintf ("select * from %s where %s and not (%s)" ,
355- quote_qualified_identifier (get_namespace_name (namespaceId ),
356- get_rel_name (heapRelationId )),
357- deparse_expression (stmt -> whereClause , deparseCtx , false, false),
358- deparse_expression ((Node * )make_ands_explicit (indexInfo -> ii_Predicate ), deparseCtx , false, false));
359- plan = SPI_prepare (select , 0 , NULL );
360- if (plan == NULL ) {
361- ereport (ERROR ,
362- (errcode (ERRCODE_INVALID_CURSOR_STATE ),
363- errmsg ("Failed to preapre statement %s" , select )));
364- }
365- portal = SPI_cursor_open (NULL , plan , NULL , NULL , true);
366- if (portal == NULL ) {
367+
368+ select = psprintf ("select * from %s where %s and not (%s) limit 1" ,
369+ relationName , oldIndexPredicate , newIndexPredicate );
370+ if (SPI_execute (select , true, 1 ) != SPI_OK_SELECT )
371+ {
367372 ereport (ERROR ,
368373 (errcode (ERRCODE_INVALID_CURSOR_STATE ),
369- errmsg ("Failed to open cursor for %s" , select )));
374+ errmsg ("Failed to execute statement %s" , select )));
370375 }
371- while (true)
372- {
373- SPI_cursor_fetch (portal , true, 1 );
374- if (!SPI_processed ) {
375- break ;
376- }
377- tuple = SPI_tuptable -> vals [0 ];
378- tupleid = & tuple -> t_data -> t_ctid ;
379- ExecStoreTuple (tuple , slot , InvalidBuffer , false);
376+ if (SPI_processed ) {
377+ /* There is no way in Postgres to exclude records from index, so we have to completelty rebuild index in this case */
378+ bool relpersistence = indexRelation -> rd_rel -> relpersistence ;
379+ index_close (indexRelation , NoLock );
380+ indexRelation -> rd_indpred = make_ands_implicit ((Expr * ) stmt -> whereClause );
381+ indexRelation = NULL ;
382+ UpdateIndex (indexRelationId , stmt -> whereClause );
383+ reindex_index (indexRelationId , false, relpersistence , 0 );
384+ } else {
385+ select = psprintf ("select * from %s where %s and not (%s)" ,
386+ relationName , newIndexPredicate , oldIndexPredicate );
387+ plan = SPI_prepare (select , 0 , NULL );
388+ if (plan == NULL ) {
389+ ereport (ERROR ,
390+ (errcode (ERRCODE_INVALID_CURSOR_STATE ),
391+ errmsg ("Failed to preapre statement %s" , select )));
392+ }
393+ portal = SPI_cursor_open (NULL , plan , NULL , NULL , true);
394+ if (portal == NULL ) {
395+ ereport (ERROR ,
396+ (errcode (ERRCODE_INVALID_CURSOR_STATE ),
397+ errmsg ("Failed to open cursor for %s" , select )));
398+ }
399+ while (true)
400+ {
401+ SPI_cursor_fetch (portal , true, 1 );
402+ if (!SPI_processed ) {
403+ break ;
404+ }
405+ tuple = SPI_tuptable -> vals [0 ];
406+ tupleid = & tuple -> t_data -> t_ctid ;
407+ ExecStoreTuple (tuple , slot , InvalidBuffer , false);
408+
409+ FormIndexDatum (indexInfo ,
410+ slot ,
411+ estate ,
412+ values ,
413+ isnull );
414+ index_insert (indexRelation , /* index relation */
415+ values , /* array of index Datums */
416+ isnull , /* null flags */
417+ tupleid , /* tid of heap tuple */
418+ heapRelation , /* heap relation */
419+ checkUnique ); /* type of uniqueness check to do */
380420
381- FormIndexDatum (indexInfo ,
382- slot ,
383- estate ,
384- values ,
385- isnull );
386- index_insert (indexRelation , /* index relation */
387- values , /* array of index Datums */
388- isnull , /* null flags */
389- tupleid , /* tid of heap tuple */
390- heapRelation , /* heap relation */
391- checkUnique ); /* type of uniqueness check to do */
392-
393- SPI_freetuple (tuple );
394- SPI_freetuptable (SPI_tuptable );
421+ SPI_freetuple (tuple );
422+ SPI_freetuptable (SPI_tuptable );
423+ }
424+ SPI_cursor_close (portal );
425+
426+ UpdateIndex (indexRelationId , stmt -> whereClause );
395427 }
396- SPI_cursor_close (portal );
397428 SPI_finish ();
398429
399430 ExecDropSingleTupleTableSlot (slot );
400431 FreeExecutorState (estate );
401432
402433 heap_close (heapRelation , NoLock );
403- index_close (indexRelation , NoLock );
434+ if (indexRelation ) {
435+ index_close (indexRelation , NoLock );
436+ }
404437}
405438
406439/*
0 commit comments