|
|
|
@ -2817,6 +2817,7 @@ PLy_spi_prepare(PyObject *self, PyObject *args) |
|
|
|
|
char *query; |
|
|
|
|
void *tmpplan; |
|
|
|
|
volatile MemoryContext oldcontext; |
|
|
|
|
int nargs; |
|
|
|
|
|
|
|
|
|
if (!PyArg_ParseTuple(args, "s|O", &query, &list)) |
|
|
|
|
{ |
|
|
|
@ -2835,80 +2836,78 @@ PLy_spi_prepare(PyObject *self, PyObject *args) |
|
|
|
|
if ((plan = (PLyPlanObject *) PLy_plan_new()) == NULL) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
nargs = list ? PySequence_Length(list) : 0; |
|
|
|
|
|
|
|
|
|
plan->nargs = nargs; |
|
|
|
|
plan->types = nargs ? PLy_malloc(sizeof(Oid) * nargs) : NULL; |
|
|
|
|
plan->values = nargs ? PLy_malloc(sizeof(Datum) * nargs) : NULL; |
|
|
|
|
plan->args = nargs ? PLy_malloc(sizeof(PLyTypeInfo) * nargs) : NULL; |
|
|
|
|
|
|
|
|
|
oldcontext = CurrentMemoryContext; |
|
|
|
|
PG_TRY(); |
|
|
|
|
{ |
|
|
|
|
if (list != NULL) |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* the other loop might throw an exception, if PLyTypeInfo |
|
|
|
|
* member isn't properly initialized the Py_DECREF(plan) will |
|
|
|
|
* go boom |
|
|
|
|
*/ |
|
|
|
|
for (i = 0; i < nargs; i++) |
|
|
|
|
{ |
|
|
|
|
int nargs, |
|
|
|
|
i; |
|
|
|
|
PLy_typeinfo_init(&plan->args[i]); |
|
|
|
|
plan->values[i] = PointerGetDatum(NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
nargs = PySequence_Length(list); |
|
|
|
|
if (nargs > 0) |
|
|
|
|
for (i = 0; i < nargs; i++) |
|
|
|
|
{ |
|
|
|
|
char *sptr; |
|
|
|
|
HeapTuple typeTup; |
|
|
|
|
Oid typeId; |
|
|
|
|
int32 typmod; |
|
|
|
|
Form_pg_type typeStruct; |
|
|
|
|
|
|
|
|
|
optr = PySequence_GetItem(list, i); |
|
|
|
|
if (PyString_Check(optr)) |
|
|
|
|
sptr = PyString_AsString(optr); |
|
|
|
|
else if (PyUnicode_Check(optr)) |
|
|
|
|
sptr = PLyUnicode_AsString(optr); |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
plan->nargs = nargs; |
|
|
|
|
plan->types = PLy_malloc(sizeof(Oid) * nargs); |
|
|
|
|
plan->values = PLy_malloc(sizeof(Datum) * nargs); |
|
|
|
|
plan->args = PLy_malloc(sizeof(PLyTypeInfo) * nargs); |
|
|
|
|
ereport(ERROR, |
|
|
|
|
(errmsg("plpy.prepare: type name at ordinal position %d is not a string", i))); |
|
|
|
|
sptr = NULL; /* keep compiler quiet */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* the other loop might throw an exception, if PLyTypeInfo |
|
|
|
|
* member isn't properly initialized the Py_DECREF(plan) will |
|
|
|
|
* go boom |
|
|
|
|
*/ |
|
|
|
|
for (i = 0; i < nargs; i++) |
|
|
|
|
{ |
|
|
|
|
PLy_typeinfo_init(&plan->args[i]); |
|
|
|
|
plan->values[i] = PointerGetDatum(NULL); |
|
|
|
|
} |
|
|
|
|
/********************************************************
|
|
|
|
|
* Resolve argument type names and then look them up by |
|
|
|
|
* oid in the system cache, and remember the required |
|
|
|
|
*information for input conversion. |
|
|
|
|
********************************************************/ |
|
|
|
|
|
|
|
|
|
for (i = 0; i < nargs; i++) |
|
|
|
|
{ |
|
|
|
|
char *sptr; |
|
|
|
|
HeapTuple typeTup; |
|
|
|
|
Oid typeId; |
|
|
|
|
int32 typmod; |
|
|
|
|
Form_pg_type typeStruct; |
|
|
|
|
|
|
|
|
|
optr = PySequence_GetItem(list, i); |
|
|
|
|
if (PyString_Check(optr)) |
|
|
|
|
sptr = PyString_AsString(optr); |
|
|
|
|
else if (PyUnicode_Check(optr)) |
|
|
|
|
sptr = PLyUnicode_AsString(optr); |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
ereport(ERROR, |
|
|
|
|
(errmsg("plpy.prepare: type name at ordinal position %d is not a string", i))); |
|
|
|
|
sptr = NULL; /* keep compiler quiet */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/********************************************************
|
|
|
|
|
* Resolve argument type names and then look them up by |
|
|
|
|
* oid in the system cache, and remember the required |
|
|
|
|
*information for input conversion. |
|
|
|
|
********************************************************/ |
|
|
|
|
|
|
|
|
|
parseTypeString(sptr, &typeId, &typmod); |
|
|
|
|
|
|
|
|
|
typeTup = SearchSysCache1(TYPEOID, |
|
|
|
|
ObjectIdGetDatum(typeId)); |
|
|
|
|
if (!HeapTupleIsValid(typeTup)) |
|
|
|
|
elog(ERROR, "cache lookup failed for type %u", typeId); |
|
|
|
|
|
|
|
|
|
Py_DECREF(optr); |
|
|
|
|
optr = NULL; /* this is important */ |
|
|
|
|
|
|
|
|
|
plan->types[i] = typeId; |
|
|
|
|
typeStruct = (Form_pg_type) GETSTRUCT(typeTup); |
|
|
|
|
if (typeStruct->typtype != TYPTYPE_COMPOSITE) |
|
|
|
|
PLy_output_datum_func(&plan->args[i], typeTup); |
|
|
|
|
else |
|
|
|
|
ereport(ERROR, |
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
|
|
|
|
errmsg("plpy.prepare does not support composite types"))); |
|
|
|
|
ReleaseSysCache(typeTup); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parseTypeString(sptr, &typeId, &typmod); |
|
|
|
|
|
|
|
|
|
typeTup = SearchSysCache1(TYPEOID, |
|
|
|
|
ObjectIdGetDatum(typeId)); |
|
|
|
|
if (!HeapTupleIsValid(typeTup)) |
|
|
|
|
elog(ERROR, "cache lookup failed for type %u", typeId); |
|
|
|
|
|
|
|
|
|
Py_DECREF(optr); |
|
|
|
|
/*
|
|
|
|
|
* set optr to NULL, so we won't try to unref it again in |
|
|
|
|
* case of an error |
|
|
|
|
*/ |
|
|
|
|
optr = NULL; |
|
|
|
|
|
|
|
|
|
plan->types[i] = typeId; |
|
|
|
|
typeStruct = (Form_pg_type) GETSTRUCT(typeTup); |
|
|
|
|
if (typeStruct->typtype != TYPTYPE_COMPOSITE) |
|
|
|
|
PLy_output_datum_func(&plan->args[i], typeTup); |
|
|
|
|
else |
|
|
|
|
ereport(ERROR, |
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
|
|
|
|
errmsg("plpy.prepare does not support composite types"))); |
|
|
|
|
ReleaseSysCache(typeTup); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pg_verifymbstr(query, strlen(query), false); |
|
|
|
@ -2943,6 +2942,7 @@ PLy_spi_prepare(PyObject *self, PyObject *args) |
|
|
|
|
} |
|
|
|
|
PG_END_TRY(); |
|
|
|
|
|
|
|
|
|
Assert(plan->plan != NULL); |
|
|
|
|
return (PyObject *) plan; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|