Building on my earlier plperl refactoring patch, here's a draft of my first plperl feature patch.
Significant changes in this patch: - New GUC plperl.on_perl_init='...perl...' for admin use. - New GUC plperl.on_trusted_init='...perl...' for plperl user use. - New GUC plperl.on_untrusted_init='...perl...' for plperlu user use. - END blocks now run at backend exit (fixes bug #5066). - Stored procedure subs are now given names ($name__$oid). - More error checking and reporting. - Warnings no longer have an extra newline in the NOTICE text. - Various minor optimizations like pre-growing data structures. I'm working on adding tests and documentation now, meanwhile I'd very much appreciate any feedback on the patch. Tim. p.s. Once this patch is complete I plan to work on patches that: - add quote_literal and quote_identifier functions in C. - generalize the Safe setup code to enable more control. - formalize namespace usage, moving things out of main:: - add a way to perform inter-sub calling (at least for simple cases). - possibly rewrite _plperl_to_pg_array in C.
diff --git a/src/pl/plperl/GNUmakefile b/src/pl/plperl/GNUmakefile index 8989b14..5a9ad2f 100644 *** a/src/pl/plperl/GNUmakefile --- b/src/pl/plperl/GNUmakefile *************** include $(top_srcdir)/src/Makefile.shlib *** 48,54 **** plperl.o: perlchunks.h perlchunks.h: plc_*.pl ! $(PERL) text2macro.pl --strip='^(\#.*|\s*)$$' plc_*.pl > perlchunks.htmp mv perlchunks.htmp perlchunks.h all: all-lib --- 48,54 ---- plperl.o: perlchunks.h perlchunks.h: plc_*.pl ! $(PERL) text2macro.pl --strip='^\s*(\#.*|)$$' plc_*.pl > perlchunks.htmp mv perlchunks.htmp perlchunks.h all: all-lib diff --git a/src/pl/plperl/expected/plperl_elog.out b/src/pl/plperl/expected/plperl_elog.out index 1791d3c..89497e3 100644 *** a/src/pl/plperl/expected/plperl_elog.out --- b/src/pl/plperl/expected/plperl_elog.out *************** create or replace function perl_warn(tex *** 21,27 **** $$; select perl_warn('implicit elog via warn'); NOTICE: implicit elog via warn at line 4. - CONTEXT: PL/Perl function "perl_warn" perl_warn ----------- --- 21,26 ---- diff --git a/src/pl/plperl/plc_perlboot.pl b/src/pl/plperl/plc_perlboot.pl index d2d5518..b9c6878 100644 *** a/src/pl/plperl/plc_perlboot.pl --- b/src/pl/plperl/plc_perlboot.pl *************** *** 1,8 **** --- 1,12 ---- SPI::bootstrap(); + + use strict; + use warnings; use vars qw(%_SHARED); sub ::plperl_warn { (my $msg = shift) =~ s/\(eval \d+\) //g; + chomp $msg; &elog(&NOTICE, $msg); } $SIG{__WARN__} = \&::plperl_warn; *************** sub ::plperl_die { *** 13,28 **** } $SIG{__DIE__} = \&::plperl_die; ! sub ::mkunsafefunc { ! my $ret = eval(qq[ sub { $_[0] $_[1] } ]); ! $@ =~ s/\(eval \d+\) //g if $@; ! return $ret; ! } ! use strict; ! sub ::mk_strict_unsafefunc { ! my $ret = eval(qq[ sub { use strict; $_[0] $_[1] } ]); $@ =~ s/\(eval \d+\) //g if $@; return $ret; } --- 17,44 ---- } $SIG{__DIE__} = \&::plperl_die; ! sub ::mkfuncsrc { ! my ($name, $imports, $prolog, $src) = @_; ! my $BEGIN = join "\n", map { ! my $names = $imports->{$_} || []; ! "$_->import(qw(@$names));" ! } keys %$imports; ! $BEGIN &&= "BEGIN { $BEGIN }"; ! $name =~ s/\\/\\\\/g; ! $name =~ s/::|'/_/g; # avoid package delimiters ! ! my $funcsrc; ! $funcsrc .= qq[ undef *{'$name'}; *{'$name'} = sub { $BEGIN $prolog $src } ]; ! #warn "plperl mkfuncsrc: $funcsrc\n"; ! return $funcsrc; ! } ! ! # see also mksafefunc() in plc_safe_ok.pl ! sub ::mkunsafefunc { ! no strict; # default to no strict for the eval ! my $ret = eval(::mkfuncsrc(@_)); $@ =~ s/\(eval \d+\) //g if $@; return $ret; } *************** sub ::_plperl_to_pg_array { *** 39,46 **** } elsif (defined($elem)) { my $str = qq($elem); ! $str =~ s/([\"\\])/\\$1/g; ! $res .= qq(\"$str\"); } else { $res .= 'NULL' ; --- 55,62 ---- } elsif (defined($elem)) { my $str = qq($elem); ! $str =~ s/(["\\])/\\$1/g; ! $res .= qq("$str"); } else { $res .= 'NULL' ; diff --git a/src/pl/plperl/plc_safe_bad.pl b/src/pl/plperl/plc_safe_bad.pl index 838ccc6..da47341 100644 *** a/src/pl/plperl/plc_safe_bad.pl --- b/src/pl/plperl/plc_safe_bad.pl *************** *** 1,15 **** ! use vars qw($PLContainer); ! ! $PLContainer = new Safe('PLPerl'); ! $PLContainer->permit_only(':default'); ! $PLContainer->share(qw[&elog &ERROR]); my $msg = 'trusted Perl functions disabled - please upgrade Perl Safe module to version 2.09 or later'; - sub ::mksafefunc { - return $PLContainer->reval(qq[sub { elog(ERROR,'$msg') }]); - } ! sub ::mk_strict_safefunc { ! return $PLContainer->reval(qq[sub { elog(ERROR,'$msg') }]); } - --- 1,13 ---- ! # Minimal version of plc_safe_ok.pl ! # Executed if Safe is too old or doesn't load for any reason my $msg = 'trusted Perl functions disabled - please upgrade Perl Safe module to version 2.09 or later'; ! sub mksafefunc { ! my ($name, $pragma, $prolog, $src) = @_; ! # replace $src with code to generate an error ! $src = qq{ ::elog(::ERROR,"$msg\n") }; ! my $ret = eval(::mkfuncsrc($name, $pragma, '', $src)); ! $@ =~ s/\(eval \d+\) //g if $@; ! return $ret; } diff --git a/src/pl/plperl/plc_safe_ok.pl b/src/pl/plperl/plc_safe_ok.pl index 73c5573..cc8f433 100644 *** a/src/pl/plperl/plc_safe_ok.pl --- b/src/pl/plperl/plc_safe_ok.pl *************** *** 1,3 **** --- 1,5 ---- + use strict; + use warnings; use vars qw($PLContainer); $PLContainer = new Safe('PLPerl'); *************** $PLContainer->share(qw[&elog &return_nex *** 17,33 **** # notice. It is quite safe, as caller is informational only, and in any case # we only enable it while we load the 'strict' module. $PLContainer->permit(qw[require caller]); ! $PLContainer->reval('use strict;'); $PLContainer->deny(qw[require caller]); ! sub ::mksafefunc { ! my $ret = $PLContainer->reval(qq[sub { $_[0] $_[1] }]); $@ =~ s/\(eval \d+\) //g if $@; return $ret; } ! sub ::mk_strict_safefunc { ! my $ret = $PLContainer->reval(qq[sub { BEGIN { strict->import(); } $_[0] $_[1] }]); ! $@ =~ s/\(eval \d+\) //g if $@; ! return $ret; } --- 19,34 ---- # notice. It is quite safe, as caller is informational only, and in any case # we only enable it while we load the 'strict' module. $PLContainer->permit(qw[require caller]); ! $PLContainer->reval('require strict;') or die $@; $PLContainer->deny(qw[require caller]); ! # called directly for plperl.on_trusted_init ! sub ::safe_eval { ! my $ret = $PLContainer->reval(shift); $@ =~ s/\(eval \d+\) //g if $@; return $ret; } ! sub ::mksafefunc { ! return ::safe_eval(::mkfuncsrc(@_)); } diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index f919f04..812d8ae 100644 *** a/src/pl/plperl/plperl.c --- b/src/pl/plperl/plperl.c *************** static HTAB *plperl_proc_hash = NULL; *** 137,142 **** --- 137,145 ---- static HTAB *plperl_query_hash = NULL; static bool plperl_use_strict = false; + static char *plperl_on_perl_init = NULL; + static char *plperl_on_trusted_init = NULL; + static char *plperl_on_untrusted_init = NULL; /* this is saved and restored by plperl_call_handler */ static plperl_call_data *current_call_data = NULL; *************** Datum plperl_inline_handler(PG_FUNCTION *** 149,155 **** Datum plperl_validator(PG_FUNCTION_ARGS); void _PG_init(void); ! static PerlInterpreter *plperl_init_interp(void); static Datum plperl_func_handler(PG_FUNCTION_ARGS); static Datum plperl_trigger_handler(PG_FUNCTION_ARGS); --- 152,160 ---- Datum plperl_validator(PG_FUNCTION_ARGS); void _PG_init(void); ! static PerlInterpreter *plperl_create_interp(void); ! static void plperl_destroy_interp(PerlInterpreter **); ! static void plperl_fini(void); static Datum plperl_func_handler(PG_FUNCTION_ARGS); static Datum plperl_trigger_handler(PG_FUNCTION_ARGS); *************** static plperl_proc_desc *compile_plperl_ *** 159,173 **** static SV *plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc); static void plperl_init_shared_libs(pTHX); static void plperl_safe_init(void); static HV *plperl_spi_execute_fetch_result(SPITupleTable *, int, int); static SV *newSVstring(const char *str); static SV **hv_store_string(HV *hv, const char *key, SV *val); static SV **hv_fetch_string(HV *hv, const char *key); ! static void plperl_create_sub(plperl_proc_desc *desc, char *s); static SV *plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo); static void plperl_compile_callback(void *arg); static void plperl_exec_callback(void *arg); static void plperl_inline_callback(void *arg); /* * This routine is a crock, and so is everyplace that calls it. The problem --- 164,180 ---- static SV *plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc); static void plperl_init_shared_libs(pTHX); static void plperl_safe_init(void); + static SV *plperl_eval_pv(const char *src, const char *errfmt); static HV *plperl_spi_execute_fetch_result(SPITupleTable *, int, int); static SV *newSVstring(const char *str); static SV **hv_store_string(HV *hv, const char *key, SV *val); static SV **hv_fetch_string(HV *hv, const char *key); ! static void plperl_create_sub(plperl_proc_desc *desc, char *s, Oid fn_oid); static SV *plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo); static void plperl_compile_callback(void *arg); static void plperl_exec_callback(void *arg); static void plperl_inline_callback(void *arg); + static char *strip_trailing_ws(const char *msg); /* * This routine is a crock, and so is everyplace that calls it. The problem *************** _PG_init(void) *** 212,217 **** --- 219,248 ---- PGC_USERSET, 0, NULL, NULL); + DefineCustomStringVariable("plperl.on_perl_init", + gettext_noop("Perl code to execute when interpreter is initialized."), + NULL, + &plperl_on_perl_init, + NULL, + PGC_SUSET, 0, + NULL, NULL); + + DefineCustomStringVariable("plperl.on_trusted_init", + gettext_noop("Perl code to execute when plperl is initialized for user."), + NULL, + &plperl_on_trusted_init, + NULL, + PGC_USERSET, 0, + NULL, NULL); + + DefineCustomStringVariable("plperl.on_untrusted_init", + gettext_noop("Perl code to execute when plperlu is initialized for user."), + NULL, + &plperl_on_untrusted_init, + NULL, + PGC_USERSET, 0, + NULL, NULL); + EmitWarningsOnPlaceholders("plperl"); MemSet(&hash_ctl, 0, sizeof(hash_ctl)); *************** _PG_init(void) *** 230,241 **** &hash_ctl, HASH_ELEM); ! plperl_held_interp = plperl_init_interp(); interp_state = INTERP_HELD; inited = true; } #define SAFE_MODULE \ "require Safe; $Safe::VERSION" --- 261,288 ---- &hash_ctl, HASH_ELEM); ! plperl_held_interp = plperl_create_interp(); interp_state = INTERP_HELD; + atexit(plperl_fini); + inited = true; } + + /* + * Cleanup perl interpreters, including running END blocks. + * Does not fully undo the actions of _PG_init() nor make it callable again. + */ + static void + plperl_fini(void) + { + plperl_destroy_interp(&plperl_trusted_interp); + plperl_destroy_interp(&plperl_untrusted_interp); + plperl_destroy_interp(&plperl_held_interp); + } + + #define SAFE_MODULE \ "require Safe; $Safe::VERSION" *************** _PG_init(void) *** 246,259 **** * assign that interpreter if it is available to either the trusted or * untrusted interpreter. If it has already been assigned, and we need to * create the other interpreter, we do that if we can, or error out. - * We detect if it is safe to run two interpreters during the setup of the - * dummy interpreter. */ static void check_interp(bool trusted) { if (interp_state == INTERP_HELD) { if (trusted) --- 293,325 ---- * assign that interpreter if it is available to either the trusted or * untrusted interpreter. If it has already been assigned, and we need to * create the other interpreter, we do that if we can, or error out. */ static void check_interp(bool trusted) { + /* + * handle simple cases + */ + if (interp_state == INTERP_BOTH || + ( trusted && interp_state == INTERP_TRUSTED) || + (!trusted && interp_state == INTERP_UNTRUSTED)) + { + if (trusted_context != trusted) + { + if (trusted) + PERL_SET_CONTEXT(plperl_trusted_interp); + else + PERL_SET_CONTEXT(plperl_untrusted_interp); + trusted_context = trusted; + } + return; + } + + /* + * adopt held interp if free, else create new one if possible + */ if (interp_state == INTERP_HELD) { if (trusted) *************** check_interp(bool trusted) *** 266,307 **** plperl_untrusted_interp = plperl_held_interp; interp_state = INTERP_UNTRUSTED; } - plperl_held_interp = NULL; - trusted_context = trusted; - if (trusted) /* done last to avoid recursion */ - plperl_safe_init(); - } - else if (interp_state == INTERP_BOTH || - (trusted && interp_state == INTERP_TRUSTED) || - (!trusted && interp_state == INTERP_UNTRUSTED)) - { - if (trusted_context != trusted) - { - if (trusted) - PERL_SET_CONTEXT(plperl_trusted_interp); - else - PERL_SET_CONTEXT(plperl_untrusted_interp); - trusted_context = trusted; - } } else { #ifdef MULTIPLICITY ! PerlInterpreter *plperl = plperl_init_interp(); if (trusted) plperl_trusted_interp = plperl; else plperl_untrusted_interp = plperl; - plperl_held_interp = NULL; - trusted_context = trusted; interp_state = INTERP_BOTH; - if (trusted) /* done last to avoid recursion */ - plperl_safe_init(); #else elog(ERROR, "cannot allocate second Perl interpreter on this platform"); #endif } } /* --- 332,369 ---- plperl_untrusted_interp = plperl_held_interp; interp_state = INTERP_UNTRUSTED; } } else { #ifdef MULTIPLICITY ! PerlInterpreter *plperl = plperl_create_interp(); if (trusted) plperl_trusted_interp = plperl; else plperl_untrusted_interp = plperl; interp_state = INTERP_BOTH; #else elog(ERROR, "cannot allocate second Perl interpreter on this platform"); #endif } + plperl_held_interp = NULL; + trusted_context = trusted; + + /* + * initialization - done last to ensure a clean state + * (and thereby avoid recursion via plperl_safe_init) + */ + if (trusted) + plperl_safe_init(); + else + { + if (plperl_on_untrusted_init && *plperl_on_untrusted_init) + { + plperl_eval_pv(plperl_on_untrusted_init, + "Error executing plperl.on_untrusted_init: %s"); + } + } } /* *************** restore_context(bool old_context) *** 321,336 **** } static PerlInterpreter * ! plperl_init_interp(void) { PerlInterpreter *plperl; static int perl_sys_init_done; ! static char *embedding[3] = { "", "-e", PLC_PERLBOOT }; int nargs = 3; #ifdef WIN32 /* --- 383,408 ---- } static PerlInterpreter * ! plperl_create_interp(void) { PerlInterpreter *plperl; static int perl_sys_init_done; ! /* ! * The perl interpreter configuration can be altered via the environment variables ! * like PERL5LIB, PERL5OPT, PERL_UNICODE etc., documented in the perlrun documentation. ! */ ! static char *embedding[3+2] = { "", "-e", PLC_PERLBOOT }; int nargs = 3; + if (plperl_on_perl_init) + { + embedding[nargs++] = "-e"; + embedding[nargs++] = plperl_on_perl_init; + } + #ifdef WIN32 /* *************** plperl_init_interp(void) *** 399,404 **** --- 471,478 ---- PERL_SET_CONTEXT(plperl); perl_construct(plperl); + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; + perl_parse(plperl, plperl_init_shared_libs, nargs, embedding, NULL); perl_run(plperl); *************** plperl_init_interp(void) *** 449,459 **** static void plperl_safe_init(void) { SV *safe_version_sv; ! safe_version_sv = eval_pv(SAFE_MODULE, FALSE); /* TRUE = croak if failure */ /* * We actually want to reject Safe version < 2.09, but it's risky to --- 523,545 ---- static void + plperl_destroy_interp(PerlInterpreter **interp) + { + if (interp && *interp) + { + perl_destruct(*interp); + perl_free(*interp); + *interp = NULL; + } + } + + + static void plperl_safe_init(void) { SV *safe_version_sv; ! safe_version_sv = plperl_eval_pv(SAFE_MODULE, "%s"); /* * We actually want to reject Safe version < 2.09, but it's risky to *************** plperl_safe_init(void) *** 463,473 **** if (SvNV(safe_version_sv) < 2.0899) { /* not safe, so disallow all trusted funcs */ ! eval_pv(PLC_SAFE_BAD, FALSE); } else { ! eval_pv(PLC_SAFE_OK, FALSE); if (GetDatabaseEncoding() == PG_UTF8) { /* --- 549,560 ---- if (SvNV(safe_version_sv) < 2.0899) { /* not safe, so disallow all trusted funcs */ ! plperl_eval_pv(PLC_SAFE_BAD, "Error initializing stub plperl: %s"); } else { ! plperl_eval_pv(PLC_SAFE_OK, "Error initializing plperl: %s"); ! if (GetDatabaseEncoding() == PG_UTF8) { /* *************** plperl_safe_init(void) *** 488,494 **** /* compile the function */ plperl_create_sub(&desc, ! "return shift =~ /\\xa9/i ? 'true' : 'false' ;"); /* set up to call the function with a single text argument 'a' */ fcinfo.arg[0] = CStringGetTextDatum("a"); --- 575,581 ---- /* compile the function */ plperl_create_sub(&desc, ! "return shift =~ /\\xa9/i ? 'true' : 'false' ;", 0); /* set up to call the function with a single text argument 'a' */ fcinfo.arg[0] = CStringGetTextDatum("a"); *************** plperl_safe_init(void) *** 497,506 **** --- 584,626 ---- /* and make the call */ (void) plperl_call_perl_func(&desc, &fcinfo); } + + if (plperl_on_trusted_init && *plperl_on_trusted_init) + { + dSP; + + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVstring(plperl_on_trusted_init))); + PUTBACK; + + call_pv("::safe_eval", G_VOID); + + if (SvTRUE(ERRSV)) + { + elog(ERROR, "Error executing plperl.on_trusted_init: %s", + strip_trailing_ws(SvPV_nolen(ERRSV))); + } + } } } /* + * wrapper for eval_pv that calls elog on error + */ + static SV * + plperl_eval_pv(const char *src, const char *errfmt) + { + SV *sv; + + sv = eval_pv(src, (errfmt) ? FALSE : TRUE); /* croak if error and errfmt is NULL */ + if (SvTRUE(ERRSV)) + { + elog(ERROR, errfmt, strip_trailing_ws(SvPV_nolen(ERRSV))); + } + return sv; + } + + /* * Perl likes to put a newline after its error messages; clean up such */ static char * *************** plperl_convert_to_pg_array(SV *src) *** 557,563 **** { SV *rv; int count; - dSP; PUSHMARK(SP); --- 677,682 ---- *************** plperl_trigger_build_args(FunctionCallIn *** 594,599 **** --- 713,719 ---- HV *hv; hv = newHV(); + hv_ksplit(hv, 12); /* pre-grow the hash */ tdata = (TriggerData *) fcinfo->context; tupdesc = tdata->tg_relation->rd_att; *************** plperl_trigger_build_args(FunctionCallIn *** 648,653 **** --- 768,774 ---- { AV *av = newAV(); + av_extend(av, tdata->tg_trigger->tgnargs); for (i = 0; i < tdata->tg_trigger->tgnargs; i++) av_push(av, newSVstring(tdata->tg_trigger->tgargs[i])); hv_store_string(hv, "args", newRV_noinc((SV *) av)); *************** plperl_inline_handler(PG_FUNCTION_ARGS) *** 870,876 **** check_interp(desc.lanpltrusted); ! plperl_create_sub(&desc, codeblock->source_text); if (!desc.reference) /* can this happen? */ elog(ERROR, "could not create internal procedure for anonymous code block"); --- 991,997 ---- check_interp(desc.lanpltrusted); ! plperl_create_sub(&desc, codeblock->source_text, 0); if (!desc.reference) /* can this happen? */ elog(ERROR, "could not create internal procedure for anonymous code block"); *************** plperl_validator(PG_FUNCTION_ARGS) *** 975,997 **** /* ! * Uses mksafefunc/mkunsafefunc to create an anonymous sub whose text is ! * supplied in s, and returns a reference to the closure. */ static void ! plperl_create_sub(plperl_proc_desc *prodesc, char *s) { dSP; bool trusted = prodesc->lanpltrusted; ! SV *subref; ! int count; ! char *compile_sub; ENTER; SAVETMPS; PUSHMARK(SP); ! XPUSHs(sv_2mortal(newSVstring("our $_TD; local $_TD=$_[0]; shift;"))); ! XPUSHs(sv_2mortal(newSVstring(s))); PUTBACK; /* --- 1096,1128 ---- /* ! * Uses mksafefunc/mkunsafefunc to create a subroutine whose text is ! * supplied in s, and returns a reference to it */ static void ! plperl_create_sub(plperl_proc_desc *prodesc, char *s, Oid fn_oid) { dSP; bool trusted = prodesc->lanpltrusted; ! char subname[NAMEDATALEN+40]; ! HV *pragma_hv = newHV(); ! SV *subref = NULL; ! int count; ! char *compile_sub; ! ! sprintf(subname, "%s__%u", prodesc->proname, fn_oid); ! ! if (plperl_use_strict) ! hv_store_string(pragma_hv, "strict", (SV*)newAV()); ENTER; SAVETMPS; PUSHMARK(SP); ! EXTEND(SP,4); ! PUSHs(sv_2mortal(newSVstring(subname))); ! PUSHs(sv_2mortal(newRV_noinc((SV*)pragma_hv))); ! PUSHs(sv_2mortal(newSVstring("our $_TD; local $_TD=shift;"))); ! PUSHs(sv_2mortal(newSVstring(s))); PUTBACK; /* *************** plperl_create_sub(plperl_proc_desc *prod *** 999,1055 **** * errors properly. Perhaps it's because there's another level of eval * inside mksafefunc? */ ! ! if (trusted && plperl_use_strict) ! compile_sub = "::mk_strict_safefunc"; ! else if (plperl_use_strict) ! compile_sub = "::mk_strict_unsafefunc"; ! else if (trusted) ! compile_sub = "::mksafefunc"; ! else ! compile_sub = "::mkunsafefunc"; ! count = perl_call_pv(compile_sub, G_SCALAR | G_EVAL | G_KEEPERR); SPAGAIN; ! if (count != 1) ! { ! PUTBACK; ! FREETMPS; ! LEAVE; ! elog(ERROR, "didn't get a return item from mksafefunc"); } ! subref = POPs; if (SvTRUE(ERRSV)) { - PUTBACK; - FREETMPS; - LEAVE; ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s", strip_trailing_ws(SvPV_nolen(ERRSV))))); } ! if (!SvROK(subref) || SvTYPE(SvRV(subref)) != SVt_PVCV) { ! PUTBACK; ! FREETMPS; ! LEAVE; ! elog(ERROR, "didn't get a code ref"); } - /* - * need to make a copy of the return, it comes off the stack as a - * temporary. - */ prodesc->reference = newSVsv(subref); - PUTBACK; - FREETMPS; - LEAVE; - return; } --- 1130,1165 ---- * errors properly. Perhaps it's because there's another level of eval * inside mksafefunc? */ ! compile_sub = (trusted) ? "::mksafefunc" : "::mkunsafefunc"; count = perl_call_pv(compile_sub, G_SCALAR | G_EVAL | G_KEEPERR); SPAGAIN; ! if (count == 1) { ! GV *sub_glob = (GV*)POPs; ! if (sub_glob && SvTYPE(sub_glob) == SVt_PVGV) ! subref = newRV((SV*)GvCVu((GV*)sub_glob)); } ! PUTBACK; ! FREETMPS; ! LEAVE; if (SvTRUE(ERRSV)) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s", strip_trailing_ws(SvPV_nolen(ERRSV))))); } ! if (!subref) { ! ereport(ERROR, ! (errcode(ERRCODE_INTERNAL_ERROR), ! errmsg("didn't get a GLOB from compiling %s via %s", prodesc->proname, compile_sub))); } prodesc->reference = newSVsv(subref); return; } *************** plperl_call_perl_func(plperl_proc_desc * *** 1089,1101 **** SAVETMPS; PUSHMARK(SP); ! XPUSHs(&PL_sv_undef); /* no trigger data */ for (i = 0; i < desc->nargs; i++) { if (fcinfo->argnull[i]) ! XPUSHs(&PL_sv_undef); else if (desc->arg_is_rowtype[i]) { HeapTupleHeader td; --- 1199,1212 ---- SAVETMPS; PUSHMARK(SP); + EXTEND(sp, 1 + desc->nargs); ! PUSHs(&PL_sv_undef); /* no trigger data */ for (i = 0; i < desc->nargs; i++) { if (fcinfo->argnull[i]) ! PUSHs(&PL_sv_undef); else if (desc->arg_is_rowtype[i]) { HeapTupleHeader td; *************** plperl_call_perl_func(plperl_proc_desc * *** 1115,1121 **** tmptup.t_data = td; hashref = plperl_hash_from_tuple(&tmptup, tupdesc); ! XPUSHs(sv_2mortal(hashref)); ReleaseTupleDesc(tupdesc); } else --- 1226,1232 ---- tmptup.t_data = td; hashref = plperl_hash_from_tuple(&tmptup, tupdesc); ! PUSHs(sv_2mortal(hashref)); ReleaseTupleDesc(tupdesc); } else *************** plperl_call_perl_func(plperl_proc_desc * *** 1125,1131 **** tmp = OutputFunctionCall(&(desc->arg_out_func[i]), fcinfo->arg[i]); sv = newSVstring(tmp); ! XPUSHs(sv_2mortal(sv)); pfree(tmp); } } --- 1236,1242 ---- tmp = OutputFunctionCall(&(desc->arg_out_func[i]), fcinfo->arg[i]); sv = newSVstring(tmp); ! PUSHs(sv_2mortal(sv)); pfree(tmp); } } *************** compile_plperl_function(Oid fn_oid, bool *** 1732,1738 **** check_interp(prodesc->lanpltrusted); ! plperl_create_sub(prodesc, proc_source); restore_context(oldcontext); --- 1843,1849 ---- check_interp(prodesc->lanpltrusted); ! plperl_create_sub(prodesc, proc_source, fn_oid); restore_context(oldcontext); *************** plperl_hash_from_tuple(HeapTuple tuple, *** 1768,1773 **** --- 1879,1885 ---- int i; hv = newHV(); + hv_ksplit(hv, tupdesc->natts); /* pre-grow the hash */ for (i = 0; i < tupdesc->natts; i++) { *************** plperl_spi_execute_fetch_result(SPITuple *** 1895,1900 **** --- 2007,2013 ---- int i; rows = newAV(); + av_extend(rows, processed); for (i = 0; i < processed; i++) { row = plperl_hash_from_tuple(tuptable->vals[i], tuptable->tupdesc);
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers