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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers