| File: | plpy_spi.c |
| Location: | line 444, column 20 |
| Description: | Access to field 'tupdesc' results in a dereference of a null pointer (loaded from variable 'result') |
| 1 | /* | |||
| 2 | * interface to SPI functions | |||
| 3 | * | |||
| 4 | * src/pl/plpython/plpy_spi.c | |||
| 5 | */ | |||
| 6 | ||||
| 7 | #include "postgres.h" | |||
| 8 | ||||
| 9 | #include <limits.h> | |||
| 10 | ||||
| 11 | #include "access/htup_details.h" | |||
| 12 | #include "access/xact.h" | |||
| 13 | #include "catalog/pg_type.h" | |||
| 14 | #include "executor/spi.h" | |||
| 15 | #include "mb/pg_wchar.h" | |||
| 16 | #include "parser/parse_type.h" | |||
| 17 | #include "utils/memutils.h" | |||
| 18 | #include "utils/syscache.h" | |||
| 19 | ||||
| 20 | #include "plpython.h" | |||
| 21 | ||||
| 22 | #include "plpy_spi.h" | |||
| 23 | ||||
| 24 | #include "plpy_elog.h" | |||
| 25 | #include "plpy_main.h" | |||
| 26 | #include "plpy_planobject.h" | |||
| 27 | #include "plpy_plpymodule.h" | |||
| 28 | #include "plpy_procedure.h" | |||
| 29 | #include "plpy_resultobject.h" | |||
| 30 | ||||
| 31 | ||||
| 32 | static PyObject *PLy_spi_execute_query(char *query, long limit); | |||
| 33 | static PyObject *PLy_spi_execute_fetch_result(SPITupleTable *tuptable, | |||
| 34 | uint64 rows, int status); | |||
| 35 | static void PLy_spi_exception_set(PyObject *excclass, ErrorData *edata); | |||
| 36 | ||||
| 37 | ||||
| 38 | /* prepare(query="select * from foo") | |||
| 39 | * prepare(query="select * from foo where bar = $1", params=["text"]) | |||
| 40 | * prepare(query="select * from foo where bar = $1", params=["text"], limit=5) | |||
| 41 | */ | |||
| 42 | PyObject * | |||
| 43 | PLy_spi_prepare(PyObject *self, PyObject *args) | |||
| 44 | { | |||
| 45 | PLyPlanObject *plan; | |||
| 46 | PyObject *list = NULL((void*)0); | |||
| 47 | PyObject *volatile optr = NULL((void*)0); | |||
| 48 | char *query; | |||
| 49 | PLyExecutionContext *exec_ctx = PLy_current_execution_context(); | |||
| 50 | volatile MemoryContext oldcontext; | |||
| 51 | volatile ResourceOwner oldowner; | |||
| 52 | volatile int nargs; | |||
| 53 | ||||
| 54 | if (!PyArg_ParseTuple(args, "s|O:prepare", &query, &list)) | |||
| 55 | return NULL((void*)0); | |||
| 56 | ||||
| 57 | if (list && (!PySequence_Check(list))) | |||
| 58 | { | |||
| 59 | PLy_exception_set(PyExc_TypeError, | |||
| 60 | "second argument of plpy.prepare must be a sequence"); | |||
| 61 | return NULL((void*)0); | |||
| 62 | } | |||
| 63 | ||||
| 64 | if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL((void*)0)) | |||
| 65 | return NULL((void*)0); | |||
| 66 | ||||
| 67 | plan->mcxt = AllocSetContextCreate(TopMemoryContext, | |||
| 68 | "PL/Python plan context", | |||
| 69 | ALLOCSET_DEFAULT_SIZES0, (8 * 1024), (8 * 1024 * 1024)); | |||
| 70 | oldcontext = MemoryContextSwitchTo(plan->mcxt); | |||
| 71 | ||||
| 72 | nargs = list ? PySequence_LengthPySequence_Size(list) : 0; | |||
| 73 | ||||
| 74 | plan->nargs = nargs; | |||
| 75 | plan->types = nargs ? palloc0(sizeof(Oid) * nargs) : NULL((void*)0); | |||
| 76 | plan->values = nargs ? palloc0(sizeof(Datum) * nargs) : NULL((void*)0); | |||
| 77 | plan->args = nargs ? palloc0(sizeof(PLyObToDatum) * nargs) : NULL((void*)0); | |||
| 78 | ||||
| 79 | MemoryContextSwitchTo(oldcontext); | |||
| 80 | ||||
| 81 | oldcontext = CurrentMemoryContext; | |||
| 82 | oldowner = CurrentResourceOwner; | |||
| 83 | ||||
| 84 | PLy_spi_subtransaction_begin(oldcontext, oldowner); | |||
| 85 | ||||
| 86 | PG_TRY()do { sigjmp_buf *save_exception_stack = PG_exception_stack; ErrorContextCallback *save_context_stack = error_context_stack; sigjmp_buf local_sigjmp_buf ; if (__sigsetjmp (local_sigjmp_buf, 0) == 0) { PG_exception_stack = &local_sigjmp_buf; | |||
| 87 | { | |||
| 88 | int i; | |||
| 89 | ||||
| 90 | for (i = 0; i < nargs; i++) | |||
| 91 | { | |||
| 92 | char *sptr; | |||
| 93 | Oid typeId; | |||
| 94 | int32 typmod; | |||
| 95 | ||||
| 96 | optr = PySequence_GetItem(list, i); | |||
| 97 | if (PyString_Check(optr)((((((PyObject*)(optr))->ob_type))->tp_flags & ((1L <<27))) != 0)) | |||
| 98 | sptr = PyString_AsString(optr); | |||
| 99 | else if (PyUnicode_Check(optr)((((((PyObject*)(optr))->ob_type))->tp_flags & ((1L <<28))) != 0)) | |||
| 100 | sptr = PLyUnicode_AsString(optr); | |||
| 101 | else | |||
| 102 | { | |||
| 103 | ereport(ERROR,do { if (errstart(20, "plpy_spi.c", 104, __func__, ("plpython" "-" "11"))) errfinish (errmsg("plpy.prepare: type name at ordinal position %d is not a string" , i)); if (__builtin_constant_p(20) && (20) >= 20) abort(); } while(0) | |||
| 104 | (errmsg("plpy.prepare: type name at ordinal position %d is not a string", i)))do { if (errstart(20, "plpy_spi.c", 104, __func__, ("plpython" "-" "11"))) errfinish (errmsg("plpy.prepare: type name at ordinal position %d is not a string" , i)); if (__builtin_constant_p(20) && (20) >= 20) abort(); } while(0); | |||
| 105 | sptr = NULL((void*)0); /* keep compiler quiet */ | |||
| 106 | } | |||
| 107 | ||||
| 108 | /******************************************************** | |||
| 109 | * Resolve argument type names and then look them up by | |||
| 110 | * oid in the system cache, and remember the required | |||
| 111 | *information for input conversion. | |||
| 112 | ********************************************************/ | |||
| 113 | ||||
| 114 | parseTypeString(sptr, &typeId, &typmod, false((bool) 0)); | |||
| 115 | ||||
| 116 | Py_DECREF(optr)do { if ( --((PyObject*)(optr))->ob_refcnt != 0) ; else ( ( *(((PyObject*)((PyObject *)(optr)))->ob_type)->tp_dealloc )((PyObject *)((PyObject *)(optr)))); } while (0); | |||
| 117 | ||||
| 118 | /* | |||
| 119 | * set optr to NULL, so we won't try to unref it again in case of | |||
| 120 | * an error | |||
| 121 | */ | |||
| 122 | optr = NULL((void*)0); | |||
| 123 | ||||
| 124 | plan->types[i] = typeId; | |||
| 125 | PLy_output_setup_func(&plan->args[i], plan->mcxt, | |||
| 126 | typeId, typmod, | |||
| 127 | exec_ctx->curr_proc); | |||
| 128 | } | |||
| 129 | ||||
| 130 | pg_verifymbstr(query, strlen(query), false((bool) 0)); | |||
| 131 | plan->plan = SPI_prepare(query, plan->nargs, plan->types); | |||
| 132 | if (plan->plan == NULL((void*)0)) | |||
| 133 | elog(ERROR, "SPI_prepare failed: %s",do { elog_start("plpy_spi.c", 134, __func__); elog_finish(20, "SPI_prepare failed: %s", SPI_result_code_string(SPI_result) ); if (__builtin_constant_p(20) && (20) >= 20) abort (); } while(0) | |||
| 134 | SPI_result_code_string(SPI_result))do { elog_start("plpy_spi.c", 134, __func__); elog_finish(20, "SPI_prepare failed: %s", SPI_result_code_string(SPI_result) ); if (__builtin_constant_p(20) && (20) >= 20) abort (); } while(0); | |||
| 135 | ||||
| 136 | /* transfer plan from procCxt to topCxt */ | |||
| 137 | if (SPI_keepplan(plan->plan)) | |||
| 138 | elog(ERROR, "SPI_keepplan failed")do { elog_start("plpy_spi.c", 138, __func__); elog_finish(20, "SPI_keepplan failed"); if (__builtin_constant_p(20) && (20) >= 20) abort(); } while(0); | |||
| 139 | ||||
| 140 | PLy_spi_subtransaction_commit(oldcontext, oldowner); | |||
| 141 | } | |||
| 142 | PG_CATCH()} else { PG_exception_stack = save_exception_stack; error_context_stack = save_context_stack; | |||
| 143 | { | |||
| 144 | Py_DECREF(plan)do { if ( --((PyObject*)(plan))->ob_refcnt != 0) ; else ( ( *(((PyObject*)((PyObject *)(plan)))->ob_type)->tp_dealloc )((PyObject *)((PyObject *)(plan)))); } while (0); | |||
| 145 | Py_XDECREF(optr)do { if ((optr) == ((void*)0)) ; else do { if ( --((PyObject* )(optr))->ob_refcnt != 0) ; else ( (*(((PyObject*)((PyObject *)(optr)))->ob_type)->tp_dealloc)((PyObject *)((PyObject *)(optr)))); } while (0); } while (0); | |||
| 146 | ||||
| 147 | PLy_spi_subtransaction_abort(oldcontext, oldowner); | |||
| 148 | return NULL((void*)0); | |||
| 149 | } | |||
| 150 | PG_END_TRY()} PG_exception_stack = save_exception_stack; error_context_stack = save_context_stack; } while (0); | |||
| 151 | ||||
| 152 | Assert(plan->plan != NULL)do { if (!(plan->plan != ((void*)0))) ExceptionalCondition ("!(plan->plan != ((void*)0))", ("FailedAssertion"), "plpy_spi.c" , 152); } while (0); | |||
| 153 | return (PyObject *) plan; | |||
| 154 | } | |||
| 155 | ||||
| 156 | /* execute(query="select * from foo", limit=5) | |||
| 157 | * execute(plan=plan, values=(foo, bar), limit=5) | |||
| 158 | */ | |||
| 159 | PyObject * | |||
| 160 | PLy_spi_execute(PyObject *self, PyObject *args) | |||
| 161 | { | |||
| 162 | char *query; | |||
| 163 | PyObject *plan; | |||
| 164 | PyObject *list = NULL((void*)0); | |||
| 165 | long limit = 0; | |||
| 166 | ||||
| 167 | if (PyArg_ParseTuple(args, "s|l", &query, &limit)) | |||
| 168 | return PLy_spi_execute_query(query, limit); | |||
| 169 | ||||
| 170 | PyErr_Clear(); | |||
| 171 | ||||
| 172 | if (PyArg_ParseTuple(args, "O|Ol", &plan, &list, &limit) && | |||
| 173 | is_PLyPlanObject(plan)) | |||
| 174 | return PLy_spi_execute_plan(plan, list, limit); | |||
| 175 | ||||
| 176 | PLy_exception_set(PLy_exc_error, "plpy.execute expected a query or a plan"); | |||
| 177 | return NULL((void*)0); | |||
| 178 | } | |||
| 179 | ||||
| 180 | PyObject * | |||
| 181 | PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit) | |||
| 182 | { | |||
| 183 | volatile int nargs; | |||
| 184 | int i, | |||
| 185 | rv; | |||
| 186 | PLyPlanObject *plan; | |||
| 187 | volatile MemoryContext oldcontext; | |||
| 188 | volatile ResourceOwner oldowner; | |||
| 189 | PyObject *ret; | |||
| 190 | ||||
| 191 | if (list != NULL((void*)0)) | |||
| 192 | { | |||
| 193 | if (!PySequence_Check(list) || PyString_Check(list)((((((PyObject*)(list))->ob_type))->tp_flags & ((1L <<27))) != 0) || PyUnicode_Check(list)((((((PyObject*)(list))->ob_type))->tp_flags & ((1L <<28))) != 0)) | |||
| 194 | { | |||
| 195 | PLy_exception_set(PyExc_TypeError, "plpy.execute takes a sequence as its second argument"); | |||
| 196 | return NULL((void*)0); | |||
| 197 | } | |||
| 198 | nargs = PySequence_LengthPySequence_Size(list); | |||
| 199 | } | |||
| 200 | else | |||
| 201 | nargs = 0; | |||
| 202 | ||||
| 203 | plan = (PLyPlanObject *) ob; | |||
| 204 | ||||
| 205 | if (nargs != plan->nargs) | |||
| 206 | { | |||
| 207 | char *sv; | |||
| 208 | PyObject *so = PyObject_Str(list); | |||
| 209 | ||||
| 210 | if (!so) | |||
| 211 | PLy_elog(ERROR, "could not execute plan")do { PLy_elog_impl(20, "could not execute plan"); if (__builtin_constant_p (20) && (20) >= 20) abort(); } while(0); | |||
| 212 | sv = PyString_AsString(so); | |||
| 213 | PLy_exception_set_plural(PyExc_TypeError, | |||
| 214 | "Expected sequence of %d argument, got %d: %s", | |||
| 215 | "Expected sequence of %d arguments, got %d: %s", | |||
| 216 | plan->nargs, | |||
| 217 | plan->nargs, nargs, sv); | |||
| 218 | Py_DECREF(so)do { if ( --((PyObject*)(so))->ob_refcnt != 0) ; else ( (* (((PyObject*)((PyObject *)(so)))->ob_type)->tp_dealloc) ((PyObject *)((PyObject *)(so)))); } while (0); | |||
| 219 | ||||
| 220 | return NULL((void*)0); | |||
| 221 | } | |||
| 222 | ||||
| 223 | oldcontext = CurrentMemoryContext; | |||
| 224 | oldowner = CurrentResourceOwner; | |||
| 225 | ||||
| 226 | PLy_spi_subtransaction_begin(oldcontext, oldowner); | |||
| 227 | ||||
| 228 | PG_TRY()do { sigjmp_buf *save_exception_stack = PG_exception_stack; ErrorContextCallback *save_context_stack = error_context_stack; sigjmp_buf local_sigjmp_buf ; if (__sigsetjmp (local_sigjmp_buf, 0) == 0) { PG_exception_stack = &local_sigjmp_buf; | |||
| 229 | { | |||
| 230 | PLyExecutionContext *exec_ctx = PLy_current_execution_context(); | |||
| 231 | char *volatile nulls; | |||
| 232 | volatile int j; | |||
| 233 | ||||
| 234 | if (nargs > 0) | |||
| 235 | nulls = palloc(nargs * sizeof(char)); | |||
| 236 | else | |||
| 237 | nulls = NULL((void*)0); | |||
| 238 | ||||
| 239 | for (j = 0; j < nargs; j++) | |||
| 240 | { | |||
| 241 | PLyObToDatum *arg = &plan->args[j]; | |||
| 242 | PyObject *elem; | |||
| 243 | ||||
| 244 | elem = PySequence_GetItem(list, j); | |||
| 245 | PG_TRY()do { sigjmp_buf *save_exception_stack = PG_exception_stack; ErrorContextCallback *save_context_stack = error_context_stack; sigjmp_buf local_sigjmp_buf ; if (__sigsetjmp (local_sigjmp_buf, 0) == 0) { PG_exception_stack = &local_sigjmp_buf; | |||
| 246 | { | |||
| 247 | bool isnull; | |||
| 248 | ||||
| 249 | plan->values[j] = PLy_output_convert(arg, elem, &isnull); | |||
| 250 | nulls[j] = isnull ? 'n' : ' '; | |||
| 251 | } | |||
| 252 | PG_CATCH()} else { PG_exception_stack = save_exception_stack; error_context_stack = save_context_stack; | |||
| 253 | { | |||
| 254 | Py_DECREF(elem)do { if ( --((PyObject*)(elem))->ob_refcnt != 0) ; else ( ( *(((PyObject*)((PyObject *)(elem)))->ob_type)->tp_dealloc )((PyObject *)((PyObject *)(elem)))); } while (0); | |||
| 255 | PG_RE_THROW()pg_re_throw(); | |||
| 256 | } | |||
| 257 | PG_END_TRY()} PG_exception_stack = save_exception_stack; error_context_stack = save_context_stack; } while (0); | |||
| 258 | Py_DECREF(elem)do { if ( --((PyObject*)(elem))->ob_refcnt != 0) ; else ( ( *(((PyObject*)((PyObject *)(elem)))->ob_type)->tp_dealloc )((PyObject *)((PyObject *)(elem)))); } while (0); | |||
| 259 | } | |||
| 260 | ||||
| 261 | rv = SPI_execute_plan(plan->plan, plan->values, nulls, | |||
| 262 | exec_ctx->curr_proc->fn_readonly, limit); | |||
| 263 | ret = PLy_spi_execute_fetch_result(SPI_tuptable, SPI_processed, rv); | |||
| 264 | ||||
| 265 | if (nargs > 0) | |||
| 266 | pfree(nulls); | |||
| 267 | ||||
| 268 | PLy_spi_subtransaction_commit(oldcontext, oldowner); | |||
| 269 | } | |||
| 270 | PG_CATCH()} else { PG_exception_stack = save_exception_stack; error_context_stack = save_context_stack; | |||
| 271 | { | |||
| 272 | int k; | |||
| 273 | ||||
| 274 | /* | |||
| 275 | * cleanup plan->values array | |||
| 276 | */ | |||
| 277 | for (k = 0; k < nargs; k++) | |||
| 278 | { | |||
| 279 | if (!plan->args[k].typbyval && | |||
| 280 | (plan->values[k] != PointerGetDatum(NULL)((Datum) (((void*)0))))) | |||
| 281 | { | |||
| 282 | pfree(DatumGetPointer(plan->values[k])((Pointer) (plan->values[k]))); | |||
| 283 | plan->values[k] = PointerGetDatum(NULL)((Datum) (((void*)0))); | |||
| 284 | } | |||
| 285 | } | |||
| 286 | ||||
| 287 | PLy_spi_subtransaction_abort(oldcontext, oldowner); | |||
| 288 | return NULL((void*)0); | |||
| 289 | } | |||
| 290 | PG_END_TRY()} PG_exception_stack = save_exception_stack; error_context_stack = save_context_stack; } while (0); | |||
| 291 | ||||
| 292 | for (i = 0; i < nargs; i++) | |||
| 293 | { | |||
| 294 | if (!plan->args[i].typbyval && | |||
| 295 | (plan->values[i] != PointerGetDatum(NULL)((Datum) (((void*)0))))) | |||
| 296 | { | |||
| 297 | pfree(DatumGetPointer(plan->values[i])((Pointer) (plan->values[i]))); | |||
| 298 | plan->values[i] = PointerGetDatum(NULL)((Datum) (((void*)0))); | |||
| 299 | } | |||
| 300 | } | |||
| 301 | ||||
| 302 | if (rv < 0) | |||
| 303 | { | |||
| 304 | PLy_exception_set(PLy_exc_spi_error, | |||
| 305 | "SPI_execute_plan failed: %s", | |||
| 306 | SPI_result_code_string(rv)); | |||
| 307 | return NULL((void*)0); | |||
| 308 | } | |||
| 309 | ||||
| 310 | return ret; | |||
| 311 | } | |||
| 312 | ||||
| 313 | static PyObject * | |||
| 314 | PLy_spi_execute_query(char *query, long limit) | |||
| 315 | { | |||
| 316 | int rv; | |||
| 317 | volatile MemoryContext oldcontext; | |||
| 318 | volatile ResourceOwner oldowner; | |||
| 319 | PyObject *ret = NULL((void*)0); | |||
| 320 | ||||
| 321 | oldcontext = CurrentMemoryContext; | |||
| 322 | oldowner = CurrentResourceOwner; | |||
| 323 | ||||
| 324 | PLy_spi_subtransaction_begin(oldcontext, oldowner); | |||
| 325 | ||||
| 326 | PG_TRY()do { sigjmp_buf *save_exception_stack = PG_exception_stack; ErrorContextCallback *save_context_stack = error_context_stack; sigjmp_buf local_sigjmp_buf ; if (__sigsetjmp (local_sigjmp_buf, 0) == 0) { PG_exception_stack = &local_sigjmp_buf; | |||
| 327 | { | |||
| 328 | PLyExecutionContext *exec_ctx = PLy_current_execution_context(); | |||
| 329 | ||||
| 330 | pg_verifymbstr(query, strlen(query), false((bool) 0)); | |||
| 331 | rv = SPI_execute(query, exec_ctx->curr_proc->fn_readonly, limit); | |||
| 332 | ret = PLy_spi_execute_fetch_result(SPI_tuptable, SPI_processed, rv); | |||
| 333 | ||||
| 334 | PLy_spi_subtransaction_commit(oldcontext, oldowner); | |||
| 335 | } | |||
| 336 | PG_CATCH()} else { PG_exception_stack = save_exception_stack; error_context_stack = save_context_stack; | |||
| 337 | { | |||
| 338 | PLy_spi_subtransaction_abort(oldcontext, oldowner); | |||
| 339 | return NULL((void*)0); | |||
| 340 | } | |||
| 341 | PG_END_TRY()} PG_exception_stack = save_exception_stack; error_context_stack = save_context_stack; } while (0); | |||
| 342 | ||||
| 343 | if (rv < 0) | |||
| 344 | { | |||
| 345 | Py_XDECREF(ret)do { if ((ret) == ((void*)0)) ; else do { if ( --((PyObject*) (ret))->ob_refcnt != 0) ; else ( (*(((PyObject*)((PyObject *)(ret)))->ob_type)->tp_dealloc)((PyObject *)((PyObject *)(ret)))); } while (0); } while (0); | |||
| 346 | PLy_exception_set(PLy_exc_spi_error, | |||
| 347 | "SPI_execute failed: %s", | |||
| 348 | SPI_result_code_string(rv)); | |||
| 349 | return NULL((void*)0); | |||
| 350 | } | |||
| 351 | ||||
| 352 | return ret; | |||
| 353 | } | |||
| 354 | ||||
| 355 | static PyObject * | |||
| 356 | PLy_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 rows, int status) | |||
| 357 | { | |||
| 358 | PLyResultObject *result; | |||
| 359 | PLyExecutionContext *exec_ctx = PLy_current_execution_context(); | |||
| 360 | volatile MemoryContext oldcontext; | |||
| 361 | ||||
| 362 | result = (PLyResultObject *) PLy_result_new(); | |||
| 363 | if (!result) | |||
| ||||
| 364 | return NULL((void*)0); | |||
| 365 | Py_DECREF(result->status)do { if ( --((PyObject*)(result->status))->ob_refcnt != 0) ; else ( (*(((PyObject*)((PyObject *)(result->status)) )->ob_type)->tp_dealloc)((PyObject *)((PyObject *)(result ->status)))); } while (0); | |||
| 366 | result->status = PyInt_FromLong(status); | |||
| 367 | ||||
| 368 | if (status > 0 && tuptable == NULL((void*)0)) | |||
| 369 | { | |||
| 370 | Py_DECREF(result->nrows)do { if ( --((PyObject*)(result->nrows))->ob_refcnt != 0 ) ; else ( (*(((PyObject*)((PyObject *)(result->nrows)))-> ob_type)->tp_dealloc)((PyObject *)((PyObject *)(result-> nrows)))); } while (0); | |||
| 371 | result->nrows = (rows > (uint64) LONG_MAX9223372036854775807L) ? | |||
| 372 | PyFloat_FromDouble((double) rows) : | |||
| 373 | PyInt_FromLong((long) rows); | |||
| 374 | } | |||
| 375 | else if (status > 0 && tuptable != NULL((void*)0)) | |||
| 376 | { | |||
| 377 | PLyDatumToOb ininfo; | |||
| 378 | MemoryContext cxt; | |||
| 379 | ||||
| 380 | Py_DECREF(result->nrows)do { if ( --((PyObject*)(result->nrows))->ob_refcnt != 0 ) ; else ( (*(((PyObject*)((PyObject *)(result->nrows)))-> ob_type)->tp_dealloc)((PyObject *)((PyObject *)(result-> nrows)))); } while (0); | |||
| 381 | result->nrows = (rows > (uint64) LONG_MAX9223372036854775807L) ? | |||
| 382 | PyFloat_FromDouble((double) rows) : | |||
| 383 | PyInt_FromLong((long) rows); | |||
| 384 | ||||
| 385 | cxt = AllocSetContextCreate(CurrentMemoryContext, | |||
| 386 | "PL/Python temp context", | |||
| 387 | ALLOCSET_DEFAULT_SIZES0, (8 * 1024), (8 * 1024 * 1024)); | |||
| 388 | ||||
| 389 | /* Initialize for converting result tuples to Python */ | |||
| 390 | PLy_input_setup_func(&ininfo, cxt, RECORDOID2249, -1, | |||
| 391 | exec_ctx->curr_proc); | |||
| 392 | ||||
| 393 | oldcontext = CurrentMemoryContext; | |||
| 394 | PG_TRY()do { sigjmp_buf *save_exception_stack = PG_exception_stack; ErrorContextCallback *save_context_stack = error_context_stack; sigjmp_buf local_sigjmp_buf ; if (__sigsetjmp (local_sigjmp_buf, 0) == 0) { PG_exception_stack = &local_sigjmp_buf; | |||
| 395 | { | |||
| 396 | MemoryContext oldcontext2; | |||
| 397 | ||||
| 398 | if (rows) | |||
| 399 | { | |||
| 400 | uint64 i; | |||
| 401 | ||||
| 402 | /* | |||
| 403 | * PyList_New() and PyList_SetItem() use Py_ssize_t for list | |||
| 404 | * size and list indices; so we cannot support a result larger | |||
| 405 | * than PY_SSIZE_T_MAX. | |||
| 406 | */ | |||
| 407 | if (rows > (uint64) PY_SSIZE_T_MAX((Py_ssize_t)(((size_t)-1)>>1))) | |||
| 408 | ereport(ERROR,do { if (errstart(20, "plpy_spi.c", 410, __func__, ("plpython" "-" "11"))) errfinish (errcode((((('5') - '0') & 0x3F) + (((('4') - '0') & 0x3F) << 6) + (((('0') - '0') & 0x3F) << 12) + (((('0') - '0') & 0x3F) << 18 ) + (((('0') - '0') & 0x3F) << 24))), errmsg("query result has too many rows to fit in a Python list" )); if (__builtin_constant_p(20) && (20) >= 20) abort (); } while(0) | |||
| 409 | (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),do { if (errstart(20, "plpy_spi.c", 410, __func__, ("plpython" "-" "11"))) errfinish (errcode((((('5') - '0') & 0x3F) + (((('4') - '0') & 0x3F) << 6) + (((('0') - '0') & 0x3F) << 12) + (((('0') - '0') & 0x3F) << 18 ) + (((('0') - '0') & 0x3F) << 24))), errmsg("query result has too many rows to fit in a Python list" )); if (__builtin_constant_p(20) && (20) >= 20) abort (); } while(0) | |||
| 410 | errmsg("query result has too many rows to fit in a Python list")))do { if (errstart(20, "plpy_spi.c", 410, __func__, ("plpython" "-" "11"))) errfinish (errcode((((('5') - '0') & 0x3F) + (((('4') - '0') & 0x3F) << 6) + (((('0') - '0') & 0x3F) << 12) + (((('0') - '0') & 0x3F) << 18 ) + (((('0') - '0') & 0x3F) << 24))), errmsg("query result has too many rows to fit in a Python list" )); if (__builtin_constant_p(20) && (20) >= 20) abort (); } while(0); | |||
| 411 | ||||
| 412 | Py_DECREF(result->rows)do { if ( --((PyObject*)(result->rows))->ob_refcnt != 0 ) ; else ( (*(((PyObject*)((PyObject *)(result->rows)))-> ob_type)->tp_dealloc)((PyObject *)((PyObject *)(result-> rows)))); } while (0); | |||
| 413 | result->rows = PyList_New(rows); | |||
| 414 | if (!result->rows) | |||
| 415 | { | |||
| 416 | Py_DECREF(result)do { if ( --((PyObject*)(result))->ob_refcnt != 0) ; else ( (*(((PyObject*)((PyObject *)(result)))->ob_type)->tp_dealloc )((PyObject *)((PyObject *)(result)))); } while (0); | |||
| 417 | result = NULL((void*)0); | |||
| 418 | } | |||
| 419 | else | |||
| 420 | { | |||
| 421 | PLy_input_setup_tuple(&ininfo, tuptable->tupdesc, | |||
| 422 | exec_ctx->curr_proc); | |||
| 423 | ||||
| 424 | for (i = 0; i < rows; i++) | |||
| 425 | { | |||
| 426 | PyObject *row = PLy_input_from_tuple(&ininfo, | |||
| 427 | tuptable->vals[i], | |||
| 428 | tuptable->tupdesc); | |||
| 429 | ||||
| 430 | PyList_SetItem(result->rows, i, row); | |||
| 431 | } | |||
| 432 | } | |||
| 433 | } | |||
| 434 | ||||
| 435 | /* | |||
| 436 | * Save tuple descriptor for later use by result set metadata | |||
| 437 | * functions. Save it in TopMemoryContext so that it survives | |||
| 438 | * outside of an SPI context. We trust that PLy_result_dealloc() | |||
| 439 | * will clean it up when the time is right. (Do this as late as | |||
| 440 | * possible, to minimize the number of ways the tupdesc could get | |||
| 441 | * leaked due to errors.) | |||
| 442 | */ | |||
| 443 | oldcontext2 = MemoryContextSwitchTo(TopMemoryContext); | |||
| 444 | result->tupdesc = CreateTupleDescCopy(tuptable->tupdesc); | |||
| ||||
| 445 | MemoryContextSwitchTo(oldcontext2); | |||
| 446 | } | |||
| 447 | PG_CATCH()} else { PG_exception_stack = save_exception_stack; error_context_stack = save_context_stack; | |||
| 448 | { | |||
| 449 | MemoryContextSwitchTo(oldcontext); | |||
| 450 | MemoryContextDelete(cxt); | |||
| 451 | Py_DECREF(result)do { if ( --((PyObject*)(result))->ob_refcnt != 0) ; else ( (*(((PyObject*)((PyObject *)(result)))->ob_type)->tp_dealloc )((PyObject *)((PyObject *)(result)))); } while (0); | |||
| 452 | PG_RE_THROW()pg_re_throw(); | |||
| 453 | } | |||
| 454 | PG_END_TRY()} PG_exception_stack = save_exception_stack; error_context_stack = save_context_stack; } while (0); | |||
| 455 | ||||
| 456 | MemoryContextDelete(cxt); | |||
| 457 | SPI_freetuptable(tuptable); | |||
| 458 | } | |||
| 459 | ||||
| 460 | return (PyObject *) result; | |||
| 461 | } | |||
| 462 | ||||
| 463 | /* | |||
| 464 | * Utilities for running SPI functions in subtransactions. | |||
| 465 | * | |||
| 466 | * Usage: | |||
| 467 | * | |||
| 468 | * MemoryContext oldcontext = CurrentMemoryContext; | |||
| 469 | * ResourceOwner oldowner = CurrentResourceOwner; | |||
| 470 | * | |||
| 471 | * PLy_spi_subtransaction_begin(oldcontext, oldowner); | |||
| 472 | * PG_TRY(); | |||
| 473 | * { | |||
| 474 | * <call SPI functions> | |||
| 475 | * PLy_spi_subtransaction_commit(oldcontext, oldowner); | |||
| 476 | * } | |||
| 477 | * PG_CATCH(); | |||
| 478 | * { | |||
| 479 | * <do cleanup> | |||
| 480 | * PLy_spi_subtransaction_abort(oldcontext, oldowner); | |||
| 481 | * return NULL; | |||
| 482 | * } | |||
| 483 | * PG_END_TRY(); | |||
| 484 | * | |||
| 485 | * These utilities take care of restoring connection to the SPI manager and | |||
| 486 | * setting a Python exception in case of an abort. | |||
| 487 | */ | |||
| 488 | void | |||
| 489 | PLy_spi_subtransaction_begin(MemoryContext oldcontext, ResourceOwner oldowner) | |||
| 490 | { | |||
| 491 | BeginInternalSubTransaction(NULL((void*)0)); | |||
| 492 | /* Want to run inside function's memory context */ | |||
| 493 | MemoryContextSwitchTo(oldcontext); | |||
| 494 | } | |||
| 495 | ||||
| 496 | void | |||
| 497 | PLy_spi_subtransaction_commit(MemoryContext oldcontext, ResourceOwner oldowner) | |||
| 498 | { | |||
| 499 | /* Commit the inner transaction, return to outer xact context */ | |||
| 500 | ReleaseCurrentSubTransaction(); | |||
| 501 | MemoryContextSwitchTo(oldcontext); | |||
| 502 | CurrentResourceOwner = oldowner; | |||
| 503 | } | |||
| 504 | ||||
| 505 | void | |||
| 506 | PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner) | |||
| 507 | { | |||
| 508 | ErrorData *edata; | |||
| 509 | PLyExceptionEntry *entry; | |||
| 510 | PyObject *exc; | |||
| 511 | ||||
| 512 | /* Save error info */ | |||
| 513 | MemoryContextSwitchTo(oldcontext); | |||
| 514 | edata = CopyErrorData(); | |||
| 515 | FlushErrorState(); | |||
| 516 | ||||
| 517 | /* Abort the inner transaction */ | |||
| 518 | RollbackAndReleaseCurrentSubTransaction(); | |||
| 519 | MemoryContextSwitchTo(oldcontext); | |||
| 520 | CurrentResourceOwner = oldowner; | |||
| 521 | ||||
| 522 | /* Look up the correct exception */ | |||
| 523 | entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode), | |||
| 524 | HASH_FIND, NULL((void*)0)); | |||
| 525 | ||||
| 526 | /* | |||
| 527 | * This could be a custom error code, if that's the case fallback to | |||
| 528 | * SPIError | |||
| 529 | */ | |||
| 530 | exc = entry ? entry->exc : PLy_exc_spi_error; | |||
| 531 | /* Make Python raise the exception */ | |||
| 532 | PLy_spi_exception_set(exc, edata); | |||
| 533 | FreeErrorData(edata); | |||
| 534 | } | |||
| 535 | ||||
| 536 | /* | |||
| 537 | * Raise a SPIError, passing in it more error details, like the | |||
| 538 | * internal query and error position. | |||
| 539 | */ | |||
| 540 | static void | |||
| 541 | PLy_spi_exception_set(PyObject *excclass, ErrorData *edata) | |||
| 542 | { | |||
| 543 | PyObject *args = NULL((void*)0); | |||
| 544 | PyObject *spierror = NULL((void*)0); | |||
| 545 | PyObject *spidata = NULL((void*)0); | |||
| 546 | ||||
| 547 | args = Py_BuildValue("(s)", edata->message); | |||
| 548 | if (!args) | |||
| 549 | goto failure; | |||
| 550 | ||||
| 551 | /* create a new SPI exception with the error message as the parameter */ | |||
| 552 | spierror = PyObject_CallObject(excclass, args); | |||
| 553 | if (!spierror) | |||
| 554 | goto failure; | |||
| 555 | ||||
| 556 | spidata = Py_BuildValue("(izzzizzzzz)", edata->sqlerrcode, edata->detail, edata->hint, | |||
| 557 | edata->internalquery, edata->internalpos, | |||
| 558 | edata->schema_name, edata->table_name, edata->column_name, | |||
| 559 | edata->datatype_name, edata->constraint_name); | |||
| 560 | if (!spidata) | |||
| 561 | goto failure; | |||
| 562 | ||||
| 563 | if (PyObject_SetAttrString(spierror, "spidata", spidata) == -1) | |||
| 564 | goto failure; | |||
| 565 | ||||
| 566 | PyErr_SetObject(excclass, spierror); | |||
| 567 | ||||
| 568 | Py_DECREF(args)do { if ( --((PyObject*)(args))->ob_refcnt != 0) ; else ( ( *(((PyObject*)((PyObject *)(args)))->ob_type)->tp_dealloc )((PyObject *)((PyObject *)(args)))); } while (0); | |||
| 569 | Py_DECREF(spierror)do { if ( --((PyObject*)(spierror))->ob_refcnt != 0) ; else ( (*(((PyObject*)((PyObject *)(spierror)))->ob_type)-> tp_dealloc)((PyObject *)((PyObject *)(spierror)))); } while ( 0); | |||
| 570 | Py_DECREF(spidata)do { if ( --((PyObject*)(spidata))->ob_refcnt != 0) ; else ( (*(((PyObject*)((PyObject *)(spidata)))->ob_type)->tp_dealloc )((PyObject *)((PyObject *)(spidata)))); } while (0); | |||
| 571 | return; | |||
| 572 | ||||
| 573 | failure: | |||
| 574 | Py_XDECREF(args)do { if ((args) == ((void*)0)) ; else do { if ( --((PyObject* )(args))->ob_refcnt != 0) ; else ( (*(((PyObject*)((PyObject *)(args)))->ob_type)->tp_dealloc)((PyObject *)((PyObject *)(args)))); } while (0); } while (0); | |||
| 575 | Py_XDECREF(spierror)do { if ((spierror) == ((void*)0)) ; else do { if ( --((PyObject *)(spierror))->ob_refcnt != 0) ; else ( (*(((PyObject*)((PyObject *)(spierror)))->ob_type)->tp_dealloc)((PyObject *)((PyObject *)(spierror)))); } while (0); } while (0); | |||
| 576 | Py_XDECREF(spidata)do { if ((spidata) == ((void*)0)) ; else do { if ( --((PyObject *)(spidata))->ob_refcnt != 0) ; else ( (*(((PyObject*)((PyObject *)(spidata)))->ob_type)->tp_dealloc)((PyObject *)((PyObject *)(spidata)))); } while (0); } while (0); | |||
| 577 | elog(ERROR, "could not convert SPI error to Python exception")do { elog_start("plpy_spi.c", 577, __func__); elog_finish(20, "could not convert SPI error to Python exception"); if (__builtin_constant_p (20) && (20) >= 20) abort(); } while(0); | |||
| 578 | } |