@@ -188,7 +188,40 @@ SpoolerClose(Spooler *self)
188188
189189 /* Terminate spooler. */
190190 ExecDropSingleTupleTableSlot (self -> slot );
191- #if PG_VERSION_NUM >= 140000
191+ #if PG_VERSION_NUM >= 180000
192+ /*
193+ * In PostgreSQL 18 and later, ExecCloseIndices() asserts that it is not
194+ * called on a ResultRelInfo with already-closed indexes. However,
195+ * IndexSpoolEnd() may have already closed some indexes (e.g. non-btree
196+ * indexes that get reindexed), which causes the assertion to fail.
197+ *
198+ * To work around this, we replicate the logic of ExecCloseIndices()
199+ * here, but with a check to skip already-closed indexes, similar to how
200+ * older PostgreSQL versions behaved. We don't call
201+ * ExecCloseResultRelations() to avoid the problematic assertion.
202+ */
203+ if (self -> relinfo )
204+ {
205+ ResultRelInfo * resultRelInfo = self -> relinfo ;
206+ int i ;
207+
208+ if (resultRelInfo -> ri_NumIndices > 0 )
209+ {
210+ for (i = 0 ; i < resultRelInfo -> ri_NumIndices ; i ++ )
211+ {
212+ if (resultRelInfo -> ri_IndexRelationDescs [i ] == NULL )
213+ continue ;
214+
215+ /* Give the index a chance to do some post-insert cleanup */
216+ index_insert_cleanup (resultRelInfo -> ri_IndexRelationDescs [i ],
217+ resultRelInfo -> ri_IndexRelationInfo [i ]);
218+
219+ /* Drop lock acquired by ExecOpenIndices */
220+ index_close (resultRelInfo -> ri_IndexRelationDescs [i ], RowExclusiveLock );
221+ }
222+ }
223+ }
224+ #elif PG_VERSION_NUM >= 140000
192225 if (self -> relinfo )
193226 ExecCloseResultRelations (self -> estate );
194227#else
0 commit comments