#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#include "ppport.h"

Go to the source code of this file.
Defines | |
| #define | NEED_eval_pv |
| #define | NEED_newRV_noinc |
| #define | NEED_sv_2pv_flags |
| #define | HeUTF8(he) |
| #define | GvCV_set(gv, cv) (GvCV(gv) = cv) |
Functions | |
| HV * | plperl_spi_exec (char *, int) |
| void | plperl_return_next (SV *) |
| SV * | plperl_spi_query (char *) |
| SV * | plperl_spi_fetchrow (char *) |
| SV * | plperl_spi_prepare (char *, int, SV **) |
| HV * | plperl_spi_exec_prepared (char *, HV *, int, SV **) |
| SV * | plperl_spi_query_prepared (char *, int, SV **) |
| void | plperl_spi_freeplan (char *) |
| void | plperl_spi_cursor_close (char *) |
| char * | plperl_sv_to_literal (SV *, char *) |
| #define GvCV_set | ( | gv, | ||
| cv | ||||
| ) | (GvCV(gv) = cv) |
Definition at line 90 of file plperl.h.
Referenced by plperl_trusted_init().
| #define HeUTF8 | ( | he | ) |
((HeKLEN(he) == HEf_SVKEY) ? \
SvUTF8(HeKEY_sv(he)) : \
(U32)HeKUTF8(he))
Definition at line 83 of file plperl.h.
Referenced by hek2cstr().
| void plperl_return_next | ( | SV * | ) |
Definition at line 2925 of file plperl.c.
References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), ReturnSetInfo::allowedModes, Assert, CreateTupleDescCopy(), CurrentMemoryContext, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, ereport, errcode(), errmsg(), ERROR, ReturnSetInfo::expectedDesc, plperl_call_data::fcinfo, plperl_proc_desc::fn_retisset, plperl_proc_desc::fn_retistuple, get_call_result_type(), MemoryContextReset(), MemoryContextSwitchTo(), NULL, plperl_build_tuple_result(), plperl_sv_to_datum(), plperl_call_data::prodesc, plperl_proc_desc::result_in_func, plperl_proc_desc::result_oid, plperl_proc_desc::result_typioparam, FunctionCallInfoData::resultinfo, plperl_call_data::ret_tdesc, SFRM_Materialize_Random, plperl_call_data::tmp_cxt, plperl_call_data::tuple_store, tuplestore_begin_heap(), tuplestore_puttuple(), tuplestore_putvalues(), and work_mem.
Referenced by plperl_func_handler().
{
plperl_proc_desc *prodesc;
FunctionCallInfo fcinfo;
ReturnSetInfo *rsi;
MemoryContext old_cxt;
if (!sv)
return;
prodesc = current_call_data->prodesc;
fcinfo = current_call_data->fcinfo;
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
if (!prodesc->fn_retisset)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("cannot use return_next in a non-SETOF function")));
if (!current_call_data->ret_tdesc)
{
TupleDesc tupdesc;
Assert(!current_call_data->tuple_store);
/*
* This is the first call to return_next in the current PL/Perl
* function call, so memoize some lookups
*/
if (prodesc->fn_retistuple)
(void) get_call_result_type(fcinfo, NULL, &tupdesc);
else
tupdesc = rsi->expectedDesc;
/*
* Make sure the tuple_store and ret_tdesc are sufficiently
* long-lived.
*/
old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
current_call_data->ret_tdesc = CreateTupleDescCopy(tupdesc);
current_call_data->tuple_store =
tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
false, work_mem);
MemoryContextSwitchTo(old_cxt);
}
/*
* Producing the tuple we want to return requires making plenty of
* palloc() allocations that are not cleaned up. Since this function can
* be called many times before the current memory context is reset, we
* need to do those allocations in a temporary context.
*/
if (!current_call_data->tmp_cxt)
{
current_call_data->tmp_cxt =
AllocSetContextCreate(CurrentMemoryContext,
"PL/Perl return_next temporary cxt",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
}
old_cxt = MemoryContextSwitchTo(current_call_data->tmp_cxt);
if (prodesc->fn_retistuple)
{
HeapTuple tuple;
if (!(SvOK(sv) && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("SETOF-composite-returning PL/Perl function "
"must call return_next with reference to hash")));
tuple = plperl_build_tuple_result((HV *) SvRV(sv),
current_call_data->ret_tdesc);
tuplestore_puttuple(current_call_data->tuple_store, tuple);
}
else
{
Datum ret;
bool isNull;
ret = plperl_sv_to_datum(sv,
prodesc->result_oid,
-1,
fcinfo,
&prodesc->result_in_func,
prodesc->result_typioparam,
&isNull);
tuplestore_putvalues(current_call_data->tuple_store,
current_call_data->ret_tdesc,
&ret, &isNull);
}
MemoryContextSwitchTo(old_cxt);
MemoryContextReset(current_call_data->tmp_cxt);
}
| void plperl_spi_cursor_close | ( | char * | ) |
Definition at line 3197 of file plperl.c.
References check_spi_usage_allowed(), SPI_cursor_close(), and SPI_cursor_find().
{
Portal p;
check_spi_usage_allowed();
p = SPI_cursor_find(cursor);
if (p)
SPI_cursor_close(p);
}
| HV* plperl_spi_exec | ( | char * | , | |
| int | ||||
| ) |
Definition at line 2806 of file plperl.c.
References BeginInternalSubTransaction(), check_spi_usage_allowed(), CopyErrorData(), CurrentMemoryContext, CurrentResourceOwner, FlushErrorState(), plperl_proc_desc::fn_readonly, MemoryContextSwitchTo(), ErrorData::message, NULL, PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), plperl_spi_execute_fetch_result(), plperl_call_data::prodesc, ReleaseCurrentSubTransaction(), RollbackAndReleaseCurrentSubTransaction(), SPI_execute(), SPI_processed, SPI_restore_connection(), and SPI_tuptable.
{
HV *ret_hv;
/*
* Execute the query inside a sub-transaction, so we can cope with errors
* sanely
*/
MemoryContext oldcontext = CurrentMemoryContext;
ResourceOwner oldowner = CurrentResourceOwner;
check_spi_usage_allowed();
BeginInternalSubTransaction(NULL);
/* Want to run inside function's memory context */
MemoryContextSwitchTo(oldcontext);
PG_TRY();
{
int spi_rv;
pg_verifymbstr(query, strlen(query), false);
spi_rv = SPI_execute(query, current_call_data->prodesc->fn_readonly,
limit);
ret_hv = plperl_spi_execute_fetch_result(SPI_tuptable, SPI_processed,
spi_rv);
/* Commit the inner transaction, return to outer xact context */
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/*
* AtEOSubXact_SPI() should not have popped any SPI context, but just
* in case it did, make sure we remain connected.
*/
SPI_restore_connection();
}
PG_CATCH();
{
ErrorData *edata;
/* Save error info */
MemoryContextSwitchTo(oldcontext);
edata = CopyErrorData();
FlushErrorState();
/* Abort the inner transaction */
RollbackAndReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/*
* If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
* have left us in a disconnected state. We need this hack to return
* to connected state.
*/
SPI_restore_connection();
/* Punt the error to Perl */
croak("%s", edata->message);
/* Can't get here, but keep compiler quiet */
return NULL;
}
PG_END_TRY();
return ret_hv;
}
| HV* plperl_spi_exec_prepared | ( | char * | , | |
| HV * | , | |||
| int | , | |||
| SV ** | ||||
| ) |
Definition at line 3375 of file plperl.c.
References plperl_query_desc::arginfuncs, plperl_query_desc::argtypes, plperl_query_desc::argtypioparams, BeginInternalSubTransaction(), check_spi_usage_allowed(), CopyErrorData(), CurrentMemoryContext, CurrentResourceOwner, elog, ERROR, FlushErrorState(), plperl_proc_desc::fn_readonly, HASH_FIND, hash_search(), hv_fetch_string(), i, MemoryContextSwitchTo(), ErrorData::message, plperl_query_desc::nargs, NULL, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_TRY, plperl_query_desc::plan, plperl_spi_execute_fetch_result(), plperl_sv_to_datum(), plperl_call_data::prodesc, plperl_query_entry::query_data, plperl_interp_desc::query_hash, ReleaseCurrentSubTransaction(), RollbackAndReleaseCurrentSubTransaction(), SPI_execute_plan(), SPI_processed, SPI_restore_connection(), and SPI_tuptable.
{
HV *ret_hv;
SV **sv;
int i,
limit,
spi_rv;
char *nulls;
Datum *argvalues;
plperl_query_desc *qdesc;
plperl_query_entry *hash_entry;
/*
* Execute the query inside a sub-transaction, so we can cope with errors
* sanely
*/
MemoryContext oldcontext = CurrentMemoryContext;
ResourceOwner oldowner = CurrentResourceOwner;
check_spi_usage_allowed();
BeginInternalSubTransaction(NULL);
/* Want to run inside function's memory context */
MemoryContextSwitchTo(oldcontext);
PG_TRY();
{
/************************************************************
* Fetch the saved plan descriptor, see if it's o.k.
************************************************************/
hash_entry = hash_search(plperl_active_interp->query_hash, query,
HASH_FIND, NULL);
if (hash_entry == NULL)
elog(ERROR, "spi_exec_prepared: Invalid prepared query passed");
qdesc = hash_entry->query_data;
if (qdesc == NULL)
elog(ERROR, "spi_exec_prepared: plperl query_hash value vanished");
if (qdesc->nargs != argc)
elog(ERROR, "spi_exec_prepared: expected %d argument(s), %d passed",
qdesc->nargs, argc);
/************************************************************
* Parse eventual attributes
************************************************************/
limit = 0;
if (attr != NULL)
{
sv = hv_fetch_string(attr, "limit");
if (sv && *sv && SvIOK(*sv))
limit = SvIV(*sv);
}
/************************************************************
* Set up arguments
************************************************************/
if (argc > 0)
{
nulls = (char *) palloc(argc);
argvalues = (Datum *) palloc(argc * sizeof(Datum));
}
else
{
nulls = NULL;
argvalues = NULL;
}
for (i = 0; i < argc; i++)
{
bool isnull;
argvalues[i] = plperl_sv_to_datum(argv[i],
qdesc->argtypes[i],
-1,
NULL,
&qdesc->arginfuncs[i],
qdesc->argtypioparams[i],
&isnull);
nulls[i] = isnull ? 'n' : ' ';
}
/************************************************************
* go
************************************************************/
spi_rv = SPI_execute_plan(qdesc->plan, argvalues, nulls,
current_call_data->prodesc->fn_readonly, limit);
ret_hv = plperl_spi_execute_fetch_result(SPI_tuptable, SPI_processed,
spi_rv);
if (argc > 0)
{
pfree(argvalues);
pfree(nulls);
}
/* Commit the inner transaction, return to outer xact context */
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/*
* AtEOSubXact_SPI() should not have popped any SPI context, but just
* in case it did, make sure we remain connected.
*/
SPI_restore_connection();
}
PG_CATCH();
{
ErrorData *edata;
/* Save error info */
MemoryContextSwitchTo(oldcontext);
edata = CopyErrorData();
FlushErrorState();
/* Abort the inner transaction */
RollbackAndReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/*
* If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
* have left us in a disconnected state. We need this hack to return
* to connected state.
*/
SPI_restore_connection();
/* Punt the error to Perl */
croak("%s", edata->message);
/* Can't get here, but keep compiler quiet */
return NULL;
}
PG_END_TRY();
return ret_hv;
}
| SV* plperl_spi_fetchrow | ( | char * | ) |
Definition at line 3112 of file plperl.c.
References BeginInternalSubTransaction(), check_spi_usage_allowed(), CopyErrorData(), CurrentMemoryContext, CurrentResourceOwner, FlushErrorState(), MemoryContextSwitchTo(), ErrorData::message, NULL, PG_CATCH, PG_END_TRY, PG_TRY, plperl_hash_from_tuple(), ReleaseCurrentSubTransaction(), RollbackAndReleaseCurrentSubTransaction(), SPI_cursor_close(), SPI_cursor_fetch(), SPI_cursor_find(), SPI_freetuptable(), SPI_processed, SPI_restore_connection(), SPI_tuptable, SPITupleTable::tupdesc, and SPITupleTable::vals.
{
SV *row;
/*
* Execute the FETCH inside a sub-transaction, so we can cope with errors
* sanely
*/
MemoryContext oldcontext = CurrentMemoryContext;
ResourceOwner oldowner = CurrentResourceOwner;
check_spi_usage_allowed();
BeginInternalSubTransaction(NULL);
/* Want to run inside function's memory context */
MemoryContextSwitchTo(oldcontext);
PG_TRY();
{
Portal p = SPI_cursor_find(cursor);
if (!p)
{
row = &PL_sv_undef;
}
else
{
SPI_cursor_fetch(p, true, 1);
if (SPI_processed == 0)
{
SPI_cursor_close(p);
row = &PL_sv_undef;
}
else
{
row = plperl_hash_from_tuple(SPI_tuptable->vals[0],
SPI_tuptable->tupdesc);
}
SPI_freetuptable(SPI_tuptable);
}
/* Commit the inner transaction, return to outer xact context */
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/*
* AtEOSubXact_SPI() should not have popped any SPI context, but just
* in case it did, make sure we remain connected.
*/
SPI_restore_connection();
}
PG_CATCH();
{
ErrorData *edata;
/* Save error info */
MemoryContextSwitchTo(oldcontext);
edata = CopyErrorData();
FlushErrorState();
/* Abort the inner transaction */
RollbackAndReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/*
* If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
* have left us in a disconnected state. We need this hack to return
* to connected state.
*/
SPI_restore_connection();
/* Punt the error to Perl */
croak("%s", edata->message);
/* Can't get here, but keep compiler quiet */
return NULL;
}
PG_END_TRY();
return row;
}
| void plperl_spi_freeplan | ( | char * | ) |
Definition at line 3642 of file plperl.c.
References check_spi_usage_allowed(), elog, ERROR, HASH_FIND, HASH_REMOVE, hash_search(), MemoryContextDelete(), NULL, plperl_query_desc::plan, plperl_query_desc::plan_cxt, plperl_query_entry::query_data, plperl_interp_desc::query_hash, and SPI_freeplan().
{
SPIPlanPtr plan;
plperl_query_desc *qdesc;
plperl_query_entry *hash_entry;
check_spi_usage_allowed();
hash_entry = hash_search(plperl_active_interp->query_hash, query,
HASH_FIND, NULL);
if (hash_entry == NULL)
elog(ERROR, "spi_freeplan: Invalid prepared query passed");
qdesc = hash_entry->query_data;
if (qdesc == NULL)
elog(ERROR, "spi_freeplan: plperl query_hash value vanished");
plan = qdesc->plan;
/*
* free all memory before SPI_freeplan, so if it dies, nothing will be
* left over
*/
hash_search(plperl_active_interp->query_hash, query,
HASH_REMOVE, NULL);
MemoryContextDelete(qdesc->plan_cxt);
SPI_freeplan(plan);
}
| SV* plperl_spi_prepare | ( | char * | , | |
| int | , | |||
| SV ** | ||||
| ) |
Definition at line 3210 of file plperl.c.
References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), plperl_query_desc::arginfuncs, plperl_query_desc::argtypes, plperl_query_desc::argtypioparams, BeginInternalSubTransaction(), CHECK_FOR_INTERRUPTS, check_spi_usage_allowed(), CopyErrorData(), cstr2sv(), CurrentMemoryContext, CurrentResourceOwner, elog, ERROR, FlushErrorState(), fmgr_info_cxt(), getTypeInputInfo(), HASH_ENTER, HASH_REMOVE, hash_search(), i, MemoryContextDelete(), MemoryContextSwitchTo(), ErrorData::message, plperl_query_desc::nargs, NULL, palloc(), palloc0(), parseTypeString(), pfree(), PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), plperl_query_desc::plan, plperl_query_desc::plan_cxt, plperl_query_desc::qname, plperl_query_entry::query_data, plperl_interp_desc::query_hash, ReleaseCurrentSubTransaction(), RollbackAndReleaseCurrentSubTransaction(), snprintf(), SPI_freeplan(), SPI_keepplan(), SPI_prepare(), SPI_restore_connection(), SPI_result, SPI_result_code_string(), sv2cstr(), and TopMemoryContext.
{
volatile SPIPlanPtr plan = NULL;
volatile MemoryContext plan_cxt = NULL;
plperl_query_desc *volatile qdesc = NULL;
plperl_query_entry *volatile hash_entry = NULL;
MemoryContext oldcontext = CurrentMemoryContext;
ResourceOwner oldowner = CurrentResourceOwner;
MemoryContext work_cxt;
bool found;
int i;
check_spi_usage_allowed();
BeginInternalSubTransaction(NULL);
MemoryContextSwitchTo(oldcontext);
PG_TRY();
{
CHECK_FOR_INTERRUPTS();
/************************************************************
* Allocate the new querydesc structure
*
* The qdesc struct, as well as all its subsidiary data, lives in its
* plan_cxt. But note that the SPIPlan does not.
************************************************************/
plan_cxt = AllocSetContextCreate(TopMemoryContext,
"PL/Perl spi_prepare query",
ALLOCSET_SMALL_MINSIZE,
ALLOCSET_SMALL_INITSIZE,
ALLOCSET_SMALL_MAXSIZE);
MemoryContextSwitchTo(plan_cxt);
qdesc = (plperl_query_desc *) palloc0(sizeof(plperl_query_desc));
snprintf(qdesc->qname, sizeof(qdesc->qname), "%p", qdesc);
qdesc->plan_cxt = plan_cxt;
qdesc->nargs = argc;
qdesc->argtypes = (Oid *) palloc(argc * sizeof(Oid));
qdesc->arginfuncs = (FmgrInfo *) palloc(argc * sizeof(FmgrInfo));
qdesc->argtypioparams = (Oid *) palloc(argc * sizeof(Oid));
MemoryContextSwitchTo(oldcontext);
/************************************************************
* Do the following work in a short-lived context so that we don't
* leak a lot of memory in the PL/Perl function's SPI Proc context.
************************************************************/
work_cxt = AllocSetContextCreate(CurrentMemoryContext,
"PL/Perl spi_prepare workspace",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
MemoryContextSwitchTo(work_cxt);
/************************************************************
* 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 < argc; i++)
{
Oid typId,
typInput,
typIOParam;
int32 typmod;
char *typstr;
typstr = sv2cstr(argv[i]);
parseTypeString(typstr, &typId, &typmod);
pfree(typstr);
getTypeInputInfo(typId, &typInput, &typIOParam);
qdesc->argtypes[i] = typId;
fmgr_info_cxt(typInput, &(qdesc->arginfuncs[i]), plan_cxt);
qdesc->argtypioparams[i] = typIOParam;
}
/* Make sure the query is validly encoded */
pg_verifymbstr(query, strlen(query), false);
/************************************************************
* Prepare the plan and check for errors
************************************************************/
plan = SPI_prepare(query, argc, qdesc->argtypes);
if (plan == NULL)
elog(ERROR, "SPI_prepare() failed:%s",
SPI_result_code_string(SPI_result));
/************************************************************
* Save the plan into permanent memory (right now it's in the
* SPI procCxt, which will go away at function end).
************************************************************/
if (SPI_keepplan(plan))
elog(ERROR, "SPI_keepplan() failed");
qdesc->plan = plan;
/************************************************************
* Insert a hashtable entry for the plan.
************************************************************/
hash_entry = hash_search(plperl_active_interp->query_hash,
qdesc->qname,
HASH_ENTER, &found);
hash_entry->query_data = qdesc;
/* Get rid of workspace */
MemoryContextDelete(work_cxt);
/* Commit the inner transaction, return to outer xact context */
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/*
* AtEOSubXact_SPI() should not have popped any SPI context, but just
* in case it did, make sure we remain connected.
*/
SPI_restore_connection();
}
PG_CATCH();
{
ErrorData *edata;
/* Save error info */
MemoryContextSwitchTo(oldcontext);
edata = CopyErrorData();
FlushErrorState();
/* Drop anything we managed to allocate */
if (hash_entry)
hash_search(plperl_active_interp->query_hash,
qdesc->qname,
HASH_REMOVE, NULL);
if (plan_cxt)
MemoryContextDelete(plan_cxt);
if (plan)
SPI_freeplan(plan);
/* Abort the inner transaction */
RollbackAndReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/*
* If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
* have left us in a disconnected state. We need this hack to return
* to connected state.
*/
SPI_restore_connection();
/* Punt the error to Perl */
croak("%s", edata->message);
/* Can't get here, but keep compiler quiet */
return NULL;
}
PG_END_TRY();
/************************************************************
* Return the query's hash key to the caller.
************************************************************/
return cstr2sv(qdesc->qname);
}
| SV* plperl_spi_query | ( | char * | ) |
Definition at line 3029 of file plperl.c.
References BeginInternalSubTransaction(), check_spi_usage_allowed(), CopyErrorData(), cstr2sv(), CurrentMemoryContext, CurrentResourceOwner, elog, ERROR, FlushErrorState(), MemoryContextSwitchTo(), ErrorData::message, PortalData::name, NULL, PG_CATCH, PG_END_TRY, PG_TRY, pg_verifymbstr(), ReleaseCurrentSubTransaction(), RollbackAndReleaseCurrentSubTransaction(), SPI_cursor_open(), SPI_freeplan(), SPI_prepare(), SPI_restore_connection(), SPI_result, and SPI_result_code_string().
{
SV *cursor;
/*
* Execute the query inside a sub-transaction, so we can cope with errors
* sanely
*/
MemoryContext oldcontext = CurrentMemoryContext;
ResourceOwner oldowner = CurrentResourceOwner;
check_spi_usage_allowed();
BeginInternalSubTransaction(NULL);
/* Want to run inside function's memory context */
MemoryContextSwitchTo(oldcontext);
PG_TRY();
{
SPIPlanPtr plan;
Portal portal;
/* Make sure the query is validly encoded */
pg_verifymbstr(query, strlen(query), false);
/* Create a cursor for the query */
plan = SPI_prepare(query, 0, NULL);
if (plan == NULL)
elog(ERROR, "SPI_prepare() failed:%s",
SPI_result_code_string(SPI_result));
portal = SPI_cursor_open(NULL, plan, NULL, NULL, false);
SPI_freeplan(plan);
if (portal == NULL)
elog(ERROR, "SPI_cursor_open() failed:%s",
SPI_result_code_string(SPI_result));
cursor = cstr2sv(portal->name);
/* Commit the inner transaction, return to outer xact context */
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/*
* AtEOSubXact_SPI() should not have popped any SPI context, but just
* in case it did, make sure we remain connected.
*/
SPI_restore_connection();
}
PG_CATCH();
{
ErrorData *edata;
/* Save error info */
MemoryContextSwitchTo(oldcontext);
edata = CopyErrorData();
FlushErrorState();
/* Abort the inner transaction */
RollbackAndReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/*
* If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
* have left us in a disconnected state. We need this hack to return
* to connected state.
*/
SPI_restore_connection();
/* Punt the error to Perl */
croak("%s", edata->message);
/* Can't get here, but keep compiler quiet */
return NULL;
}
PG_END_TRY();
return cursor;
}
| SV* plperl_spi_query_prepared | ( | char * | , | |
| int | , | |||
| SV ** | ||||
| ) |
Definition at line 3513 of file plperl.c.
References plperl_query_desc::arginfuncs, plperl_query_desc::argtypes, plperl_query_desc::argtypioparams, BeginInternalSubTransaction(), check_spi_usage_allowed(), CopyErrorData(), cstr2sv(), CurrentMemoryContext, CurrentResourceOwner, elog, ERROR, FlushErrorState(), plperl_proc_desc::fn_readonly, HASH_FIND, hash_search(), i, MemoryContextSwitchTo(), ErrorData::message, PortalData::name, plperl_query_desc::nargs, NULL, palloc(), pfree(), PG_CATCH, PG_END_TRY, PG_TRY, plperl_query_desc::plan, plperl_sv_to_datum(), plperl_call_data::prodesc, plperl_query_entry::query_data, plperl_interp_desc::query_hash, ReleaseCurrentSubTransaction(), RollbackAndReleaseCurrentSubTransaction(), SPI_cursor_open(), SPI_restore_connection(), SPI_result, and SPI_result_code_string().
{
int i;
char *nulls;
Datum *argvalues;
plperl_query_desc *qdesc;
plperl_query_entry *hash_entry;
SV *cursor;
Portal portal = NULL;
/*
* Execute the query inside a sub-transaction, so we can cope with errors
* sanely
*/
MemoryContext oldcontext = CurrentMemoryContext;
ResourceOwner oldowner = CurrentResourceOwner;
check_spi_usage_allowed();
BeginInternalSubTransaction(NULL);
/* Want to run inside function's memory context */
MemoryContextSwitchTo(oldcontext);
PG_TRY();
{
/************************************************************
* Fetch the saved plan descriptor, see if it's o.k.
************************************************************/
hash_entry = hash_search(plperl_active_interp->query_hash, query,
HASH_FIND, NULL);
if (hash_entry == NULL)
elog(ERROR, "spi_query_prepared: Invalid prepared query passed");
qdesc = hash_entry->query_data;
if (qdesc == NULL)
elog(ERROR, "spi_query_prepared: plperl query_hash value vanished");
if (qdesc->nargs != argc)
elog(ERROR, "spi_query_prepared: expected %d argument(s), %d passed",
qdesc->nargs, argc);
/************************************************************
* Set up arguments
************************************************************/
if (argc > 0)
{
nulls = (char *) palloc(argc);
argvalues = (Datum *) palloc(argc * sizeof(Datum));
}
else
{
nulls = NULL;
argvalues = NULL;
}
for (i = 0; i < argc; i++)
{
bool isnull;
argvalues[i] = plperl_sv_to_datum(argv[i],
qdesc->argtypes[i],
-1,
NULL,
&qdesc->arginfuncs[i],
qdesc->argtypioparams[i],
&isnull);
nulls[i] = isnull ? 'n' : ' ';
}
/************************************************************
* go
************************************************************/
portal = SPI_cursor_open(NULL, qdesc->plan, argvalues, nulls,
current_call_data->prodesc->fn_readonly);
if (argc > 0)
{
pfree(argvalues);
pfree(nulls);
}
if (portal == NULL)
elog(ERROR, "SPI_cursor_open() failed:%s",
SPI_result_code_string(SPI_result));
cursor = cstr2sv(portal->name);
/* Commit the inner transaction, return to outer xact context */
ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/*
* AtEOSubXact_SPI() should not have popped any SPI context, but just
* in case it did, make sure we remain connected.
*/
SPI_restore_connection();
}
PG_CATCH();
{
ErrorData *edata;
/* Save error info */
MemoryContextSwitchTo(oldcontext);
edata = CopyErrorData();
FlushErrorState();
/* Abort the inner transaction */
RollbackAndReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext);
CurrentResourceOwner = oldowner;
/*
* If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
* have left us in a disconnected state. We need this hack to return
* to connected state.
*/
SPI_restore_connection();
/* Punt the error to Perl */
croak("%s", edata->message);
/* Can't get here, but keep compiler quiet */
return NULL;
}
PG_END_TRY();
return cursor;
}
| char* plperl_sv_to_literal | ( | SV * | , | |
| char * | ||||
| ) |
Definition at line 1355 of file plperl.c.
References CStringGetDatum, DirectFunctionCall1, elog, ERROR, getTypeOutputInfo(), InvalidOid, NULL, OidIsValid, OidOutputFunctionCall(), plperl_sv_to_datum(), and regtypein().
{
Datum str = CStringGetDatum(fqtypename);
Oid typid = DirectFunctionCall1(regtypein, str);
Oid typoutput;
Datum datum;
bool typisvarlena,
isnull;
if (!OidIsValid(typid))
elog(ERROR, "lookup failed for type %s", fqtypename);
datum = plperl_sv_to_datum(sv,
typid, -1,
NULL, NULL, InvalidOid,
&isnull);
if (isnull)
return NULL;
getTypeOutputInfo(typid,
&typoutput, &typisvarlena);
return OidOutputFunctionCall(typoutput, datum);
}
1.7.1