| 245 | } |
| 246 | |
| 247 | static void |
| 248 | _SPI_commit(bool chain) |
| 249 | { |
| 250 | MemoryContext oldcontext = CurrentMemoryContext; |
| 251 | |
| 252 | /* |
| 253 | * Complain if we are in a context that doesn't permit transaction |
| 254 | * termination. (Note: here and _SPI_rollback should be the only places |
| 255 | * that throw ERRCODE_INVALID_TRANSACTION_TERMINATION, so that callers can |
| 256 | * test for that with security that they know what happened.) |
| 257 | */ |
| 258 | if (_SPI_current->atomic) |
| 259 | ereport(ERROR, |
| 260 | (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION), |
| 261 | errmsg("invalid transaction termination"))); |
| 262 | |
| 263 | /* |
| 264 | * This restriction is required by PLs implemented on top of SPI. They |
| 265 | * use subtransactions to establish exception blocks that are supposed to |
| 266 | * be rolled back together if there is an error. Terminating the |
| 267 | * top-level transaction in such a block violates that idea. A future PL |
| 268 | * implementation might have different ideas about this, in which case |
| 269 | * this restriction would have to be refined or the check possibly be |
| 270 | * moved out of SPI into the PLs. Note however that the code below relies |
| 271 | * on not being within a subtransaction. |
| 272 | */ |
| 273 | if (IsSubTransaction()) |
| 274 | ereport(ERROR, |
| 275 | (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION), |
| 276 | errmsg("cannot commit while a subtransaction is active"))); |
| 277 | |
| 278 | /* XXX this ain't re-entrant enough for my taste */ |
| 279 | if (chain) |
| 280 | SaveTransactionCharacteristics(); |
| 281 | |
| 282 | /* Catch any error occurring during the COMMIT */ |
| 283 | PG_TRY(); |
| 284 | { |
| 285 | /* Protect current SPI stack entry against deletion */ |
| 286 | _SPI_current->internal_xact = true; |
| 287 | |
| 288 | /* |
| 289 | * Hold any pinned portals that any PLs might be using. We have to do |
| 290 | * this before changing transaction state, since this will run |
| 291 | * user-defined code that might throw an error. |
| 292 | */ |
| 293 | HoldPinnedPortals(); |
| 294 | |
| 295 | /* Release snapshots associated with portals */ |
| 296 | ForgetPortalSnapshots(); |
| 297 | |
| 298 | /* Do the deed */ |
| 299 | CommitTransactionCommand(); |
| 300 | |
| 301 | /* Immediately start a new transaction */ |
| 302 | StartTransactionCommand(); |
| 303 | if (chain) |
| 304 | RestoreTransactionCharacteristics(); |
no test coverage detected