mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Add support for anonymous code blocks (DO blocks) to PL/Perl.
Joshua Tolley, reviewed by Brendan Jurd and Tim Bunce
This commit is contained in:
		@@ -1,4 +1,4 @@
 | 
				
			|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/plperl.sgml,v 2.70 2009/08/15 00:33:12 petere Exp $ -->
 | 
					<!-- $PostgreSQL: pgsql/doc/src/sgml/plperl.sgml,v 2.71 2009/11/29 03:02:27 tgl Exp $ -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 <chapter id="plperl">
 | 
					 <chapter id="plperl">
 | 
				
			||||||
  <title>PL/Perl - Perl Procedural Language</title>
 | 
					  <title>PL/Perl - Perl Procedural Language</title>
 | 
				
			||||||
@@ -59,11 +59,26 @@ CREATE FUNCTION <replaceable>funcname</replaceable> (<replaceable>argument-types
 | 
				
			|||||||
    # PL/Perl function body
 | 
					    # PL/Perl function body
 | 
				
			||||||
$$ LANGUAGE plperl;
 | 
					$$ LANGUAGE plperl;
 | 
				
			||||||
</programlisting>
 | 
					</programlisting>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   The body of the function is ordinary Perl code. In fact, the PL/Perl
 | 
					   The body of the function is ordinary Perl code. In fact, the PL/Perl
 | 
				
			||||||
   glue code wraps it inside a Perl subroutine. A PL/Perl function must
 | 
					   glue code wraps it inside a Perl subroutine.  A PL/Perl function is
 | 
				
			||||||
   always return a scalar value.  You can return more complex structures
 | 
					   called in a scalar context, so it can't return a list.  You can return
 | 
				
			||||||
   (arrays, records, and sets) by returning a reference, as discussed below.
 | 
					   non-scalar values (arrays, records, and sets) by returning a reference,
 | 
				
			||||||
   Never return a list.
 | 
					   as discussed below.
 | 
				
			||||||
 | 
					  </para>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <para>
 | 
				
			||||||
 | 
					   PL/Perl also supports anonymous code blocks called with the
 | 
				
			||||||
 | 
					   <xref linkend="sql-do" endterm="sql-do-title"> statement:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<programlisting>
 | 
				
			||||||
 | 
					DO $$
 | 
				
			||||||
 | 
					    # PL/Perl code
 | 
				
			||||||
 | 
					$$ LANGUAGE plperl;
 | 
				
			||||||
 | 
					</programlisting>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   An anonymous code block receives no arguments, and whatever value it
 | 
				
			||||||
 | 
					   might return is discarded.  Otherwise it behaves just like a function.
 | 
				
			||||||
  </para>
 | 
					  </para>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <note>
 | 
					  <note>
 | 
				
			||||||
@@ -669,6 +684,13 @@ $$ LANGUAGE plperl;
 | 
				
			|||||||
   <literal>plperlu</>, execution would succeed.
 | 
					   <literal>plperlu</>, execution would succeed.
 | 
				
			||||||
  </para>
 | 
					  </para>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <para>
 | 
				
			||||||
 | 
					   In the same way, anonymous code blocks written in Perl can use
 | 
				
			||||||
 | 
					   restricted operations if the language is specified as
 | 
				
			||||||
 | 
					   <literal>plperlu</> rather than <literal>plperl</>, but the caller
 | 
				
			||||||
 | 
					   must be a superuser.
 | 
				
			||||||
 | 
					  </para>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <note>
 | 
					  <note>
 | 
				
			||||||
    <para>
 | 
					    <para>
 | 
				
			||||||
      For security reasons, to stop a leak of privileged operations from
 | 
					      For security reasons, to stop a leak of privileged operations from
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,7 +37,7 @@
 | 
				
			|||||||
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 | 
					 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 | 
				
			||||||
 * Portions Copyright (c) 1994, Regents of the University of California
 | 
					 * Portions Copyright (c) 1994, Regents of the University of California
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.552 2009/11/28 23:38:07 tgl Exp $
 | 
					 * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.553 2009/11/29 03:02:27 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -53,6 +53,6 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*							yyyymmddN */
 | 
					/*							yyyymmddN */
 | 
				
			||||||
#define CATALOG_VERSION_NO	200911281
 | 
					#define CATALOG_VERSION_NO	200911282
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@
 | 
				
			|||||||
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 | 
					 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 | 
				
			||||||
 * Portions Copyright (c) 1994, Regents of the University of California
 | 
					 * Portions Copyright (c) 1994, Regents of the University of California
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.8 2009/09/22 23:43:41 tgl Exp $
 | 
					 * $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.9 2009/11/29 03:02:27 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * NOTES
 | 
					 * NOTES
 | 
				
			||||||
 *	  the genbki.sh script reads this file and generates .bki
 | 
					 *	  the genbki.sh script reads this file and generates .bki
 | 
				
			||||||
@@ -70,8 +70,8 @@ typedef FormData_pg_pltemplate *Form_pg_pltemplate;
 | 
				
			|||||||
DATA(insert ( "plpgsql"		t t "plpgsql_call_handler" "plpgsql_inline_handler" "plpgsql_validator" "$libdir/plpgsql" _null_ ));
 | 
					DATA(insert ( "plpgsql"		t t "plpgsql_call_handler" "plpgsql_inline_handler" "plpgsql_validator" "$libdir/plpgsql" _null_ ));
 | 
				
			||||||
DATA(insert ( "pltcl"		t t "pltcl_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
 | 
					DATA(insert ( "pltcl"		t t "pltcl_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
 | 
				
			||||||
DATA(insert ( "pltclu"		f f "pltclu_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
 | 
					DATA(insert ( "pltclu"		f f "pltclu_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
 | 
				
			||||||
DATA(insert ( "plperl"		t t "plperl_call_handler" _null_ "plperl_validator" "$libdir/plperl" _null_ ));
 | 
					DATA(insert ( "plperl"		t t "plperl_call_handler" "plperl_inline_handler" "plperl_validator" "$libdir/plperl" _null_ ));
 | 
				
			||||||
DATA(insert ( "plperlu"		f f "plperl_call_handler" _null_ "plperl_validator" "$libdir/plperl" _null_ ));
 | 
					DATA(insert ( "plperlu"		f f "plperl_call_handler" "plperl_inline_handler" "plperl_validator" "$libdir/plperl" _null_ ));
 | 
				
			||||||
DATA(insert ( "plpythonu"	f f "plpython_call_handler" _null_ _null_ "$libdir/plpython" _null_ ));
 | 
					DATA(insert ( "plpythonu"	f f "plpython_call_handler" _null_ _null_ "$libdir/plpython" _null_ ));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif   /* PG_PLTEMPLATE_H */
 | 
					#endif   /* PG_PLTEMPLATE_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -555,3 +555,14 @@ $$ LANGUAGE plperl;
 | 
				
			|||||||
SELECT perl_spi_prepared_bad(4.35) as "double precision";
 | 
					SELECT perl_spi_prepared_bad(4.35) as "double precision";
 | 
				
			||||||
ERROR:  type "does_not_exist" does not exist at line 2.
 | 
					ERROR:  type "does_not_exist" does not exist at line 2.
 | 
				
			||||||
CONTEXT:  PL/Perl function "perl_spi_prepared_bad"
 | 
					CONTEXT:  PL/Perl function "perl_spi_prepared_bad"
 | 
				
			||||||
 | 
					-- simple test of a DO block
 | 
				
			||||||
 | 
					DO $$
 | 
				
			||||||
 | 
					  $a = 'This is a test';
 | 
				
			||||||
 | 
					  elog(NOTICE, $a);
 | 
				
			||||||
 | 
					$$ LANGUAGE plperl;
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
/**********************************************************************
 | 
					/**********************************************************************
 | 
				
			||||||
 * plperl.c - perl as a procedural language for PostgreSQL
 | 
					 * plperl.c - perl as a procedural language for PostgreSQL
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *	  $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.153 2009/10/31 18:11:59 tgl Exp $
 | 
					 *	  $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.154 2009/11/29 03:02:27 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 **********************************************************************/
 | 
					 **********************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -144,6 +144,7 @@ static plperl_call_data *current_call_data = NULL;
 | 
				
			|||||||
 * Forward declarations
 | 
					 * Forward declarations
 | 
				
			||||||
 **********************************************************************/
 | 
					 **********************************************************************/
 | 
				
			||||||
Datum		plperl_call_handler(PG_FUNCTION_ARGS);
 | 
					Datum		plperl_call_handler(PG_FUNCTION_ARGS);
 | 
				
			||||||
 | 
					Datum		plperl_inline_handler(PG_FUNCTION_ARGS);
 | 
				
			||||||
Datum		plperl_validator(PG_FUNCTION_ARGS);
 | 
					Datum		plperl_validator(PG_FUNCTION_ARGS);
 | 
				
			||||||
void		_PG_init(void);
 | 
					void		_PG_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -160,10 +161,11 @@ static HV  *plperl_spi_execute_fetch_result(SPITupleTable *, int, int);
 | 
				
			|||||||
static SV  *newSVstring(const char *str);
 | 
					static SV  *newSVstring(const char *str);
 | 
				
			||||||
static SV **hv_store_string(HV *hv, const char *key, SV *val);
 | 
					static SV **hv_store_string(HV *hv, const char *key, SV *val);
 | 
				
			||||||
static SV **hv_fetch_string(HV *hv, const char *key);
 | 
					static SV **hv_fetch_string(HV *hv, const char *key);
 | 
				
			||||||
static SV  *plperl_create_sub(char *proname, char *s, bool trusted);
 | 
					static SV  *plperl_create_sub(const char *proname, const char *s, bool trusted);
 | 
				
			||||||
static SV  *plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo);
 | 
					static SV  *plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo);
 | 
				
			||||||
static void plperl_compile_callback(void *arg);
 | 
					static void plperl_compile_callback(void *arg);
 | 
				
			||||||
static void plperl_exec_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
 | 
					 * This routine is a crock, and so is everyplace that calls it.  The problem
 | 
				
			||||||
@@ -862,9 +864,13 @@ plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This is the only externally-visible part of the plperl call interface.
 | 
					 * There are three externally visible pieces to plperl: plperl_call_handler,
 | 
				
			||||||
 * The Postgres function and trigger managers call it to execute a
 | 
					 * plperl_inline_handler, and plperl_validator.
 | 
				
			||||||
 * perl function.
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The call handler is called to run normal functions (including trigger
 | 
				
			||||||
 | 
					 * functions) that are defined in pg_proc.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
PG_FUNCTION_INFO_V1(plperl_call_handler);
 | 
					PG_FUNCTION_INFO_V1(plperl_call_handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -896,8 +902,102 @@ plperl_call_handler(PG_FUNCTION_ARGS)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This is the other externally visible function - it is called when CREATE
 | 
					 * The inline handler runs anonymous code blocks (DO blocks).
 | 
				
			||||||
 * FUNCTION is issued to validate the function being created/replaced.
 | 
					 */
 | 
				
			||||||
 | 
					PG_FUNCTION_INFO_V1(plperl_inline_handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Datum
 | 
				
			||||||
 | 
					plperl_inline_handler(PG_FUNCTION_ARGS)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						InlineCodeBlock *codeblock = (InlineCodeBlock *) PG_GETARG_POINTER(0);
 | 
				
			||||||
 | 
						FunctionCallInfoData fake_fcinfo;
 | 
				
			||||||
 | 
						FmgrInfo flinfo;
 | 
				
			||||||
 | 
						plperl_proc_desc desc;
 | 
				
			||||||
 | 
						plperl_call_data *save_call_data = current_call_data;
 | 
				
			||||||
 | 
						bool		oldcontext = trusted_context;
 | 
				
			||||||
 | 
						ErrorContextCallback pl_error_context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set up a callback for error reporting */
 | 
				
			||||||
 | 
						pl_error_context.callback = plperl_inline_callback;
 | 
				
			||||||
 | 
						pl_error_context.previous = error_context_stack;
 | 
				
			||||||
 | 
						pl_error_context.arg = (Datum) 0;
 | 
				
			||||||
 | 
						error_context_stack = &pl_error_context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Set up a fake fcinfo and descriptor with just enough info to satisfy
 | 
				
			||||||
 | 
						 * plperl_call_perl_func().  In particular note that this sets things up
 | 
				
			||||||
 | 
						 * with no arguments passed, and a result type of VOID.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
 | 
				
			||||||
 | 
						MemSet(&flinfo, 0, sizeof(flinfo));
 | 
				
			||||||
 | 
						MemSet(&desc, 0, sizeof(desc));
 | 
				
			||||||
 | 
						fake_fcinfo.flinfo = &flinfo;
 | 
				
			||||||
 | 
						flinfo.fn_oid = InvalidOid;
 | 
				
			||||||
 | 
						flinfo.fn_mcxt = CurrentMemoryContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						desc.proname = "inline_code_block";
 | 
				
			||||||
 | 
						desc.fn_readonly = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						desc.lanpltrusted = codeblock->langIsTrusted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						desc.fn_retistuple = false;
 | 
				
			||||||
 | 
						desc.fn_retisset = false;
 | 
				
			||||||
 | 
						desc.fn_retisarray = false;
 | 
				
			||||||
 | 
						desc.result_oid = VOIDOID;
 | 
				
			||||||
 | 
						desc.nargs = 0;
 | 
				
			||||||
 | 
						desc.reference = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						current_call_data = (plperl_call_data *) palloc0(sizeof(plperl_call_data));
 | 
				
			||||||
 | 
						current_call_data->fcinfo = &fake_fcinfo;
 | 
				
			||||||
 | 
						current_call_data->prodesc = &desc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PG_TRY();
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							SV		   *perlret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (SPI_connect() != SPI_OK_CONNECT)
 | 
				
			||||||
 | 
								elog(ERROR, "could not connect to SPI manager");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							check_interp(desc.lanpltrusted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							desc.reference = plperl_create_sub(desc.proname,
 | 
				
			||||||
 | 
															   codeblock->source_text,
 | 
				
			||||||
 | 
															   desc.lanpltrusted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!desc.reference)	/* can this happen? */
 | 
				
			||||||
 | 
								elog(ERROR, "could not create internal procedure for anonymous code block");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							perlret = plperl_call_perl_func(&desc, &fake_fcinfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SvREFCNT_dec(perlret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (SPI_finish() != SPI_OK_FINISH)
 | 
				
			||||||
 | 
								elog(ERROR, "SPI_finish() failed");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						PG_CATCH();
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							current_call_data = save_call_data;
 | 
				
			||||||
 | 
							restore_context(oldcontext);
 | 
				
			||||||
 | 
							if (desc.reference)
 | 
				
			||||||
 | 
								SvREFCNT_dec(desc.reference);
 | 
				
			||||||
 | 
							PG_RE_THROW();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						PG_END_TRY();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						current_call_data = save_call_data;
 | 
				
			||||||
 | 
						restore_context(oldcontext);
 | 
				
			||||||
 | 
						if (desc.reference)
 | 
				
			||||||
 | 
							SvREFCNT_dec(desc.reference);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						error_context_stack = pl_error_context.previous;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						PG_RETURN_VOID();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The validator is called during CREATE FUNCTION to validate the function
 | 
				
			||||||
 | 
					 * being created/replaced. The precise behavior of the validator may be
 | 
				
			||||||
 | 
					 * modified by the check_function_bodies GUC.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
PG_FUNCTION_INFO_V1(plperl_validator);
 | 
					PG_FUNCTION_INFO_V1(plperl_validator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -971,7 +1071,7 @@ plperl_validator(PG_FUNCTION_ARGS)
 | 
				
			|||||||
 * supplied in s, and returns a reference to the closure.
 | 
					 * supplied in s, and returns a reference to the closure.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static SV  *
 | 
					static SV  *
 | 
				
			||||||
plperl_create_sub(char *proname, char *s, bool trusted)
 | 
					plperl_create_sub(const char *proname, const char *s, bool trusted)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dSP;
 | 
						dSP;
 | 
				
			||||||
	SV		   *subref;
 | 
						SV		   *subref;
 | 
				
			||||||
@@ -2736,3 +2836,12 @@ plperl_compile_callback(void *arg)
 | 
				
			|||||||
	if (procname)
 | 
						if (procname)
 | 
				
			||||||
		errcontext("compilation of PL/Perl function \"%s\"", procname);
 | 
							errcontext("compilation of PL/Perl function \"%s\"", procname);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Provide error context for the inline handler
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					plperl_inline_callback(void *arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						errcontext("PL/Perl anonymous code block");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -361,3 +361,11 @@ CREATE OR REPLACE FUNCTION perl_spi_prepared_bad(double precision) RETURNS doubl
 | 
				
			|||||||
$$ LANGUAGE plperl;
 | 
					$$ LANGUAGE plperl;
 | 
				
			||||||
SELECT perl_spi_prepared_bad(4.35) as "double precision";
 | 
					SELECT perl_spi_prepared_bad(4.35) as "double precision";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- simple test of a DO block
 | 
				
			||||||
 | 
					DO $$
 | 
				
			||||||
 | 
					  $a = 'This is a test';
 | 
				
			||||||
 | 
					  elog(NOTICE, $a);
 | 
				
			||||||
 | 
					$$ LANGUAGE plperl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- check that restricted operations are rejected in a plperl DO block
 | 
				
			||||||
 | 
					DO $$ use Config; $$ LANGUAGE plperl;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user