plperl.c 60.9 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.105 2006/03/11 16:43:22 momjian 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
#include "utils/lsyscache.h"
23
#include "utils/memutils.h"
24
#include "utils/typcache.h"
25
#include "miscadmin.h"
26
#include "mb/pg_wchar.h"
A
 
Andrew Dunstan 已提交
27
#include "parser/parse_type.h"
28

A
 
Andrew Dunstan 已提交
29 30 31
/* define this before the perl headers get a chance to mangle DLLIMPORT */
extern DLLIMPORT bool check_function_bodies;

32
/* perl stuff */
A
 
Andrew Dunstan 已提交
33
#include "plperl.h"
34 35 36 37 38 39 40

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

57 58 59 60 61 62 63 64 65 66 67 68 69 70
/*
 * The information we cache for the duration of a single call to a
 * function.
 */
typedef struct plperl_call_data
{
	plperl_proc_desc *prodesc;
	FunctionCallInfo  fcinfo;
	Tuplestorestate  *tuple_store;
	TupleDesc		  ret_tdesc;
	AttInMetadata	 *attinmeta;
	MemoryContext	  tmp_cxt;
} plperl_call_data;

A
 
Andrew Dunstan 已提交
71 72 73 74 75 76 77 78 79 80 81 82
/**********************************************************************
 * 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;
83 84 85 86

/**********************************************************************
 * Global data
 **********************************************************************/
87
static bool plperl_firstcall = true;
88
static bool plperl_safe_init_done = false;
89
static PerlInterpreter *plperl_interp = NULL;
90
static HV  *plperl_proc_hash = NULL;
A
 
Andrew Dunstan 已提交
91
static HV  *plperl_query_hash = NULL;
92

93 94
static bool plperl_use_strict = false;

95 96
/* this is saved and restored by plperl_call_handler */
static plperl_call_data *current_call_data = NULL;
97

98 99 100 101
/**********************************************************************
 * Forward declarations
 **********************************************************************/
static void plperl_init_all(void);
102
static void plperl_init_interp(void);
103

B
Bruce Momjian 已提交
104
Datum		plperl_call_handler(PG_FUNCTION_ARGS);
105
Datum		plperl_validator(PG_FUNCTION_ARGS);
106
void		plperl_init(void);
107

108
static Datum plperl_func_handler(PG_FUNCTION_ARGS);
109

110
static Datum plperl_trigger_handler(PG_FUNCTION_ARGS);
111 112
static plperl_proc_desc *compile_plperl_function(Oid fn_oid, bool is_trigger);

113
static SV  *plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc);
114
static void plperl_init_shared_libs(pTHX);
115
static HV  *plperl_spi_execute_fetch_result(SPITupleTable *, int, int);
116

117 118 119 120 121 122 123
/*
 * 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,
124 125 126
 * 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.
127 128 129 130
 */
static void
perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
{
131
	fmgr_info_cxt(functionId, finfo, TopMemoryContext);
132 133
}

134 135 136

/* Perform initialization during postmaster startup. */

137 138
void
plperl_init(void)
139 140 141 142
{
	if (!plperl_firstcall)
		return;

143
	DefineCustomBoolVariable(
B
Bruce Momjian 已提交
144 145 146 147 148 149
							 "plperl.use_strict",
	  "If true, will compile trusted and untrusted perl code in strict mode",
							 NULL,
							 &plperl_use_strict,
							 PGC_USERSET,
							 NULL, NULL);
150 151

	EmitWarningsOnPlaceholders("plperl");
152

153
	plperl_init_interp();
154
	plperl_firstcall = false;
155 156
}

157 158 159

/* Perform initialization during backend startup. */

160 161 162 163 164 165
static void
plperl_init_all(void)
{
	if (plperl_firstcall)
		plperl_init();

166
	/* We don't need to do anything yet when a new backend starts. */
167 168
}

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
/* 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 已提交
196
	"    elsif (defined($elem)) " \
197 198 199 200 201
	"    { " \
	"      my $str = qq($elem); " \
	"      $str =~ s/([\"\\\\])/\\\\$1/g; " \
	"      $res .= qq(\"$str\"); " \
	"    } " \
A
 
Andrew Dunstan 已提交
202 203 204 205
	"    else " \
	"    { "\
	"      $res .= 'NULL' ; " \
	"    } "\
206 207 208 209 210 211 212 213 214 215 216 217
	"  } " \
	"  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 已提交
218 219
	"&spi_query &spi_fetchrow &spi_cursor_close " \
	"&spi_prepare &spi_exec_prepared &spi_query_prepared &spi_freeplan " \
220 221 222 223 224 225 226 227 228
	"&_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 已提交
229
	"      $@ =~ s/\\(eval \\d+\\) //g if $@; return $ret; }"
230 231 232 233 234 235 236 237 238 239 240 241

#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');}]); }"

242 243

static void
244
plperl_init_interp(void)
245
{
B
Bruce Momjian 已提交
246
	static char *embedding[3] = {
247
		"", "-e", PERLBOOT
248 249
	};

A
 
Andrew Dunstan 已提交
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
#ifdef WIN32

	/* 
	 * The perl library on startup does horrible things like call
	 * 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.
	 *
	 * 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.
	 *
	 * We restore them using Perl's POSIX::setlocale() function so that
	 * Perl doesn't have a different idea of the locale from Postgres.
	 *
	 */

	char *loc;
	char *save_collate, *save_ctype, *save_monetary, *save_numeric, *save_time;
	char buf[1024];

	loc = setlocale(LC_COLLATE,NULL);
	save_collate = loc ? pstrdup(loc) : NULL;
	loc = setlocale(LC_CTYPE,NULL);
	save_ctype = loc ? pstrdup(loc) : NULL;
	loc = setlocale(LC_MONETARY,NULL);
	save_monetary = loc ? pstrdup(loc) : NULL;
	loc = setlocale(LC_NUMERIC,NULL);
	save_numeric = loc ? pstrdup(loc) : NULL;
	loc = setlocale(LC_TIME,NULL);
	save_time = loc ? pstrdup(loc) : NULL;

#endif

289 290
	plperl_interp = perl_alloc();
	if (!plperl_interp)
291
		elog(ERROR, "could not allocate Perl interpreter");
292

293
	perl_construct(plperl_interp);
294
	perl_parse(plperl_interp, plperl_init_shared_libs, 3, embedding, NULL);
295
	perl_run(plperl_interp);
296

297
	plperl_proc_hash = newHV();
A
 
Andrew Dunstan 已提交
298
	plperl_query_hash = newHV();
A
 
Andrew Dunstan 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341

#ifdef WIN32

	eval_pv("use POSIX qw(locale_h);", TRUE); /* croak on failure */

	if (save_collate != NULL)
	{
		snprintf(buf, sizeof(buf),"setlocale(%s,'%s');",
				 "LC_COLLATE",save_collate);
		eval_pv(buf,TRUE);
		pfree(save_collate);
	}
	if (save_ctype != NULL)
	{
		snprintf(buf, sizeof(buf),"setlocale(%s,'%s');",
				 "LC_CTYPE",save_ctype);
		eval_pv(buf,TRUE);
		pfree(save_ctype);
	}
	if (save_monetary != NULL)
	{
		snprintf(buf, sizeof(buf),"setlocale(%s,'%s');",
				 "LC_MONETARY",save_monetary);
		eval_pv(buf,TRUE);
		pfree(save_monetary);
	}
	if (save_numeric != NULL)
	{
		snprintf(buf, sizeof(buf),"setlocale(%s,'%s');",
				 "LC_NUMERIC",save_numeric);
		eval_pv(buf,TRUE);
		pfree(save_numeric);
	}
	if (save_time != NULL)
	{
		snprintf(buf, sizeof(buf),"setlocale(%s,'%s');",
				 "LC_TIME",save_time);
		eval_pv(buf,TRUE);
		pfree(save_time);
	}

#endif

342 343
}

344 345 346 347

static void
plperl_safe_init(void)
{
B
Bruce Momjian 已提交
348
	SV		   *res;
349
	double		safe_version;
350

351
	res = eval_pv(SAFE_MODULE, FALSE);	/* TRUE = croak if failure */
352 353 354

	safe_version = SvNV(res);

355 356 357 358 359
	/*
	 * 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 已提交
360
	if (safe_version < 2.0899)
361 362
	{
		/* not safe, so disallow all trusted funcs */
363
		eval_pv(SAFE_BAD, FALSE);
364 365 366
	}
	else
	{
367
		eval_pv(SAFE_OK, FALSE);
368
	}
369 370 371 372

	plperl_safe_init_done = true;
}

373 374 375 376 377 378
/*
 * Perl likes to put a newline after its error messages; clean up such
 */
static char *
strip_trailing_ws(const char *msg)
{
B
Bruce Momjian 已提交
379 380
	char	   *res = pstrdup(msg);
	int			len = strlen(res);
381

B
Bruce Momjian 已提交
382
	while (len > 0 && isspace((unsigned char) res[len - 1]))
383 384 385 386 387
		res[--len] = '\0';
	return res;
}


388 389
/* Build a tuple from a hash. */

390
static HeapTuple
391
plperl_build_tuple_result(HV *perlhash, AttInMetadata *attinmeta)
392
{
393 394 395 396 397 398
	TupleDesc	td = attinmeta->tupdesc;
	char	  **values;
	SV		   *val;
	char	   *key;
	I32			klen;
	HeapTuple	tup;
399

400
	values = (char **) palloc0(td->natts * sizeof(char *));
401

402 403 404
	hv_iterinit(perlhash);
	while ((val = hv_iternextsv(perlhash, &key, &klen)))
	{
B
Bruce Momjian 已提交
405
		int			attn = SPI_fnumber(td, key);
406

407
		if (attn <= 0 || td->attrs[attn - 1]->attisdropped)
408 409 410 411
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_COLUMN),
					 errmsg("Perl hash contains nonexistent column \"%s\"",
							key)));
412
		if (SvOK(val) && SvTYPE(val) != SVt_NULL)
413
			values[attn - 1] = SvPV(val, PL_na);
414
	}
415 416 417 418 419
	hv_iterinit(perlhash);

	tup = BuildTupleFromCStrings(attinmeta, values);
	pfree(values);
	return tup;
420 421
}

422 423 424
/*
 * convert perl array to postgres string representation
 */
B
Bruce Momjian 已提交
425
static SV  *
426
plperl_convert_to_pg_array(SV *src)
427
{
B
Bruce Momjian 已提交
428 429 430 431
	SV		   *rv;
	int			count;

	dSP;
432

B
Bruce Momjian 已提交
433
	PUSHMARK(SP);
434
	XPUSHs(src);
B
Bruce Momjian 已提交
435
	PUTBACK;
436

437
	count = call_pv("::_plperl_to_pg_array", G_SCALAR);
438

B
Bruce Momjian 已提交
439
	SPAGAIN;
440 441

	if (count != 1)
442
		elog(ERROR, "unexpected _plperl_to_pg_array failure");
443 444 445

	rv = POPs;

B
Bruce Momjian 已提交
446 447 448
	PUTBACK;

	return rv;
449 450
}

451

452 453
/* Set up the arguments for a trigger call. */

454 455 456 457 458
static SV  *
plperl_trigger_build_args(FunctionCallInfo fcinfo)
{
	TriggerData *tdata;
	TupleDesc	tupdesc;
459
	int			i;
460 461 462 463 464
	char	   *level;
	char	   *event;
	char	   *relid;
	char	   *when;
	HV		   *hv;
465

466
	hv = newHV();
467 468 469 470

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

471
	relid = DatumGetCString(
B
Bruce Momjian 已提交
472 473 474 475
							DirectFunctionCall1(oidout,
								  ObjectIdGetDatum(tdata->tg_relation->rd_id)
												)
		);
476 477 478

	hv_store(hv, "name", 4, newSVpv(tdata->tg_trigger->tgname, 0), 0);
	hv_store(hv, "relid", 5, newSVpv(relid, 0), 0);
479 480 481

	if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
	{
482
		event = "INSERT";
483 484 485 486
		if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
			hv_store(hv, "new", 3,
					 plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc),
					 0);
487 488 489
	}
	else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
	{
490
		event = "DELETE";
491 492 493 494
		if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
			hv_store(hv, "old", 3,
					 plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc),
					 0);
495 496 497
	}
	else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
	{
498
		event = "UPDATE";
499 500 501 502 503 504 505 506 507
		if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
		{
			hv_store(hv, "old", 3,
					 plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc),
					 0);
			hv_store(hv, "new", 3,
					 plperl_hash_from_tuple(tdata->tg_newtuple, tupdesc),
					 0);
		}
508
	}
509
	else
510
		event = "UNKNOWN";
511

512 513
	hv_store(hv, "event", 5, newSVpv(event, 0), 0);
	hv_store(hv, "argc", 4, newSViv(tdata->tg_trigger->tgnargs), 0);
514

515
	if (tdata->tg_trigger->tgnargs > 0)
516
	{
B
Bruce Momjian 已提交
517 518 519
		AV		   *av = newAV();

		for (i = 0; i < tdata->tg_trigger->tgnargs; i++)
520
			av_push(av, newSVpv(tdata->tg_trigger->tgargs[i], 0));
B
Bruce Momjian 已提交
521
		hv_store(hv, "args", 4, newRV_noinc((SV *) av), 0);
522
	}
523 524 525

	hv_store(hv, "relname", 7,
			 newSVpv(SPI_getrelname(tdata->tg_relation), 0), 0);
526 527

	if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
528
		when = "BEFORE";
529
	else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
530
		when = "AFTER";
531
	else
532 533
		when = "UNKNOWN";
	hv_store(hv, "when", 4, newSVpv(when, 0), 0);
534 535

	if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
536
		level = "ROW";
537
	else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
538
		level = "STATEMENT";
539
	else
540 541
		level = "UNKNOWN";
	hv_store(hv, "level", 5, newSVpv(level, 0), 0);
542

B
Bruce Momjian 已提交
543
	return newRV_noinc((SV *) hv);
544 545 546
}


547
/* Set up the new tuple returned from a trigger. */
548

549
static HeapTuple
550
plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup)
551 552 553 554
{
	SV		  **svp;
	HV		   *hvNew;
	HeapTuple	rtup;
555 556 557 558 559 560 561 562
	SV		   *val;
	char	   *key;
	I32			klen;
	int			slotsused;
	int		   *modattrs;
	Datum	   *modvalues;
	char	   *modnulls;

563 564 565 566 567
	TupleDesc	tupdesc;

	tupdesc = tdata->tg_relation->rd_att;

	svp = hv_fetch(hvTD, "new", 3, FALSE);
568
	if (!svp)
569 570 571
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_COLUMN),
				 errmsg("$_TD->{new} does not exist")));
572
	if (!SvOK(*svp) || SvTYPE(*svp) != SVt_RV || SvTYPE(SvRV(*svp)) != SVt_PVHV)
573 574 575
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("$_TD->{new} is not a hash reference")));
576 577
	hvNew = (HV *) SvRV(*svp);

578 579 580 581
	modattrs = palloc(tupdesc->natts * sizeof(int));
	modvalues = palloc(tupdesc->natts * sizeof(Datum));
	modnulls = palloc(tupdesc->natts * sizeof(char));
	slotsused = 0;
582

583 584
	hv_iterinit(hvNew);
	while ((val = hv_iternextsv(hvNew, &key, &klen)))
585
	{
586
		int			attn = SPI_fnumber(tupdesc, key);
587

588
		if (attn <= 0 || tupdesc->attrs[attn - 1]->attisdropped)
589 590 591 592
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_COLUMN),
					 errmsg("Perl hash contains nonexistent column \"%s\"",
							key)));
593
		if (SvOK(val) && SvTYPE(val) != SVt_NULL)
594
		{
595 596 597 598 599 600 601 602 603
			Oid			typinput;
			Oid			typioparam;
			FmgrInfo	finfo;

			/* XXX would be better to cache these lookups */
			getTypeInputInfo(tupdesc->attrs[attn - 1]->atttypid,
							 &typinput, &typioparam);
			fmgr_info(typinput, &finfo);
			modvalues[slotsused] = FunctionCall3(&finfo,
B
Bruce Momjian 已提交
604 605
										   CStringGetDatum(SvPV(val, PL_na)),
												 ObjectIdGetDatum(typioparam),
606 607
						 Int32GetDatum(tupdesc->attrs[attn - 1]->atttypmod));
			modnulls[slotsused] = ' ';
608 609 610
		}
		else
		{
611 612
			modvalues[slotsused] = (Datum) 0;
			modnulls[slotsused] = 'n';
613
		}
614 615
		modattrs[slotsused] = attn;
		slotsused++;
616
	}
617 618 619 620
	hv_iterinit(hvNew);

	rtup = SPI_modifytuple(tdata->tg_relation, otup, slotsused,
						   modattrs, modvalues, modnulls);
621 622 623 624

	pfree(modattrs);
	pfree(modvalues);
	pfree(modnulls);
625

626
	if (rtup == NULL)
627
		elog(ERROR, "SPI_modifytuple failed: %s",
628
			 SPI_result_code_string(SPI_result));
629 630 631

	return rtup;
}
632

633

634 635
/*
 * This is the only externally-visible part of the plperl call interface.
636
 * The Postgres function and trigger managers call it to execute a
637 638
 * perl function.
 */
639
PG_FUNCTION_INFO_V1(plperl_call_handler);
640 641

Datum
642
plperl_call_handler(PG_FUNCTION_ARGS)
643
{
B
Bruce Momjian 已提交
644
	Datum		retval;
645
	plperl_call_data *save_call_data;
646

647
	plperl_init_all();
648

649
	save_call_data = current_call_data;
650 651 652 653 654 655 656 657 658
	PG_TRY();
	{
		if (CALLED_AS_TRIGGER(fcinfo))
			retval = PointerGetDatum(plperl_trigger_handler(fcinfo));
		else
			retval = plperl_func_handler(fcinfo);
	}
	PG_CATCH();
	{
659
		current_call_data = save_call_data;
660 661 662 663
		PG_RE_THROW();
	}
	PG_END_TRY();

664
	current_call_data = save_call_data;
665 666 667
	return retval;
}

668 669 670 671 672 673 674 675 676 677 678 679
/*
 * 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;
680 681 682 683 684
	char		functyptype;
	int			numargs;
	Oid		   *argtypes;
	char	  **argnames;
	char	   *argmodes;
685
	bool		istrigger = false;
686
	int			i;
687 688 689 690 691 692 693 694 695

	/* 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);

696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
	functyptype = get_typtype(proc->prorettype);

	/* Disallow pseudotype result */
	/* except for TRIGGER, RECORD, or VOID */
	if (functyptype == 'p')
	{
		/* 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))));
	}

	/* Disallow pseudotypes in arguments (either IN or OUT) */
	numargs = get_func_arg_info(tuple,
								&argtypes, &argnames, &argmodes);
	for (i = 0; i < numargs; i++)
	{
		if (get_typtype(argtypes[i]) == 'p')
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("plperl functions cannot take type %s",
							format_type_be(argtypes[i]))));
	}
725 726 727

	ReleaseSysCache(tuple);

728 729 730 731 732 733 734 735 736
	/* Postpone body checks if !check_function_bodies */
	if (check_function_bodies)
	{
		plperl_proc_desc *prodesc;

		plperl_init_all();

		prodesc = compile_plperl_function(funcoid, istrigger);
	}
737 738 739 740 741

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

742

743 744 745
/* Uses mksafefunc/mkunsafefunc to create an anonymous sub whose text is
 * supplied in s, and returns a reference to the closure. */

B
Bruce Momjian 已提交
746
static SV  *
747
plperl_create_sub(char *s, bool trusted)
748
{
749
	dSP;
750
	SV		   *subref;
B
Bruce Momjian 已提交
751
	int			count;
B
Bruce Momjian 已提交
752
	char	   *compile_sub;
753

B
Bruce Momjian 已提交
754
	if (trusted && !plperl_safe_init_done)
755
	{
756
		plperl_safe_init();
757 758
		SPAGAIN;
	}
759

760 761 762
	ENTER;
	SAVETMPS;
	PUSHMARK(SP);
763
	XPUSHs(sv_2mortal(newSVpv("my $_TD=$_[0]; shift;", 0)));
B
Bruce Momjian 已提交
764
	XPUSHs(sv_2mortal(newSVpv(s, 0)));
B
Bruce Momjian 已提交
765
	PUTBACK;
B
Bruce Momjian 已提交
766

767 768
	/*
	 * G_KEEPERR seems to be needed here, else we don't recognize compile
B
Bruce Momjian 已提交
769 770
	 * errors properly.  Perhaps it's because there's another level of eval
	 * inside mksafefunc?
771
	 */
772 773 774 775 776 777 778 779 780 781 782

	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);
783 784
	SPAGAIN;

785 786 787 788 789
	if (count != 1)
	{
		PUTBACK;
		FREETMPS;
		LEAVE;
790
		elog(ERROR, "didn't get a return item from mksafefunc");
791 792
	}

793
	if (SvTRUE(ERRSV))
794
	{
795
		(void) POPs;
796 797 798
		PUTBACK;
		FREETMPS;
		LEAVE;
799 800 801 802
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("creation of Perl function failed: %s",
						strip_trailing_ws(SvPV(ERRSV, PL_na)))));
803 804 805
	}

	/*
806 807
	 * need to make a deep copy of the return. it comes off the stack as a
	 * temporary.
808 809 810
	 */
	subref = newSVsv(POPs);

811
	if (!SvROK(subref) || SvTYPE(SvRV(subref)) != SVt_PVCV)
812
	{
813 814 815
		PUTBACK;
		FREETMPS;
		LEAVE;
816

817 818 819 820
		/*
		 * subref is our responsibility because it is not mortal
		 */
		SvREFCNT_dec(subref);
821
		elog(ERROR, "didn't get a code ref");
822 823 824 825 826
	}

	PUTBACK;
	FREETMPS;
	LEAVE;
827

828 829 830
	return subref;
}

831

832
/**********************************************************************
833
 * plperl_init_shared_libs()		-
834 835 836 837
 *
 * 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.
838
 *
839 840
 **********************************************************************/

841 842
EXTERN_C void boot_DynaLoader(pTHX_ CV *cv);
EXTERN_C void boot_SPI(pTHX_ CV *cv);
843

844
static void
845
plperl_init_shared_libs(pTHX)
846
{
847 848
	char	   *file = __FILE__;

849
	newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
850
	newXS("SPI::bootstrap", boot_SPI, file);
851 852
}

853

B
Bruce Momjian 已提交
854
static SV  *
855
plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
856 857
{
	dSP;
858 859 860
	SV		   *retval;
	int			i;
	int			count;
B
Bruce Momjian 已提交
861
	SV		   *sv;
862 863 864 865

	ENTER;
	SAVETMPS;

866
	PUSHMARK(SP);
867

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

870 871
	for (i = 0; i < desc->nargs; i++)
	{
872 873 874
		if (fcinfo->argnull[i])
			XPUSHs(&PL_sv_undef);
		else if (desc->arg_is_rowtype[i])
875
		{
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
			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;

892 893
			hashref = plperl_hash_from_tuple(&tmptup, tupdesc);
			XPUSHs(sv_2mortal(hashref));
894 895 896
		}
		else
		{
897 898
			char	   *tmp;

899 900
			tmp = DatumGetCString(FunctionCall1(&(desc->arg_out_func[i]),
												fcinfo->arg[i]));
901 902
			sv = newSVpv(tmp, 0);
#if PERL_BCDVERSION >= 0x5006000L
B
Bruce Momjian 已提交
903 904
			if (GetDatabaseEncoding() == PG_UTF8)
				SvUTF8_on(sv);
905 906
#endif
			XPUSHs(sv_2mortal(sv));
907
			pfree(tmp);
908 909 910
		}
	}
	PUTBACK;
911 912 913

	/* Do NOT use G_KEEPERR here */
	count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL);
914 915 916

	SPAGAIN;

917 918 919 920
	if (count != 1)
	{
		PUTBACK;
		FREETMPS;
921
		LEAVE;
922
		elog(ERROR, "didn't get a return item from function");
923 924
	}

925
	if (SvTRUE(ERRSV))
926
	{
927
		(void) POPs;
928 929
		PUTBACK;
		FREETMPS;
930
		LEAVE;
931 932 933 934
		/* XXX need to find a way to assign an errcode here */
		ereport(ERROR,
				(errmsg("error from Perl function: %s",
						strip_trailing_ws(SvPV(ERRSV, PL_na)))));
935 936 937 938
	}

	retval = newSVsv(POPs);

939 940 941
	PUTBACK;
	FREETMPS;
	LEAVE;
942 943 944 945

	return retval;
}

946

947
static SV  *
948 949
plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo,
							  SV *td)
950 951 952
{
	dSP;
	SV		   *retval;
953
	Trigger    *tg_trigger;
954 955 956 957 958 959 960
	int			i;
	int			count;

	ENTER;
	SAVETMPS;

	PUSHMARK(sp);
961

962
	XPUSHs(td);
963

964 965 966
	tg_trigger = ((TriggerData *) fcinfo->context)->tg_trigger;
	for (i = 0; i < tg_trigger->tgnargs; i++)
		XPUSHs(sv_2mortal(newSVpv(tg_trigger->tgargs[i], 0)));
967 968
	PUTBACK;

969 970
	/* Do NOT use G_KEEPERR here */
	count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL);
971 972 973 974 975 976 977 978

	SPAGAIN;

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

	if (SvTRUE(ERRSV))
	{
984
		(void) POPs;
985 986 987
		PUTBACK;
		FREETMPS;
		LEAVE;
988 989 990 991
		/* XXX need to find a way to assign an errcode here */
		ereport(ERROR,
				(errmsg("error from Perl trigger function: %s",
						strip_trailing_ws(SvPV(ERRSV, PL_na)))));
992 993 994 995 996 997 998 999 1000 1001
	}

	retval = newSVsv(POPs);

	PUTBACK;
	FREETMPS;
	LEAVE;

	return retval;
}
1002

1003

1004
static Datum
1005
plperl_func_handler(PG_FUNCTION_ARGS)
1006 1007
{
	plperl_proc_desc *prodesc;
1008 1009
	SV		   *perlret;
	Datum		retval;
1010
	ReturnSetInfo *rsi;
B
Bruce Momjian 已提交
1011
	SV		   *array_ret = NULL;
1012

1013 1014 1015 1016 1017 1018 1019
	/*
	 * Create the call_data beforing connecting to SPI, so that it is
	 * not allocated in the SPI memory context
	 */
	current_call_data = (plperl_call_data *) palloc0(sizeof(plperl_call_data));
	current_call_data->fcinfo = fcinfo;

1020 1021 1022
	if (SPI_connect() != SPI_OK_CONNECT)
		elog(ERROR, "could not connect to SPI manager");

1023
	prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, false);
1024
	current_call_data->prodesc = prodesc;
1025

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

T
Tom Lane 已提交
1028
	if (prodesc->fn_retisset)
1029
	{
T
Tom Lane 已提交
1030 1031 1032 1033 1034 1035 1036 1037
		/* 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")));
1038 1039
	}

1040
	perlret = plperl_call_perl_func(prodesc, fcinfo);
1041 1042 1043 1044 1045 1046 1047 1048

	/************************************************************
	 * 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)
1049
		elog(ERROR, "SPI_finish() failed");
1050

T
Tom Lane 已提交
1051
	if (prodesc->fn_retisset)
1052
	{
T
Tom Lane 已提交
1053 1054
		/*
		 * If the Perl function returned an arrayref, we pretend that it
B
Bruce Momjian 已提交
1055 1056 1057
		 * 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
		 * value is an error.
T
Tom Lane 已提交
1058
		 */
1059 1060
		if (SvTYPE(perlret) == SVt_RV &&
			SvTYPE(SvRV(perlret)) == SVt_PVAV)
1061
		{
B
Bruce Momjian 已提交
1062 1063 1064 1065 1066
			int			i = 0;
			SV		  **svp = 0;
			AV		   *rav = (AV *) SvRV(perlret);

			while ((svp = av_fetch(rav, i, FALSE)) != NULL)
1067
			{
1068 1069 1070
				plperl_return_next(*svp);
				i++;
			}
1071
		}
1072
		else if (SvTYPE(perlret) != SVt_NULL)
1073
		{
1074 1075
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
1076 1077
					 errmsg("set-returning Perl function must return "
							"reference to array or use return_next")));
1078
		}
B
Bruce Momjian 已提交
1079

1080
		rsi->returnMode = SFRM_Materialize;
1081
		if (current_call_data->tuple_store)
1082
		{
1083 1084
			rsi->setResult = current_call_data->tuple_store;
			rsi->setDesc = current_call_data->ret_tdesc;
1085
		}
B
Bruce Momjian 已提交
1086
		retval = (Datum) 0;
1087 1088 1089 1090 1091 1092 1093
	}
	else if (SvTYPE(perlret) == SVt_NULL)
	{
		/* Return NULL if Perl code returned undef */
		if (rsi && IsA(rsi, ReturnSetInfo))
			rsi->isDone = ExprEndResult;
		fcinfo->isnull = true;
B
Bruce Momjian 已提交
1094
		retval = (Datum) 0;
B
Bruce Momjian 已提交
1095
	}
1096
	else if (prodesc->fn_retistuple)
1097
	{
1098
		/* Return a perl hash converted to a Datum */
B
Bruce Momjian 已提交
1099
		TupleDesc	td;
1100
		AttInMetadata *attinmeta;
B
Bruce Momjian 已提交
1101
		HeapTuple	tup;
1102

1103 1104 1105
		if (!SvOK(perlret) || SvTYPE(perlret) != SVt_RV ||
			SvTYPE(SvRV(perlret)) != SVt_PVHV)
		{
1106 1107
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
1108 1109 1110
					 errmsg("composite-returning Perl function "
							"must return reference to hash")));
		}
1111

1112 1113 1114 1115 1116 1117 1118 1119
		/* 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")));
		}
1120

1121
		attinmeta = TupleDescGetAttInMetadata(td);
B
Bruce Momjian 已提交
1122
		tup = plperl_build_tuple_result((HV *) SvRV(perlret), attinmeta);
1123 1124 1125 1126
		retval = HeapTupleGetDatum(tup);
	}
	else
	{
B
Bruce Momjian 已提交
1127 1128 1129 1130
		/* Return a perl string converted to a Datum */
		char	   *val;

		if (prodesc->fn_retisarray && SvROK(perlret) &&
1131
			SvTYPE(SvRV(perlret)) == SVt_PVAV)
B
Bruce Momjian 已提交
1132 1133 1134 1135 1136
		{
			array_ret = plperl_convert_to_pg_array(perlret);
			SvREFCNT_dec(perlret);
			perlret = array_ret;
		}
1137 1138 1139

		val = SvPV(perlret, PL_na);

1140 1141 1142 1143
		retval = FunctionCall3(&prodesc->result_in_func,
							   CStringGetDatum(val),
							   ObjectIdGetDatum(prodesc->result_typioparam),
							   Int32GetDatum(-1));
1144
	}
1145

1146
	if (array_ret == NULL)
B
Bruce Momjian 已提交
1147
		SvREFCNT_dec(perlret);
1148

1149
	current_call_data = NULL;
1150 1151 1152
	return retval;
}

1153

1154 1155 1156 1157 1158 1159 1160 1161 1162
static Datum
plperl_trigger_handler(PG_FUNCTION_ARGS)
{
	plperl_proc_desc *prodesc;
	SV		   *perlret;
	Datum		retval;
	SV		   *svTD;
	HV		   *hvTD;

1163 1164 1165 1166 1167 1168 1169
	/*
	 * Create the call_data beforing connecting to SPI, so that it is
	 * not allocated in the SPI memory context
	 */
	current_call_data = (plperl_call_data *) palloc0(sizeof(plperl_call_data));
	current_call_data->fcinfo = fcinfo;

1170 1171 1172 1173
	/* Connect to SPI manager */
	if (SPI_connect() != SPI_OK_CONNECT)
		elog(ERROR, "could not connect to SPI manager");

1174 1175
	/* Find or compile the function */
	prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, true);
1176
	current_call_data->prodesc = prodesc;
1177

1178 1179
	svTD = plperl_trigger_build_args(fcinfo);
	perlret = plperl_call_perl_trigger_func(prodesc, fcinfo, svTD);
1180
	hvTD = (HV *) SvRV(svTD);
1181 1182 1183 1184 1185 1186 1187 1188

	/************************************************************
	* 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)
1189
		elog(ERROR, "SPI_finish() failed");
1190

1191
	if (!(perlret && SvOK(perlret) && SvTYPE(perlret) != SVt_NULL))
1192
	{
1193
		/* undef result means go ahead with original tuple */
1194 1195 1196 1197 1198 1199 1200 1201
		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;
1202
		else
B
Bruce Momjian 已提交
1203
			retval = (Datum) 0; /* can this happen? */
1204 1205 1206
	}
	else
	{
1207 1208
		HeapTuple	trv;
		char	   *tmp;
1209

1210
		tmp = SvPV(perlret, PL_na);
1211

1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
		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);
1224 1225
			else
			{
1226 1227
				ereport(WARNING,
						(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
B
Bruce Momjian 已提交
1228
					   errmsg("ignoring modified tuple in DELETE trigger")));
1229 1230 1231
				trv = NULL;
			}
		}
1232
		else
1233
		{
1234 1235
			ereport(ERROR,
					(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1236 1237
					 errmsg("result of Perl trigger function must be undef, "
							"\"SKIP\" or \"MODIFY\"")));
1238 1239 1240
			trv = NULL;
		}
		retval = PointerGetDatum(trv);
1241 1242
	}

1243 1244 1245
	SvREFCNT_dec(svTD);
	if (perlret)
		SvREFCNT_dec(perlret);
1246

1247
	current_call_data = NULL;
1248 1249
	return retval;
}
1250

1251

1252 1253
static plperl_proc_desc *
compile_plperl_function(Oid fn_oid, bool is_trigger)
1254
{
1255 1256 1257 1258 1259
	HeapTuple	procTup;
	Form_pg_proc procStruct;
	char		internal_proname[64];
	int			proname_len;
	plperl_proc_desc *prodesc = NULL;
1260
	int			i;
B
Bruce Momjian 已提交
1261
	SV		  **svp;
1262

1263 1264 1265 1266 1267
	/* We'll need the pg_proc tuple in any case... */
	procTup = SearchSysCache(PROCOID,
							 ObjectIdGetDatum(fn_oid),
							 0, 0, 0);
	if (!HeapTupleIsValid(procTup))
1268
		elog(ERROR, "cache lookup failed for function %u", fn_oid);
1269
	procStruct = (Form_pg_proc) GETSTRUCT(procTup);
1270 1271

	/************************************************************
1272
	 * Build our internal proc name from the function's Oid
1273
	 ************************************************************/
1274 1275 1276 1277
	if (!is_trigger)
		sprintf(internal_proname, "__PLPerl_proc_%u", fn_oid);
	else
		sprintf(internal_proname, "__PLPerl_proc_%u_trigger", fn_oid);
1278

1279
	proname_len = strlen(internal_proname);
1280 1281 1282 1283

	/************************************************************
	 * Lookup the internal proc name in the hashtable
	 ************************************************************/
1284 1285
	svp = hv_fetch(plperl_proc_hash, internal_proname, proname_len, FALSE);
	if (svp)
1286
	{
1287 1288
		bool		uptodate;

A
 
Andrew Dunstan 已提交
1289
		prodesc = INT2PTR( plperl_proc_desc *, SvUV(*svp));
1290

1291
		/************************************************************
1292 1293 1294
		 * 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.
1295
		 ************************************************************/
1296
		uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
B
Bruce Momjian 已提交
1297
				prodesc->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data));
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307

		if (!uptodate)
		{
			/* need we delete old entry? */
			prodesc = NULL;
		}
	}

	/************************************************************
	 * If we haven't found it in the hashtable, we analyze
1308
	 * the function's arguments and return type and store
1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
	 * 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;
1320 1321
		Datum		prosrcdatum;
		bool		isnull;
1322 1323 1324 1325 1326 1327
		char	   *proc_source;

		/************************************************************
		 * Allocate a new procedure description block
		 ************************************************************/
		prodesc = (plperl_proc_desc *) malloc(sizeof(plperl_proc_desc));
1328
		if (prodesc == NULL)
1329 1330 1331
			ereport(ERROR,
					(errcode(ERRCODE_OUT_OF_MEMORY),
					 errmsg("out of memory")));
1332 1333
		MemSet(prodesc, 0, sizeof(plperl_proc_desc));
		prodesc->proname = strdup(internal_proname);
1334 1335
		prodesc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
		prodesc->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);
1336

1337 1338 1339 1340
		/* Remember if function is STABLE/IMMUTABLE */
		prodesc->fn_readonly =
			(procStruct->provolatile != PROVOLATILE_VOLATILE);

1341
		/************************************************************
1342
		 * Lookup the pg_language tuple by Oid
1343
		 ************************************************************/
1344 1345
		langTup = SearchSysCache(LANGOID,
								 ObjectIdGetDatum(procStruct->prolang),
1346
								 0, 0, 0);
1347
		if (!HeapTupleIsValid(langTup))
1348 1349 1350
		{
			free(prodesc->proname);
			free(prodesc);
1351
			elog(ERROR, "cache lookup failed for language %u",
1352
				 procStruct->prolang);
1353
		}
1354 1355 1356
		langStruct = (Form_pg_language) GETSTRUCT(langTup);
		prodesc->lanpltrusted = langStruct->lanpltrusted;
		ReleaseSysCache(langTup);
1357 1358

		/************************************************************
1359 1360
		 * Get the required information for input conversion of the
		 * return value.
1361
		 ************************************************************/
1362 1363 1364
		if (!is_trigger)
		{
			typeTup = SearchSysCache(TYPEOID,
B
Bruce Momjian 已提交
1365
									 ObjectIdGetDatum(procStruct->prorettype),
1366 1367 1368 1369 1370
									 0, 0, 0);
			if (!HeapTupleIsValid(typeTup))
			{
				free(prodesc->proname);
				free(prodesc);
1371
				elog(ERROR, "cache lookup failed for type %u",
1372
					 procStruct->prorettype);
1373 1374 1375
			}
			typeStruct = (Form_pg_type) GETSTRUCT(typeTup);

1376
			/* Disallow pseudotype result, except VOID or RECORD */
1377 1378
			if (typeStruct->typtype == 'p')
			{
1379 1380
				if (procStruct->prorettype == VOIDOID ||
					procStruct->prorettype == RECORDOID)
B
Bruce Momjian 已提交
1381
					 /* okay */ ;
1382
				else if (procStruct->prorettype == TRIGGEROID)
1383 1384 1385
				{
					free(prodesc->proname);
					free(prodesc);
1386 1387
					ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1388 1389
							 errmsg("trigger functions may only be called "
									"as triggers")));
1390 1391 1392 1393 1394
				}
				else
				{
					free(prodesc->proname);
					free(prodesc);
1395 1396
					ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
B
Bruce Momjian 已提交
1397 1398
							 errmsg("plperl functions cannot return type %s",
									format_type_be(procStruct->prorettype))));
1399 1400 1401
				}
			}

1402 1403 1404 1405
			prodesc->result_oid = procStruct->prorettype;
			prodesc->fn_retisset = procStruct->proretset;
			prodesc->fn_retistuple = (typeStruct->typtype == 'c' ||
									  procStruct->prorettype == RECORDOID);
1406

B
Bruce Momjian 已提交
1407 1408
			prodesc->fn_retisarray =
				(typeStruct->typlen == -1 && typeStruct->typelem);
1409

1410
			perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
1411
			prodesc->result_typioparam = getTypeIOParam(typeTup);
1412 1413 1414

			ReleaseSysCache(typeTup);
		}
1415 1416

		/************************************************************
1417 1418
		 * Get the required information for output conversion
		 * of all procedure arguments
1419
		 ************************************************************/
1420 1421 1422 1423 1424 1425
		if (!is_trigger)
		{
			prodesc->nargs = procStruct->pronargs;
			for (i = 0; i < prodesc->nargs; i++)
			{
				typeTup = SearchSysCache(TYPEOID,
B
Bruce Momjian 已提交
1426
						 ObjectIdGetDatum(procStruct->proargtypes.values[i]),
1427 1428 1429 1430 1431
										 0, 0, 0);
				if (!HeapTupleIsValid(typeTup))
				{
					free(prodesc->proname);
					free(prodesc);
1432
					elog(ERROR, "cache lookup failed for type %u",
1433
						 procStruct->proargtypes.values[i]);
1434 1435 1436
				}
				typeStruct = (Form_pg_type) GETSTRUCT(typeTup);

1437 1438 1439 1440 1441
				/* Disallow pseudotype argument */
				if (typeStruct->typtype == 'p')
				{
					free(prodesc->proname);
					free(prodesc);
1442 1443
					ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
B
Bruce Momjian 已提交
1444 1445
							 errmsg("plperl functions cannot take type %s",
						format_type_be(procStruct->proargtypes.values[i]))));
1446 1447
				}

1448 1449
				if (typeStruct->typtype == 'c')
					prodesc->arg_is_rowtype[i] = true;
1450
				else
1451 1452 1453 1454 1455
				{
					prodesc->arg_is_rowtype[i] = false;
					perm_fmgr_info(typeStruct->typoutput,
								   &(prodesc->arg_out_func[i]));
				}
1456 1457 1458 1459

				ReleaseSysCache(typeTup);
			}
		}
1460

1461 1462 1463 1464 1465
		/************************************************************
		 * create the text of the anonymous subroutine.
		 * we do not use a named subroutine so that we can call directly
		 * through the reference.
		 ************************************************************/
1466 1467 1468 1469
		prosrcdatum = SysCacheGetAttr(PROCOID, procTup,
									  Anum_pg_proc_prosrc, &isnull);
		if (isnull)
			elog(ERROR, "null prosrc");
1470
		proc_source = DatumGetCString(DirectFunctionCall1(textout,
1471
														  prosrcdatum));
1472 1473

		/************************************************************
1474
		 * Create the procedure in the interpreter
1475
		 ************************************************************/
1476 1477
		prodesc->reference = plperl_create_sub(proc_source, prodesc->lanpltrusted);
		pfree(proc_source);
B
Bruce Momjian 已提交
1478
		if (!prodesc->reference)	/* can this happen? */
1479 1480 1481
		{
			free(prodesc->proname);
			free(prodesc);
1482
			elog(ERROR, "could not create internal procedure \"%s\"",
1483
				 internal_proname);
1484 1485
		}

1486
		hv_store(plperl_proc_hash, internal_proname, proname_len,
A
 
Andrew Dunstan 已提交
1487
				 newSVuv( PTR2UV( prodesc)), 0);
1488 1489
	}

1490
	ReleaseSysCache(procTup);
1491

1492 1493
	return prodesc;
}
1494 1495


1496 1497
/* Build a hash from all attributes of a given tuple. */

B
Bruce Momjian 已提交
1498
static SV  *
1499
plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc)
1500
{
1501
	HV		   *hv;
1502
	int			i;
1503

1504
	hv = newHV();
1505 1506 1507

	for (i = 0; i < tupdesc->natts; i++)
	{
1508 1509 1510 1511 1512 1513 1514
		Datum		attr;
		bool		isnull;
		char	   *attname;
		char	   *outputstr;
		Oid			typoutput;
		bool		typisvarlena;
		int			namelen;
B
Bruce Momjian 已提交
1515
		SV		   *sv;
1516

1517 1518 1519
		if (tupdesc->attrs[i]->attisdropped)
			continue;

1520
		attname = NameStr(tupdesc->attrs[i]->attname);
1521
		namelen = strlen(attname);
1522 1523
		attr = heap_getattr(tuple, i + 1, tupdesc, &isnull);

B
Bruce Momjian 已提交
1524 1525
		if (isnull)
		{
1526 1527
			/* Store (attname => undef) and move on. */
			hv_store(hv, attname, namelen, newSV(0), 0);
1528 1529 1530
			continue;
		}

1531
		/* XXX should have a way to cache these lookups */
1532

1533
		getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
1534
						  &typoutput, &typisvarlena);
1535

1536
		outputstr = DatumGetCString(OidFunctionCall1(typoutput, attr));
1537

1538 1539
		sv = newSVpv(outputstr, 0);
#if PERL_BCDVERSION >= 0x5006000L
1540 1541
		if (GetDatabaseEncoding() == PG_UTF8)
			SvUTF8_on(sv);
1542 1543
#endif
		hv_store(hv, attname, namelen, sv, 0);
1544 1545

		pfree(outputstr);
1546
	}
1547

1548
	return newRV_noinc((SV *) hv);
1549
}
1550 1551 1552 1553 1554 1555 1556


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

1557
	/*
B
Bruce Momjian 已提交
1558 1559
	 * Execute the query inside a sub-transaction, so we can cope with errors
	 * sanely
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571
	 */
	MemoryContext oldcontext = CurrentMemoryContext;
	ResourceOwner oldowner = CurrentResourceOwner;

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

	PG_TRY();
	{
		int			spi_rv;

1572
		spi_rv = SPI_execute(query, current_call_data->prodesc->fn_readonly,
1573 1574 1575 1576 1577 1578 1579 1580
							 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 已提交
1581

1582
		/*
B
Bruce Momjian 已提交
1583 1584
		 * AtEOSubXact_SPI() should not have popped any SPI context, but just
		 * in case it did, make sure we remain connected.
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602
		 */
		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 已提交
1603 1604 1605
		 * 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.
1606 1607 1608 1609 1610 1611 1612 1613 1614 1615
		 */
		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();
1616 1617 1618 1619

	return ret_hv;
}

1620

1621
static HV  *
1622 1623
plperl_spi_execute_fetch_result(SPITupleTable *tuptable, int processed,
								int status)
1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635
{
	HV		   *result;

	result = newHV();

	hv_store(result, "status", strlen("status"),
			 newSVpv((char *) SPI_result_code_string(status), 0), 0);
	hv_store(result, "processed", strlen("processed"),
			 newSViv(processed), 0);

	if (status == SPI_OK_SELECT)
	{
1636
		AV		   *rows;
1637
		SV		   *row;
1638
		int			i;
1639

1640 1641 1642 1643
		rows = newAV();
		for (i = 0; i < processed; i++)
		{
			row = plperl_hash_from_tuple(tuptable->vals[i], tuptable->tupdesc);
1644
			av_push(rows, row);
1645
		}
1646 1647
		hv_store(result, "rows", strlen("rows"),
				 newRV_noinc((SV *) rows), 0);
1648 1649 1650 1651 1652 1653
	}

	SPI_freetuptable(tuptable);

	return result;
}
1654 1655


1656 1657
/*
 * Note: plperl_return_next is called both in Postgres and Perl contexts.
1658
 * We report any errors in Postgres fashion (via ereport).	If called in
1659 1660 1661 1662 1663
 * 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.
 */
1664
void
1665
plperl_return_next(SV *sv)
1666
{
1667 1668 1669 1670
	plperl_proc_desc *prodesc;
	FunctionCallInfo fcinfo;
	ReturnSetInfo *rsi;
	MemoryContext old_cxt;
B
Bruce Momjian 已提交
1671
	HeapTuple	tuple;
1672 1673 1674 1675

	if (!sv)
		return;

1676 1677 1678 1679
	prodesc = current_call_data->prodesc;
	fcinfo = current_call_data->fcinfo;
	rsi = (ReturnSetInfo *) fcinfo->resultinfo;

1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691
	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")));

1692 1693 1694 1695 1696 1697
	if (!current_call_data->ret_tdesc)
	{
		TupleDesc tupdesc;

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

1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715
		/*
		 * This is the first call to return_next in the current
		 * PL/Perl function call, so memoize some lookups
		 */
		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 =
1716
			tuplestore_begin_heap(true, false, work_mem);
1717 1718 1719 1720 1721
		if (prodesc->fn_retistuple)
		{
			current_call_data->attinmeta =
				TupleDescGetAttInMetadata(current_call_data->ret_tdesc);
		}
1722

1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
		MemoryContextSwitchTo(old_cxt);
	}		

	/*
	 * Producing the tuple we want to return requires making plenty of
	 * 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.
	 */
	if (!current_call_data->tmp_cxt)
1734
	{
1735 1736 1737 1738 1739 1740 1741 1742 1743
		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);
1744

1745 1746 1747 1748
	if (prodesc->fn_retistuple)
	{
		tuple = plperl_build_tuple_result((HV *) SvRV(sv),
										  current_call_data->attinmeta);
1749 1750 1751
	}
	else
	{
1752 1753
		Datum		ret = (Datum) 0;
		bool		isNull = true;
1754 1755 1756

		if (SvOK(sv) && SvTYPE(sv) != SVt_NULL)
		{
B
Bruce Momjian 已提交
1757 1758
			char	   *val = SvPV(sv, PL_na);

1759 1760 1761 1762 1763 1764 1765
			ret = FunctionCall3(&prodesc->result_in_func,
								PointerGetDatum(val),
								ObjectIdGetDatum(prodesc->result_typioparam),
								Int32GetDatum(-1));
			isNull = false;
		}

1766
		tuple = heap_form_tuple(current_call_data->ret_tdesc, &ret, &isNull);
1767 1768
	}

1769 1770 1771 1772
	/* 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);
1773

1774
	MemoryContextReset(current_call_data->tmp_cxt);
1775
}
1776 1777 1778 1779 1780


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

1783 1784 1785 1786
	/*
	 * Execute the query inside a sub-transaction, so we can cope with errors
	 * sanely
	 */
1787 1788 1789 1790
	MemoryContext oldcontext = CurrentMemoryContext;
	ResourceOwner oldowner = CurrentResourceOwner;

	BeginInternalSubTransaction(NULL);
1791
	/* Want to run inside function's memory context */
1792 1793 1794 1795
	MemoryContextSwitchTo(oldcontext);

	PG_TRY();
	{
B
Bruce Momjian 已提交
1796
		void	   *plan;
A
 
Andrew Dunstan 已提交
1797
		Portal		portal;
1798

1799
		/* Create a cursor for the query */
1800
		plan = SPI_prepare(query, 0, NULL);
A
 
Andrew Dunstan 已提交
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810
		if ( plan == NULL)
			elog(ERROR, "SPI_prepare() failed:%s",
				SPI_result_code_string(SPI_result));

		portal = SPI_cursor_open(NULL, plan, NULL, NULL, false);
		SPI_freeplan( plan);
		if ( portal == NULL) 
			elog(ERROR, "SPI_cursor_open() failed:%s",
				SPI_result_code_string(SPI_result));
		cursor = newSVpv(portal->name, 0);
1811

1812
		/* Commit the inner transaction, return to outer xact context */
1813 1814 1815
		ReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;
1816 1817 1818 1819 1820

		/*
		 * AtEOSubXact_SPI() should not have popped any SPI context, but just
		 * in case it did, make sure we remain connected.
		 */
1821 1822 1823 1824 1825 1826
		SPI_restore_connection();
	}
	PG_CATCH();
	{
		ErrorData  *edata;

1827
		/* Save error info */
1828 1829 1830 1831
		MemoryContextSwitchTo(oldcontext);
		edata = CopyErrorData();
		FlushErrorState();

1832
		/* Abort the inner transaction */
1833 1834 1835 1836
		RollbackAndReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;

1837 1838 1839 1840 1841
		/*
		 * 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.
		 */
1842
		SPI_restore_connection();
1843 1844

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

		/* Can't get here, but keep compiler quiet */
1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858
		return NULL;
	}
	PG_END_TRY();

	return cursor;
}


SV *
plperl_spi_fetchrow(char *cursor)
{
1859 1860 1861 1862 1863 1864 1865 1866
	SV		   *row;

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

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

1872
	PG_TRY();
B
Bruce Momjian 已提交
1873
	{
1874 1875 1876
		Portal		p = SPI_cursor_find(cursor);

		if (!p)
A
 
Andrew Dunstan 已提交
1877 1878 1879
		{
			row = &PL_sv_undef;
		}
1880 1881 1882 1883 1884 1885
		else
		{
			SPI_cursor_fetch(p, true, 1);
			if (SPI_processed == 0)
			{
				SPI_cursor_close(p);
A
 
Andrew Dunstan 已提交
1886
				row = &PL_sv_undef;
1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905
			}
			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();
1906
	}
1907 1908 1909
	PG_CATCH();
	{
		ErrorData  *edata;
1910

1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934
		/* 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();
1935 1936 1937

	return row;
}
A
 
Andrew Dunstan 已提交
1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 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 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385

void
plperl_spi_cursor_close(char *cursor)
{
	Portal p = SPI_cursor_find(cursor);
	if (p)
		SPI_cursor_close(p);
}

SV *
plperl_spi_prepare(char* query, int argc, SV ** argv)
{
	plperl_query_desc *qdesc;
	void	   *plan;
	int			i;
	HeapTuple	typeTup;

	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));
	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));

	PG_TRY();
	{
		/************************************************************
		 * Lookup the argument types by name in the system cache
		 * and remember the required information for input conversion
		 ************************************************************/
		for (i = 0; i < argc; i++)
		{
			char	   *argcopy;
			List	   *names = NIL;
			ListCell   *l;
			TypeName   *typename;

			/************************************************************
			 * Use SplitIdentifierString() on a copy of the type name,
			 * turn the resulting pointer list into a TypeName node
			 * and call typenameType() to get the pg_type tuple.
			 ************************************************************/
			argcopy = pstrdup(SvPV(argv[i],PL_na));
			SplitIdentifierString(argcopy, '.', &names);
			typename = makeNode(TypeName);
			foreach(l, names)
				typename->names = lappend(typename->names, makeString(lfirst(l)));

			typeTup = typenameType(typename);
			qdesc->argtypes[i] = HeapTupleGetOid(typeTup);
			perm_fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,
						   &(qdesc->arginfuncs[i]));
			qdesc->argtypioparams[i] = getTypeIOParam(typeTup);
			ReleaseSysCache(typeTup);

			list_free(typename->names);
			pfree(typename);
			list_free(names);
			pfree(argcopy);
		}

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

		if (plan == NULL)
			elog(ERROR, "SPI_prepare() failed:%s",
				SPI_result_code_string(SPI_result));

		/************************************************************
		 * 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)
			elog(ERROR, "SPI_saveplan() failed: %s", 
				SPI_result_code_string(SPI_result));

		/* 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;
		/*
		 * AtEOSubXact_SPI() should not have popped any SPI context,
		 * but just in case it did, make sure we remain connected.
		 */
		SPI_restore_connection();
	}
	PG_CATCH();
	{
		ErrorData  *edata;
		
		free(qdesc-> argtypes);
		free(qdesc-> arginfuncs);
		free(qdesc-> argtypioparams);
		free(qdesc);

		/* 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();

	/************************************************************
	 * Insert a hashtable entry for the plan and return
	 * the key to the caller.
	 ************************************************************/
	hv_store( plperl_query_hash, qdesc->qname, strlen(qdesc->qname), newSVuv( PTR2UV( qdesc)), 0);

	return newSVpv( qdesc->qname, strlen(qdesc->qname));
}	

HV *
plperl_spi_exec_prepared(char* query, HV * attr, int argc, SV ** argv)
{
	HV		   *ret_hv;
	SV **sv;
	int i, limit, spi_rv;
	char * nulls;
	Datum	   *argvalues;
	plperl_query_desc *qdesc;

	/*
	 * Execute the query inside a sub-transaction, so we can cope with
	 * errors sanely
	 */
	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.
		 ************************************************************/
		sv = hv_fetch(plperl_query_hash, query, strlen(query), 0);
		if ( sv == NULL) 
			elog(ERROR, "spi_exec_prepared: Invalid prepared query passed");
		if ( *sv == NULL || !SvOK( *sv))
			elog(ERROR, "spi_exec_prepared: panic - plperl_query_hash value corrupted");

		qdesc = INT2PTR( plperl_query_desc *, SvUV(*sv));
		if ( qdesc == NULL)
			elog(ERROR, "spi_exec_prepared: panic - plperl_query_hash value vanished");

		if ( qdesc-> nargs != argc) 
			elog(ERROR, "spi_exec_prepared: expected %d argument(s), %d passed", 
				qdesc-> nargs, argc);
		
		/************************************************************
		 * Parse eventual attributes
		 ************************************************************/
		limit = 0;
		if ( attr != NULL) 
		{
			sv = hv_fetch( attr, "limit", 5, 0);
			if ( *sv && SvIOK( *sv))
				limit = SvIV( *sv);
		}
		/************************************************************
		 * Set up arguments
		 ************************************************************/
		if ( argc > 0) 
		{
			nulls = (char *)palloc( argc);
			argvalues = (Datum *) palloc(argc * sizeof(Datum));
			if ( nulls == NULL || argvalues == NULL) 
				elog(ERROR, "spi_exec_prepared: not enough memory");
		} 
		else 
		{
			nulls = NULL;
			argvalues = NULL;
		}

		for ( i = 0; i < argc; i++) 
		{
			if ( SvTYPE( argv[i]) != SVt_NULL) 
			{
				argvalues[i] =
					FunctionCall3( &qdesc->arginfuncs[i],
						  CStringGetDatum( SvPV( argv[i], PL_na)),
						  ObjectIdGetDatum( qdesc->argtypioparams[i]),
						  Int32GetDatum(-1)
					);
				nulls[i] = ' ';
			} 
			else 
			{
				argvalues[i] = (Datum) 0;
				nulls[i] = 'n';
			}
		}

		/************************************************************
		 * go
		 ************************************************************/
		spi_rv = SPI_execute_plan(qdesc-> plan, argvalues, nulls, 
							 current_call_data->prodesc->fn_readonly, limit);
		ret_hv = plperl_spi_execute_fetch_result(SPI_tuptable, SPI_processed,
												 spi_rv);
		if ( argc > 0) 
		{
			pfree( argvalues);
			pfree( nulls);
		}

		/* 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();
	}
	PG_CATCH();
	{
		ErrorData  *edata;

		/* 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();

	return ret_hv;
}

SV *
plperl_spi_query_prepared(char* query, int argc, SV ** argv)
{
	SV **sv;
	int i;
	char * nulls;
	Datum	   *argvalues;
	plperl_query_desc *qdesc;
	SV *cursor;
	Portal portal = NULL;

	/*
	 * Execute the query inside a sub-transaction, so we can cope with
	 * errors sanely
	 */
	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.
		 ************************************************************/
		sv = hv_fetch(plperl_query_hash, query, strlen(query), 0);
		if ( sv == NULL) 
			elog(ERROR, "spi_query_prepared: Invalid prepared query passed");
		if ( *sv == NULL || !SvOK( *sv))
			elog(ERROR, "spi_query_prepared: panic - plperl_query_hash value corrupted");

		qdesc = INT2PTR( plperl_query_desc *, SvUV(*sv));
		if ( qdesc == NULL)
			elog(ERROR, "spi_query_prepared: panic - plperl_query_hash value vanished");

		if ( qdesc-> nargs != argc) 
			elog(ERROR, "spi_query_prepared: expected %d argument(s), %d passed", 
				qdesc-> nargs, argc);
		
		/************************************************************
		 * Set up arguments
		 ************************************************************/
		if ( argc > 0) 
		{
			nulls = (char *)palloc( argc);
			argvalues = (Datum *) palloc(argc * sizeof(Datum));
			if ( nulls == NULL || argvalues == NULL) 
				elog(ERROR, "spi_query_prepared: not enough memory");
		} 
		else 
		{
			nulls = NULL;
			argvalues = NULL;
		}

		for ( i = 0; i < argc; i++) 
		{
			if ( SvTYPE( argv[i]) != SVt_NULL) 
			{
				argvalues[i] =
					FunctionCall3( &qdesc->arginfuncs[i],
						  CStringGetDatum( SvPV( argv[i], PL_na)),
						  ObjectIdGetDatum( qdesc->argtypioparams[i]),
						  Int32GetDatum(-1)
					);
				nulls[i] = ' ';
			} 
			else 
			{
				argvalues[i] = (Datum) 0;
				nulls[i] = 'n';
			}
		}

		/************************************************************
		 * go
		 ************************************************************/
		portal = SPI_cursor_open(NULL, qdesc-> plan, argvalues, nulls, 
							current_call_data->prodesc->fn_readonly);
		if ( argc > 0) 
		{
			pfree( argvalues);
			pfree( nulls);
		}
		if ( portal == NULL) 
			elog(ERROR, "SPI_cursor_open() failed:%s",
				SPI_result_code_string(SPI_result));

		cursor = newSVpv(portal->name, 0);

		/* 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();
	}
	PG_CATCH();
	{
		ErrorData  *edata;

		/* 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();

	return cursor;
}

void
plperl_spi_freeplan(char *query)
{
	SV ** sv;
	void * plan;
	plperl_query_desc *qdesc;

	sv = hv_fetch(plperl_query_hash, query, strlen(query), 0);
	if ( sv == NULL) 
		elog(ERROR, "spi_exec_freeplan: Invalid prepared query passed");
	if ( *sv == NULL || !SvOK( *sv))
		elog(ERROR, "spi_exec_freeplan: panic - plperl_query_hash value corrupted");

	qdesc = INT2PTR( plperl_query_desc *, SvUV(*sv));
	if ( qdesc == NULL)
		elog(ERROR, "spi_exec_freeplan: panic - plperl_query_hash value vanished");

	/*
	*	free all memory before SPI_freeplan, so if it dies, nothing will be left over
	*/
	hv_delete(plperl_query_hash, query, strlen(query), G_DISCARD);
	plan = qdesc-> plan;
	free(qdesc-> argtypes);
	free(qdesc-> arginfuncs);
	free(qdesc-> argtypioparams);
	free(qdesc);

	SPI_freeplan( plan);
}