| 75 | |
| 76 | |
| 77 | static PyObject * |
| 78 | PLy_cursor_query(const char *query) |
| 79 | { |
| 80 | PLyCursorObject *cursor; |
| 81 | PLyExecutionContext *exec_ctx = PLy_current_execution_context(); |
| 82 | volatile MemoryContext oldcontext; |
| 83 | volatile ResourceOwner oldowner; |
| 84 | |
| 85 | if ((cursor = PyObject_New(PLyCursorObject, &PLy_CursorType)) == NULL) |
| 86 | return NULL; |
| 87 | cursor->portalname = NULL; |
| 88 | cursor->closed = false; |
| 89 | cursor->mcxt = AllocSetContextCreate(TopMemoryContext, |
| 90 | "PL/Python cursor context", |
| 91 | ALLOCSET_DEFAULT_SIZES); |
| 92 | |
| 93 | /* Initialize for converting result tuples to Python */ |
| 94 | PLy_input_setup_func(&cursor->result, cursor->mcxt, |
| 95 | RECORDOID, -1, |
| 96 | exec_ctx->curr_proc); |
| 97 | |
| 98 | oldcontext = CurrentMemoryContext; |
| 99 | oldowner = CurrentResourceOwner; |
| 100 | |
| 101 | if(!PLy_spi_subtransaction_begin(oldcontext, oldowner)) |
| 102 | return NULL; |
| 103 | |
| 104 | PG_TRY(); |
| 105 | { |
| 106 | SPIPlanPtr plan; |
| 107 | Portal portal; |
| 108 | |
| 109 | pg_verifymbstr(query, strlen(query), false); |
| 110 | |
| 111 | plan = SPI_prepare(query, 0, NULL); |
| 112 | if (plan == NULL) |
| 113 | elog(ERROR, "SPI_prepare failed: %s", |
| 114 | SPI_result_code_string(SPI_result)); |
| 115 | |
| 116 | portal = SPI_cursor_open(NULL, plan, NULL, NULL, |
| 117 | exec_ctx->curr_proc->fn_readonly); |
| 118 | SPI_freeplan(plan); |
| 119 | |
| 120 | if (portal == NULL) |
| 121 | elog(ERROR, "SPI_cursor_open() failed: %s", |
| 122 | SPI_result_code_string(SPI_result)); |
| 123 | |
| 124 | cursor->portalname = MemoryContextStrdup(cursor->mcxt, portal->name); |
| 125 | |
| 126 | PinPortal(portal); |
| 127 | |
| 128 | PLy_spi_subtransaction_commit(oldcontext, oldowner); |
| 129 | } |
| 130 | PG_CATCH(); |
| 131 | { |
| 132 | PLy_spi_subtransaction_abort(oldcontext, oldowner); |
| 133 | return NULL; |
| 134 | } |
no test coverage detected