| 1411 | } |
| 1412 | |
| 1413 | void |
| 1414 | SPI_freetuptable(SPITupleTable *tuptable) |
| 1415 | { |
| 1416 | bool found = false; |
| 1417 | |
| 1418 | /* ignore call if NULL pointer */ |
| 1419 | if (tuptable == NULL) |
| 1420 | return; |
| 1421 | |
| 1422 | /* |
| 1423 | * Search only the topmost SPI context for a matching tuple table. |
| 1424 | */ |
| 1425 | if (_SPI_current != NULL) |
| 1426 | { |
| 1427 | slist_mutable_iter siter; |
| 1428 | |
| 1429 | /* find tuptable in active list, then remove it */ |
| 1430 | slist_foreach_modify(siter, &_SPI_current->tuptables) |
| 1431 | { |
| 1432 | SPITupleTable *tt; |
| 1433 | |
| 1434 | tt = slist_container(SPITupleTable, next, siter.cur); |
| 1435 | if (tt == tuptable) |
| 1436 | { |
| 1437 | slist_delete_current(&siter); |
| 1438 | found = true; |
| 1439 | break; |
| 1440 | } |
| 1441 | } |
| 1442 | } |
| 1443 | |
| 1444 | /* |
| 1445 | * Refuse the deletion if we didn't find it in the topmost SPI context. |
| 1446 | * This is primarily a guard against double deletion, but might prevent |
| 1447 | * other errors as well. Since the worst consequence of not deleting a |
| 1448 | * tuptable would be a transient memory leak, this is just a WARNING. |
| 1449 | */ |
| 1450 | if (!found) |
| 1451 | { |
| 1452 | elog(WARNING, "attempt to delete invalid SPITupleTable %p", tuptable); |
| 1453 | return; |
| 1454 | } |
| 1455 | |
| 1456 | /* for safety, reset global variables that might point at tuptable */ |
| 1457 | if (tuptable == _SPI_current->tuptable) |
| 1458 | _SPI_current->tuptable = NULL; |
| 1459 | if (tuptable == SPI_tuptable) |
| 1460 | SPI_tuptable = NULL; |
| 1461 | |
| 1462 | /* release all memory belonging to tuptable */ |
| 1463 | MemoryContextDelete(tuptable->tuptabcxt); |
| 1464 | } |
| 1465 | |
| 1466 | |
| 1467 | /* |
no test coverage detected