@@ -189,6 +189,8 @@ typedef struct TransactionStateData
189
189
bool startedInRecovery ; /* did we start in recovery? */
190
190
bool didLogXid ; /* has xid been included in WAL record? */
191
191
int parallelModeLevel ; /* Enter/ExitParallelMode counter */
192
+ bool isCachedSubXact ;
193
+ struct TransactionStateData * cachedSubXact ;
192
194
struct TransactionStateData * parent ; /* back link to parent */
193
195
} TransactionStateData ;
194
196
@@ -302,7 +304,7 @@ static void CommitSubTransaction(void);
302
304
static void AbortSubTransaction (void );
303
305
static void CleanupSubTransaction (void );
304
306
static void PushTransaction (void );
305
- static void PopTransaction (void );
307
+ static void PopTransaction (bool free );
306
308
307
309
static void AtSubAbort_Memory (void );
308
310
static void AtSubCleanup_Memory (void );
@@ -316,6 +318,8 @@ static void ShowTransactionStateRec(const char *str, TransactionState state);
316
318
static const char * BlockStateAsString (TBlockState blockState );
317
319
static const char * TransStateAsString (TransState state );
318
320
321
+ static void ReleaseCurrentCachedSubTransaction (void );
322
+ static void RollbackAndReleaseCurrentCachedSubTransaction (void );
319
323
320
324
/* ----------------------------------------------------------------
321
325
* transaction state accessors
@@ -2768,6 +2772,8 @@ CommitTransactionCommand(void)
2768
2772
{
2769
2773
TransactionState s = CurrentTransactionState ;
2770
2774
2775
+ ReleaseCurrentCachedSubTransaction ();
2776
+
2771
2777
switch (s -> blockState )
2772
2778
{
2773
2779
/*
@@ -3008,6 +3014,8 @@ AbortCurrentTransaction(void)
3008
3014
{
3009
3015
TransactionState s = CurrentTransactionState ;
3010
3016
3017
+ RollbackAndReleaseCurrentCachedSubTransaction ();
3018
+
3011
3019
switch (s -> blockState )
3012
3020
{
3013
3021
case TBLOCK_DEFAULT :
@@ -4155,6 +4163,47 @@ RollbackToSavepoint(const char *name)
4155
4163
BlockStateAsString (xact -> blockState ));
4156
4164
}
4157
4165
4166
+ static void
4167
+ RestoreSubTransactionState (TransactionState subxact )
4168
+ {
4169
+ CurrentTransactionState = subxact ;
4170
+
4171
+ CurTransactionContext = subxact -> curTransactionContext ;
4172
+ MemoryContextSwitchTo (CurTransactionContext );
4173
+ CurTransactionResourceOwner = subxact -> curTransactionOwner ;
4174
+ CurrentResourceOwner = subxact -> curTransactionOwner ;
4175
+ }
4176
+
4177
+ static void
4178
+ ReleaseCurrentCachedSubTransaction (void )
4179
+ {
4180
+ TransactionState s = CurrentTransactionState ;
4181
+
4182
+ if (s -> cachedSubXact )
4183
+ {
4184
+ RestoreSubTransactionState (s -> cachedSubXact );
4185
+ ReleaseCurrentCachedSubTransaction ();
4186
+ MemoryContextSwitchTo (CurTransactionContext );
4187
+ CommitSubTransaction ();
4188
+ Assert (s == CurrentTransactionState );
4189
+ s -> cachedSubXact = NULL ;
4190
+ }
4191
+ }
4192
+
4193
+ static void
4194
+ RollbackAndReleaseCurrentCachedSubTransaction (void )
4195
+ {
4196
+ TransactionState s = CurrentTransactionState ;
4197
+
4198
+ if (s -> cachedSubXact )
4199
+ {
4200
+ RestoreSubTransactionState (s -> cachedSubXact );
4201
+ RollbackAndReleaseCurrentSubTransaction ();
4202
+ Assert (s == CurrentTransactionState );
4203
+ s -> cachedSubXact = NULL ;
4204
+ }
4205
+ }
4206
+
4158
4207
/*
4159
4208
* BeginInternalSubTransaction
4160
4209
* This is the same as DefineSavepoint except it allows TBLOCK_STARTED,
@@ -4165,8 +4214,8 @@ RollbackToSavepoint(const char *name)
4165
4214
* CommitTransactionCommand/StartTransactionCommand instead of expecting
4166
4215
* the caller to do it.
4167
4216
*/
4168
- void
4169
- BeginInternalSubTransaction (const char * name )
4217
+ static void
4218
+ BeginInternalSubTransactionInternal (const char * name , bool cached )
4170
4219
{
4171
4220
TransactionState s = CurrentTransactionState ;
4172
4221
@@ -4193,10 +4242,31 @@ BeginInternalSubTransaction(const char *name)
4193
4242
case TBLOCK_END :
4194
4243
case TBLOCK_PREPARE :
4195
4244
case TBLOCK_SUBINPROGRESS :
4245
+ if (s -> cachedSubXact )
4246
+ {
4247
+ TransactionState subxact = s -> cachedSubXact ;
4248
+
4249
+ s -> cachedSubXact = NULL ;
4250
+
4251
+ Assert (subxact -> subTransactionId == currentSubTransactionId );
4252
+ if (subxact -> subTransactionId == currentSubTransactionId )
4253
+ {
4254
+ /* reuse cached subtransaction */
4255
+ RestoreSubTransactionState (subxact );
4256
+ return ;
4257
+ }
4258
+ else
4259
+ {
4260
+ ReleaseCurrentCachedSubTransaction ();
4261
+ }
4262
+ }
4263
+
4196
4264
/* Normal subtransaction start */
4197
4265
PushTransaction ();
4198
4266
s = CurrentTransactionState ; /* changed by push */
4199
4267
4268
+ s -> isCachedSubXact = cached ;
4269
+
4200
4270
/*
4201
4271
* Savepoint names, like the TransactionState block itself, live
4202
4272
* in TopTransactionContext.
@@ -4229,6 +4299,18 @@ BeginInternalSubTransaction(const char *name)
4229
4299
StartTransactionCommand ();
4230
4300
}
4231
4301
4302
+ void
4303
+ BeginInternalSubTransaction (const char * name )
4304
+ {
4305
+ BeginInternalSubTransactionInternal (name , false);
4306
+ }
4307
+
4308
+ void
4309
+ BeginInternalCachedSubTransaction (const char * name )
4310
+ {
4311
+ BeginInternalSubTransactionInternal (name , true);
4312
+ }
4313
+
4232
4314
/*
4233
4315
* ReleaseCurrentSubTransaction
4234
4316
*
@@ -4257,8 +4339,40 @@ ReleaseCurrentSubTransaction(void)
4257
4339
elog (ERROR , "ReleaseCurrentSubTransaction: unexpected state %s" ,
4258
4340
BlockStateAsString (s -> blockState ));
4259
4341
Assert (s -> state == TRANS_INPROGRESS );
4260
- MemoryContextSwitchTo (CurTransactionContext );
4261
- CommitSubTransaction ();
4342
+
4343
+ ReleaseCurrentCachedSubTransaction ();
4344
+
4345
+ if (s -> isCachedSubXact &&
4346
+ !TransactionIdIsValid (s -> transactionId ) &&
4347
+ !s -> cachedSubXact /*&
4348
+ (!s->curTransactionOwner ||
4349
+ (!s->curTransactionOwner->firstchild &&
4350
+ s->curTransactionOwner->nlocks <= 0))*/ )
4351
+ {
4352
+ if (s -> curTransactionOwner )
4353
+ {
4354
+ ResourceOwnerRelease (s -> curTransactionOwner ,
4355
+ RESOURCE_RELEASE_BEFORE_LOCKS ,
4356
+ true, false);
4357
+ ResourceOwnerRelease (s -> curTransactionOwner ,
4358
+ RESOURCE_RELEASE_LOCKS ,
4359
+ true, false);
4360
+ ResourceOwnerRelease (s -> curTransactionOwner ,
4361
+ RESOURCE_RELEASE_AFTER_LOCKS ,
4362
+ true, false);
4363
+ }
4364
+
4365
+ Assert (!s -> parent -> cachedSubXact );
4366
+ s -> parent -> cachedSubXact = s ;
4367
+
4368
+ PopTransaction (false);
4369
+ }
4370
+ else
4371
+ {
4372
+ MemoryContextSwitchTo (CurTransactionContext );
4373
+ CommitSubTransaction ();
4374
+ }
4375
+
4262
4376
s = CurrentTransactionState ; /* changed by pop */
4263
4377
Assert (s -> state == TRANS_INPROGRESS );
4264
4378
}
@@ -4314,6 +4428,8 @@ RollbackAndReleaseCurrentSubTransaction(void)
4314
4428
break ;
4315
4429
}
4316
4430
4431
+ RollbackAndReleaseCurrentCachedSubTransaction ();
4432
+
4317
4433
/*
4318
4434
* Abort the current subtransaction, if needed.
4319
4435
*/
@@ -4678,7 +4794,7 @@ CommitSubTransaction(void)
4678
4794
4679
4795
s -> state = TRANS_DEFAULT ;
4680
4796
4681
- PopTransaction ();
4797
+ PopTransaction (true );
4682
4798
}
4683
4799
4684
4800
/*
@@ -4856,7 +4972,7 @@ CleanupSubTransaction(void)
4856
4972
4857
4973
s -> state = TRANS_DEFAULT ;
4858
4974
4859
- PopTransaction ();
4975
+ PopTransaction (true );
4860
4976
}
4861
4977
4862
4978
/*
@@ -4926,11 +5042,11 @@ PushTransaction(void)
4926
5042
* if it has a local pointer to it after calling this function.
4927
5043
*/
4928
5044
static void
4929
- PopTransaction (void )
5045
+ PopTransaction (bool free )
4930
5046
{
4931
5047
TransactionState s = CurrentTransactionState ;
4932
5048
4933
- if (s -> state != TRANS_DEFAULT )
5049
+ if (free && s -> state != TRANS_DEFAULT )
4934
5050
elog (WARNING , "PopTransaction while in %s state" ,
4935
5051
TransStateAsString (s -> state ));
4936
5052
@@ -4947,6 +5063,9 @@ PopTransaction(void)
4947
5063
CurTransactionResourceOwner = s -> parent -> curTransactionOwner ;
4948
5064
CurrentResourceOwner = s -> parent -> curTransactionOwner ;
4949
5065
5066
+ if (!free )
5067
+ return ;
5068
+
4950
5069
/* Free the old child structure */
4951
5070
if (s -> name )
4952
5071
pfree (s -> name );
0 commit comments