* SPI_cursor_open_internal() * * Common code for SPI_cursor_open variants */
| 1602 | * Common code for SPI_cursor_open variants |
| 1603 | */ |
| 1604 | static Portal |
| 1605 | SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, |
| 1606 | ParamListInfo paramLI, bool read_only) |
| 1607 | { |
| 1608 | CachedPlanSource *plansource; |
| 1609 | CachedPlan *cplan; |
| 1610 | List *stmt_list; |
| 1611 | char *query_string; |
| 1612 | ListCell *lc; |
| 1613 | Snapshot snapshot; |
| 1614 | MemoryContext oldcontext; |
| 1615 | Portal portal; |
| 1616 | SPICallbackArg spicallbackarg; |
| 1617 | ErrorContextCallback spierrcontext; |
| 1618 | |
| 1619 | /* |
| 1620 | * Check that the plan is something the Portal code will special-case as |
| 1621 | * returning one tupleset. |
| 1622 | */ |
| 1623 | if (!SPI_is_cursor_plan(plan)) |
| 1624 | { |
| 1625 | /* try to give a good error message */ |
| 1626 | const char *cmdtag; |
| 1627 | |
| 1628 | if (list_length(plan->plancache_list) != 1) |
| 1629 | ereport(ERROR, |
| 1630 | (errcode(ERRCODE_INVALID_CURSOR_DEFINITION), |
| 1631 | errmsg("cannot open multi-query plan as cursor"))); |
| 1632 | plansource = (CachedPlanSource *) linitial(plan->plancache_list); |
| 1633 | /* A SELECT that fails SPI_is_cursor_plan() must be SELECT INTO */ |
| 1634 | if (plansource->commandTag == CMDTAG_SELECT) |
| 1635 | cmdtag = "SELECT INTO"; |
| 1636 | else |
| 1637 | cmdtag = GetCommandTagName(plansource->commandTag); |
| 1638 | ereport(ERROR, |
| 1639 | (errcode(ERRCODE_INVALID_CURSOR_DEFINITION), |
| 1640 | /* translator: %s is name of a SQL command, eg INSERT */ |
| 1641 | errmsg("cannot open %s query as cursor", cmdtag))); |
| 1642 | } |
| 1643 | |
| 1644 | Assert(list_length(plan->plancache_list) == 1); |
| 1645 | plansource = (CachedPlanSource *) linitial(plan->plancache_list); |
| 1646 | |
| 1647 | /* Push the SPI stack */ |
| 1648 | if (_SPI_begin_call(true) < 0) |
| 1649 | elog(ERROR, "SPI_cursor_open called while not connected"); |
| 1650 | |
| 1651 | /* Reset SPI result (note we deliberately don't touch lastoid) */ |
| 1652 | SPI_processed = 0; |
| 1653 | SPI_tuptable = NULL; |
| 1654 | _SPI_current->processed = 0; |
| 1655 | _SPI_current->tuptable = NULL; |
| 1656 | |
| 1657 | /* Create the portal */ |
| 1658 | if (name == NULL || name[0] == '\0') |
| 1659 | { |
| 1660 | /* Use a random nonconflicting name */ |
| 1661 | portal = CreateNewPortal(); |
no test coverage detected