This is the second of the patches to be split out from the former
'plperl feature patch 1'.

Changes in this patch:

- Allow (ineffective) use of 'require' in plperl
    If the required module is not already loaded then it dies.
    So "use strict;" now works in plperl.

- Pre-load the feature module if perl >= 5.10.
    So "use feature :5.10;" now works in plperl.

- Stored procedure subs are now given names.
    The names are not visible in ordinary use, but they make
    tools like Devel::NYTProf and Devel::Cover _much_ more useful.

- Simplified and generalized the subroutine creation code.
    Now one code path for generating sub source code, not four.
    Can generate multiple 'use' statements with specific imports
    (which handles plperl.use_strict currently and can easily
    be extended to handle a plperl.use_feature=':5.12' in future).

- Disallows use of Safe version 2.20 which is broken for PL/Perl.
    http://rt.perl.org/rt3/Ticket/Display.html?id=72068

- Assorted minor optimizations by pre-growing data structures.

This patch will apply cleanly over the 'add functions' patch:
https://commitfest.postgresql.org/action/patch_view?id=264

Tim.
diff --git a/doc/src/sgml/plperl.sgml b/doc/src/sgml/plperl.sgml
index 94db722..6fee031 100644
*** a/doc/src/sgml/plperl.sgml
--- b/doc/src/sgml/plperl.sgml
*************** SELECT * FROM perl_set();
*** 285,313 ****
    </para>
  
    <para>
!    If you wish to use the <literal>strict</> pragma with your code,
!    the easiest way to do so is to <command>SET</>
!    <literal>plperl.use_strict</literal> to true.  This parameter affects
!    subsequent compilations of <application>PL/Perl</> functions, but not
!    functions already compiled in the current session.  To set the
!    parameter before <application>PL/Perl</> has been loaded, it is
!    necessary to have added <quote><literal>plperl</></> to the <xref
!    linkend="guc-custom-variable-classes"> list in
!    <filename>postgresql.conf</filename>.
    </para>
  
    <para>
!    Another way to use the <literal>strict</> pragma is to put:
  <programlisting>
  use strict;
  </programlisting>
!    in the function body.  But this only works in <application>PL/PerlU</>
!    functions, since the <literal>use</> triggers a <literal>require</>
!    which is not a trusted operation.  In
!    <application>PL/Perl</> functions you can instead do:
! <programlisting>
! BEGIN { strict->import(); }
! </programlisting>
    </para>
   </sect1>
  
--- 285,323 ----
    </para>
  
    <para>
!    If you wish to use the <literal>strict</> pragma with your code you have a few options.
!    For temporary global use you can <command>SET</> <literal>plperl.use_strict</literal>
!    to true (see <xref linkend="plperl.use_strict">).
!    This will affect subsequent compilations of <application>PL/Perl</>
!    functions, but not functions already compiled in the current session.
!    For permanent global use you can set <literal>plperl.use_strict</literal>
!    to true in the <filename>postgresql.conf</filename> file.
    </para>
  
    <para>
!    For permanent use in specific functions you can simply put:
  <programlisting>
  use strict;
  </programlisting>
!    at the top of the function body.
!   </para>
! 
!   <para>
!   The <literal>feature</> pragma is also available to <function>use</> if your Perl is version 5.10.0 or higher.
!   </para>
! 
!  </sect1>
! 
!  <sect1 id="plperl-data">
!   <title>Data Values in PL/Perl</title>
! 
!   <para>
!    The argument values supplied to a PL/Perl function's code are
!    simply the input arguments converted to text form (just as if they
!    had been displayed by a <command>SELECT</command> statement).
!    Conversely, the <function>return</function> and <function>return_next</function>
!    commands will accept any string that is acceptable input format
!    for the function's declared return type.
    </para>
   </sect1>
  
*************** SELECT done();
*** 682,699 ****
   </sect2>
   </sect1>
  
-  <sect1 id="plperl-data">
-   <title>Data Values in PL/Perl</title>
- 
-   <para>
-    The argument values supplied to a PL/Perl function's code are
-    simply the input arguments converted to text form (just as if they
-    had been displayed by a <command>SELECT</command> statement).
-    Conversely, the <literal>return</> command will accept any string
-    that is acceptable input format for the function's declared return
-    type.  So, within the PL/Perl function,
-    all values are just text strings.
-   </para>
   </sect1>
  
   <sect1 id="plperl-global">
--- 692,697 ----
*************** CREATE TRIGGER test_valid_id_trig
*** 1042,1049 ****
     <itemizedlist>
      <listitem>
       <para>
!       PL/Perl functions cannot call each other directly (because they
!       are anonymous subroutines inside Perl).
       </para>
      </listitem>
  
--- 1040,1046 ----
     <itemizedlist>
      <listitem>
       <para>
!       PL/Perl functions cannot call each other directly.
       </para>
      </listitem>
  
*************** CREATE TRIGGER test_valid_id_trig
*** 1072,1077 ****
--- 1069,1076 ----
      </listitem>
     </itemizedlist>
    </para>
+  </sect2>
+ 
   </sect1>
  
  </chapter>
diff --git a/src/pl/plperl/expected/plperl.out b/src/pl/plperl/expected/plperl.out
index b942739..ebf9afd 100644
*** a/src/pl/plperl/expected/plperl.out
--- b/src/pl/plperl/expected/plperl.out
*************** $$ LANGUAGE plperl;
*** 563,568 ****
  NOTICE:  This is a test
  CONTEXT:  PL/Perl anonymous code block
  -- check that restricted operations are rejected in a plperl DO block
! DO $$ use Config; $$ LANGUAGE plperl;
! ERROR:  'require' trapped by operation mask at line 1.
  CONTEXT:  PL/Perl anonymous code block
--- 563,579 ----
  NOTICE:  This is a test
  CONTEXT:  PL/Perl anonymous code block
  -- check that restricted operations are rejected in a plperl DO block
! DO $$ eval "1+1"; $$ LANGUAGE plperl;
! ERROR:  'eval "string"' trapped by operation mask at line 1.
! CONTEXT:  PL/Perl anonymous code block
! -- check that we can't "use" a module that's not been loaded already
! -- compile-time error: "Unable to load blib.pm into plperl"
! DO $$ use blib; $$ LANGUAGE plperl;
! ERROR:  Unable to load blib.pm into plperl at line 1.
! BEGIN failed--compilation aborted at line 1.
! CONTEXT:  PL/Perl anonymous code block
! -- check that we can "use" a module that has already been loaded
! -- runtime error: "Can't use string ("foo") as a SCALAR ref while "strict refs" in use
! DO $do$ use strict; my $name = "foo"; my $ref = $$name; $do$ LANGUAGE plperl;
! ERROR:  Can't use string ("foo") as a SCALAR ref while "strict refs" in use at line 1.
  CONTEXT:  PL/Perl anonymous code block
diff --git a/src/pl/plperl/expected/plperl_plperlu.out b/src/pl/plperl/expected/plperl_plperlu.out
index 80824e0..e940f71 100644
*** a/src/pl/plperl/expected/plperl_plperlu.out
--- b/src/pl/plperl/expected/plperl_plperlu.out
***************
*** 1,18 ****
  -- test plperl/plperlu interaction
  CREATE OR REPLACE FUNCTION bar() RETURNS integer AS $$
      #die 'BANG!'; # causes server process to exit(2)
      # alternative - causes server process to exit(255)
      spi_exec_query("invalid sql statement");
! $$ language plperl; -- plperl or plperlu
     
  CREATE OR REPLACE FUNCTION foo() RETURNS integer AS $$
      spi_exec_query("SELECT * FROM bar()");
      return 1;
! $$ LANGUAGE plperlu; -- must be opposite to language of bar
     
! SELECT * FROM bar(); -- throws exception normally
  ERROR:  syntax error at or near "invalid" at line 4.
  CONTEXT:  PL/Perl function "bar"
! SELECT * FROM foo(); -- used to cause backend crash
  ERROR:  syntax error at or near "invalid" at line 4. at line 2.
  CONTEXT:  PL/Perl function "foo"
--- 1,19 ----
  -- test plperl/plperlu interaction
+ -- the language and call ordering of this test sequence is useful
  CREATE OR REPLACE FUNCTION bar() RETURNS integer AS $$
      #die 'BANG!'; # causes server process to exit(2)
      # alternative - causes server process to exit(255)
      spi_exec_query("invalid sql statement");
! $$ language plperl; -- compile plperl code
     
  CREATE OR REPLACE FUNCTION foo() RETURNS integer AS $$
      spi_exec_query("SELECT * FROM bar()");
      return 1;
! $$ LANGUAGE plperlu; -- compile plperlu code
     
! SELECT * FROM bar(); -- throws exception normally (running plperl)
  ERROR:  syntax error at or near "invalid" at line 4.
  CONTEXT:  PL/Perl function "bar"
! SELECT * FROM foo(); -- used to cause backend crash (after switching to plperlu)
  ERROR:  syntax error at or near "invalid" at line 4. at line 2.
  CONTEXT:  PL/Perl function "foo"
diff --git a/src/pl/plperl/plc_perlboot.pl b/src/pl/plperl/plc_perlboot.pl
index b4d1e04..769721d 100644
*** a/src/pl/plperl/plc_perlboot.pl
--- b/src/pl/plperl/plc_perlboot.pl
*************** sub ::plperl_die {
*** 18,34 ****
  }
  $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;
  }
--- 18,45 ----
  }
  $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 ::encode_array_constructor {
*** 61,67 ****
  		if ref $arg ne 'ARRAY';
  	my $res = join ", ", map {
  		(ref $_) ? ::encode_array_constructor($_)
! 				 : ::quote_nullable($_)
  	} @$arg;
  	return "ARRAY[$res]";
  }
--- 72,78 ----
  		if ref $arg ne 'ARRAY';
  	my $res = join ", ", map {
  		(ref $_) ? ::encode_array_constructor($_)
! 		         : ::quote_nullable($_)
  	} @$arg;
  	return "ARRAY[$res]";
  }
diff --git a/src/pl/plperl/plc_safe_bad.pl b/src/pl/plperl/plc_safe_bad.pl
index 838ccc6..36ef6ae 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
! # that's used if Safe is too old or doesn't load for any reason
  
! my $msg = 'trusted Perl functions disabled - please upgrade Perl Safe module';
  
! 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 aec5cdc..dc33dd6 100644
*** a/src/pl/plperl/plc_safe_ok.pl
--- b/src/pl/plperl/plc_safe_ok.pl
***************
*** 1,8 ****
  use vars qw($PLContainer);
  
  $PLContainer = new Safe('PLPerl');
  $PLContainer->permit_only(':default');
! $PLContainer->permit(qw[:base_math !:base_io sort time]);
  
  $PLContainer->share(qw[&elog &return_next
  	&spi_query &spi_fetchrow &spi_cursor_close &spi_exec_query
--- 1,9 ----
+ use strict;
  use vars qw($PLContainer);
  
  $PLContainer = new Safe('PLPerl');
  $PLContainer->permit_only(':default');
! $PLContainer->permit(qw[:base_math !:base_io sort time require]);
  
  $PLContainer->share(qw[&elog &return_next
  	&spi_query &spi_fetchrow &spi_cursor_close &spi_exec_query
*************** $PLContainer->share(qw[&elog &return_nex
*** 14,36 ****
  	&looks_like_number
  ]);
  
! # Load strict into the container.
! # The temporary enabling of the caller opcode here is to work around a
! # bug in perl 5.10, which unkindly changed the way its Safe.pm works, without
! # 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;
  }
--- 15,38 ----
  	&looks_like_number
  ]);
  
! # Load widely useful pragmas into the container to make them available.
! # (Temporarily enable caller here as work around for bug in perl 5.10,
! # which changed the way its Safe.pm works. It is quite safe, as caller is
! # informational only.)
! $PLContainer->permit(qw[caller]);
! ::safe_eval(q{
! 	require strict;
! 	require feature if $] >= 5.010000;
! 	1;
! }) or die $@;
! $PLContainer->deny(qw[caller]);
  
! 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 6f577f0..9277072 100644
*** a/src/pl/plperl/plperl.c
--- b/src/pl/plperl/plperl.c
*************** static InterpState interp_state = INTERP
*** 132,137 ****
--- 132,138 ----
  static PerlInterpreter *plperl_trusted_interp = NULL;
  static PerlInterpreter *plperl_untrusted_interp = NULL;
  static PerlInterpreter *plperl_held_interp = NULL;
+ static OP *(*pp_require_orig)(pTHX) = NULL;
  static bool trusted_context;
  static HTAB *plperl_proc_hash = NULL;
  static HTAB *plperl_query_hash = NULL;
*************** static HV  *plperl_spi_execute_fetch_res
*** 163,173 ****
  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);
  
  /*
   * Convert an SV to char * and verify the encoding via pg_verifymbstr()
--- 164,177 ----
  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);
+ static OP * pp_require_safe(pTHX);
+ static int restore_context(bool);
  
  /*
   * Convert an SV to char * and verify the encoding via pg_verifymbstr()
*************** sv2text_mbverified(SV *sv)
*** 187,193 ****
  	 */
  	val = SvPV(sv, len);
  	pg_verifymbstr(val, len, false);
!     return val;
  }
  
  /*
--- 191,197 ----
  	 */
  	val = SvPV(sv, len);
  	pg_verifymbstr(val, len, false);
! 	return val;
  }
  
  /*
*************** _PG_init(void)
*** 267,280 ****
   * 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)
--- 271,291 ----
   * 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
! select_perl_context(bool trusted)
  {
+ 	/*
+ 	 * handle simple cases
+ 	 */
+ 	if (restore_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)
*** 287,309 ****
  			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
  	{
--- 298,303 ----
*************** check_interp(bool trusted)
*** 313,344 ****
  			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
  	}
  }
  
  /*
   * Restore previous interpreter selection, if two are active
   */
! static void
! restore_context(bool old_context)
  {
! 	if (interp_state == INTERP_BOTH && trusted_context != old_context)
  	{
! 		if (old_context)
! 			PERL_SET_CONTEXT(plperl_trusted_interp);
! 		else
! 			PERL_SET_CONTEXT(plperl_untrusted_interp);
! 		trusted_context = old_context;
  	}
  }
  
  static PerlInterpreter *
--- 307,358 ----
  			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 after plperl_*_interp and trusted_context
+ 	 * updates above to ensure a clean state (and thereby avoid recursion via
+ 	 * plperl_safe_init caling plperl_call_perl_func for utf8fix)
+ 	 */
+ 	if (trusted) {
+ 		plperl_safe_init();
+ 		PL_ppaddr[OP_REQUIRE] = pp_require_safe;
+ 	}
  }
  
  /*
   * Restore previous interpreter selection, if two are active
   */
! static int
! restore_context(bool trusted)
  {
! 	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);
! 				PL_ppaddr[OP_REQUIRE] = pp_require_safe;
! 			}
! 			else {
! 				PERL_SET_CONTEXT(plperl_untrusted_interp);
! 				PL_ppaddr[OP_REQUIRE] = pp_require_orig;
! 			}
! 			trusted_context = trusted;
! 		}
! 		return 1; /* context restored */
  	}
+ 
+ 	return 0;     /* unable - appropriate interpreter not available */
  }
  
  static PerlInterpreter *
*************** plperl_init_interp(void)
*** 422,427 ****
--- 436,451 ----
  
  	PERL_SET_CONTEXT(plperl);
  	perl_construct(plperl);
+ 
+ 	/*
+ 	 * Record the original function for the 'require' opcode.
+ 	 * 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;
+ 
  	perl_parse(plperl, plperl_init_shared_libs,
  			   nargs, embedding, NULL);
  	perl_run(plperl);
*************** plperl_init_interp(void)
*** 471,496 ****
  }
  
  
  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
! 	 * assume that floating-point comparisons are exact, so use a slightly
! 	 * smaller comparison value.
  	 */
! 	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)
  		{
  			/*
--- 495,565 ----
  }
  
  
+ /*
+  * Our safe implementation of the require opcode.
+  * This is safe because it's completely unable to load any code.
+  * If the requested file/module has already been loaded it'll return true.
+  * If not, it'll die.
+  * So now "use Foo;" will work iff Foo has already been loaded.
+  */
+ static OP *
+ pp_require_safe(pTHX)
+ {
+ 	dVAR; dSP;
+ 	SV *sv, **svp;
+ 	char *name;
+ 	STRLEN len;
+ 
+     sv = POPs;
+     name = SvPV(sv, len);
+     if (!(name && len > 0 && *name))
+         RETPUSHNO;
+ 
+ 	svp = hv_fetch(GvHVn(PL_incgv), name, len, 0);
+ 	if (svp && *svp != &PL_sv_undef)
+ 		RETPUSHYES;
+ 
+ 	DIE(aTHX_ "Unable to load %s into plperl", name);
+ }
+ 
+ 
  static void
  plperl_safe_init(void)
  {
  	SV		   *safe_version_sv;
+ 	IV			safe_version_x100;
  
  	safe_version_sv = eval_pv(SAFE_MODULE, FALSE);	/* TRUE = croak if failure */
+ 	safe_version_x100 = (int)(SvNV(safe_version_sv) * 100);
  
  	/*
! 	 * Reject too-old versions of Safe and some others:
! 	 * 2.20: http://rt.perl.org/rt3/Ticket/Display.html?id=72068
  	 */
! 	if (safe_version_x100 < 209 || safe_version_x100 == 220)
  	{
  		/* not safe, so disallow all trusted funcs */
  		eval_pv(PLC_SAFE_BAD, FALSE);
+ 		if (SvTRUE(ERRSV))
+ 		{
+ 			ereport(ERROR,
+ 				(errcode(ERRCODE_INTERNAL_ERROR),
+ 				 errmsg("%s", strip_trailing_ws(SvPV_nolen(ERRSV))),
+ 				 errdetail("While executing PLC_SAFE_BAD")));
+ 		}
+ 
  	}
  	else
  	{
  		eval_pv(PLC_SAFE_OK, FALSE);
+ 		if (SvTRUE(ERRSV))
+ 		{
+ 			ereport(ERROR,
+ 				(errcode(ERRCODE_INTERNAL_ERROR),
+ 				 errmsg("%s", strip_trailing_ws(SvPV_nolen(ERRSV))),
+ 				 errdetail("While executing PLC_SAFE_OK")));
+ 		}
+ 
  		if (GetDatabaseEncoding() == PG_UTF8)
  		{
  			/*
*************** plperl_safe_init(void)
*** 502,507 ****
--- 571,577 ----
  			 */
  			plperl_proc_desc desc;
  			FunctionCallInfoData fcinfo;
+ 			SV *perlret;
  
  			desc.proname = "utf8fix";
  			desc.lanpltrusted = true;
*************** plperl_safe_init(void)
*** 511,524 ****
  
  			/* 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");
  			fcinfo.argnull[0] = false;
  
  			/* and make the call */
! 			(void) plperl_call_perl_func(&desc, &fcinfo);
  		}
  	}
  }
--- 581,596 ----
  
  			/* 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");
  			fcinfo.argnull[0] = false;
  
  			/* and make the call */
! 			perlret = plperl_call_perl_func(&desc, &fcinfo);
! 
! 			SvREFCNT_dec(perlret);
  		}
  	}
  }
*************** plperl_convert_to_pg_array(SV *src)
*** 582,588 ****
  {
  	SV		   *rv;
  	int			count;
- 
  	dSP;
  
  	PUSHMARK(SP);
--- 654,659 ----
*************** plperl_trigger_build_args(FunctionCallIn
*** 619,624 ****
--- 690,696 ----
  	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
*** 673,678 ****
--- 745,751 ----
  	{
  		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)
*** 893,901 ****
  		if (SPI_connect() != SPI_OK_CONNECT)
  			elog(ERROR, "could not connect to SPI manager");
  
! 		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");
--- 966,974 ----
  		if (SPI_connect() != SPI_OK_CONNECT)
  			elog(ERROR, "could not connect to SPI manager");
  
! 		select_perl_context(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)
*** 1000,1022 ****
  
  
  /*
!  * 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;
  
  	/*
--- 1073,1105 ----
  
  
  /*
!  * 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
*** 1024,1080 ****
  	 * 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;
  }
  
--- 1107,1142 ----
  	 * 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_inc((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 *
*** 1118,1130 ****
  	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;
--- 1180,1193 ----
  	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 *
*** 1144,1150 ****
  			tmptup.t_data = td;
  
  			hashref = plperl_hash_from_tuple(&tmptup, tupdesc);
! 			XPUSHs(sv_2mortal(hashref));
  			ReleaseTupleDesc(tupdesc);
  		}
  		else
--- 1207,1213 ----
  			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 *
*** 1154,1160 ****
  			tmp = OutputFunctionCall(&(desc->arg_out_func[i]),
  									 fcinfo->arg[i]);
  			sv = newSVstring(tmp);
! 			XPUSHs(sv_2mortal(sv));
  			pfree(tmp);
  		}
  	}
--- 1217,1223 ----
  			tmp = OutputFunctionCall(&(desc->arg_out_func[i]),
  									 fcinfo->arg[i]);
  			sv = newSVstring(tmp);
! 			PUSHs(sv_2mortal(sv));
  			pfree(tmp);
  		}
  	}
*************** plperl_func_handler(PG_FUNCTION_ARGS)
*** 1293,1299 ****
  							"cannot accept a set")));
  	}
  
! 	check_interp(prodesc->lanpltrusted);
  
  	perlret = plperl_call_perl_func(prodesc, fcinfo);
  
--- 1356,1362 ----
  							"cannot accept a set")));
  	}
  
! 	select_perl_context(prodesc->lanpltrusted);
  
  	perlret = plperl_call_perl_func(prodesc, fcinfo);
  
*************** plperl_trigger_handler(PG_FUNCTION_ARGS)
*** 1440,1446 ****
  	pl_error_context.arg = prodesc->proname;
  	error_context_stack = &pl_error_context;
  
! 	check_interp(prodesc->lanpltrusted);
  
  	svTD = plperl_trigger_build_args(fcinfo);
  	perlret = plperl_call_perl_trigger_func(prodesc, fcinfo, svTD);
--- 1503,1509 ----
  	pl_error_context.arg = prodesc->proname;
  	error_context_stack = &pl_error_context;
  
! 	select_perl_context(prodesc->lanpltrusted);
  
  	svTD = plperl_trigger_build_args(fcinfo);
  	perlret = plperl_call_perl_trigger_func(prodesc, fcinfo, svTD);
*************** compile_plperl_function(Oid fn_oid, bool
*** 1757,1765 ****
  		 * Create the procedure in the interpreter
  		 ************************************************************/
  
! 		check_interp(prodesc->lanpltrusted);
  
! 		plperl_create_sub(prodesc, proc_source);
  
  		restore_context(oldcontext);
  
--- 1820,1828 ----
  		 * Create the procedure in the interpreter
  		 ************************************************************/
  
! 		select_perl_context(prodesc->lanpltrusted);
  
! 		plperl_create_sub(prodesc, proc_source, fn_oid);
  
  		restore_context(oldcontext);
  
*************** plperl_hash_from_tuple(HeapTuple tuple, 
*** 1795,1800 ****
--- 1858,1864 ----
  	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
*** 1922,1927 ****
--- 1986,1992 ----
  		int			i;
  
  		rows = newAV();
+ 		av_extend(rows, processed);
  		for (i = 0; i < processed; i++)
  		{
  			row = plperl_hash_from_tuple(tuptable->vals[i], tuptable->tupdesc);
diff --git a/src/pl/plperl/sql/plperl.sql b/src/pl/plperl/sql/plperl.sql
index 08e5371..e6ef5f0 100644
*** a/src/pl/plperl/sql/plperl.sql
--- b/src/pl/plperl/sql/plperl.sql
*************** DO $$
*** 368,372 ****
  $$ LANGUAGE plperl;
  
  -- check that restricted operations are rejected in a plperl DO block
! DO $$ use Config; $$ LANGUAGE plperl;
  
--- 368,380 ----
  $$ LANGUAGE plperl;
  
  -- check that restricted operations are rejected in a plperl DO block
! DO $$ eval "1+1"; $$ LANGUAGE plperl;
! 
! -- check that we can't "use" a module that's not been loaded already
! -- compile-time error: "Unable to load blib.pm into plperl"
! DO $$ use blib; $$ LANGUAGE plperl;
! 
! -- check that we can "use" a module that has already been loaded
! -- runtime error: "Can't use string ("foo") as a SCALAR ref while "strict refs" in use
! DO $do$ use strict; my $name = "foo"; my $ref = $$name; $do$ LANGUAGE plperl;
  
diff --git a/src/pl/plperl/sql/plperl_plperlu.sql b/src/pl/plperl/sql/plperl_plperlu.sql
index 5b57a82..fc2bb7b 100644
*** a/src/pl/plperl/sql/plperl_plperlu.sql
--- b/src/pl/plperl/sql/plperl_plperlu.sql
***************
*** 1,17 ****
  -- test plperl/plperlu interaction
  
  CREATE OR REPLACE FUNCTION bar() RETURNS integer AS $$
      #die 'BANG!'; # causes server process to exit(2)
      # alternative - causes server process to exit(255)
      spi_exec_query("invalid sql statement");
! $$ language plperl; -- plperl or plperlu
     
  CREATE OR REPLACE FUNCTION foo() RETURNS integer AS $$
      spi_exec_query("SELECT * FROM bar()");
      return 1;
! $$ LANGUAGE plperlu; -- must be opposite to language of bar
     
! SELECT * FROM bar(); -- throws exception normally
! SELECT * FROM foo(); -- used to cause backend crash
  
  
--- 1,19 ----
  -- test plperl/plperlu interaction
  
+ -- the language and call ordering of this test sequence is useful
+ 
  CREATE OR REPLACE FUNCTION bar() RETURNS integer AS $$
      #die 'BANG!'; # causes server process to exit(2)
      # alternative - causes server process to exit(255)
      spi_exec_query("invalid sql statement");
! $$ language plperl; -- compile plperl code
     
  CREATE OR REPLACE FUNCTION foo() RETURNS integer AS $$
      spi_exec_query("SELECT * FROM bar()");
      return 1;
! $$ LANGUAGE plperlu; -- compile plperlu code
     
! SELECT * FROM bar(); -- throws exception normally (running plperl)
! SELECT * FROM foo(); -- used to cause backend crash (after switching to plperlu)
  
  
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to