From 30a5c8bfbd7bec07385c7d40305b06385d700b3f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 31 Jul 2017 12:10:36 -0400 Subject: [PATCH] PL/Perl portability fix: avoid including XSUB.h in plperl.c. Back-patch of commit bebe174bb4462ef079a1d7eeafb82ff969f160a4, which see for more info. Patch by me, with some help from Ashutosh Sharma Discussion: https://postgr.es/m/CANFyU97OVQ3+Mzfmt3MhuUm5NwPU=-FtbNH5Eb7nZL9ua8=rcA@mail.gmail.com --- contrib/hstore_plperl/hstore_plperl.c | 6 +- src/pl/plperl/SPI.xs | 32 +--- src/pl/plperl/Util.xs | 44 +---- src/pl/plperl/plperl.c | 244 +++++++++++++++++++------- src/pl/plperl/plperl.h | 17 +- src/pl/plperl/plperl_helpers.h | 4 + 6 files changed, 210 insertions(+), 137 deletions(-) diff --git a/contrib/hstore_plperl/hstore_plperl.c b/contrib/hstore_plperl/hstore_plperl.c index d40a792730..e5303b3b92 100644 --- a/contrib/hstore_plperl/hstore_plperl.c +++ b/contrib/hstore_plperl/hstore_plperl.c @@ -13,6 +13,7 @@ PG_FUNCTION_INFO_V1(hstore_to_plperl); Datum hstore_to_plperl(PG_FUNCTION_ARGS) { + dTHX; HStore *in = PG_GETARG_HS(0); int i; int count = HS_COUNT(in); @@ -45,7 +46,8 @@ PG_FUNCTION_INFO_V1(plperl_to_hstore); Datum plperl_to_hstore(PG_FUNCTION_ARGS) { - HV *hv; + dTHX; + HV *hv = (HV *) SvRV((SV *) PG_GETARG_POINTER(0)); HE *he; int32 buflen; int32 i; @@ -53,8 +55,6 @@ plperl_to_hstore(PG_FUNCTION_ARGS) HStore *out; Pairs *pairs; - hv = (HV *) SvRV((SV *) PG_GETARG_POINTER(0)); - pcount = hv_iterinit(hv); pairs = palloc(pcount * sizeof(Pairs)); diff --git a/src/pl/plperl/SPI.xs b/src/pl/plperl/SPI.xs index 0447c50df1..d9e6f579d4 100644 --- a/src/pl/plperl/SPI.xs +++ b/src/pl/plperl/SPI.xs @@ -9,44 +9,16 @@ /* this must be first: */ #include "postgres.h" -#include "mb/pg_wchar.h" /* for GetDatabaseEncoding */ /* Defined by Perl */ #undef _ /* perl stuff */ +#define PG_NEED_PERL_XSUB_H #include "plperl.h" #include "plperl_helpers.h" -/* - * Interface routine to catch ereports and punt them to Perl - */ -static void -do_plperl_return_next(SV *sv) -{ - MemoryContext oldcontext = CurrentMemoryContext; - - PG_TRY(); - { - plperl_return_next(sv); - } - PG_CATCH(); - { - ErrorData *edata; - - /* Must reset elog.c's state */ - MemoryContextSwitchTo(oldcontext); - edata = CopyErrorData(); - FlushErrorState(); - - /* Punt the error to Perl */ - croak_cstr(edata->message); - } - PG_END_TRY(); -} - - MODULE = PostgreSQL::InServer::SPI PREFIX = spi_ PROTOTYPES: ENABLE @@ -76,7 +48,7 @@ void spi_return_next(rv) SV *rv; CODE: - do_plperl_return_next(rv); + plperl_return_next(rv); SV * spi_spi_query(sv) diff --git a/src/pl/plperl/Util.xs b/src/pl/plperl/Util.xs index 8c3c47fec9..629d12aaaf 100644 --- a/src/pl/plperl/Util.xs +++ b/src/pl/plperl/Util.xs @@ -15,53 +15,15 @@ #include "fmgr.h" #include "utils/builtins.h" #include "utils/bytea.h" /* for byteain & byteaout */ -#include "mb/pg_wchar.h" /* for GetDatabaseEncoding */ + /* Defined by Perl */ #undef _ /* perl stuff */ +#define PG_NEED_PERL_XSUB_H #include "plperl.h" #include "plperl_helpers.h" -/* - * Implementation of plperl's elog() function - * - * If the error level is less than ERROR, we'll just emit the message and - * return. When it is ERROR, elog() will longjmp, which we catch and - * turn into a Perl croak(). Note we are assuming that elog() can't have - * any internal failures that are so bad as to require a transaction abort. - * - * This is out-of-line to suppress "might be clobbered by longjmp" warnings. - */ -static void -do_util_elog(int level, SV *msg) -{ - MemoryContext oldcontext = CurrentMemoryContext; - char * volatile cmsg = NULL; - - PG_TRY(); - { - cmsg = sv2cstr(msg); - elog(level, "%s", cmsg); - pfree(cmsg); - } - PG_CATCH(); - { - ErrorData *edata; - - /* Must reset elog.c's state */ - MemoryContextSwitchTo(oldcontext); - edata = CopyErrorData(); - FlushErrorState(); - - if (cmsg) - pfree(cmsg); - - /* Punt the error to Perl */ - croak_cstr(edata->message); - } - PG_END_TRY(); -} static text * sv2text(SV *sv) @@ -105,7 +67,7 @@ util_elog(level, msg) level = ERROR; if (level < DEBUG5) level = DEBUG5; - do_util_elog(level, msg); + plperl_util_elog(level, msg); SV * util_quote_literal(sv) diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index 2cd761496d..e58c85c7b4 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -6,6 +6,7 @@ **********************************************************************/ #include "postgres.h" + /* Defined by Perl */ #undef _ @@ -283,6 +284,7 @@ static void plperl_init_shared_libs(pTHX); static void plperl_trusted_init(void); static void plperl_untrusted_init(void); static HV *plperl_spi_execute_fetch_result(SPITupleTable *, uint64, int); +static void plperl_return_next_internal(SV *sv); static char *hek2cstr(HE *he); static SV **hv_store_string(HV *hv, const char *key, SV *val); static SV **hv_fetch_string(HV *hv, const char *key); @@ -300,12 +302,27 @@ static void activate_interpreter(plperl_interp_desc *interp_desc); static char *setlocale_perl(int category, char *locale); #endif +/* + * Decrement the refcount of the given SV within the active Perl interpreter + * + * This is handy because it reloads the active-interpreter pointer, saving + * some notation in callers that switch the active interpreter. + */ +static inline void +SvREFCNT_dec_current(SV *sv) +{ + dTHX; + + SvREFCNT_dec(sv); +} + /* * convert a HE (hash entry) key to a cstr in the current database encoding */ static char * hek2cstr(HE *he) { + dTHX; char *ret; SV *sv; @@ -656,15 +673,19 @@ select_perl_context(bool trusted) * to the database AFTER on_*_init code has run. See * http://archives.postgresql.org/pgsql-hackers/2010-01/msg02669.php */ - newXS("PostgreSQL::InServer::SPI::bootstrap", - boot_PostgreSQL__InServer__SPI, __FILE__); + { + dTHX; - eval_pv("PostgreSQL::InServer::SPI::bootstrap()", FALSE); - if (SvTRUE(ERRSV)) - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), - errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), - errcontext("while executing PostgreSQL::InServer::SPI::bootstrap"))); + newXS("PostgreSQL::InServer::SPI::bootstrap", + boot_PostgreSQL__InServer__SPI, __FILE__); + + eval_pv("PostgreSQL::InServer::SPI::bootstrap()", FALSE); + if (SvTRUE(ERRSV)) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), + errcontext("while executing PostgreSQL::InServer::SPI::bootstrap"))); + } /* Fully initialized, so mark the hashtable entry valid */ interp_desc->interp = interp; @@ -807,53 +828,62 @@ plperl_init_interp(void) PERL_SET_CONTEXT(plperl); perl_construct(plperl); - /* run END blocks in perl_destruct instead of perl_run */ - PL_exit_flags |= PERL_EXIT_DESTRUCT_END; - /* - * Record the original function for the 'require' and 'dofile' opcodes. - * (They share the same implementation.) Ensure it's used for new - * interpreters. + * Run END blocks in perl_destruct instead of perl_run. Note that dTHX + * loads up a pointer to the current interpreter, so we have to postpone + * it to here rather than put it at the function head. */ - if (!pp_require_orig) - pp_require_orig = PL_ppaddr[OP_REQUIRE]; - else { - PL_ppaddr[OP_REQUIRE] = pp_require_orig; - PL_ppaddr[OP_DOFILE] = pp_require_orig; - } + dTHX; + + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; + + /* + * Record the original function for the 'require' and 'dofile' + * opcodes. (They share the same implementation.) Ensure it's used + * for new interpreters. + */ + if (!pp_require_orig) + pp_require_orig = PL_ppaddr[OP_REQUIRE]; + else + { + PL_ppaddr[OP_REQUIRE] = pp_require_orig; + PL_ppaddr[OP_DOFILE] = pp_require_orig; + } #ifdef PLPERL_ENABLE_OPMASK_EARLY - /* - * For regression testing to prove that the PLC_PERLBOOT and PLC_TRUSTED - * code doesn't even compile any unsafe ops. In future there may be a - * valid need for them to do so, in which case this could be softened - * (perhaps moved to plperl_trusted_init()) or removed. - */ - PL_op_mask = plperl_opmask; + /* + * For regression testing to prove that the PLC_PERLBOOT and + * PLC_TRUSTED code doesn't even compile any unsafe ops. In future + * there may be a valid need for them to do so, in which case this + * could be softened (perhaps moved to plperl_trusted_init()) or + * removed. + */ + PL_op_mask = plperl_opmask; #endif - if (perl_parse(plperl, plperl_init_shared_libs, - nargs, embedding, NULL) != 0) - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), - errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), - errcontext("while parsing Perl initialization"))); + if (perl_parse(plperl, plperl_init_shared_libs, + nargs, embedding, NULL) != 0) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), + errcontext("while parsing Perl initialization"))); - if (perl_run(plperl) != 0) - ereport(ERROR, - (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), - errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), - errcontext("while running Perl initialization"))); + if (perl_run(plperl) != 0) + ereport(ERROR, + (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), + errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))), + errcontext("while running Perl initialization"))); #ifdef PLPERL_RESTORE_LOCALE - PLPERL_RESTORE_LOCALE(LC_COLLATE, save_collate); - PLPERL_RESTORE_LOCALE(LC_CTYPE, save_ctype); - PLPERL_RESTORE_LOCALE(LC_MONETARY, save_monetary); - PLPERL_RESTORE_LOCALE(LC_NUMERIC, save_numeric); - PLPERL_RESTORE_LOCALE(LC_TIME, save_time); + PLPERL_RESTORE_LOCALE(LC_COLLATE, save_collate); + PLPERL_RESTORE_LOCALE(LC_CTYPE, save_ctype); + PLPERL_RESTORE_LOCALE(LC_MONETARY, save_monetary); + PLPERL_RESTORE_LOCALE(LC_NUMERIC, save_numeric); + PLPERL_RESTORE_LOCALE(LC_TIME, save_time); #endif + } return plperl; } @@ -919,6 +949,7 @@ plperl_destroy_interp(PerlInterpreter **interp) * public API so isn't portably available.) Meanwhile END blocks can * be used to perform manual cleanup. */ + dTHX; /* Run END blocks - based on perl's perl_destruct() */ if (PL_exit_flags & PERL_EXIT_DESTRUCT_END) @@ -945,6 +976,7 @@ plperl_destroy_interp(PerlInterpreter **interp) static void plperl_trusted_init(void) { + dTHX; HV *stash; SV *sv; char *key; @@ -1025,6 +1057,8 @@ plperl_trusted_init(void) static void plperl_untrusted_init(void) { + dTHX; + /* * Nothing to do except execute plperl.on_plperlu_init */ @@ -1060,6 +1094,7 @@ strip_trailing_ws(const char *msg) static HeapTuple plperl_build_tuple_result(HV *perlhash, TupleDesc td) { + dTHX; Datum *values; bool *nulls; HE *he; @@ -1116,6 +1151,8 @@ plperl_hash_to_datum(SV *src, TupleDesc td) static SV * get_perl_array_ref(SV *sv) { + dTHX; + if (SvOK(sv) && SvROK(sv)) { if (SvTYPE(SvRV(sv)) == SVt_PVAV) @@ -1144,6 +1181,7 @@ array_to_datum_internal(AV *av, ArrayBuildState *astate, Oid arraytypid, Oid elemtypid, int32 typmod, FmgrInfo *finfo, Oid typioparam) { + dTHX; int i; int len = av_len(av) + 1; @@ -1215,6 +1253,7 @@ array_to_datum_internal(AV *av, ArrayBuildState *astate, static Datum plperl_array_to_datum(SV *src, Oid typid, int32 typmod) { + dTHX; ArrayBuildState *astate; Oid elemtypid; FmgrInfo finfo; @@ -1417,6 +1456,7 @@ plperl_sv_to_literal(SV *sv, char *fqtypename) static SV * plperl_ref_from_pg_array(Datum arg, Oid typid) { + dTHX; ArrayType *ar = DatumGetArrayTypeP(arg); Oid elementtype = ARR_ELEMTYPE(ar); int16 typlen; @@ -1485,6 +1525,7 @@ plperl_ref_from_pg_array(Datum arg, Oid typid) static SV * split_array(plperl_array_info *info, int first, int last, int nest) { + dTHX; int i; AV *result; @@ -1518,6 +1559,7 @@ split_array(plperl_array_info *info, int first, int last, int nest) static SV * make_array_ref(plperl_array_info *info, int first, int last) { + dTHX; int i; AV *result = newAV(); @@ -1555,6 +1597,7 @@ make_array_ref(plperl_array_info *info, int first, int last) static SV * plperl_trigger_build_args(FunctionCallInfo fcinfo) { + dTHX; TriggerData *tdata; TupleDesc tupdesc; int i; @@ -1661,6 +1704,7 @@ plperl_trigger_build_args(FunctionCallInfo fcinfo) static SV * plperl_event_trigger_build_args(FunctionCallInfo fcinfo) { + dTHX; EventTriggerData *tdata; HV *hv; @@ -1679,6 +1723,7 @@ plperl_event_trigger_build_args(FunctionCallInfo fcinfo) static HeapTuple plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup) { + dTHX; SV **svp; HV *hvNew; HE *he; @@ -1880,7 +1925,7 @@ plperl_inline_handler(PG_FUNCTION_ARGS) perlret = plperl_call_perl_func(&desc, &fake_fcinfo); - SvREFCNT_dec(perlret); + SvREFCNT_dec_current(perlret); if (SPI_finish() != SPI_OK_FINISH) elog(ERROR, "SPI_finish() failed"); @@ -1888,7 +1933,7 @@ plperl_inline_handler(PG_FUNCTION_ARGS) PG_CATCH(); { if (desc.reference) - SvREFCNT_dec(desc.reference); + SvREFCNT_dec_current(desc.reference); current_call_data = save_call_data; activate_interpreter(oldinterp); PG_RE_THROW(); @@ -1896,7 +1941,7 @@ plperl_inline_handler(PG_FUNCTION_ARGS) PG_END_TRY(); if (desc.reference) - SvREFCNT_dec(desc.reference); + SvREFCNT_dec_current(desc.reference); current_call_data = save_call_data; activate_interpreter(oldinterp); @@ -2024,6 +2069,7 @@ plperlu_validator(PG_FUNCTION_ARGS) static void plperl_create_sub(plperl_proc_desc *prodesc, char *s, Oid fn_oid) { + dTHX; dSP; char subname[NAMEDATALEN + 40]; HV *pragma_hv = newHV(); @@ -2110,6 +2156,7 @@ plperl_init_shared_libs(pTHX) static SV * plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo) { + dTHX; dSP; SV *retval; int i; @@ -2203,6 +2250,7 @@ static SV * plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo, SV *td) { + dTHX; dSP; SV *retval, *TDsv; @@ -2271,6 +2319,7 @@ plperl_call_perl_event_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo, SV *td) { + dTHX; dSP; SV *retval, *TDsv; @@ -2390,13 +2439,14 @@ plperl_func_handler(PG_FUNCTION_ARGS) sav = get_perl_array_ref(perlret); if (sav) { + dTHX; int i = 0; SV **svp = 0; AV *rav = (AV *) SvRV(sav); while ((svp = av_fetch(rav, i, FALSE)) != NULL) { - plperl_return_next(*svp); + plperl_return_next_internal(*svp); i++; } } @@ -2433,7 +2483,7 @@ plperl_func_handler(PG_FUNCTION_ARGS) /* Restore the previous error callback */ error_context_stack = pl_error_context.previous; - SvREFCNT_dec(perlret); + SvREFCNT_dec_current(perlret); return retval; } @@ -2537,9 +2587,9 @@ plperl_trigger_handler(PG_FUNCTION_ARGS) /* Restore the previous error callback */ error_context_stack = pl_error_context.previous; - SvREFCNT_dec(svTD); + SvREFCNT_dec_current(svTD); if (perlret) - SvREFCNT_dec(perlret); + SvREFCNT_dec_current(perlret); return retval; } @@ -2578,9 +2628,7 @@ plperl_event_trigger_handler(PG_FUNCTION_ARGS) /* Restore the previous error callback */ error_context_stack = pl_error_context.previous; - SvREFCNT_dec(svTD); - - return; + SvREFCNT_dec_current(svTD); } @@ -2623,7 +2671,7 @@ free_plperl_function(plperl_proc_desc *prodesc) plperl_interp_desc *oldinterp = plperl_active_interp; activate_interpreter(prodesc->interp); - SvREFCNT_dec(prodesc->reference); + SvREFCNT_dec_current(prodesc->reference); activate_interpreter(oldinterp); } /* Get rid of what we conveniently can of our own structs */ @@ -2937,6 +2985,7 @@ plperl_hash_from_datum(Datum attr) static SV * plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc) { + dTHX; HV *hv; int i; @@ -3095,6 +3144,7 @@ static HV * plperl_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 processed, int status) { + dTHX; HV *result; check_spi_usage_allowed(); @@ -3138,15 +3188,40 @@ plperl_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 processed, /* - * Note: plperl_return_next is called both in Postgres and Perl contexts. - * We report any errors in Postgres fashion (via ereport). If called in - * Perl context, it is SPI.xs's responsibility to catch the error and - * convert to a Perl error. We assume (perhaps without adequate justification) - * that we need not abort the current transaction if the Perl code traps the - * error. + * plperl_return_next catches any error and converts it to a Perl error. + * We assume (perhaps without adequate justification) that we need not abort + * the current transaction if the Perl code traps the error. */ void plperl_return_next(SV *sv) +{ + MemoryContext oldcontext = CurrentMemoryContext; + + PG_TRY(); + { + plperl_return_next_internal(sv); + } + PG_CATCH(); + { + ErrorData *edata; + + /* Must reset elog.c's state */ + MemoryContextSwitchTo(oldcontext); + edata = CopyErrorData(); + FlushErrorState(); + + /* Punt the error to Perl */ + croak_cstr(edata->message); + } + PG_END_TRY(); +} + +/* + * plperl_return_next_internal reports any errors in Postgres fashion + * (via ereport). + */ +static void +plperl_return_next_internal(SV *sv) { plperl_proc_desc *prodesc; FunctionCallInfo fcinfo; @@ -3350,6 +3425,7 @@ plperl_spi_fetchrow(char *cursor) PG_TRY(); { + dTHX; Portal p = SPI_cursor_find(cursor); if (!p) @@ -3617,6 +3693,8 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv) PG_TRY(); { + dTHX; + /************************************************************ * Fetch the saved plan descriptor, see if it's o.k. ************************************************************/ @@ -3887,6 +3965,47 @@ plperl_spi_freeplan(char *query) SPI_freeplan(plan); } +/* + * Implementation of plperl's elog() function + * + * If the error level is less than ERROR, we'll just emit the message and + * return. When it is ERROR, elog() will longjmp, which we catch and + * turn into a Perl croak(). Note we are assuming that elog() can't have + * any internal failures that are so bad as to require a transaction abort. + * + * The main reason this is out-of-line is to avoid conflicts between XSUB.h + * and the PG_TRY macros. + */ +void +plperl_util_elog(int level, SV *msg) +{ + MemoryContext oldcontext = CurrentMemoryContext; + char *volatile cmsg = NULL; + + PG_TRY(); + { + cmsg = sv2cstr(msg); + elog(level, "%s", cmsg); + pfree(cmsg); + } + PG_CATCH(); + { + ErrorData *edata; + + /* Must reset elog.c's state */ + MemoryContextSwitchTo(oldcontext); + edata = CopyErrorData(); + FlushErrorState(); + + if (cmsg) + pfree(cmsg); + + /* Punt the error to Perl */ + croak_cstr(edata->message); + } + PG_END_TRY(); +} + /* * Store an SV into a hash table under a key that is a string assumed to be * in the current database's encoding. @@ -3894,6 +4013,7 @@ plperl_spi_freeplan(char *query) static SV ** hv_store_string(HV *hv, const char *key, SV *val) { + dTHX; int32 hlen; char *hkey; SV **ret; @@ -3920,6 +4040,7 @@ hv_store_string(HV *hv, const char *key, SV *val) static SV ** hv_fetch_string(HV *hv, const char *key) { + dTHX; int32 hlen; char *hkey; SV **ret; @@ -3978,6 +4099,7 @@ plperl_inline_callback(void *arg) static char * setlocale_perl(int category, char *locale) { + dTHX; char *RETVAL = setlocale(category, locale); if (RETVAL) @@ -4042,4 +4164,4 @@ setlocale_perl(int category, char *locale) return RETVAL; } -#endif +#endif /* WIN32 */ diff --git a/src/pl/plperl/plperl.h b/src/pl/plperl/plperl.h index 0146d60a11..a4593cac37 100644 --- a/src/pl/plperl/plperl.h +++ b/src/pl/plperl/plperl.h @@ -24,7 +24,7 @@ #ifdef isnan #undef isnan #endif -#endif +#endif /* WIN32 */ /* * Supply a value of PERL_UNUSED_DECL that will satisfy gcc - the one @@ -43,10 +43,22 @@ #endif -/* required for perl API */ +/* + * Get the basic Perl API. We use PERL_NO_GET_CONTEXT mode so that our code + * can compile against MULTIPLICITY Perl builds without including XSUB.h. + */ +#define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" + +/* + * We want to include XSUB.h only within .xs files, because on some platforms + * it undesirably redefines a lot of libc functions. But it must appear + * before ppport.h, so use a #define flag to control inclusion here. + */ +#ifdef PG_NEED_PERL_XSUB_H #include "XSUB.h" +#endif /* put back our snprintf and vsnprintf */ #ifdef USE_REPL_SNPRINTF @@ -106,5 +118,6 @@ 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 *); +void plperl_util_elog(int level, SV *msg); #endif /* PL_PERL_H */ diff --git a/src/pl/plperl/plperl_helpers.h b/src/pl/plperl/plperl_helpers.h index f8aa06835c..8861736f9c 100644 --- a/src/pl/plperl/plperl_helpers.h +++ b/src/pl/plperl/plperl_helpers.h @@ -50,6 +50,7 @@ utf_e2u(const char *str) static inline char * sv2cstr(SV *sv) { + dTHX; char *val, *res; STRLEN len; @@ -107,6 +108,7 @@ sv2cstr(SV *sv) static inline SV * cstr2sv(const char *str) { + dTHX; SV *sv; char *utf8_str; @@ -134,6 +136,8 @@ cstr2sv(const char *str) static inline void croak_cstr(const char *str) { + dTHX; + #ifdef croak_sv /* Use sv_2mortal() to be sure the transient SV gets freed */ croak_sv(sv_2mortal(cstr2sv(str))); -- 2.40.0