plperl.c 66.4 KB
Newer Older
1 2 3
/**********************************************************************
 * plperl.c - perl as a procedural language for PostgreSQL
 *
4
 *	  $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.133 2007/12/01 15:20:34 adunstan Exp $
5
 *
6 7
 **********************************************************************/

8
#include "postgres.h"
9
/* Defined by Perl */
10
#undef _
11 12

/* system stuff */
13
#include <ctype.h>
14
#include <fcntl.h>
15
#include <unistd.h>
A
 
Andrew Dunstan 已提交
16
#include <locale.h>
17 18

/* postgreSQL stuff */
19 20
#include "commands/trigger.h"
#include "executor/spi.h"
21
#include "funcapi.h"
22 23 24 25
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "parser/parse_type.h"
26
#include "utils/guc.h"
27
#include "utils/lsyscache.h"
28
#include "utils/memutils.h"
29
#include "utils/typcache.h"
30
#include "utils/hsearch.h"
31 32

/* perl stuff */
A
 
Andrew Dunstan 已提交
33
#include "plperl.h"
34

35 36
PG_MODULE_MAGIC;

37 38 39 40 41
/**********************************************************************
 * The information we cache about loaded procedures
 **********************************************************************/
typedef struct plperl_proc_desc
{
42
	char	   *proname;		/* user name of procedure */
43
	TransactionId fn_xmin;
44
	ItemPointerData fn_tid;
45
	bool		fn_readonly;
46
	bool		lanpltrusted;
47
	bool		fn_retistuple;	/* true, if function returns tuple */
B
Bruce Momjian 已提交
48
	bool		fn_retisset;	/* true, if function returns set */
B
Bruce Momjian 已提交
49
	bool		fn_retisarray;	/* true if function returns array */
50
	Oid			result_oid;		/* Oid of result type */
B
Bruce Momjian 已提交
51
	FmgrInfo	result_in_func; /* I/O function and arg for result type */
52
	Oid			result_typioparam;
53 54
	int			nargs;
	FmgrInfo	arg_out_func[FUNC_MAX_ARGS];
55
	bool		arg_is_rowtype[FUNC_MAX_ARGS];
56
	SV		   *reference;
57
} plperl_proc_desc;
58

59 60 61 62
/* hash table entry for proc desc  */

typedef struct plperl_proc_entry
{
B
Bruce Momjian 已提交
63 64
	char		proc_name[NAMEDATALEN]; /* internal name, eg
										 * __PLPerl_proc_39987 */
65
	plperl_proc_desc *proc_data;
66
} plperl_proc_entry;
67

68 69 70 71 72 73 74
/*
 * The information we cache for the duration of a single call to a
 * function.
 */
typedef struct plperl_call_data
{
	plperl_proc_desc *prodesc;
B
Bruce Momjian 已提交
75 76 77 78 79
	FunctionCallInfo fcinfo;
	Tuplestorestate *tuple_store;
	TupleDesc	ret_tdesc;
	AttInMetadata *attinmeta;
	MemoryContext tmp_cxt;
80 81
} plperl_call_data;

A
 
Andrew Dunstan 已提交
82 83 84 85 86 87 88 89 90 91 92 93
/**********************************************************************
 * The information we cache about prepared and saved plans
 **********************************************************************/
typedef struct plperl_query_desc
{
	char		qname[sizeof(long) * 2 + 1];
	void	   *plan;
	int			nargs;
	Oid		   *argtypes;
	FmgrInfo   *arginfuncs;
	Oid		   *argtypioparams;
} plperl_query_desc;
94

B
Bruce Momjian 已提交
95
/* hash table entry for query desc	*/
96 97 98

typedef struct plperl_query_entry
{
B
Bruce Momjian 已提交
99
	char		query_name[NAMEDATALEN];
100
	plperl_query_desc *query_data;
101
} plperl_query_entry;
102

103 104 105
/**********************************************************************
 * Global data
 **********************************************************************/
106 107 108 109 110 111 112 113

typedef enum
{
	INTERP_NONE,
	INTERP_HELD,
	INTERP_TRUSTED,
	INTERP_UNTRUSTED,
	INTERP_BOTH
114
} InterpState;
115 116 117 118

static InterpState interp_state = INTERP_NONE;
static bool can_run_two = false;

119
static bool plperl_safe_init_done = false;
120 121 122 123
static PerlInterpreter *plperl_trusted_interp = NULL;
static PerlInterpreter *plperl_untrusted_interp = NULL;
static PerlInterpreter *plperl_held_interp = NULL;
static bool trusted_context;
B
Bruce Momjian 已提交
124 125
static HTAB *plperl_proc_hash = NULL;
static HTAB *plperl_query_hash = NULL;
126

127 128
static bool plperl_use_strict = false;

129 130
/* this is saved and restored by plperl_call_handler */
static plperl_call_data *current_call_data = NULL;
131

132 133 134
/**********************************************************************
 * Forward declarations
 **********************************************************************/
B
Bruce Momjian 已提交
135
Datum		plperl_call_handler(PG_FUNCTION_ARGS);
136
Datum		plperl_validator(PG_FUNCTION_ARGS);
137 138 139
void		_PG_init(void);

static void plperl_init_interp(void);
140

141
static Datum plperl_func_handler(PG_FUNCTION_ARGS);
142

143
static Datum plperl_trigger_handler(PG_FUNCTION_ARGS);
144 145
static plperl_proc_desc *compile_plperl_function(Oid fn_oid, bool is_trigger);

146
static SV  *plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc);
147
static void plperl_init_shared_libs(pTHX);
148
static HV  *plperl_spi_execute_fetch_result(SPITupleTable *, int, int);
149 150 151
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);
152 153
static SV  *plperl_create_sub(char *proname, char *s, bool trusted);
static SV  *plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo);
154

155 156 157 158 159 160 161
/*
 * This routine is a crock, and so is everyplace that calls it.  The problem
 * is that the cached form of plperl functions/queries is allocated permanently
 * (mostly via malloc()) and never released until backend exit.  Subsidiary
 * data structures such as fmgr info records therefore must live forever
 * as well.  A better implementation would store all this stuff in a per-
 * function memory context that could be reclaimed at need.  In the meantime,
162 163 164
 * fmgr_info_cxt must be called specifying TopMemoryContext so that whatever
 * it might allocate, and whatever the eventual function might allocate using
 * fn_mcxt, will live forever too.
165 166 167 168
 */
static void
perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
{
169
	fmgr_info_cxt(functionId, finfo, TopMemoryContext);
170 171
}

172

173 174 175 176 177
/*
 * _PG_init()			- library load-time initialization
 *
 * DO NOT make this static nor change its name!
 */
178
void
179
_PG_init(void)
180
{
181 182
	/* Be sure we do initialization only once (should be redundant now) */
	static bool inited = false;
B
Bruce Momjian 已提交
183
	HASHCTL		hash_ctl;
184 185

	if (inited)
186 187
		return;

188
	DefineCustomBoolVariable("plperl.use_strict",
B
Bruce Momjian 已提交
189 190 191 192 193
	  "If true, will compile trusted and untrusted perl code in strict mode",
							 NULL,
							 &plperl_use_strict,
							 PGC_USERSET,
							 NULL, NULL);
194 195

	EmitWarningsOnPlaceholders("plperl");
196

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
	MemSet(&hash_ctl, 0, sizeof(hash_ctl));

	hash_ctl.keysize = NAMEDATALEN;
	hash_ctl.entrysize = sizeof(plperl_proc_entry);

	plperl_proc_hash = hash_create("PLPerl Procedures",
								   32,
								   &hash_ctl,
								   HASH_ELEM);

	hash_ctl.entrysize = sizeof(plperl_query_entry);
	plperl_query_hash = hash_create("PLPerl Queries",
									32,
									&hash_ctl,
									HASH_ELEM);

213 214
	plperl_init_interp();

215
	inited = true;
216 217
}

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
/* Each of these macros must represent a single string literal */

#define PERLBOOT \
	"SPI::bootstrap(); use vars qw(%_SHARED);" \
	"sub ::plperl_warn { my $msg = shift; " \
	"       $msg =~ s/\\(eval \\d+\\) //g; &elog(&NOTICE, $msg); } " \
	"$SIG{__WARN__} = \\&::plperl_warn; " \
	"sub ::plperl_die { my $msg = shift; " \
	"       $msg =~ s/\\(eval \\d+\\) //g; die $msg; } " \
	"$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; } " \
	"sub ::_plperl_to_pg_array {" \
	"  my $arg = shift; ref $arg eq 'ARRAY' || return $arg; " \
	"  my $res = ''; my $first = 1; " \
	"  foreach my $elem (@$arg) " \
	"  { " \
	"    $res .= ', ' unless $first; $first = undef; " \
	"    if (ref $elem) " \
	"    { " \
	"      $res .= _plperl_to_pg_array($elem); " \
	"    } " \
A
 
Andrew Dunstan 已提交
245
	"    elsif (defined($elem)) " \
246 247 248 249 250
	"    { " \
	"      my $str = qq($elem); " \
	"      $str =~ s/([\"\\\\])/\\\\$1/g; " \
	"      $res .= qq(\"$str\"); " \
	"    } " \
A
 
Andrew Dunstan 已提交
251 252 253 254
	"    else " \
	"    { "\
	"      $res .= 'NULL' ; " \
	"    } "\
255 256 257 258 259 260 261 262 263 264 265 266
	"  } " \
	"  return qq({$res}); " \
	"} "

#define SAFE_MODULE \
	"require Safe; $Safe::VERSION"

#define SAFE_OK \
	"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 &spi_exec_query &return_next " \
A
 
Andrew Dunstan 已提交
267 268
	"&spi_query &spi_fetchrow &spi_cursor_close " \
	"&spi_prepare &spi_exec_prepared &spi_query_prepared &spi_freeplan " \
269 270 271 272 273 274 275 276 277
	"&_plperl_to_pg_array " \
	"&DEBUG &LOG &INFO &NOTICE &WARNING &ERROR %_SHARED ]);" \
	"sub ::mksafefunc {" \
	"      my $ret = $PLContainer->reval(qq[sub { $_[0] $_[1] }]); " \
	"      $@ =~ s/\\(eval \\d+\\) //g if $@; return $ret; }" \
	"$PLContainer->permit('require'); $PLContainer->reval('use strict;');" \
	"$PLContainer->deny('require');" \
	"sub ::mk_strict_safefunc {" \
	"      my $ret = $PLContainer->reval(qq[sub { BEGIN { strict->import(); } $_[0] $_[1] }]); " \
B
Bruce Momjian 已提交
278
	"      $@ =~ s/\\(eval \\d+\\) //g if $@; return $ret; }"
279 280 281 282 283 284 285 286 287 288 289 290

#define SAFE_BAD \
	"use vars qw($PLContainer); $PLContainer = new Safe('PLPerl');" \
	"$PLContainer->permit_only(':default');" \
	"$PLContainer->share(qw[&elog &ERROR ]);" \
	"sub ::mksafefunc { return $PLContainer->reval(qq[sub { " \
	"      elog(ERROR,'trusted Perl functions disabled - " \
	"      please upgrade Perl Safe module to version 2.09 or later');}]); }" \
	"sub ::mk_strict_safefunc { return $PLContainer->reval(qq[sub { " \
	"      elog(ERROR,'trusted Perl functions disabled - " \
	"      please upgrade Perl Safe module to version 2.09 or later');}]); }"

291 292
#define TEST_FOR_MULTI \
	"use Config; " \
B
Bruce Momjian 已提交
293 294
	"$Config{usemultiplicity} eq 'define' or "	\
	"($Config{usethreads} eq 'define' " \
295 296 297 298 299 300 301
	" and $Config{useithreads} eq 'define')"


/********************************************************************
 *
 * We start out by creating a "held" interpreter that we can use in
 * trusted or untrusted mode (but not both) as the need arises. Later, we
302
 * assign that interpreter if it is available to either the trusted or
303 304 305 306 307 308 309
 * 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.
 */


310
static void
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
check_interp(bool trusted)
{
	if (interp_state == INTERP_HELD)
	{
		if (trusted)
		{
			plperl_trusted_interp = plperl_held_interp;
			interp_state = INTERP_TRUSTED;
		}
		else
		{
			plperl_untrusted_interp = plperl_held_interp;
			interp_state = INTERP_UNTRUSTED;
		}
		plperl_held_interp = NULL;
		trusted_context = trusted;
	}
328
	else if (interp_state == INTERP_BOTH ||
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
			 (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 if (can_run_two)
	{
		PERL_SET_CONTEXT(plperl_held_interp);
		plperl_init_interp();
		if (trusted)
			plperl_trusted_interp = plperl_held_interp;
		else
			plperl_untrusted_interp = plperl_held_interp;
		interp_state = INTERP_BOTH;
		plperl_held_interp = NULL;
		trusted_context = trusted;
	}
	else
	{
355
		elog(ERROR,
356
			 "cannot allocate second Perl interpreter on this platform");
357 358 359 360 361
	}
}


static void
B
Bruce Momjian 已提交
362
restore_context(bool old_context)
363 364 365 366 367 368 369 370 371 372
{
	if (trusted_context != old_context)
	{
		if (old_context)
			PERL_SET_CONTEXT(plperl_trusted_interp);
		else
			PERL_SET_CONTEXT(plperl_untrusted_interp);
		trusted_context = old_context;
	}
}
373 374

static void
375
plperl_init_interp(void)
376
{
B
Bruce Momjian 已提交
377
	static char *embedding[3] = {
378
		"", "-e", PERLBOOT
379 380
	};

A
 
Andrew Dunstan 已提交
381 382
#ifdef WIN32

B
Bruce Momjian 已提交
383
	/*
A
 
Andrew Dunstan 已提交
384
	 * The perl library on startup does horrible things like call
B
Bruce Momjian 已提交
385 386 387 388 389
	 * setlocale(LC_ALL,""). We have protected against that on most platforms
	 * by setting the environment appropriately. However, on Windows,
	 * setlocale() does not consult the environment, so we need to save the
	 * existing locale settings before perl has a chance to mangle them and
	 * restore them after its dirty deeds are done.
A
 
Andrew Dunstan 已提交
390 391 392 393 394 395 396 397
	 *
	 * MSDN ref:
	 * http://msdn.microsoft.com/library/en-us/vclib/html/_crt_locale.asp
	 *
	 * It appears that we only need to do this on interpreter startup, and
	 * subsequent calls to the interpreter don't mess with the locale
	 * settings.
	 *
B
Bruce Momjian 已提交
398 399
	 * We restore them using Perl's POSIX::setlocale() function so that Perl
	 * doesn't have a different idea of the locale from Postgres.
A
 
Andrew Dunstan 已提交
400 401 402
	 *
	 */

B
Bruce Momjian 已提交
403 404 405 406 407 408 409
	char	   *loc;
	char	   *save_collate,
			   *save_ctype,
			   *save_monetary,
			   *save_numeric,
			   *save_time;
	char		buf[1024];
A
 
Andrew Dunstan 已提交
410

B
Bruce Momjian 已提交
411
	loc = setlocale(LC_COLLATE, NULL);
A
 
Andrew Dunstan 已提交
412
	save_collate = loc ? pstrdup(loc) : NULL;
B
Bruce Momjian 已提交
413
	loc = setlocale(LC_CTYPE, NULL);
A
 
Andrew Dunstan 已提交
414
	save_ctype = loc ? pstrdup(loc) : NULL;
B
Bruce Momjian 已提交
415
	loc = setlocale(LC_MONETARY, NULL);
A
 
Andrew Dunstan 已提交
416
	save_monetary = loc ? pstrdup(loc) : NULL;
B
Bruce Momjian 已提交
417
	loc = setlocale(LC_NUMERIC, NULL);
A
 
Andrew Dunstan 已提交
418
	save_numeric = loc ? pstrdup(loc) : NULL;
B
Bruce Momjian 已提交
419
	loc = setlocale(LC_TIME, NULL);
A
 
Andrew Dunstan 已提交
420 421 422
	save_time = loc ? pstrdup(loc) : NULL;
#endif

423 424 425

	plperl_held_interp = perl_alloc();
	if (!plperl_held_interp)
426
		elog(ERROR, "could not allocate Perl interpreter");
427

428
	perl_construct(plperl_held_interp);
429
	perl_parse(plperl_held_interp, plperl_init_shared_libs,
430 431
			   3, embedding, NULL);
	perl_run(plperl_held_interp);
432

433 434
	if (interp_state == INTERP_NONE)
	{
B
Bruce Momjian 已提交
435
		SV		   *res;
436

B
Bruce Momjian 已提交
437
		res = eval_pv(TEST_FOR_MULTI, TRUE);
438
		can_run_two = SvIV(res);
439 440
		interp_state = INTERP_HELD;
	}
A
 
Andrew Dunstan 已提交
441 442 443

#ifdef WIN32

B
Bruce Momjian 已提交
444
	eval_pv("use POSIX qw(locale_h);", TRUE);	/* croak on failure */
A
 
Andrew Dunstan 已提交
445 446 447

	if (save_collate != NULL)
	{
B
Bruce Momjian 已提交
448 449 450
		snprintf(buf, sizeof(buf), "setlocale(%s,'%s');",
				 "LC_COLLATE", save_collate);
		eval_pv(buf, TRUE);
A
 
Andrew Dunstan 已提交
451 452 453 454
		pfree(save_collate);
	}
	if (save_ctype != NULL)
	{
B
Bruce Momjian 已提交
455 456 457
		snprintf(buf, sizeof(buf), "setlocale(%s,'%s');",
				 "LC_CTYPE", save_ctype);
		eval_pv(buf, TRUE);
A
 
Andrew Dunstan 已提交
458 459 460 461
		pfree(save_ctype);
	}
	if (save_monetary != NULL)
	{
B
Bruce Momjian 已提交
462 463 464
		snprintf(buf, sizeof(buf), "setlocale(%s,'%s');",
				 "LC_MONETARY", save_monetary);
		eval_pv(buf, TRUE);
A
 
Andrew Dunstan 已提交
465 466 467 468
		pfree(save_monetary);
	}
	if (save_numeric != NULL)
	{
B
Bruce Momjian 已提交
469 470 471
		snprintf(buf, sizeof(buf), "setlocale(%s,'%s');",
				 "LC_NUMERIC", save_numeric);
		eval_pv(buf, TRUE);
A
 
Andrew Dunstan 已提交
472 473 474 475
		pfree(save_numeric);
	}
	if (save_time != NULL)
	{
B
Bruce Momjian 已提交
476 477 478
		snprintf(buf, sizeof(buf), "setlocale(%s,'%s');",
				 "LC_TIME", save_time);
		eval_pv(buf, TRUE);
A
 
Andrew Dunstan 已提交
479 480 481 482
		pfree(save_time);
	}
#endif

483 484
}

485 486 487 488

static void
plperl_safe_init(void)
{
B
Bruce Momjian 已提交
489
	SV		   *res;
490
	double		safe_version;
491

492
	res = eval_pv(SAFE_MODULE, FALSE);	/* TRUE = croak if failure */
493 494 495

	safe_version = SvNV(res);

496 497 498 499 500
	/*
	 * 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.
	 */
B
Bruce Momjian 已提交
501
	if (safe_version < 2.0899)
502 503
	{
		/* not safe, so disallow all trusted funcs */
504
		eval_pv(SAFE_BAD, FALSE);
505 506 507
	}
	else
	{
508
		eval_pv(SAFE_OK, FALSE);
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
		if (GetDatabaseEncoding() == PG_UTF8)
		{

			/* 
			 * Fill in just enough information to set up this perl
			 * function in the safe container and call it.
			 * For some reason not entirely clear, it prevents errors that
			 * can arise from the regex code later trying to load
			 * utf8 modules.
			 */

			plperl_proc_desc desc;			
			FunctionCallInfoData fcinfo;
			FmgrInfo outfunc;
			HeapTuple   typeTup;
			Form_pg_type typeStruct;
			SV *ret;
			SV *func;

			/* make sure we don't call ourselves recursively */
			plperl_safe_init_done = true;

			/* compile the function */
			func = plperl_create_sub(
				"utf8fix",
				"return shift =~ /\\xa9/i ? 'true' : 'false' ;",
				true);


			/* set up to call the function with a single text argument 'a' */
			desc.reference = func;
			desc.nargs = 1;
			desc.arg_is_rowtype[0] = false;
			fcinfo.argnull[0] = false;
			fcinfo.arg[0] = 
				DatumGetTextP(DirectFunctionCall1(textin, 
												  CStringGetDatum("a")));
			typeTup = SearchSysCache(TYPEOID,
									 TEXTOID,
									 0, 0, 0);
			typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
			fmgr_info(typeStruct->typoutput,&(desc.arg_out_func[0]));
			ReleaseSysCache(typeTup);
			
			/* and make the call */
			ret = plperl_call_perl_func(&desc,&fcinfo);
		}
556
	}
557 558 559 560

	plperl_safe_init_done = true;
}

561 562 563 564 565 566
/*
 * Perl likes to put a newline after its error messages; clean up such
 */
static char *
strip_trailing_ws(const char *msg)
{
B
Bruce Momjian 已提交
567 568
	char	   *res = pstrdup(msg);
	int			len = strlen(res);
569

B
Bruce Momjian 已提交
570
	while (len > 0 && isspace((unsigned char) res[len - 1]))
571 572 573 574 575
		res[--len] = '\0';
	return res;
}


576 577
/* Build a tuple from a hash. */

578
static HeapTuple
579
plperl_build_tuple_result(HV *perlhash, AttInMetadata *attinmeta)
580
{
581 582 583 584 585 586
	TupleDesc	td = attinmeta->tupdesc;
	char	  **values;
	SV		   *val;
	char	   *key;
	I32			klen;
	HeapTuple	tup;
587

588
	values = (char **) palloc0(td->natts * sizeof(char *));
589

590 591 592
	hv_iterinit(perlhash);
	while ((val = hv_iternextsv(perlhash, &key, &klen)))
	{
B
Bruce Momjian 已提交
593
		int			attn = SPI_fnumber(td, key);
594

595
		if (attn <= 0 || td->attrs[attn - 1]->attisdropped)
596 597 598 599
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_COLUMN),
					 errmsg("Perl hash contains nonexistent column \"%s\"",
							key)));
600
		if (SvOK(val))
601
			values[attn - 1] = SvPV(val, PL_na);
602
	}
603 604 605 606 607
	hv_iterinit(perlhash);

	tup = BuildTupleFromCStrings(attinmeta, values);
	pfree(values);
	return tup;
608 609
}

610 611 612
/*
 * convert perl array to postgres string representation
 */
B
Bruce Momjian 已提交
613
static SV  *
614
plperl_convert_to_pg_array(SV *src)
615
{
B
Bruce Momjian 已提交
616 617 618 619
	SV		   *rv;
	int			count;

	dSP;
620

B
Bruce Momjian 已提交
621
	PUSHMARK(SP);
622
	XPUSHs(src);
B
Bruce Momjian 已提交
623
	PUTBACK;
624

625
	count = call_pv("::_plperl_to_pg_array", G_SCALAR);
626

B
Bruce Momjian 已提交
627
	SPAGAIN;
628 629

	if (count != 1)
630
		elog(ERROR, "unexpected _plperl_to_pg_array failure");
631 632 633

	rv = POPs;

B
Bruce Momjian 已提交
634 635 636
	PUTBACK;

	return rv;
637 638
}

639

640 641
/* Set up the arguments for a trigger call. */

642 643 644 645 646
static SV  *
plperl_trigger_build_args(FunctionCallInfo fcinfo)
{
	TriggerData *tdata;
	TupleDesc	tupdesc;
647
	int			i;
648 649 650 651 652
	char	   *level;
	char	   *event;
	char	   *relid;
	char	   *when;
	HV		   *hv;
653

654
	hv = newHV();
655 656 657 658

	tdata = (TriggerData *) fcinfo->context;
	tupdesc = tdata->tg_relation->rd_att;

659
	relid = DatumGetCString(
B
Bruce Momjian 已提交
660 661 662 663
							DirectFunctionCall1(oidout,
								  ObjectIdGetDatum(tdata->tg_relation->rd_id)
												)
		);
664

665 666
	hv_store_string(hv, "name", newSVstring(tdata->tg_trigger->tgname));
	hv_store_string(hv, "relid", newSVstring(relid));
667 668 669

	if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
	{
670
		event = "INSERT";
671
		if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
672 673 674
			hv_store_string(hv, "new",
							plperl_hash_from_tuple(tdata->tg_trigtuple,
												   tupdesc));
675 676 677
	}
	else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
	{
678
		event = "DELETE";
679
		if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
680 681 682
			hv_store_string(hv, "old",
							plperl_hash_from_tuple(tdata->tg_trigtuple,
												   tupdesc));
683 684 685
	}
	else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
	{
686
		event = "UPDATE";
687 688
		if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
		{
689 690 691 692 693 694
			hv_store_string(hv, "old",
							plperl_hash_from_tuple(tdata->tg_trigtuple,
												   tupdesc));
			hv_store_string(hv, "new",
							plperl_hash_from_tuple(tdata->tg_newtuple,
												   tupdesc));
695
		}
696
	}
697
	else
698
		event = "UNKNOWN";
699

700 701
	hv_store_string(hv, "event", newSVstring(event));
	hv_store_string(hv, "argc", newSViv(tdata->tg_trigger->tgnargs));
702

703
	if (tdata->tg_trigger->tgnargs > 0)
704
	{
B
Bruce Momjian 已提交
705 706 707
		AV		   *av = newAV();

		for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
708 709
			av_push(av, newSVstring(tdata->tg_trigger->tgargs[i]));
		hv_store_string(hv, "args", newRV_noinc((SV *) av));
710
	}
711

712 713
	hv_store_string(hv, "relname",
					newSVstring(SPI_getrelname(tdata->tg_relation)));
714

715 716
	hv_store_string(hv, "table_name",
					newSVstring(SPI_getrelname(tdata->tg_relation)));
A
 
Andrew Dunstan 已提交
717

718 719
	hv_store_string(hv, "table_schema",
					newSVstring(SPI_getnspname(tdata->tg_relation)));
A
 
Andrew Dunstan 已提交
720

721
	if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
722
		when = "BEFORE";
723
	else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
724
		when = "AFTER";
725
	else
726
		when = "UNKNOWN";
727
	hv_store_string(hv, "when", newSVstring(when));
728 729

	if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
730
		level = "ROW";
731
	else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
732
		level = "STATEMENT";
733
	else
734
		level = "UNKNOWN";
735
	hv_store_string(hv, "level", newSVstring(level));
736

B
Bruce Momjian 已提交
737
	return newRV_noinc((SV *) hv);
738 739 740
}


741
/* Set up the new tuple returned from a trigger. */
742

743
static HeapTuple
744
plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup)
745 746 747 748
{
	SV		  **svp;
	HV		   *hvNew;
	HeapTuple	rtup;
749 750 751 752 753 754 755 756
	SV		   *val;
	char	   *key;
	I32			klen;
	int			slotsused;
	int		   *modattrs;
	Datum	   *modvalues;
	char	   *modnulls;

757 758 759 760
	TupleDesc	tupdesc;

	tupdesc = tdata->tg_relation->rd_att;

761
	svp = hv_fetch_string(hvTD, "new");
762
	if (!svp)
763 764 765
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_COLUMN),
				 errmsg("$_TD->{new} does not exist")));
766
	if (!SvOK(*svp) || SvTYPE(*svp) != SVt_RV || SvTYPE(SvRV(*svp)) != SVt_PVHV)
767 768 769
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("$_TD->{new} is not a hash reference")));
770 771
	hvNew = (HV *) SvRV(*svp);

772 773 774 775
	modattrs = palloc(tupdesc->natts * sizeof(int));
	modvalues = palloc(tupdesc->natts * sizeof(Datum));
	modnulls = palloc(tupdesc->natts * sizeof(char));
	slotsused = 0;
776

777 778
	hv_iterinit(hvNew);
	while ((val = hv_iternextsv(hvNew, &key, &klen)))
779
	{
780
		int			attn = SPI_fnumber(tupdesc, key);
781 782 783 784
		Oid			typinput;
		Oid			typioparam;
		int32		atttypmod;
		FmgrInfo	finfo;
785

786
		if (attn <= 0 || tupdesc->attrs[attn - 1]->attisdropped)
787 788 789 790
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_COLUMN),
					 errmsg("Perl hash contains nonexistent column \"%s\"",
							key)));
791 792 793 794 795
		/* XXX would be better to cache these lookups */
		getTypeInputInfo(tupdesc->attrs[attn - 1]->atttypid,
						 &typinput, &typioparam);
		fmgr_info(typinput, &finfo);
		atttypmod = tupdesc->attrs[attn - 1]->atttypmod;
796
		if (SvOK(val))
797
		{
798 799 800 801
			modvalues[slotsused] = InputFunctionCall(&finfo,
													 SvPV(val, PL_na),
													 typioparam,
													 atttypmod);
802
			modnulls[slotsused] = ' ';
803 804 805
		}
		else
		{
806 807 808 809
			modvalues[slotsused] = InputFunctionCall(&finfo,
													 NULL,
													 typioparam,
													 atttypmod);
810
			modnulls[slotsused] = 'n';
811
		}
812 813
		modattrs[slotsused] = attn;
		slotsused++;
814
	}
815 816 817 818
	hv_iterinit(hvNew);

	rtup = SPI_modifytuple(tdata->tg_relation, otup, slotsused,
						   modattrs, modvalues, modnulls);
819 820 821 822

	pfree(modattrs);
	pfree(modvalues);
	pfree(modnulls);
823

824
	if (rtup == NULL)
825
		elog(ERROR, "SPI_modifytuple failed: %s",
826
			 SPI_result_code_string(SPI_result));
827 828 829

	return rtup;
}
830

831

832 833
/*
 * This is the only externally-visible part of the plperl call interface.
834
 * The Postgres function and trigger managers call it to execute a
835 836
 * perl function.
 */
837
PG_FUNCTION_INFO_V1(plperl_call_handler);
838 839

Datum
840
plperl_call_handler(PG_FUNCTION_ARGS)
841
{
B
Bruce Momjian 已提交
842
	Datum		retval;
843
	plperl_call_data *save_call_data;
844

845
	save_call_data = current_call_data;
846 847 848 849 850 851 852 853 854
	PG_TRY();
	{
		if (CALLED_AS_TRIGGER(fcinfo))
			retval = PointerGetDatum(plperl_trigger_handler(fcinfo));
		else
			retval = plperl_func_handler(fcinfo);
	}
	PG_CATCH();
	{
855
		current_call_data = save_call_data;
856 857 858 859
		PG_RE_THROW();
	}
	PG_END_TRY();

860
	current_call_data = save_call_data;
861 862 863
	return retval;
}

864 865 866 867 868 869 870 871 872 873 874 875
/*
 * This is the other externally visible function - it is called when CREATE
 * FUNCTION is issued to validate the function being created/replaced.
 */
PG_FUNCTION_INFO_V1(plperl_validator);

Datum
plperl_validator(PG_FUNCTION_ARGS)
{
	Oid			funcoid = PG_GETARG_OID(0);
	HeapTuple	tuple;
	Form_pg_proc proc;
876
	char		functyptype;
877 878 879 880
	int			numargs;
	Oid		   *argtypes;
	char	  **argnames;
	char	   *argmodes;
881
	bool		istrigger = false;
882
	int			i;
883 884 885 886 887 888 889 890 891

	/* Get the new function's pg_proc entry */
	tuple = SearchSysCache(PROCOID,
						   ObjectIdGetDatum(funcoid),
						   0, 0, 0);
	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "cache lookup failed for function %u", funcoid);
	proc = (Form_pg_proc) GETSTRUCT(tuple);

892 893 894 895
	functyptype = get_typtype(proc->prorettype);

	/* Disallow pseudotype result */
	/* except for TRIGGER, RECORD, or VOID */
896
	if (functyptype == TYPTYPE_PSEUDO)
897 898 899 900 901 902 903 904 905 906 907 908 909
	{
		/* we assume OPAQUE with no arguments means a trigger */
		if (proc->prorettype == TRIGGEROID ||
			(proc->prorettype == OPAQUEOID && proc->pronargs == 0))
			istrigger = true;
		else if (proc->prorettype != RECORDOID &&
				 proc->prorettype != VOIDOID)
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("plperl functions cannot return type %s",
							format_type_be(proc->prorettype))));
	}

910 911 912 913 914
	/* Disallow pseudotypes in arguments (either IN or OUT) */
	numargs = get_func_arg_info(tuple,
								&argtypes, &argnames, &argmodes);
	for (i = 0; i < numargs; i++)
	{
915
		if (get_typtype(argtypes[i]) == TYPTYPE_PSEUDO)
916 917 918 919 920 921
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("plperl functions cannot take type %s",
							format_type_be(argtypes[i]))));
	}

922 923
	ReleaseSysCache(tuple);

924 925 926
	/* Postpone body checks if !check_function_bodies */
	if (check_function_bodies)
	{
927
		(void) compile_plperl_function(funcoid, istrigger);
928
	}
929 930 931 932 933

	/* the result of a validator is ignored */
	PG_RETURN_VOID();
}

934

935 936 937 938
/*
 * Uses mksafefunc/mkunsafefunc to create an anonymous sub whose text is
 * supplied in s, and returns a reference to the closure.
 */
B
Bruce Momjian 已提交
939
static SV  *
940
plperl_create_sub(char *proname, char *s, bool trusted)
941
{
942
	dSP;
943
	SV		   *subref;
B
Bruce Momjian 已提交
944
	int			count;
B
Bruce Momjian 已提交
945
	char	   *compile_sub;
946

B
Bruce Momjian 已提交
947
	if (trusted && !plperl_safe_init_done)
948
	{
949
		plperl_safe_init();
950 951
		SPAGAIN;
	}
952

953 954 955
	ENTER;
	SAVETMPS;
	PUSHMARK(SP);
956 957
	XPUSHs(sv_2mortal(newSVstring("our $_TD; local $_TD=$_[0]; shift;")));
	XPUSHs(sv_2mortal(newSVstring(s)));
B
Bruce Momjian 已提交
958
	PUTBACK;
B
Bruce Momjian 已提交
959

960 961
	/*
	 * G_KEEPERR seems to be needed here, else we don't recognize compile
B
Bruce Momjian 已提交
962 963
	 * errors properly.  Perhaps it's because there's another level of eval
	 * inside mksafefunc?
964
	 */
965 966 967 968 969 970 971 972 973 974 975

	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);
976 977
	SPAGAIN;

978 979 980 981 982
	if (count != 1)
	{
		PUTBACK;
		FREETMPS;
		LEAVE;
983
		elog(ERROR, "didn't get a return item from mksafefunc");
984 985
	}

986
	if (SvTRUE(ERRSV))
987
	{
988
		(void) POPs;
989 990 991
		PUTBACK;
		FREETMPS;
		LEAVE;
992 993
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
994 995
				 errmsg("creation of Perl function \"%s\" failed: %s",
						proname,
996
						strip_trailing_ws(SvPV(ERRSV, PL_na)))));
997 998 999
	}

	/*
1000 1001
	 * need to make a deep copy of the return. it comes off the stack as a
	 * temporary.
1002 1003 1004
	 */
	subref = newSVsv(POPs);

1005
	if (!SvROK(subref) || SvTYPE(SvRV(subref)) != SVt_PVCV)
1006
	{
1007 1008 1009
		PUTBACK;
		FREETMPS;
		LEAVE;
1010

1011 1012 1013 1014
		/*
		 * subref is our responsibility because it is not mortal
		 */
		SvREFCNT_dec(subref);
1015
		elog(ERROR, "didn't get a code ref");
1016 1017 1018 1019 1020
	}

	PUTBACK;
	FREETMPS;
	LEAVE;
1021

1022 1023 1024
	return subref;
}

1025

1026
/**********************************************************************
1027
 * plperl_init_shared_libs()		-
1028 1029 1030 1031
 *
 * We cannot use the DynaLoader directly to get at the Opcode
 * module (used by Safe.pm). So, we link Opcode into ourselves
 * and do the initialization behind perl's back.
1032
 *
1033 1034
 **********************************************************************/

1035 1036
EXTERN_C void boot_DynaLoader(pTHX_ CV *cv);
EXTERN_C void boot_SPI(pTHX_ CV *cv);
1037

1038
static void
1039
plperl_init_shared_libs(pTHX)
1040
{
1041 1042
	char	   *file = __FILE__;

1043
	newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
1044
	newXS("SPI::bootstrap", boot_SPI, file);
1045 1046
}

1047

B
Bruce Momjian 已提交
1048
static SV  *
1049
plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
1050 1051
{
	dSP;
1052 1053 1054
	SV		   *retval;
	int			i;
	int			count;
B
Bruce Momjian 已提交
1055
	SV		   *sv;
1056 1057 1058 1059

	ENTER;
	SAVETMPS;

1060
	PUSHMARK(SP);
1061

B
Bruce Momjian 已提交
1062
	XPUSHs(&PL_sv_undef);		/* no trigger data */
1063

1064 1065
	for (i = 0; i < desc->nargs; i++)
	{
1066 1067 1068
		if (fcinfo->argnull[i])
			XPUSHs(&PL_sv_undef);
		else if (desc->arg_is_rowtype[i])
1069
		{
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
			HeapTupleHeader td;
			Oid			tupType;
			int32		tupTypmod;
			TupleDesc	tupdesc;
			HeapTupleData tmptup;
			SV		   *hashref;

			td = DatumGetHeapTupleHeader(fcinfo->arg[i]);
			/* Extract rowtype info and find a tupdesc */
			tupType = HeapTupleHeaderGetTypeId(td);
			tupTypmod = HeapTupleHeaderGetTypMod(td);
			tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
			/* Build a temporary HeapTuple control structure */
			tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
			tmptup.t_data = td;

1086 1087
			hashref = plperl_hash_from_tuple(&tmptup, tupdesc);
			XPUSHs(sv_2mortal(hashref));
1088
			ReleaseTupleDesc(tupdesc);
1089 1090 1091
		}
		else
		{
1092 1093
			char	   *tmp;

1094 1095
			tmp = OutputFunctionCall(&(desc->arg_out_func[i]),
									 fcinfo->arg[i]);
1096
			sv = newSVstring(tmp);
1097
			XPUSHs(sv_2mortal(sv));
1098
			pfree(tmp);
1099 1100 1101
		}
	}
	PUTBACK;
1102 1103 1104

	/* Do NOT use G_KEEPERR here */
	count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL);
1105 1106 1107

	SPAGAIN;

1108 1109 1110 1111
	if (count != 1)
	{
		PUTBACK;
		FREETMPS;
1112
		LEAVE;
1113
		elog(ERROR, "didn't get a return item from function");
1114 1115
	}

1116
	if (SvTRUE(ERRSV))
1117
	{
1118
		(void) POPs;
1119 1120
		PUTBACK;
		FREETMPS;
1121
		LEAVE;
1122 1123
		/* XXX need to find a way to assign an errcode here */
		ereport(ERROR,
1124 1125
				(errmsg("error from Perl function \"%s\": %s",
						desc->proname,
1126
						strip_trailing_ws(SvPV(ERRSV, PL_na)))));
1127 1128 1129 1130
	}

	retval = newSVsv(POPs);

1131 1132 1133
	PUTBACK;
	FREETMPS;
	LEAVE;
1134 1135 1136 1137

	return retval;
}

1138

1139
static SV  *
1140 1141
plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo,
							  SV *td)
1142 1143 1144
{
	dSP;
	SV		   *retval;
1145
	Trigger    *tg_trigger;
1146 1147 1148 1149 1150 1151 1152
	int			i;
	int			count;

	ENTER;
	SAVETMPS;

	PUSHMARK(sp);
1153

1154
	XPUSHs(td);
1155

1156 1157
	tg_trigger = ((TriggerData *) fcinfo->context)->tg_trigger;
	for (i = 0; i < tg_trigger->tgnargs; i++)
1158
		XPUSHs(sv_2mortal(newSVstring(tg_trigger->tgargs[i])));
1159 1160
	PUTBACK;

1161 1162
	/* Do NOT use G_KEEPERR here */
	count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL);
1163 1164 1165 1166 1167 1168 1169 1170

	SPAGAIN;

	if (count != 1)
	{
		PUTBACK;
		FREETMPS;
		LEAVE;
1171
		elog(ERROR, "didn't get a return item from trigger function");
1172 1173 1174 1175
	}

	if (SvTRUE(ERRSV))
	{
1176
		(void) POPs;
1177 1178 1179
		PUTBACK;
		FREETMPS;
		LEAVE;
1180 1181
		/* XXX need to find a way to assign an errcode here */
		ereport(ERROR,
1182 1183
				(errmsg("error from Perl function \"%s\": %s",
						desc->proname,
1184
						strip_trailing_ws(SvPV(ERRSV, PL_na)))));
1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
	}

	retval = newSVsv(POPs);

	PUTBACK;
	FREETMPS;
	LEAVE;

	return retval;
}
1195

1196

1197
static Datum
1198
plperl_func_handler(PG_FUNCTION_ARGS)
1199 1200
{
	plperl_proc_desc *prodesc;
1201 1202
	SV		   *perlret;
	Datum		retval;
1203
	ReturnSetInfo *rsi;
B
Bruce Momjian 已提交
1204
	SV		   *array_ret = NULL;
B
Bruce Momjian 已提交
1205
	bool		oldcontext = trusted_context;
1206

1207
	/*
B
Bruce Momjian 已提交
1208 1209
	 * Create the call_data beforing connecting to SPI, so that it is not
	 * allocated in the SPI memory context
1210 1211 1212 1213
	 */
	current_call_data = (plperl_call_data *) palloc0(sizeof(plperl_call_data));
	current_call_data->fcinfo = fcinfo;

1214 1215 1216
	if (SPI_connect() != SPI_OK_CONNECT)
		elog(ERROR, "could not connect to SPI manager");

1217
	prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, false);
1218
	current_call_data->prodesc = prodesc;
1219

B
Bruce Momjian 已提交
1220
	rsi = (ReturnSetInfo *) fcinfo->resultinfo;
B
Bruce Momjian 已提交
1221

T
Tom Lane 已提交
1222
	if (prodesc->fn_retisset)
1223
	{
T
Tom Lane 已提交
1224 1225 1226 1227 1228 1229 1230 1231
		/* Check context before allowing the call to go through */
		if (!rsi || !IsA(rsi, ReturnSetInfo) ||
			(rsi->allowedModes & SFRM_Materialize) == 0 ||
			rsi->expectedDesc == NULL)
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("set-valued function called in context that "
							"cannot accept a set")));
1232 1233
	}

1234 1235
	check_interp(prodesc->lanpltrusted);

1236
	perlret = plperl_call_perl_func(prodesc, fcinfo);
1237 1238 1239 1240 1241 1242 1243 1244

	/************************************************************
	 * Disconnect from SPI manager and then create the return
	 * values datum (if the input function does a palloc for it
	 * this must not be allocated in the SPI memory context
	 * because SPI_finish would free it).
	 ************************************************************/
	if (SPI_finish() != SPI_OK_FINISH)
1245
		elog(ERROR, "SPI_finish() failed");
1246

T
Tom Lane 已提交
1247
	if (prodesc->fn_retisset)
1248
	{
T
Tom Lane 已提交
1249 1250
		/*
		 * If the Perl function returned an arrayref, we pretend that it
B
Bruce Momjian 已提交
1251 1252
		 * called return_next() for each element of the array, to handle old
		 * SRFs that didn't know about return_next(). Any other sort of return
1253
		 * value is an error, except undef which means return an empty set.
T
Tom Lane 已提交
1254
		 */
1255 1256
		if (SvOK(perlret) &&
			SvTYPE(perlret) == SVt_RV &&
1257
			SvTYPE(SvRV(perlret)) == SVt_PVAV)
1258
		{
B
Bruce Momjian 已提交
1259 1260 1261 1262 1263
			int			i = 0;
			SV		  **svp = 0;
			AV		   *rav = (AV *) SvRV(perlret);

			while ((svp = av_fetch(rav, i, FALSE)) != NULL)
1264
			{
1265 1266 1267
				plperl_return_next(*svp);
				i++;
			}
1268
		}
1269
		else if (SvOK(perlret))
1270
		{
1271 1272
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
1273 1274
					 errmsg("set-returning Perl function must return "
							"reference to array or use return_next")));
1275
		}
B
Bruce Momjian 已提交
1276

1277
		rsi->returnMode = SFRM_Materialize;
1278
		if (current_call_data->tuple_store)
1279
		{
1280 1281
			rsi->setResult = current_call_data->tuple_store;
			rsi->setDesc = current_call_data->ret_tdesc;
1282
		}
B
Bruce Momjian 已提交
1283
		retval = (Datum) 0;
1284
	}
1285
	else if (!SvOK(perlret))
1286 1287 1288 1289
	{
		/* Return NULL if Perl code returned undef */
		if (rsi && IsA(rsi, ReturnSetInfo))
			rsi->isDone = ExprEndResult;
1290 1291
		retval = InputFunctionCall(&prodesc->result_in_func, NULL,
								   prodesc->result_typioparam, -1);
1292
		fcinfo->isnull = true;
B
Bruce Momjian 已提交
1293
	}
1294
	else if (prodesc->fn_retistuple)
1295
	{
1296
		/* Return a perl hash converted to a Datum */
B
Bruce Momjian 已提交
1297
		TupleDesc	td;
1298
		AttInMetadata *attinmeta;
B
Bruce Momjian 已提交
1299
		HeapTuple	tup;
1300

1301 1302 1303
		if (!SvOK(perlret) || SvTYPE(perlret) != SVt_RV ||
			SvTYPE(SvRV(perlret)) != SVt_PVHV)
		{
1304 1305
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
1306 1307 1308
					 errmsg("composite-returning Perl function "
							"must return reference to hash")));
		}
1309

1310 1311 1312 1313 1314 1315 1316 1317
		/* XXX should cache the attinmeta data instead of recomputing */
		if (get_call_result_type(fcinfo, NULL, &td) != TYPEFUNC_COMPOSITE)
		{
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("function returning record called in context "
							"that cannot accept type record")));
		}
1318

1319
		attinmeta = TupleDescGetAttInMetadata(td);
B
Bruce Momjian 已提交
1320
		tup = plperl_build_tuple_result((HV *) SvRV(perlret), attinmeta);
1321 1322 1323 1324
		retval = HeapTupleGetDatum(tup);
	}
	else
	{
B
Bruce Momjian 已提交
1325 1326 1327 1328
		/* Return a perl string converted to a Datum */
		char	   *val;

		if (prodesc->fn_retisarray && SvROK(perlret) &&
1329
			SvTYPE(SvRV(perlret)) == SVt_PVAV)
B
Bruce Momjian 已提交
1330 1331 1332 1333 1334
		{
			array_ret = plperl_convert_to_pg_array(perlret);
			SvREFCNT_dec(perlret);
			perlret = array_ret;
		}
1335 1336 1337

		val = SvPV(perlret, PL_na);

1338 1339
		retval = InputFunctionCall(&prodesc->result_in_func, val,
								   prodesc->result_typioparam, -1);
1340
	}
1341

1342
	if (array_ret == NULL)
B
Bruce Momjian 已提交
1343
		SvREFCNT_dec(perlret);
1344

1345
	current_call_data = NULL;
1346 1347
	restore_context(oldcontext);

1348 1349 1350
	return retval;
}

1351

1352 1353 1354 1355 1356 1357 1358 1359
static Datum
plperl_trigger_handler(PG_FUNCTION_ARGS)
{
	plperl_proc_desc *prodesc;
	SV		   *perlret;
	Datum		retval;
	SV		   *svTD;
	HV		   *hvTD;
B
Bruce Momjian 已提交
1360
	bool		oldcontext = trusted_context;
1361

1362
	/*
B
Bruce Momjian 已提交
1363 1364
	 * Create the call_data beforing connecting to SPI, so that it is not
	 * allocated in the SPI memory context
1365 1366 1367 1368
	 */
	current_call_data = (plperl_call_data *) palloc0(sizeof(plperl_call_data));
	current_call_data->fcinfo = fcinfo;

1369 1370 1371 1372
	/* Connect to SPI manager */
	if (SPI_connect() != SPI_OK_CONNECT)
		elog(ERROR, "could not connect to SPI manager");

1373 1374
	/* Find or compile the function */
	prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, true);
1375
	current_call_data->prodesc = prodesc;
1376

1377 1378
	check_interp(prodesc->lanpltrusted);

1379 1380
	svTD = plperl_trigger_build_args(fcinfo);
	perlret = plperl_call_perl_trigger_func(prodesc, fcinfo, svTD);
1381
	hvTD = (HV *) SvRV(svTD);
1382 1383 1384 1385 1386 1387 1388 1389

	/************************************************************
	* Disconnect from SPI manager and then create the return
	* values datum (if the input function does a palloc for it
	* this must not be allocated in the SPI memory context
	* because SPI_finish would free it).
	************************************************************/
	if (SPI_finish() != SPI_OK_FINISH)
1390
		elog(ERROR, "SPI_finish() failed");
1391

1392
	if (perlret == NULL || !SvOK(perlret))
1393
	{
1394
		/* undef result means go ahead with original tuple */
1395 1396 1397 1398 1399 1400 1401 1402
		TriggerData *trigdata = ((TriggerData *) fcinfo->context);

		if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
			retval = (Datum) trigdata->tg_trigtuple;
		else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
			retval = (Datum) trigdata->tg_newtuple;
		else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
			retval = (Datum) trigdata->tg_trigtuple;
1403
		else
B
Bruce Momjian 已提交
1404
			retval = (Datum) 0; /* can this happen? */
1405 1406 1407
	}
	else
	{
1408 1409
		HeapTuple	trv;
		char	   *tmp;
1410

1411
		tmp = SvPV(perlret, PL_na);
1412

1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424
		if (pg_strcasecmp(tmp, "SKIP") == 0)
			trv = NULL;
		else if (pg_strcasecmp(tmp, "MODIFY") == 0)
		{
			TriggerData *trigdata = (TriggerData *) fcinfo->context;

			if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
				trv = plperl_modify_tuple(hvTD, trigdata,
										  trigdata->tg_trigtuple);
			else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
				trv = plperl_modify_tuple(hvTD, trigdata,
										  trigdata->tg_newtuple);
1425 1426
			else
			{
1427 1428
				ereport(WARNING,
						(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
B
Bruce Momjian 已提交
1429
					   errmsg("ignoring modified tuple in DELETE trigger")));
1430 1431 1432
				trv = NULL;
			}
		}
1433
		else
1434
		{
1435 1436
			ereport(ERROR,
					(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1437 1438
					 errmsg("result of Perl trigger function must be undef, "
							"\"SKIP\" or \"MODIFY\"")));
1439 1440 1441
			trv = NULL;
		}
		retval = PointerGetDatum(trv);
1442 1443
	}

1444 1445 1446
	SvREFCNT_dec(svTD);
	if (perlret)
		SvREFCNT_dec(perlret);
1447

1448
	current_call_data = NULL;
1449
	restore_context(oldcontext);
1450 1451
	return retval;
}
1452

1453

1454 1455
static plperl_proc_desc *
compile_plperl_function(Oid fn_oid, bool is_trigger)
1456
{
1457 1458
	HeapTuple	procTup;
	Form_pg_proc procStruct;
1459
	char		internal_proname[NAMEDATALEN];
1460
	plperl_proc_desc *prodesc = NULL;
1461
	int			i;
1462
	plperl_proc_entry *hash_entry;
B
Bruce Momjian 已提交
1463 1464
	bool		found;
	bool		oldcontext = trusted_context;
1465

1466 1467 1468 1469 1470
	/* We'll need the pg_proc tuple in any case... */
	procTup = SearchSysCache(PROCOID,
							 ObjectIdGetDatum(fn_oid),
							 0, 0, 0);
	if (!HeapTupleIsValid(procTup))
1471
		elog(ERROR, "cache lookup failed for function %u", fn_oid);
1472
	procStruct = (Form_pg_proc) GETSTRUCT(procTup);
1473 1474

	/************************************************************
1475
	 * Build our internal proc name from the function's Oid
1476
	 ************************************************************/
1477 1478 1479 1480
	if (!is_trigger)
		sprintf(internal_proname, "__PLPerl_proc_%u", fn_oid);
	else
		sprintf(internal_proname, "__PLPerl_proc_%u_trigger", fn_oid);
1481

1482 1483 1484
	/************************************************************
	 * Lookup the internal proc name in the hashtable
	 ************************************************************/
1485
	hash_entry = hash_search(plperl_proc_hash, internal_proname,
1486 1487 1488
							 HASH_FIND, NULL);

	if (hash_entry)
1489
	{
1490 1491
		bool		uptodate;

1492
		prodesc = hash_entry->proc_data;
1493

1494
		/************************************************************
1495 1496 1497
		 * If it's present, must check whether it's still up to date.
		 * This is needed because CREATE OR REPLACE FUNCTION can modify the
		 * function's pg_proc entry without changing its OID.
1498
		 ************************************************************/
1499
		uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
B
Bruce Momjian 已提交
1500
					ItemPointerEquals(&prodesc->fn_tid, &procTup->t_self));
1501 1502 1503

		if (!uptodate)
		{
1504 1505
			free(prodesc->proname);
			free(prodesc);
1506
			prodesc = NULL;
1507
			hash_search(plperl_proc_hash, internal_proname,
1508
						HASH_REMOVE, NULL);
1509 1510 1511 1512 1513
		}
	}

	/************************************************************
	 * If we haven't found it in the hashtable, we analyze
1514
	 * the function's arguments and return type and store
1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525
	 * the in-/out-functions in the prodesc block and create
	 * a new hashtable entry for it.
	 *
	 * Then we load the procedure into the Perl interpreter.
	 ************************************************************/
	if (prodesc == NULL)
	{
		HeapTuple	langTup;
		HeapTuple	typeTup;
		Form_pg_language langStruct;
		Form_pg_type typeStruct;
1526 1527
		Datum		prosrcdatum;
		bool		isnull;
1528 1529 1530 1531 1532 1533
		char	   *proc_source;

		/************************************************************
		 * Allocate a new procedure description block
		 ************************************************************/
		prodesc = (plperl_proc_desc *) malloc(sizeof(plperl_proc_desc));
1534
		if (prodesc == NULL)
1535 1536 1537
			ereport(ERROR,
					(errcode(ERRCODE_OUT_OF_MEMORY),
					 errmsg("out of memory")));
1538
		MemSet(prodesc, 0, sizeof(plperl_proc_desc));
1539
		prodesc->proname = strdup(NameStr(procStruct->proname));
1540
		prodesc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
1541
		prodesc->fn_tid = procTup->t_self;
1542

1543 1544 1545 1546
		/* Remember if function is STABLE/IMMUTABLE */
		prodesc->fn_readonly =
			(procStruct->provolatile != PROVOLATILE_VOLATILE);

1547
		/************************************************************
1548
		 * Lookup the pg_language tuple by Oid
1549
		 ************************************************************/
1550 1551
		langTup = SearchSysCache(LANGOID,
								 ObjectIdGetDatum(procStruct->prolang),
1552
								 0, 0, 0);
1553
		if (!HeapTupleIsValid(langTup))
1554 1555 1556
		{
			free(prodesc->proname);
			free(prodesc);
1557
			elog(ERROR, "cache lookup failed for language %u",
1558
				 procStruct->prolang);
1559
		}
1560 1561 1562
		langStruct = (Form_pg_language) GETSTRUCT(langTup);
		prodesc->lanpltrusted = langStruct->lanpltrusted;
		ReleaseSysCache(langTup);
1563 1564

		/************************************************************
1565 1566
		 * Get the required information for input conversion of the
		 * return value.
1567
		 ************************************************************/
1568 1569 1570
		if (!is_trigger)
		{
			typeTup = SearchSysCache(TYPEOID,
B
Bruce Momjian 已提交
1571
									 ObjectIdGetDatum(procStruct->prorettype),
1572 1573 1574 1575 1576
									 0, 0, 0);
			if (!HeapTupleIsValid(typeTup))
			{
				free(prodesc->proname);
				free(prodesc);
1577
				elog(ERROR, "cache lookup failed for type %u",
1578
					 procStruct->prorettype);
1579 1580 1581
			}
			typeStruct = (Form_pg_type) GETSTRUCT(typeTup);

1582
			/* Disallow pseudotype result, except VOID or RECORD */
1583
			if (typeStruct->typtype == TYPTYPE_PSEUDO)
1584
			{
1585 1586
				if (procStruct->prorettype == VOIDOID ||
					procStruct->prorettype == RECORDOID)
B
Bruce Momjian 已提交
1587
					 /* okay */ ;
1588
				else if (procStruct->prorettype == TRIGGEROID)
1589 1590 1591
				{
					free(prodesc->proname);
					free(prodesc);
1592 1593
					ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1594
							 errmsg("trigger functions can only be called "
1595
									"as triggers")));
1596 1597 1598 1599 1600
				}
				else
				{
					free(prodesc->proname);
					free(prodesc);
1601 1602
					ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
B
Bruce Momjian 已提交
1603 1604
							 errmsg("plperl functions cannot return type %s",
									format_type_be(procStruct->prorettype))));
1605 1606 1607
				}
			}

1608 1609
			prodesc->result_oid = procStruct->prorettype;
			prodesc->fn_retisset = procStruct->proretset;
1610
			prodesc->fn_retistuple = (procStruct->prorettype == RECORDOID ||
B
Bruce Momjian 已提交
1611
								   typeStruct->typtype == TYPTYPE_COMPOSITE);
1612

B
Bruce Momjian 已提交
1613 1614
			prodesc->fn_retisarray =
				(typeStruct->typlen == -1 && typeStruct->typelem);
1615

1616
			perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
1617
			prodesc->result_typioparam = getTypeIOParam(typeTup);
1618 1619 1620

			ReleaseSysCache(typeTup);
		}
1621 1622

		/************************************************************
1623 1624
		 * Get the required information for output conversion
		 * of all procedure arguments
1625
		 ************************************************************/
1626 1627 1628 1629 1630 1631
		if (!is_trigger)
		{
			prodesc->nargs = procStruct->pronargs;
			for (i = 0; i < prodesc->nargs; i++)
			{
				typeTup = SearchSysCache(TYPEOID,
B
Bruce Momjian 已提交
1632
						 ObjectIdGetDatum(procStruct->proargtypes.values[i]),
1633 1634 1635 1636 1637
										 0, 0, 0);
				if (!HeapTupleIsValid(typeTup))
				{
					free(prodesc->proname);
					free(prodesc);
1638
					elog(ERROR, "cache lookup failed for type %u",
1639
						 procStruct->proargtypes.values[i]);
1640 1641 1642
				}
				typeStruct = (Form_pg_type) GETSTRUCT(typeTup);

1643
				/* Disallow pseudotype argument */
1644
				if (typeStruct->typtype == TYPTYPE_PSEUDO)
1645 1646 1647
				{
					free(prodesc->proname);
					free(prodesc);
1648 1649
					ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
B
Bruce Momjian 已提交
1650 1651
							 errmsg("plperl functions cannot take type %s",
						format_type_be(procStruct->proargtypes.values[i]))));
1652 1653
				}

1654
				if (typeStruct->typtype == TYPTYPE_COMPOSITE)
1655
					prodesc->arg_is_rowtype[i] = true;
1656
				else
1657 1658 1659 1660 1661
				{
					prodesc->arg_is_rowtype[i] = false;
					perm_fmgr_info(typeStruct->typoutput,
								   &(prodesc->arg_out_func[i]));
				}
1662 1663 1664 1665

				ReleaseSysCache(typeTup);
			}
		}
1666

1667 1668 1669 1670 1671
		/************************************************************
		 * create the text of the anonymous subroutine.
		 * we do not use a named subroutine so that we can call directly
		 * through the reference.
		 ************************************************************/
1672 1673 1674 1675
		prosrcdatum = SysCacheGetAttr(PROCOID, procTup,
									  Anum_pg_proc_prosrc, &isnull);
		if (isnull)
			elog(ERROR, "null prosrc");
1676
		proc_source = DatumGetCString(DirectFunctionCall1(textout,
1677
														  prosrcdatum));
1678 1679

		/************************************************************
1680
		 * Create the procedure in the interpreter
1681
		 ************************************************************/
1682 1683 1684

		check_interp(prodesc->lanpltrusted);

1685 1686 1687
		prodesc->reference = plperl_create_sub(prodesc->proname,
											   proc_source,
											   prodesc->lanpltrusted);
1688 1689 1690

		restore_context(oldcontext);

1691
		pfree(proc_source);
B
Bruce Momjian 已提交
1692
		if (!prodesc->reference)	/* can this happen? */
1693 1694 1695
		{
			free(prodesc->proname);
			free(prodesc);
1696
			elog(ERROR, "could not create internal procedure \"%s\"",
1697
				 internal_proname);
1698 1699
		}

1700 1701 1702
		hash_entry = hash_search(plperl_proc_hash, internal_proname,
								 HASH_ENTER, &found);
		hash_entry->proc_data = prodesc;
1703 1704
	}

1705
	ReleaseSysCache(procTup);
1706

1707 1708
	return prodesc;
}
1709 1710


1711 1712
/* Build a hash from all attributes of a given tuple. */

B
Bruce Momjian 已提交
1713
static SV  *
1714
plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc)
1715
{
1716
	HV		   *hv;
1717
	int			i;
1718

1719
	hv = newHV();
1720 1721 1722

	for (i = 0; i < tupdesc->natts; i++)
	{
1723 1724 1725 1726 1727 1728 1729
		Datum		attr;
		bool		isnull;
		char	   *attname;
		char	   *outputstr;
		Oid			typoutput;
		bool		typisvarlena;

1730 1731 1732
		if (tupdesc->attrs[i]->attisdropped)
			continue;

1733
		attname = NameStr(tupdesc->attrs[i]->attname);
1734 1735
		attr = heap_getattr(tuple, i + 1, tupdesc, &isnull);

B
Bruce Momjian 已提交
1736 1737
		if (isnull)
		{
1738
			/* Store (attname => undef) and move on. */
1739
			hv_store_string(hv, attname, newSV(0));
1740 1741 1742
			continue;
		}

1743 1744
		/* XXX should have a way to cache these lookups */
		getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
1745
						  &typoutput, &typisvarlena);
1746

1747
		outputstr = OidOutputFunctionCall(typoutput, attr);
1748

1749
		hv_store_string(hv, attname, newSVstring(outputstr));
1750 1751

		pfree(outputstr);
1752
	}
1753

1754
	return newRV_noinc((SV *) hv);
1755
}
1756 1757 1758 1759 1760 1761 1762


HV *
plperl_spi_exec(char *query, int limit)
{
	HV		   *ret_hv;

1763
	/*
B
Bruce Momjian 已提交
1764 1765
	 * Execute the query inside a sub-transaction, so we can cope with errors
	 * sanely
1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777
	 */
	MemoryContext oldcontext = CurrentMemoryContext;
	ResourceOwner oldowner = CurrentResourceOwner;

	BeginInternalSubTransaction(NULL);
	/* Want to run inside function's memory context */
	MemoryContextSwitchTo(oldcontext);

	PG_TRY();
	{
		int			spi_rv;

1778
		spi_rv = SPI_execute(query, current_call_data->prodesc->fn_readonly,
1779 1780 1781 1782 1783 1784 1785 1786
							 limit);
		ret_hv = plperl_spi_execute_fetch_result(SPI_tuptable, SPI_processed,
												 spi_rv);

		/* Commit the inner transaction, return to outer xact context */
		ReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;
B
Bruce Momjian 已提交
1787

1788
		/*
B
Bruce Momjian 已提交
1789 1790
		 * AtEOSubXact_SPI() should not have popped any SPI context, but just
		 * in case it did, make sure we remain connected.
1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808
		 */
		SPI_restore_connection();
	}
	PG_CATCH();
	{
		ErrorData  *edata;

		/* Save error info */
		MemoryContextSwitchTo(oldcontext);
		edata = CopyErrorData();
		FlushErrorState();

		/* Abort the inner transaction */
		RollbackAndReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;

		/*
B
Bruce Momjian 已提交
1809 1810 1811
		 * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
		 * have left us in a disconnected state.  We need this hack to return
		 * to connected state.
1812 1813 1814 1815 1816 1817 1818 1819 1820 1821
		 */
		SPI_restore_connection();

		/* Punt the error to Perl */
		croak("%s", edata->message);

		/* Can't get here, but keep compiler quiet */
		return NULL;
	}
	PG_END_TRY();
1822 1823 1824 1825

	return ret_hv;
}

1826

1827
static HV  *
1828 1829
plperl_spi_execute_fetch_result(SPITupleTable *tuptable, int processed,
								int status)
1830 1831 1832 1833 1834
{
	HV		   *result;

	result = newHV();

1835 1836 1837 1838
	hv_store_string(result, "status",
					newSVstring(SPI_result_code_string(status)));
	hv_store_string(result, "processed",
					newSViv(processed));
1839

1840
	if (status > 0 && tuptable)
1841
	{
1842
		AV		   *rows;
1843
		SV		   *row;
1844
		int			i;
1845

1846 1847 1848 1849
		rows = newAV();
		for (i = 0; i < processed; i++)
		{
			row = plperl_hash_from_tuple(tuptable->vals[i], tuptable->tupdesc);
1850
			av_push(rows, row);
1851
		}
1852 1853
		hv_store_string(result, "rows",
						newRV_noinc((SV *) rows));
1854 1855 1856 1857 1858 1859
	}

	SPI_freetuptable(tuptable);

	return result;
}
1860 1861


1862 1863
/*
 * Note: plperl_return_next is called both in Postgres and Perl contexts.
1864
 * We report any errors in Postgres fashion (via ereport).	If called in
1865 1866 1867 1868 1869
 * Perl context, it is SPI.xs's responsibility to catch the error and
 * convert to a Perl error.  We assume (perhaps without adequate justification)
 * that we need not abort the current transaction if the Perl code traps the
 * error.
 */
1870
void
1871
plperl_return_next(SV *sv)
1872
{
1873 1874 1875 1876
	plperl_proc_desc *prodesc;
	FunctionCallInfo fcinfo;
	ReturnSetInfo *rsi;
	MemoryContext old_cxt;
B
Bruce Momjian 已提交
1877
	HeapTuple	tuple;
1878 1879 1880 1881

	if (!sv)
		return;

1882 1883 1884 1885
	prodesc = current_call_data->prodesc;
	fcinfo = current_call_data->fcinfo;
	rsi = (ReturnSetInfo *) fcinfo->resultinfo;

1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897
	if (!prodesc->fn_retisset)
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("cannot use return_next in a non-SETOF function")));

	if (prodesc->fn_retistuple &&
		!(SvOK(sv) && SvTYPE(sv) == SVt_RV && SvTYPE(SvRV(sv)) == SVt_PVHV))
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("setof-composite-returning Perl function "
						"must call return_next with reference to hash")));

1898 1899
	if (!current_call_data->ret_tdesc)
	{
B
Bruce Momjian 已提交
1900
		TupleDesc	tupdesc;
1901 1902 1903

		Assert(!current_call_data->tuple_store);
		Assert(!current_call_data->attinmeta);
1904

1905
		/*
B
Bruce Momjian 已提交
1906 1907
		 * This is the first call to return_next in the current PL/Perl
		 * function call, so memoize some lookups
1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921
		 */
		if (prodesc->fn_retistuple)
			(void) get_call_result_type(fcinfo, NULL, &tupdesc);
		else
			tupdesc = rsi->expectedDesc;

		/*
		 * Make sure the tuple_store and ret_tdesc are sufficiently
		 * long-lived.
		 */
		old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);

		current_call_data->ret_tdesc = CreateTupleDescCopy(tupdesc);
		current_call_data->tuple_store =
1922
			tuplestore_begin_heap(true, false, work_mem);
1923 1924 1925 1926 1927
		if (prodesc->fn_retistuple)
		{
			current_call_data->attinmeta =
				TupleDescGetAttInMetadata(current_call_data->ret_tdesc);
		}
1928

1929
		MemoryContextSwitchTo(old_cxt);
B
Bruce Momjian 已提交
1930
	}
1931 1932 1933

	/*
	 * Producing the tuple we want to return requires making plenty of
B
Bruce Momjian 已提交
1934 1935 1936
	 * palloc() allocations that are not cleaned up. Since this function can
	 * be called many times before the current memory context is reset, we
	 * need to do those allocations in a temporary context.
1937 1938
	 */
	if (!current_call_data->tmp_cxt)
1939
	{
1940 1941 1942 1943 1944 1945 1946 1947 1948
		current_call_data->tmp_cxt =
			AllocSetContextCreate(rsi->econtext->ecxt_per_tuple_memory,
								  "PL/Perl return_next temporary cxt",
								  ALLOCSET_DEFAULT_MINSIZE,
								  ALLOCSET_DEFAULT_INITSIZE,
								  ALLOCSET_DEFAULT_MAXSIZE);
	}

	old_cxt = MemoryContextSwitchTo(current_call_data->tmp_cxt);
1949

1950 1951 1952 1953
	if (prodesc->fn_retistuple)
	{
		tuple = plperl_build_tuple_result((HV *) SvRV(sv),
										  current_call_data->attinmeta);
1954 1955 1956
	}
	else
	{
1957 1958
		Datum		ret;
		bool		isNull;
1959

1960
		if (SvOK(sv))
1961
		{
1962
			char	   *val = SvPV(sv, PL_na);
B
Bruce Momjian 已提交
1963

1964 1965
			ret = InputFunctionCall(&prodesc->result_in_func, val,
									prodesc->result_typioparam, -1);
1966 1967
			isNull = false;
		}
1968 1969 1970 1971 1972 1973
		else
		{
			ret = InputFunctionCall(&prodesc->result_in_func, NULL,
									prodesc->result_typioparam, -1);
			isNull = true;
		}
1974

1975
		tuple = heap_form_tuple(current_call_data->ret_tdesc, &ret, &isNull);
1976 1977
	}

1978 1979 1980 1981
	/* Make sure to store the tuple in a long-lived memory context */
	MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
	tuplestore_puttuple(current_call_data->tuple_store, tuple);
	MemoryContextSwitchTo(old_cxt);
1982

1983
	MemoryContextReset(current_call_data->tmp_cxt);
1984
}
1985 1986 1987 1988 1989


SV *
plperl_spi_query(char *query)
{
B
Bruce Momjian 已提交
1990
	SV		   *cursor;
1991

1992 1993 1994 1995
	/*
	 * Execute the query inside a sub-transaction, so we can cope with errors
	 * sanely
	 */
1996 1997 1998 1999
	MemoryContext oldcontext = CurrentMemoryContext;
	ResourceOwner oldowner = CurrentResourceOwner;

	BeginInternalSubTransaction(NULL);
2000
	/* Want to run inside function's memory context */
2001 2002 2003 2004
	MemoryContextSwitchTo(oldcontext);

	PG_TRY();
	{
B
Bruce Momjian 已提交
2005
		void	   *plan;
A
 
Andrew Dunstan 已提交
2006
		Portal		portal;
2007

2008
		/* Create a cursor for the query */
2009
		plan = SPI_prepare(query, 0, NULL);
B
Bruce Momjian 已提交
2010
		if (plan == NULL)
A
 
Andrew Dunstan 已提交
2011
			elog(ERROR, "SPI_prepare() failed:%s",
B
Bruce Momjian 已提交
2012
				 SPI_result_code_string(SPI_result));
A
 
Andrew Dunstan 已提交
2013 2014

		portal = SPI_cursor_open(NULL, plan, NULL, NULL, false);
B
Bruce Momjian 已提交
2015 2016
		SPI_freeplan(plan);
		if (portal == NULL)
A
 
Andrew Dunstan 已提交
2017
			elog(ERROR, "SPI_cursor_open() failed:%s",
B
Bruce Momjian 已提交
2018
				 SPI_result_code_string(SPI_result));
2019
		cursor = newSVstring(portal->name);
2020

2021
		/* Commit the inner transaction, return to outer xact context */
2022 2023 2024
		ReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;
2025 2026 2027 2028 2029

		/*
		 * AtEOSubXact_SPI() should not have popped any SPI context, but just
		 * in case it did, make sure we remain connected.
		 */
2030 2031 2032 2033 2034 2035
		SPI_restore_connection();
	}
	PG_CATCH();
	{
		ErrorData  *edata;

2036
		/* Save error info */
2037 2038 2039 2040
		MemoryContextSwitchTo(oldcontext);
		edata = CopyErrorData();
		FlushErrorState();

2041
		/* Abort the inner transaction */
2042 2043 2044 2045
		RollbackAndReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;

2046 2047 2048 2049 2050
		/*
		 * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
		 * have left us in a disconnected state.  We need this hack to return
		 * to connected state.
		 */
2051
		SPI_restore_connection();
2052 2053

		/* Punt the error to Perl */
2054
		croak("%s", edata->message);
2055 2056

		/* Can't get here, but keep compiler quiet */
2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067
		return NULL;
	}
	PG_END_TRY();

	return cursor;
}


SV *
plperl_spi_fetchrow(char *cursor)
{
2068 2069 2070 2071 2072 2073 2074 2075
	SV		   *row;

	/*
	 * Execute the FETCH inside a sub-transaction, so we can cope with errors
	 * sanely
	 */
	MemoryContext oldcontext = CurrentMemoryContext;
	ResourceOwner oldowner = CurrentResourceOwner;
2076

2077 2078 2079
	BeginInternalSubTransaction(NULL);
	/* Want to run inside function's memory context */
	MemoryContextSwitchTo(oldcontext);
2080

2081
	PG_TRY();
B
Bruce Momjian 已提交
2082
	{
2083 2084 2085
		Portal		p = SPI_cursor_find(cursor);

		if (!p)
A
 
Andrew Dunstan 已提交
2086 2087 2088
		{
			row = &PL_sv_undef;
		}
2089 2090 2091 2092 2093 2094
		else
		{
			SPI_cursor_fetch(p, true, 1);
			if (SPI_processed == 0)
			{
				SPI_cursor_close(p);
A
 
Andrew Dunstan 已提交
2095
				row = &PL_sv_undef;
2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114
			}
			else
			{
				row = plperl_hash_from_tuple(SPI_tuptable->vals[0],
											 SPI_tuptable->tupdesc);
			}
			SPI_freetuptable(SPI_tuptable);
		}

		/* Commit the inner transaction, return to outer xact context */
		ReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;

		/*
		 * AtEOSubXact_SPI() should not have popped any SPI context, but just
		 * in case it did, make sure we remain connected.
		 */
		SPI_restore_connection();
2115
	}
2116 2117 2118
	PG_CATCH();
	{
		ErrorData  *edata;
2119

2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143
		/* Save error info */
		MemoryContextSwitchTo(oldcontext);
		edata = CopyErrorData();
		FlushErrorState();

		/* Abort the inner transaction */
		RollbackAndReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;

		/*
		 * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
		 * have left us in a disconnected state.  We need this hack to return
		 * to connected state.
		 */
		SPI_restore_connection();

		/* Punt the error to Perl */
		croak("%s", edata->message);

		/* Can't get here, but keep compiler quiet */
		return NULL;
	}
	PG_END_TRY();
2144 2145 2146

	return row;
}
A
 
Andrew Dunstan 已提交
2147 2148 2149 2150

void
plperl_spi_cursor_close(char *cursor)
{
B
Bruce Momjian 已提交
2151 2152
	Portal		p = SPI_cursor_find(cursor);

A
 
Andrew Dunstan 已提交
2153 2154 2155 2156 2157
	if (p)
		SPI_cursor_close(p);
}

SV *
B
Bruce Momjian 已提交
2158
plperl_spi_prepare(char *query, int argc, SV **argv)
A
 
Andrew Dunstan 已提交
2159 2160
{
	plperl_query_desc *qdesc;
2161
	plperl_query_entry *hash_entry;
B
Bruce Momjian 已提交
2162
	bool		found;
A
 
Andrew Dunstan 已提交
2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176
	void	   *plan;
	int			i;

	MemoryContext oldcontext = CurrentMemoryContext;
	ResourceOwner oldowner = CurrentResourceOwner;

	BeginInternalSubTransaction(NULL);
	MemoryContextSwitchTo(oldcontext);

	/************************************************************
	 * Allocate the new querydesc structure
	 ************************************************************/
	qdesc = (plperl_query_desc *) malloc(sizeof(plperl_query_desc));
	MemSet(qdesc, 0, sizeof(plperl_query_desc));
B
Bruce Momjian 已提交
2177 2178 2179 2180 2181
	snprintf(qdesc->qname, sizeof(qdesc->qname), "%lx", (long) qdesc);
	qdesc->nargs = argc;
	qdesc->argtypes = (Oid *) malloc(argc * sizeof(Oid));
	qdesc->arginfuncs = (FmgrInfo *) malloc(argc * sizeof(FmgrInfo));
	qdesc->argtypioparams = (Oid *) malloc(argc * sizeof(Oid));
A
 
Andrew Dunstan 已提交
2182 2183 2184 2185

	PG_TRY();
	{
		/************************************************************
2186 2187 2188
		 * Resolve argument type names and then look them up by oid
		 * in the system cache, and remember the required information
		 * for input conversion.
A
 
Andrew Dunstan 已提交
2189 2190 2191
		 ************************************************************/
		for (i = 0; i < argc; i++)
		{
B
Bruce Momjian 已提交
2192 2193 2194 2195
			Oid			typId,
						typInput,
						typIOParam;
			int32		typmod;
2196 2197 2198 2199 2200 2201

			parseTypeString(SvPV(argv[i], PL_na), &typId, &typmod);

			getTypeInputInfo(typId, &typInput, &typIOParam);

			qdesc->argtypes[i] = typId;
2202
			perm_fmgr_info(typInput, &(qdesc->arginfuncs[i]));
2203
			qdesc->argtypioparams[i] = typIOParam;
A
 
Andrew Dunstan 已提交
2204 2205 2206 2207 2208 2209 2210 2211 2212
		}

		/************************************************************
		 * Prepare the plan and check for errors
		 ************************************************************/
		plan = SPI_prepare(query, argc, qdesc->argtypes);

		if (plan == NULL)
			elog(ERROR, "SPI_prepare() failed:%s",
B
Bruce Momjian 已提交
2213
				 SPI_result_code_string(SPI_result));
A
 
Andrew Dunstan 已提交
2214 2215 2216 2217 2218 2219 2220

		/************************************************************
		 * Save the plan into permanent memory (right now it's in the
		 * SPI procCxt, which will go away at function end).
		 ************************************************************/
		qdesc->plan = SPI_saveplan(plan);
		if (qdesc->plan == NULL)
B
Bruce Momjian 已提交
2221 2222
			elog(ERROR, "SPI_saveplan() failed: %s",
				 SPI_result_code_string(SPI_result));
A
 
Andrew Dunstan 已提交
2223 2224 2225 2226 2227 2228 2229 2230

		/* Release the procCxt copy to avoid within-function memory leak */
		SPI_freeplan(plan);

		/* Commit the inner transaction, return to outer xact context */
		ReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;
B
Bruce Momjian 已提交
2231

A
 
Andrew Dunstan 已提交
2232
		/*
B
Bruce Momjian 已提交
2233 2234
		 * AtEOSubXact_SPI() should not have popped any SPI context, but just
		 * in case it did, make sure we remain connected.
A
 
Andrew Dunstan 已提交
2235 2236 2237 2238 2239 2240
		 */
		SPI_restore_connection();
	}
	PG_CATCH();
	{
		ErrorData  *edata;
B
Bruce Momjian 已提交
2241 2242 2243 2244

		free(qdesc->argtypes);
		free(qdesc->arginfuncs);
		free(qdesc->argtypioparams);
A
 
Andrew Dunstan 已提交
2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257
		free(qdesc);

		/* Save error info */
		MemoryContextSwitchTo(oldcontext);
		edata = CopyErrorData();
		FlushErrorState();

		/* Abort the inner transaction */
		RollbackAndReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;

		/*
B
Bruce Momjian 已提交
2258 2259 2260
		 * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
		 * have left us in a disconnected state.  We need this hack to return
		 * to connected state.
A
 
Andrew Dunstan 已提交
2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275
		 */
		SPI_restore_connection();

		/* Punt the error to Perl */
		croak("%s", edata->message);

		/* Can't get here, but keep compiler quiet */
		return NULL;
	}
	PG_END_TRY();

	/************************************************************
	 * Insert a hashtable entry for the plan and return
	 * the key to the caller.
	 ************************************************************/
2276 2277

	hash_entry = hash_search(plperl_query_hash, qdesc->qname,
B
Bruce Momjian 已提交
2278
							 HASH_ENTER, &found);
2279
	hash_entry->query_data = qdesc;
A
 
Andrew Dunstan 已提交
2280

2281
	return newSVstring(qdesc->qname);
B
Bruce Momjian 已提交
2282
}
A
 
Andrew Dunstan 已提交
2283 2284

HV *
B
Bruce Momjian 已提交
2285
plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv)
A
 
Andrew Dunstan 已提交
2286 2287
{
	HV		   *ret_hv;
B
Bruce Momjian 已提交
2288 2289 2290 2291 2292
	SV		  **sv;
	int			i,
				limit,
				spi_rv;
	char	   *nulls;
A
 
Andrew Dunstan 已提交
2293 2294
	Datum	   *argvalues;
	plperl_query_desc *qdesc;
2295
	plperl_query_entry *hash_entry;
A
 
Andrew Dunstan 已提交
2296 2297

	/*
B
Bruce Momjian 已提交
2298 2299
	 * Execute the query inside a sub-transaction, so we can cope with errors
	 * sanely
A
 
Andrew Dunstan 已提交
2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312
	 */
	MemoryContext oldcontext = CurrentMemoryContext;
	ResourceOwner oldowner = CurrentResourceOwner;

	BeginInternalSubTransaction(NULL);
	/* Want to run inside function's memory context */
	MemoryContextSwitchTo(oldcontext);

	PG_TRY();
	{
		/************************************************************
		 * Fetch the saved plan descriptor, see if it's o.k.
		 ************************************************************/
2313 2314

		hash_entry = hash_search(plperl_query_hash, query,
B
Bruce Momjian 已提交
2315
								 HASH_FIND, NULL);
2316
		if (hash_entry == NULL)
A
 
Andrew Dunstan 已提交
2317 2318
			elog(ERROR, "spi_exec_prepared: Invalid prepared query passed");

2319 2320
		qdesc = hash_entry->query_data;

B
Bruce Momjian 已提交
2321
		if (qdesc == NULL)
A
 
Andrew Dunstan 已提交
2322 2323
			elog(ERROR, "spi_exec_prepared: panic - plperl_query_hash value vanished");

B
Bruce Momjian 已提交
2324 2325 2326 2327
		if (qdesc->nargs != argc)
			elog(ERROR, "spi_exec_prepared: expected %d argument(s), %d passed",
				 qdesc->nargs, argc);

A
 
Andrew Dunstan 已提交
2328 2329 2330 2331
		/************************************************************
		 * Parse eventual attributes
		 ************************************************************/
		limit = 0;
B
Bruce Momjian 已提交
2332
		if (attr != NULL)
A
 
Andrew Dunstan 已提交
2333
		{
2334
			sv = hv_fetch_string(attr, "limit");
B
Bruce Momjian 已提交
2335 2336
			if (*sv && SvIOK(*sv))
				limit = SvIV(*sv);
A
 
Andrew Dunstan 已提交
2337 2338 2339 2340
		}
		/************************************************************
		 * Set up arguments
		 ************************************************************/
B
Bruce Momjian 已提交
2341
		if (argc > 0)
A
 
Andrew Dunstan 已提交
2342
		{
2343
			nulls = (char *) palloc(argc);
A
 
Andrew Dunstan 已提交
2344
			argvalues = (Datum *) palloc(argc * sizeof(Datum));
B
Bruce Momjian 已提交
2345 2346
		}
		else
A
 
Andrew Dunstan 已提交
2347 2348 2349 2350 2351
		{
			nulls = NULL;
			argvalues = NULL;
		}

B
Bruce Momjian 已提交
2352
		for (i = 0; i < argc; i++)
A
 
Andrew Dunstan 已提交
2353
		{
2354
			if (SvOK(argv[i]))
A
 
Andrew Dunstan 已提交
2355
			{
2356 2357 2358 2359
				argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
												 SvPV(argv[i], PL_na),
												 qdesc->argtypioparams[i],
												 -1);
A
 
Andrew Dunstan 已提交
2360
				nulls[i] = ' ';
B
Bruce Momjian 已提交
2361 2362
			}
			else
A
 
Andrew Dunstan 已提交
2363
			{
2364 2365 2366 2367
				argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
												 NULL,
												 qdesc->argtypioparams[i],
												 -1);
A
 
Andrew Dunstan 已提交
2368 2369 2370 2371 2372 2373 2374
				nulls[i] = 'n';
			}
		}

		/************************************************************
		 * go
		 ************************************************************/
B
Bruce Momjian 已提交
2375
		spi_rv = SPI_execute_plan(qdesc->plan, argvalues, nulls,
A
 
Andrew Dunstan 已提交
2376 2377 2378
							 current_call_data->prodesc->fn_readonly, limit);
		ret_hv = plperl_spi_execute_fetch_result(SPI_tuptable, SPI_processed,
												 spi_rv);
B
Bruce Momjian 已提交
2379
		if (argc > 0)
A
 
Andrew Dunstan 已提交
2380
		{
B
Bruce Momjian 已提交
2381 2382
			pfree(argvalues);
			pfree(nulls);
A
 
Andrew Dunstan 已提交
2383 2384 2385 2386 2387 2388
		}

		/* Commit the inner transaction, return to outer xact context */
		ReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;
B
Bruce Momjian 已提交
2389

A
 
Andrew Dunstan 已提交
2390
		/*
B
Bruce Momjian 已提交
2391 2392
		 * AtEOSubXact_SPI() should not have popped any SPI context, but just
		 * in case it did, make sure we remain connected.
A
 
Andrew Dunstan 已提交
2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410
		 */
		SPI_restore_connection();
	}
	PG_CATCH();
	{
		ErrorData  *edata;

		/* Save error info */
		MemoryContextSwitchTo(oldcontext);
		edata = CopyErrorData();
		FlushErrorState();

		/* Abort the inner transaction */
		RollbackAndReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;

		/*
B
Bruce Momjian 已提交
2411 2412 2413
		 * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
		 * have left us in a disconnected state.  We need this hack to return
		 * to connected state.
A
 
Andrew Dunstan 已提交
2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428
		 */
		SPI_restore_connection();

		/* Punt the error to Perl */
		croak("%s", edata->message);

		/* Can't get here, but keep compiler quiet */
		return NULL;
	}
	PG_END_TRY();

	return ret_hv;
}

SV *
B
Bruce Momjian 已提交
2429
plperl_spi_query_prepared(char *query, int argc, SV **argv)
A
 
Andrew Dunstan 已提交
2430
{
B
Bruce Momjian 已提交
2431 2432
	int			i;
	char	   *nulls;
A
 
Andrew Dunstan 已提交
2433 2434
	Datum	   *argvalues;
	plperl_query_desc *qdesc;
2435
	plperl_query_entry *hash_entry;
B
Bruce Momjian 已提交
2436 2437
	SV		   *cursor;
	Portal		portal = NULL;
A
 
Andrew Dunstan 已提交
2438 2439

	/*
B
Bruce Momjian 已提交
2440 2441
	 * Execute the query inside a sub-transaction, so we can cope with errors
	 * sanely
A
 
Andrew Dunstan 已提交
2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454
	 */
	MemoryContext oldcontext = CurrentMemoryContext;
	ResourceOwner oldowner = CurrentResourceOwner;

	BeginInternalSubTransaction(NULL);
	/* Want to run inside function's memory context */
	MemoryContextSwitchTo(oldcontext);

	PG_TRY();
	{
		/************************************************************
		 * Fetch the saved plan descriptor, see if it's o.k.
		 ************************************************************/
2455
		hash_entry = hash_search(plperl_query_hash, query,
B
Bruce Momjian 已提交
2456
								 HASH_FIND, NULL);
2457 2458 2459 2460
		if (hash_entry == NULL)
			elog(ERROR, "spi_exec_prepared: Invalid prepared query passed");

		qdesc = hash_entry->query_data;
A
 
Andrew Dunstan 已提交
2461

B
Bruce Momjian 已提交
2462
		if (qdesc == NULL)
A
 
Andrew Dunstan 已提交
2463 2464
			elog(ERROR, "spi_query_prepared: panic - plperl_query_hash value vanished");

B
Bruce Momjian 已提交
2465 2466 2467 2468
		if (qdesc->nargs != argc)
			elog(ERROR, "spi_query_prepared: expected %d argument(s), %d passed",
				 qdesc->nargs, argc);

A
 
Andrew Dunstan 已提交
2469 2470 2471
		/************************************************************
		 * Set up arguments
		 ************************************************************/
B
Bruce Momjian 已提交
2472
		if (argc > 0)
A
 
Andrew Dunstan 已提交
2473
		{
2474
			nulls = (char *) palloc(argc);
A
 
Andrew Dunstan 已提交
2475
			argvalues = (Datum *) palloc(argc * sizeof(Datum));
B
Bruce Momjian 已提交
2476 2477
		}
		else
A
 
Andrew Dunstan 已提交
2478 2479 2480 2481 2482
		{
			nulls = NULL;
			argvalues = NULL;
		}

B
Bruce Momjian 已提交
2483
		for (i = 0; i < argc; i++)
A
 
Andrew Dunstan 已提交
2484
		{
2485
			if (SvOK(argv[i]))
A
 
Andrew Dunstan 已提交
2486
			{
2487 2488 2489 2490
				argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
												 SvPV(argv[i], PL_na),
												 qdesc->argtypioparams[i],
												 -1);
A
 
Andrew Dunstan 已提交
2491
				nulls[i] = ' ';
B
Bruce Momjian 已提交
2492 2493
			}
			else
A
 
Andrew Dunstan 已提交
2494
			{
2495 2496 2497 2498
				argvalues[i] = InputFunctionCall(&qdesc->arginfuncs[i],
												 NULL,
												 qdesc->argtypioparams[i],
												 -1);
A
 
Andrew Dunstan 已提交
2499 2500 2501 2502 2503 2504 2505
				nulls[i] = 'n';
			}
		}

		/************************************************************
		 * go
		 ************************************************************/
B
Bruce Momjian 已提交
2506 2507 2508
		portal = SPI_cursor_open(NULL, qdesc->plan, argvalues, nulls,
								 current_call_data->prodesc->fn_readonly);
		if (argc > 0)
A
 
Andrew Dunstan 已提交
2509
		{
B
Bruce Momjian 已提交
2510 2511
			pfree(argvalues);
			pfree(nulls);
A
 
Andrew Dunstan 已提交
2512
		}
B
Bruce Momjian 已提交
2513
		if (portal == NULL)
A
 
Andrew Dunstan 已提交
2514
			elog(ERROR, "SPI_cursor_open() failed:%s",
B
Bruce Momjian 已提交
2515
				 SPI_result_code_string(SPI_result));
A
 
Andrew Dunstan 已提交
2516

2517
		cursor = newSVstring(portal->name);
A
 
Andrew Dunstan 已提交
2518 2519 2520 2521 2522

		/* Commit the inner transaction, return to outer xact context */
		ReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;
B
Bruce Momjian 已提交
2523

A
 
Andrew Dunstan 已提交
2524
		/*
B
Bruce Momjian 已提交
2525 2526
		 * AtEOSubXact_SPI() should not have popped any SPI context, but just
		 * in case it did, make sure we remain connected.
A
 
Andrew Dunstan 已提交
2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544
		 */
		SPI_restore_connection();
	}
	PG_CATCH();
	{
		ErrorData  *edata;

		/* Save error info */
		MemoryContextSwitchTo(oldcontext);
		edata = CopyErrorData();
		FlushErrorState();

		/* Abort the inner transaction */
		RollbackAndReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;

		/*
B
Bruce Momjian 已提交
2545 2546 2547
		 * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will
		 * have left us in a disconnected state.  We need this hack to return
		 * to connected state.
A
 
Andrew Dunstan 已提交
2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564
		 */
		SPI_restore_connection();

		/* Punt the error to Perl */
		croak("%s", edata->message);

		/* Can't get here, but keep compiler quiet */
		return NULL;
	}
	PG_END_TRY();

	return cursor;
}

void
plperl_spi_freeplan(char *query)
{
B
Bruce Momjian 已提交
2565
	void	   *plan;
A
 
Andrew Dunstan 已提交
2566
	plperl_query_desc *qdesc;
2567
	plperl_query_entry *hash_entry;
A
 
Andrew Dunstan 已提交
2568

2569
	hash_entry = hash_search(plperl_query_hash, query,
B
Bruce Momjian 已提交
2570
							 HASH_FIND, NULL);
2571 2572 2573 2574
	if (hash_entry == NULL)
		elog(ERROR, "spi_exec_prepared: Invalid prepared query passed");

	qdesc = hash_entry->query_data;
A
 
Andrew Dunstan 已提交
2575

B
Bruce Momjian 已提交
2576
	if (qdesc == NULL)
A
 
Andrew Dunstan 已提交
2577 2578 2579
		elog(ERROR, "spi_exec_freeplan: panic - plperl_query_hash value vanished");

	/*
B
Bruce Momjian 已提交
2580 2581 2582
	 * free all memory before SPI_freeplan, so if it dies, nothing will be
	 * left over
	 */
2583 2584
	hash_search(plperl_query_hash, query,
				HASH_REMOVE, NULL);
2585

B
Bruce Momjian 已提交
2586 2587 2588 2589
	plan = qdesc->plan;
	free(qdesc->argtypes);
	free(qdesc->arginfuncs);
	free(qdesc->argtypioparams);
A
 
Andrew Dunstan 已提交
2590 2591
	free(qdesc);

B
Bruce Momjian 已提交
2592
	SPI_freeplan(plan);
A
 
Andrew Dunstan 已提交
2593
}
2594 2595 2596 2597 2598

/*
 * Create a new SV from a string assumed to be in the current database's
 * encoding.
 */
B
Bruce Momjian 已提交
2599
static SV  *
2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618
newSVstring(const char *str)
{
	SV		   *sv;

	sv = newSVpv(str, 0);
#if PERL_BCDVERSION >= 0x5006000L
	if (GetDatabaseEncoding() == PG_UTF8)
		SvUTF8_on(sv);
#endif
	return sv;
}

/*
 * Store an SV into a hash table under a key that is a string assumed to be
 * in the current database's encoding.
 */
static SV **
hv_store_string(HV *hv, const char *key, SV *val)
{
B
Bruce Momjian 已提交
2619
	int32		klen = strlen(key);
2620 2621

	/*
B
Bruce Momjian 已提交
2622
	 * This seems nowhere documented, but under Perl 5.8.0 and up, hv_store()
2623 2624
	 * recognizes a negative klen parameter as meaning a UTF-8 encoded key. It
	 * does not appear that hashes track UTF-8-ness of keys at all in Perl
B
Bruce Momjian 已提交
2625
	 * 5.6.
2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640
	 */
#if PERL_BCDVERSION >= 0x5008000L
	if (GetDatabaseEncoding() == PG_UTF8)
		klen = -klen;
#endif
	return hv_store(hv, key, klen, val, 0);
}

/*
 * Fetch an SV from a hash table under a key that is a string assumed to be
 * in the current database's encoding.
 */
static SV **
hv_fetch_string(HV *hv, const char *key)
{
B
Bruce Momjian 已提交
2641
	int32		klen = strlen(key);
2642 2643 2644 2645 2646 2647 2648 2649

	/* See notes in hv_store_string */
#if PERL_BCDVERSION >= 0x5008000L
	if (GetDatabaseEncoding() == PG_UTF8)
		klen = -klen;
#endif
	return hv_fetch(hv, key, klen, 0);
}