plperl.c 42.0 KB
Newer Older
1 2 3 4 5 6
/**********************************************************************
 * plperl.c - perl as a procedural language for PostgreSQL
 *
 * IDENTIFICATION
 *
 *	  This software is copyrighted by Mark Hollomon
7
 *	  but is shameless cribbed from pltcl.c by Jan Wieck.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 *
 *	  The author hereby grants permission  to  use,  copy,	modify,
 *	  distribute,  and	license this software and its documentation
 *	  for any purpose, provided that existing copyright notices are
 *	  retained	in	all  copies  and  that	this notice is included
 *	  verbatim in any distributions. No written agreement, license,
 *	  or  royalty  fee	is required for any of the authorized uses.
 *	  Modifications to this software may be  copyrighted  by  their
 *	  author  and  need  not  follow  the licensing terms described
 *	  here, provided that the new terms are  clearly  indicated  on
 *	  the first page of each file where they apply.
 *
 *	  IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
 *	  PARTY  FOR  DIRECT,	INDIRECT,	SPECIAL,   INCIDENTAL,	 OR
 *	  CONSEQUENTIAL   DAMAGES  ARISING	OUT  OF  THE  USE  OF  THIS
 *	  SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
 *	  IF  THE  AUTHOR  HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
 *	  DAMAGE.
 *
 *	  THE  AUTHOR  AND	DISTRIBUTORS  SPECIFICALLY	 DISCLAIM	ANY
 *	  WARRANTIES,  INCLUDING,  BUT	NOT  LIMITED  TO,  THE	IMPLIED
 *	  WARRANTIES  OF  MERCHANTABILITY,	FITNESS  FOR  A  PARTICULAR
 *	  PURPOSE,	AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON
 *	  AN "AS IS" BASIS, AND THE AUTHOR	AND  DISTRIBUTORS  HAVE  NO
 *	  OBLIGATION   TO	PROVIDE   MAINTENANCE,	 SUPPORT,  UPDATES,
 *	  ENHANCEMENTS, OR MODIFICATIONS.
 *
35
 * IDENTIFICATION
B
Bruce Momjian 已提交
36
 *	  $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.88 2005/08/12 21:09:34 momjian Exp $
37
 *
38 39
 **********************************************************************/

40
#include "postgres.h"
41
/* Defined by Perl */
42
#undef _
43 44

/* system stuff */
45
#include <ctype.h>
46
#include <fcntl.h>
47
#include <unistd.h>
48 49

/* postgreSQL stuff */
50 51
#include "commands/trigger.h"
#include "executor/spi.h"
52
#include "funcapi.h"
53
#include "utils/lsyscache.h"
54
#include "utils/memutils.h"
55
#include "utils/typcache.h"
56
#include "miscadmin.h"
57
#include "mb/pg_wchar.h"
58 59

/* perl stuff */
B
Bruce Momjian 已提交
60 61
#include "EXTERN.h"
#include "perl.h"
62
#include "XSUB.h"
63
#include "ppport.h"
64
#include "spi_internal.h"
65

66 67 68 69 70 71
/* just in case these symbols aren't provided */
#ifndef pTHX_
#define pTHX_
#define pTHX void
#endif

72 73 74 75 76 77 78

/**********************************************************************
 * The information we cache about loaded procedures
 **********************************************************************/
typedef struct plperl_proc_desc
{
	char	   *proname;
79 80
	TransactionId fn_xmin;
	CommandId	fn_cmin;
81
	bool		fn_readonly;
82
	bool		lanpltrusted;
83
	bool		fn_retistuple;	/* true, if function returns tuple */
B
Bruce Momjian 已提交
84
	bool		fn_retisset;	/* true, if function returns set */
85
	bool        fn_retisarray;  /* true if function returns array */
86 87
	Oid			result_oid;		/* Oid of result type */
	FmgrInfo	result_in_func;	/* I/O function and arg for result type */
88
	Oid			result_typioparam;
89 90
	int			nargs;
	FmgrInfo	arg_out_func[FUNC_MAX_ARGS];
91
	bool		arg_is_rowtype[FUNC_MAX_ARGS];
92
	SV		   *reference;
93
} plperl_proc_desc;
94 95 96 97 98 99


/**********************************************************************
 * Global data
 **********************************************************************/
static int	plperl_firstcall = 1;
100
static bool plperl_safe_init_done = false;
101
static PerlInterpreter *plperl_interp = NULL;
102 103
static HV  *plperl_proc_hash = NULL;

104 105
static bool plperl_use_strict = false;

106
/* these are saved and restored by plperl_call_handler */
107
static plperl_proc_desc *plperl_current_prodesc = NULL;
108 109 110
static FunctionCallInfo plperl_current_caller_info;
static Tuplestorestate *plperl_current_tuple_store;
static TupleDesc plperl_current_tuple_desc;
111

112 113 114 115
/**********************************************************************
 * Forward declarations
 **********************************************************************/
static void plperl_init_all(void);
116
static void plperl_init_interp(void);
117

B
Bruce Momjian 已提交
118
Datum		plperl_call_handler(PG_FUNCTION_ARGS);
119
Datum		plperl_validator(PG_FUNCTION_ARGS);
120
void		plperl_init(void);
121

122
HV		   *plperl_spi_exec(char *query, int limit);
123
SV		   *plperl_spi_query(char *);
124

125
static Datum plperl_func_handler(PG_FUNCTION_ARGS);
126

127
static Datum plperl_trigger_handler(PG_FUNCTION_ARGS);
128 129
static plperl_proc_desc *compile_plperl_function(Oid fn_oid, bool is_trigger);

130
static SV  *plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc);
131
static void plperl_init_shared_libs(pTHX);
132
static HV  *plperl_spi_execute_fetch_result(SPITupleTable *, int, int);
133

134
void plperl_return_next(SV *);
135

136 137 138 139 140 141 142
/*
 * 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,
143 144 145
 * 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.
146 147 148 149
 */
static void
perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
{
150
	fmgr_info_cxt(functionId, finfo, TopMemoryContext);
151 152
}

153 154 155

/* Perform initialization during postmaster startup. */

156 157
void
plperl_init(void)
158 159 160 161
{
	if (!plperl_firstcall)
		return;

162 163 164 165 166 167 168 169 170
	DefineCustomBoolVariable(
		"plperl.use_strict",
		"If true, will compile trusted and untrusted perl code in strict mode",
		NULL,
		&plperl_use_strict,
		PGC_USERSET,
		NULL, NULL);

	EmitWarningsOnPlaceholders("plperl");
171

172
	plperl_init_interp();
173 174 175
	plperl_firstcall = 0;
}

176 177 178

/* Perform initialization during backend startup. */

179 180 181 182 183 184
static void
plperl_init_all(void)
{
	if (plperl_firstcall)
		plperl_init();

185
	/* We don't need to do anything yet when a new backend starts. */
186 187
}

188 189

static void
190
plperl_init_interp(void)
191
{
192
	static char	   *loose_embedding[3] = {
B
Bruce Momjian 已提交
193
		"", "-e",
194
		/* all one string follows (no commas please) */
195
		"SPI::bootstrap(); use vars qw(%_SHARED);"
196 197
		"sub ::plperl_warn { my $msg = shift; &elog(&NOTICE, $msg); } "
		"$SIG{__WARN__} = \\&::plperl_warn; "
198
		"sub ::mkunsafefunc {return eval(qq[ sub { $_[0] $_[1] } ]); }"
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
		"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); "
		"    } "
		"    else "
		"    { "
		"      my $str = qq($elem); "
		"      $str =~ s/([\"\\\\])/\\\\$1/g; "
		"      $res .= qq(\"$str\"); "
		"    } "
		"  } "
		"  return qq({$res}); "
		"} "
B
Bruce Momjian 已提交
219
	};
220

221

222 223 224 225
	static char	   *strict_embedding[3] = {
		"", "-e",
		/* all one string follows (no commas please) */
		"SPI::bootstrap(); use vars qw(%_SHARED);"
226 227
		"sub ::plperl_warn { my $msg = shift; &elog(&NOTICE, $msg); } "
		"$SIG{__WARN__} = \\&::plperl_warn; "
228 229 230 231
		"sub ::mkunsafefunc {return eval("
		"qq[ sub { use strict; $_[0] $_[1] } ]); }"
	};

232 233
	plperl_interp = perl_alloc();
	if (!plperl_interp)
234
		elog(ERROR, "could not allocate Perl interpreter");
235

236
	perl_construct(plperl_interp);
237 238
	perl_parse(plperl_interp, plperl_init_shared_libs, 3 ,
			   (plperl_use_strict ? strict_embedding : loose_embedding), NULL);
239
	perl_run(plperl_interp);
240

241
	plperl_proc_hash = newHV();
242 243
}

244 245 246 247

static void
plperl_safe_init(void)
{
B
Bruce Momjian 已提交
248 249
	static char *safe_module =
	"require Safe; $Safe::VERSION";
250

251
	static char *common_safe_ok =
B
Bruce Momjian 已提交
252
	"use vars qw($PLContainer); $PLContainer = new Safe('PLPerl');"
253 254
	"$PLContainer->permit_only(':default');"
	"$PLContainer->permit(qw[:base_math !:base_io sort time]);"
255
	"$PLContainer->share(qw[&elog &spi_exec_query &return_next "
256
	"&spi_query &spi_fetchrow "
257
	"&_plperl_to_pg_array "
258
	"&DEBUG &LOG &INFO &NOTICE &WARNING &ERROR %_SHARED ]);"
B
Bruce Momjian 已提交
259
			   ;
260

261 262 263 264 265 266 267 268 269 270 271 272
	static char * strict_safe_ok =
		"$PLContainer->permit('require');$PLContainer->reval('use strict;');"
		"$PLContainer->deny('require');"
		"sub ::mksafefunc { return $PLContainer->reval(qq[ "
		"             sub { BEGIN { strict->import(); } $_[0] $_[1]}]); }"
		;

	static char * loose_safe_ok =
		"sub ::mksafefunc { return $PLContainer->reval(qq[ "
		"             sub { $_[0] $_[1]}]); }"
		;

B
Bruce Momjian 已提交
273 274
	static char *safe_bad =
	"use vars qw($PLContainer); $PLContainer = new Safe('PLPerl');"
275 276
	"$PLContainer->permit_only(':default');"
	"$PLContainer->share(qw[&elog &ERROR ]);"
B
Bruce Momjian 已提交
277
	"sub ::mksafefunc { return $PLContainer->reval(qq[sub { "
278
	"elog(ERROR,'trusted Perl functions disabled - "
279
	"please upgrade Perl Safe module to version 2.09 or later');}]); }"
B
Bruce Momjian 已提交
280
			   ;
281

B
Bruce Momjian 已提交
282
	SV		   *res;
283
	double		safe_version;
284

B
Bruce Momjian 已提交
285
	res = eval_pv(safe_module, FALSE);	/* TRUE = croak if failure */
286 287 288

	safe_version = SvNV(res);

289 290 291 292 293
	/*
	 * 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.
	 */
294 295 296 297 298 299 300 301 302 303
	if (safe_version < 2.0899 )
	{
		/* not safe, so disallow all trusted funcs */
		eval_pv(safe_bad, FALSE);
	}
	else
	{
		eval_pv(common_safe_ok, FALSE);
		eval_pv((plperl_use_strict ? strict_safe_ok : loose_safe_ok), FALSE);
	}
304 305 306 307

	plperl_safe_init_done = true;
}

308

309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
/*
 * Perl likes to put a newline after its error messages; clean up such
 */
static char *
strip_trailing_ws(const char *msg)
{
	char   *res = pstrdup(msg);
	int		len = strlen(res);

	while (len > 0 && isspace((unsigned char) res[len-1]))
		res[--len] = '\0';
	return res;
}


324 325
/* Build a tuple from a hash. */

326 327
static HeapTuple
plperl_build_tuple_result(HV *perlhash, AttInMetadata *attinmeta)
328
{
329 330 331 332 333 334
	TupleDesc	td = attinmeta->tupdesc;
	char	  **values;
	SV		   *val;
	char	   *key;
	I32			klen;
	HeapTuple	tup;
335

336
	values = (char **) palloc0(td->natts * sizeof(char *));
337

338 339 340
	hv_iterinit(perlhash);
	while ((val = hv_iternextsv(perlhash, &key, &klen)))
	{
341
		int	attn = SPI_fnumber(td, key);
342

343
		if (attn <= 0 || td->attrs[attn - 1]->attisdropped)
344 345 346 347
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_COLUMN),
					 errmsg("Perl hash contains nonexistent column \"%s\"",
							key)));
348
		if (SvOK(val) && SvTYPE(val) != SVt_NULL)
349
			values[attn - 1] = SvPV(val, PL_na);
350
	}
351 352 353 354 355
	hv_iterinit(perlhash);

	tup = BuildTupleFromCStrings(attinmeta, values);
	pfree(values);
	return tup;
356 357
}

358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
/*
 * convert perl array to postgres string representation
 */
static SV*
plperl_convert_to_pg_array(SV *src)
{
    SV* rv;
	int count;
	dSP ;

	PUSHMARK(SP) ;
	XPUSHs(src);
	PUTBACK ;

	count = call_pv("_plperl_to_pg_array", G_SCALAR);

	SPAGAIN ;

	if (count != 1)
		croak("Big trouble\n") ;

	rv = POPs;
			   
	PUTBACK ;

    return rv;
}

386

387 388
/* Set up the arguments for a trigger call. */

389 390 391 392 393
static SV  *
plperl_trigger_build_args(FunctionCallInfo fcinfo)
{
	TriggerData *tdata;
	TupleDesc	tupdesc;
394
	int			i;
395 396 397 398 399
	char	   *level;
	char	   *event;
	char	   *relid;
	char	   *when;
	HV		   *hv;
400

401
	hv = newHV();
402 403 404 405

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

406
	relid = DatumGetCString(
407 408
				DirectFunctionCall1(oidout,
									ObjectIdGetDatum(tdata->tg_relation->rd_id)
409 410 411 412 413
				)
			);

	hv_store(hv, "name", 4, newSVpv(tdata->tg_trigger->tgname, 0), 0);
	hv_store(hv, "relid", 5, newSVpv(relid, 0), 0);
414 415 416

	if (TRIGGER_FIRED_BY_INSERT(tdata->tg_event))
	{
417
		event = "INSERT";
418 419 420 421
		if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
			hv_store(hv, "new", 3,
					 plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc),
					 0);
422 423 424
	}
	else if (TRIGGER_FIRED_BY_DELETE(tdata->tg_event))
	{
425
		event = "DELETE";
426 427 428 429
		if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
			hv_store(hv, "old", 3,
					 plperl_hash_from_tuple(tdata->tg_trigtuple, tupdesc),
					 0);
430 431 432
	}
	else if (TRIGGER_FIRED_BY_UPDATE(tdata->tg_event))
	{
433
		event = "UPDATE";
434 435 436 437 438 439 440 441 442
		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);
		}
443
	}
444
	else
445
		event = "UNKNOWN";
446

447 448
	hv_store(hv, "event", 5, newSVpv(event, 0), 0);
	hv_store(hv, "argc", 4, newSViv(tdata->tg_trigger->tgnargs), 0);
449

450
	if (tdata->tg_trigger->tgnargs > 0)
451
	{
452 453 454
		AV *av = newAV();
		for (i=0; i < tdata->tg_trigger->tgnargs; i++)
			av_push(av, newSVpv(tdata->tg_trigger->tgargs[i], 0));
455
		hv_store(hv, "args", 4, newRV_noinc((SV *)av), 0);
456
	}
457 458 459

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

	if (TRIGGER_FIRED_BEFORE(tdata->tg_event))
462
		when = "BEFORE";
463
	else if (TRIGGER_FIRED_AFTER(tdata->tg_event))
464
		when = "AFTER";
465
	else
466 467
		when = "UNKNOWN";
	hv_store(hv, "when", 4, newSVpv(when, 0), 0);
468 469

	if (TRIGGER_FIRED_FOR_ROW(tdata->tg_event))
470
		level = "ROW";
471
	else if (TRIGGER_FIRED_FOR_STATEMENT(tdata->tg_event))
472
		level = "STATEMENT";
473
	else
474 475
		level = "UNKNOWN";
	hv_store(hv, "level", 5, newSVpv(level, 0), 0);
476

477
	return newRV_noinc((SV*)hv);
478 479 480
}


481
/* Set up the new tuple returned from a trigger. */
482

483
static HeapTuple
484
plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup)
485 486 487 488
{
	SV		  **svp;
	HV		   *hvNew;
	HeapTuple	rtup;
489 490 491 492 493 494 495 496
	SV		   *val;
	char	   *key;
	I32			klen;
	int			slotsused;
	int		   *modattrs;
	Datum	   *modvalues;
	char	   *modnulls;

497 498 499 500 501
	TupleDesc	tupdesc;

	tupdesc = tdata->tg_relation->rd_att;

	svp = hv_fetch(hvTD, "new", 3, FALSE);
502
	if (!svp)
503 504 505
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_COLUMN),
				 errmsg("$_TD->{new} does not exist")));
506
	if (!SvOK(*svp) || SvTYPE(*svp) != SVt_RV || SvTYPE(SvRV(*svp)) != SVt_PVHV)
507 508 509
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("$_TD->{new} is not a hash reference")));
510 511
	hvNew = (HV *) SvRV(*svp);

512 513 514 515
	modattrs = palloc(tupdesc->natts * sizeof(int));
	modvalues = palloc(tupdesc->natts * sizeof(Datum));
	modnulls = palloc(tupdesc->natts * sizeof(char));
	slotsused = 0;
516

517 518
	hv_iterinit(hvNew);
	while ((val = hv_iternextsv(hvNew, &key, &klen)))
519
	{
520
		int			attn = SPI_fnumber(tupdesc, key);
521

522
		if (attn <= 0 || tupdesc->attrs[attn - 1]->attisdropped)
523 524 525 526
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_COLUMN),
					 errmsg("Perl hash contains nonexistent column \"%s\"",
							key)));
527
		if (SvOK(val) && SvTYPE(val) != SVt_NULL)
528
		{
529 530 531 532 533 534 535 536 537 538 539 540 541
			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,
										 CStringGetDatum(SvPV(val, PL_na)),
										 ObjectIdGetDatum(typioparam),
						 Int32GetDatum(tupdesc->attrs[attn - 1]->atttypmod));
			modnulls[slotsused] = ' ';
542 543 544
		}
		else
		{
545 546
			modvalues[slotsused] = (Datum) 0;
			modnulls[slotsused] = 'n';
547
		}
548 549
		modattrs[slotsused] = attn;
		slotsused++;
550
	}
551 552 553 554
	hv_iterinit(hvNew);

	rtup = SPI_modifytuple(tdata->tg_relation, otup, slotsused,
						   modattrs, modvalues, modnulls);
555 556 557 558

	pfree(modattrs);
	pfree(modvalues);
	pfree(modnulls);
559

560
	if (rtup == NULL)
561
		elog(ERROR, "SPI_modifytuple failed: %s",
562
			 SPI_result_code_string(SPI_result));
563 564 565

	return rtup;
}
566

567

568 569
/*
 * This is the only externally-visible part of the plperl call interface.
570
 * The Postgres function and trigger managers call it to execute a
571 572
 * perl function.
 */
573
PG_FUNCTION_INFO_V1(plperl_call_handler);
574 575

Datum
576
plperl_call_handler(PG_FUNCTION_ARGS)
577
{
578
	Datum retval;
579
	plperl_proc_desc *save_prodesc;
580 581 582
	FunctionCallInfo save_caller_info;
	Tuplestorestate *save_tuple_store;
	TupleDesc save_tuple_desc;
583

584
	plperl_init_all();
585

586
	save_prodesc = plperl_current_prodesc;
587 588 589
	save_caller_info = plperl_current_caller_info;
	save_tuple_store = plperl_current_tuple_store;
	save_tuple_desc = plperl_current_tuple_desc;
590

591 592 593 594 595 596 597 598 599 600
	PG_TRY();
	{
		if (CALLED_AS_TRIGGER(fcinfo))
			retval = PointerGetDatum(plperl_trigger_handler(fcinfo));
		else
			retval = plperl_func_handler(fcinfo);
	}
	PG_CATCH();
	{
		plperl_current_prodesc = save_prodesc;
601 602 603
		plperl_current_caller_info = save_caller_info;
		plperl_current_tuple_store = save_tuple_store;
		plperl_current_tuple_desc = save_tuple_desc;
604 605 606 607 608
		PG_RE_THROW();
	}
	PG_END_TRY();

	plperl_current_prodesc = save_prodesc;
609 610 611
	plperl_current_caller_info = save_caller_info;
	plperl_current_tuple_store = save_tuple_store;
	plperl_current_tuple_desc = save_tuple_desc;
612 613 614 615

	return retval;
}

616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
/*
 * 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;
	bool		istrigger = false;
	plperl_proc_desc *prodesc;

	plperl_init_all();

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

	/* we assume OPAQUE with no arguments means a trigger */
	if (proc->prorettype == TRIGGEROID ||
		(proc->prorettype == OPAQUEOID && proc->pronargs == 0))
		istrigger = true;

	ReleaseSysCache(tuple);

	prodesc = compile_plperl_function(funcoid, istrigger);

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

654

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

B
Bruce Momjian 已提交
658
static SV  *
659
plperl_create_sub(char *s, bool trusted)
660
{
661
	dSP;
662
	SV		   *subref;
B
Bruce Momjian 已提交
663
	int			count;
664

B
Bruce Momjian 已提交
665
	if (trusted && !plperl_safe_init_done)
666
	{
667
		plperl_safe_init();
668 669
		SPAGAIN;
	}
670

671 672 673
	ENTER;
	SAVETMPS;
	PUSHMARK(SP);
674
	XPUSHs(sv_2mortal(newSVpv("my $_TD=$_[0]; shift;", 0)));
B
Bruce Momjian 已提交
675
	XPUSHs(sv_2mortal(newSVpv(s, 0)));
B
Bruce Momjian 已提交
676
	PUTBACK;
B
Bruce Momjian 已提交
677

678 679
	/*
	 * G_KEEPERR seems to be needed here, else we don't recognize compile
B
Bruce Momjian 已提交
680 681
	 * errors properly.  Perhaps it's because there's another level of
	 * eval inside mksafefunc?
682
	 */
683 684
	count = perl_call_pv((trusted ? "mksafefunc" : "mkunsafefunc"),
						 G_SCALAR | G_EVAL | G_KEEPERR);
685 686
	SPAGAIN;

687 688 689 690 691
	if (count != 1)
	{
		PUTBACK;
		FREETMPS;
		LEAVE;
692
		elog(ERROR, "didn't get a return item from mksafefunc");
693 694
	}

695
	if (SvTRUE(ERRSV))
696
	{
697
		(void) POPs;
698 699 700
		PUTBACK;
		FREETMPS;
		LEAVE;
701 702 703 704
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("creation of Perl function failed: %s",
						strip_trailing_ws(SvPV(ERRSV, PL_na)))));
705 706 707
	}

	/*
708 709
	 * need to make a deep copy of the return. it comes off the stack as a
	 * temporary.
710 711 712
	 */
	subref = newSVsv(POPs);

713
	if (!SvROK(subref) || SvTYPE(SvRV(subref)) != SVt_PVCV)
714
	{
715 716 717
		PUTBACK;
		FREETMPS;
		LEAVE;
718

719 720 721 722
		/*
		 * subref is our responsibility because it is not mortal
		 */
		SvREFCNT_dec(subref);
723
		elog(ERROR, "didn't get a code ref");
724 725 726 727 728
	}

	PUTBACK;
	FREETMPS;
	LEAVE;
729

730 731 732
	return subref;
}

733

734
/**********************************************************************
735
 * plperl_init_shared_libs()		-
736 737 738 739
 *
 * 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.
740
 *
741 742
 **********************************************************************/

743 744
EXTERN_C void boot_DynaLoader(pTHX_ CV *cv);
EXTERN_C void boot_SPI(pTHX_ CV *cv);
745

746
static void
747
plperl_init_shared_libs(pTHX)
748
{
749 750
	char	   *file = __FILE__;

751
	newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
752
	newXS("SPI::bootstrap", boot_SPI, file);
753 754
}

755

B
Bruce Momjian 已提交
756
static SV  *
757
plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
758 759
{
	dSP;
760 761 762
	SV		   *retval;
	int			i;
	int			count;
763
	SV			*sv;
764 765 766 767

	ENTER;
	SAVETMPS;

768
	PUSHMARK(SP);
769

770
	XPUSHs(&PL_sv_undef); /* no trigger data */
771

772 773
	for (i = 0; i < desc->nargs; i++)
	{
774 775 776
		if (fcinfo->argnull[i])
			XPUSHs(&PL_sv_undef);
		else if (desc->arg_is_rowtype[i])
777
		{
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
			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;

794 795
			hashref = plperl_hash_from_tuple(&tmptup, tupdesc);
			XPUSHs(sv_2mortal(hashref));
796 797 798
		}
		else
		{
799 800
			char	   *tmp;

801 802
			tmp = DatumGetCString(FunctionCall1(&(desc->arg_out_func[i]),
												fcinfo->arg[i]));
803 804 805 806 807
			sv = newSVpv(tmp, 0);
#if PERL_BCDVERSION >= 0x5006000L
			if (GetDatabaseEncoding() == PG_UTF8) SvUTF8_on(sv);
#endif
			XPUSHs(sv_2mortal(sv));
808
			pfree(tmp);
809 810 811
		}
	}
	PUTBACK;
812 813 814

	/* Do NOT use G_KEEPERR here */
	count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL);
815 816 817

	SPAGAIN;

818 819 820 821
	if (count != 1)
	{
		PUTBACK;
		FREETMPS;
822
		LEAVE;
823
		elog(ERROR, "didn't get a return item from function");
824 825
	}

826
	if (SvTRUE(ERRSV))
827
	{
828
		(void) POPs;
829 830
		PUTBACK;
		FREETMPS;
831
		LEAVE;
832 833 834 835
		/* 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)))));
836 837 838 839
	}

	retval = newSVsv(POPs);

840 841 842
	PUTBACK;
	FREETMPS;
	LEAVE;
843 844 845 846

	return retval;
}

847

848
static SV  *
849 850
plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo,
							  SV *td)
851 852 853
{
	dSP;
	SV		   *retval;
854
	Trigger    *tg_trigger;
855 856 857 858 859 860 861
	int			i;
	int			count;

	ENTER;
	SAVETMPS;

	PUSHMARK(sp);
862

863
	XPUSHs(td);
864

865 866 867
	tg_trigger = ((TriggerData *) fcinfo->context)->tg_trigger;
	for (i = 0; i < tg_trigger->tgnargs; i++)
		XPUSHs(sv_2mortal(newSVpv(tg_trigger->tgargs[i], 0)));
868 869
	PUTBACK;

870 871
	/* Do NOT use G_KEEPERR here */
	count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL);
872 873 874 875 876 877 878 879

	SPAGAIN;

	if (count != 1)
	{
		PUTBACK;
		FREETMPS;
		LEAVE;
880
		elog(ERROR, "didn't get a return item from trigger function");
881 882 883 884
	}

	if (SvTRUE(ERRSV))
	{
885
		(void) POPs;
886 887 888
		PUTBACK;
		FREETMPS;
		LEAVE;
889 890 891 892
		/* 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)))));
893 894 895 896 897 898 899 900 901 902
	}

	retval = newSVsv(POPs);

	PUTBACK;
	FREETMPS;
	LEAVE;

	return retval;
}
903

904

905
static Datum
906
plperl_func_handler(PG_FUNCTION_ARGS)
907 908
{
	plperl_proc_desc *prodesc;
909 910
	SV		   *perlret;
	Datum		retval;
911
	ReturnSetInfo *rsi;
B
Bruce Momjian 已提交
912
	SV* array_ret = NULL;
913

914 915 916
	if (SPI_connect() != SPI_OK_CONNECT)
		elog(ERROR, "could not connect to SPI manager");

917
	prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, false);
918 919

	plperl_current_prodesc = prodesc;
920 921 922
	plperl_current_caller_info = fcinfo;
	plperl_current_tuple_store = 0;
	plperl_current_tuple_desc = 0;
923

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

926 927 928 929 930 931 932 933 934 935
	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")));
	}

936
	perlret = plperl_call_perl_func(prodesc, fcinfo);
937 938 939 940 941 942 943 944

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

947 948
	if (prodesc->fn_retisset) 
	{
949 950 951 952 953 954
		/* If the Perl function returned an arrayref, we pretend that it
		 * 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. */
		if (SvTYPE(perlret) == SVt_RV &&
			SvTYPE(SvRV(perlret)) == SVt_PVAV)
955
		{
956 957 958
			int i = 0;
			SV **svp = 0;
			AV *rav = (AV *)SvRV(perlret);
959 960
			while ((svp = av_fetch(rav, i, FALSE)) != NULL) 
			{
961 962 963
				plperl_return_next(*svp);
				i++;
			}
964
		}
965
		else if (SvTYPE(perlret) != SVt_NULL)
966
		{
967 968
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
969 970
					 errmsg("set-returning Perl function must return "
							"reference to array or use return_next")));
971
		}
B
Bruce Momjian 已提交
972

973
		rsi->returnMode = SFRM_Materialize;
974
		if (plperl_current_tuple_store) 
975
		{
976 977
			rsi->setResult = plperl_current_tuple_store;
			rsi->setDesc = plperl_current_tuple_desc;
978
		}
979 980 981 982 983 984 985 986 987
		retval = (Datum)0;
	}
	else if (SvTYPE(perlret) == SVt_NULL)
	{
		/* Return NULL if Perl code returned undef */
		if (rsi && IsA(rsi, ReturnSetInfo))
			rsi->isDone = ExprEndResult;
		fcinfo->isnull = true;
		retval = (Datum)0;
B
Bruce Momjian 已提交
988
	}
989
	else if (prodesc->fn_retistuple)
990
	{
991 992
		/* Return a perl hash converted to a Datum */
		TupleDesc td;
993
		AttInMetadata *attinmeta;
994
		HeapTuple tup;
995

996 997 998
		if (!SvOK(perlret) || SvTYPE(perlret) != SVt_RV ||
			SvTYPE(SvRV(perlret)) != SVt_PVHV)
		{
999 1000
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
1001 1002 1003
					 errmsg("composite-returning Perl function "
							"must return reference to hash")));
		}
1004

1005 1006 1007 1008 1009 1010 1011 1012
		/* 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")));
		}
1013

1014 1015
		attinmeta = TupleDescGetAttInMetadata(td);
		tup = plperl_build_tuple_result((HV *)SvRV(perlret), attinmeta);
1016 1017 1018 1019
		retval = HeapTupleGetDatum(tup);
	}
	else
	{
1020 1021 1022
        /* Return a perl string converted to a Datum */
        char *val;
 
1023 1024
        if (prodesc->fn_retisarray && SvROK(perlret) &&
			SvTYPE(SvRV(perlret)) == SVt_PVAV)
1025 1026 1027 1028 1029 1030 1031 1032
        {
            array_ret = plperl_convert_to_pg_array(perlret);
            SvREFCNT_dec(perlret);
            perlret = array_ret;
        }

		val = SvPV(perlret, PL_na);

1033 1034 1035 1036
		retval = FunctionCall3(&prodesc->result_in_func,
							   CStringGetDatum(val),
							   ObjectIdGetDatum(prodesc->result_typioparam),
							   Int32GetDatum(-1));
1037
	}
1038

1039 1040 1041
	if (array_ret == NULL)
	  SvREFCNT_dec(perlret);

1042 1043 1044
	return retval;
}

1045

1046 1047 1048 1049 1050 1051 1052 1053 1054
static Datum
plperl_trigger_handler(PG_FUNCTION_ARGS)
{
	plperl_proc_desc *prodesc;
	SV		   *perlret;
	Datum		retval;
	SV		   *svTD;
	HV		   *hvTD;

1055 1056 1057 1058
	/* Connect to SPI manager */
	if (SPI_connect() != SPI_OK_CONNECT)
		elog(ERROR, "could not connect to SPI manager");

1059 1060 1061
	/* Find or compile the function */
	prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, true);

1062 1063
	plperl_current_prodesc = prodesc;

1064 1065
	svTD = plperl_trigger_build_args(fcinfo);
	perlret = plperl_call_perl_trigger_func(prodesc, fcinfo, svTD);
1066
	hvTD = (HV *) SvRV(svTD);
1067 1068 1069 1070 1071 1072 1073 1074

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

1077
	if (!(perlret && SvOK(perlret) && SvTYPE(perlret) != SVt_NULL))
1078
	{
1079
		/* undef result means go ahead with original tuple */
1080 1081 1082 1083 1084 1085 1086 1087
		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;
1088 1089
		else
			retval = (Datum) 0;	/* can this happen? */
1090 1091 1092
	}
	else
	{
1093 1094
		HeapTuple	trv;
		char	   *tmp;
1095

1096
		tmp = SvPV(perlret, PL_na);
1097

1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
		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);
1110 1111
			else
			{
1112 1113 1114
				ereport(WARNING,
						(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
						 errmsg("ignoring modified tuple in DELETE trigger")));
1115 1116 1117
				trv = NULL;
			}
		}
1118
		else
1119
		{
1120 1121
			ereport(ERROR,
					(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1122 1123
					 errmsg("result of Perl trigger function must be undef, "
							"\"SKIP\" or \"MODIFY\"")));
1124 1125 1126
			trv = NULL;
		}
		retval = PointerGetDatum(trv);
1127 1128
	}

1129 1130 1131
	SvREFCNT_dec(svTD);
	if (perlret)
		SvREFCNT_dec(perlret);
1132 1133 1134

	return retval;
}
1135

1136

1137 1138
static plperl_proc_desc *
compile_plperl_function(Oid fn_oid, bool is_trigger)
1139
{
1140 1141 1142 1143 1144
	HeapTuple	procTup;
	Form_pg_proc procStruct;
	char		internal_proname[64];
	int			proname_len;
	plperl_proc_desc *prodesc = NULL;
1145
	int			i;
1146
	SV			**svp;
1147

1148 1149 1150 1151 1152
	/* We'll need the pg_proc tuple in any case... */
	procTup = SearchSysCache(PROCOID,
							 ObjectIdGetDatum(fn_oid),
							 0, 0, 0);
	if (!HeapTupleIsValid(procTup))
1153
		elog(ERROR, "cache lookup failed for function %u", fn_oid);
1154
	procStruct = (Form_pg_proc) GETSTRUCT(procTup);
1155 1156 1157 1158

	/************************************************************
	 * Build our internal proc name from the functions Oid
	 ************************************************************/
1159 1160 1161 1162
	if (!is_trigger)
		sprintf(internal_proname, "__PLPerl_proc_%u", fn_oid);
	else
		sprintf(internal_proname, "__PLPerl_proc_%u_trigger", fn_oid);
1163

1164
	proname_len = strlen(internal_proname);
1165 1166 1167 1168

	/************************************************************
	 * Lookup the internal proc name in the hashtable
	 ************************************************************/
1169 1170
	svp = hv_fetch(plperl_proc_hash, internal_proname, proname_len, FALSE);
	if (svp)
1171
	{
1172 1173
		bool		uptodate;

1174
		prodesc = (plperl_proc_desc *) SvIV(*svp);
1175

1176
		/************************************************************
1177 1178 1179
		 * 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.
1180
		 ************************************************************/
1181
		uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
B
Bruce Momjian 已提交
1182
			prodesc->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data));
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204

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

	/************************************************************
	 * If we haven't found it in the hashtable, we analyze
	 * the functions arguments and returntype and store
	 * 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;
1205 1206
		Datum		prosrcdatum;
		bool		isnull;
1207 1208 1209 1210 1211 1212
		char	   *proc_source;

		/************************************************************
		 * Allocate a new procedure description block
		 ************************************************************/
		prodesc = (plperl_proc_desc *) malloc(sizeof(plperl_proc_desc));
1213
		if (prodesc == NULL)
1214 1215 1216
			ereport(ERROR,
					(errcode(ERRCODE_OUT_OF_MEMORY),
					 errmsg("out of memory")));
1217 1218
		MemSet(prodesc, 0, sizeof(plperl_proc_desc));
		prodesc->proname = strdup(internal_proname);
1219 1220
		prodesc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
		prodesc->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);
1221

1222 1223 1224 1225
		/* Remember if function is STABLE/IMMUTABLE */
		prodesc->fn_readonly =
			(procStruct->provolatile != PROVOLATILE_VOLATILE);

1226
		/************************************************************
1227
		 * Lookup the pg_language tuple by Oid
1228
		 ************************************************************/
1229 1230
		langTup = SearchSysCache(LANGOID,
								 ObjectIdGetDatum(procStruct->prolang),
1231
								 0, 0, 0);
1232
		if (!HeapTupleIsValid(langTup))
1233 1234 1235
		{
			free(prodesc->proname);
			free(prodesc);
1236
			elog(ERROR, "cache lookup failed for language %u",
1237
				 procStruct->prolang);
1238
		}
1239 1240 1241
		langStruct = (Form_pg_language) GETSTRUCT(langTup);
		prodesc->lanpltrusted = langStruct->lanpltrusted;
		ReleaseSysCache(langTup);
1242 1243

		/************************************************************
1244 1245
		 * Get the required information for input conversion of the
		 * return value.
1246
		 ************************************************************/
1247 1248 1249
		if (!is_trigger)
		{
			typeTup = SearchSysCache(TYPEOID,
1250
								ObjectIdGetDatum(procStruct->prorettype),
1251 1252 1253 1254 1255
									 0, 0, 0);
			if (!HeapTupleIsValid(typeTup))
			{
				free(prodesc->proname);
				free(prodesc);
1256
				elog(ERROR, "cache lookup failed for type %u",
1257
					 procStruct->prorettype);
1258 1259 1260
			}
			typeStruct = (Form_pg_type) GETSTRUCT(typeTup);

1261
			/* Disallow pseudotype result, except VOID or RECORD */
1262 1263
			if (typeStruct->typtype == 'p')
			{
1264 1265
				if (procStruct->prorettype == VOIDOID ||
					procStruct->prorettype == RECORDOID)
B
Bruce Momjian 已提交
1266
					 /* okay */ ;
1267
				else if (procStruct->prorettype == TRIGGEROID)
1268 1269 1270
				{
					free(prodesc->proname);
					free(prodesc);
1271 1272
					ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1273 1274
							 errmsg("trigger functions may only be called "
									"as triggers")));
1275 1276 1277 1278 1279
				}
				else
				{
					free(prodesc->proname);
					free(prodesc);
1280 1281
					ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
B
Bruce Momjian 已提交
1282 1283
						 errmsg("plperl functions cannot return type %s",
								format_type_be(procStruct->prorettype))));
1284 1285 1286
				}
			}

1287 1288 1289 1290
			prodesc->result_oid = procStruct->prorettype;
			prodesc->fn_retisset = procStruct->proretset;
			prodesc->fn_retistuple = (typeStruct->typtype == 'c' ||
									  procStruct->prorettype == RECORDOID);
1291

1292 1293 1294
			prodesc->fn_retisarray = 
				(typeStruct->typlen == -1 && typeStruct->typelem) ;

1295
			perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
1296
			prodesc->result_typioparam = getTypeIOParam(typeTup);
1297 1298 1299

			ReleaseSysCache(typeTup);
		}
1300 1301

		/************************************************************
1302 1303
		 * Get the required information for output conversion
		 * of all procedure arguments
1304
		 ************************************************************/
1305 1306 1307 1308 1309 1310
		if (!is_trigger)
		{
			prodesc->nargs = procStruct->pronargs;
			for (i = 0; i < prodesc->nargs; i++)
			{
				typeTup = SearchSysCache(TYPEOID,
1311
							ObjectIdGetDatum(procStruct->proargtypes.values[i]),
1312 1313 1314 1315 1316
										 0, 0, 0);
				if (!HeapTupleIsValid(typeTup))
				{
					free(prodesc->proname);
					free(prodesc);
1317
					elog(ERROR, "cache lookup failed for type %u",
1318
						 procStruct->proargtypes.values[i]);
1319 1320 1321
				}
				typeStruct = (Form_pg_type) GETSTRUCT(typeTup);

1322 1323 1324 1325 1326
				/* Disallow pseudotype argument */
				if (typeStruct->typtype == 'p')
				{
					free(prodesc->proname);
					free(prodesc);
1327 1328
					ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
B
Bruce Momjian 已提交
1329
						   errmsg("plperl functions cannot take type %s",
1330
						   format_type_be(procStruct->proargtypes.values[i]))));
1331 1332
				}

1333 1334
				if (typeStruct->typtype == 'c')
					prodesc->arg_is_rowtype[i] = true;
1335
				else
1336 1337 1338 1339 1340
				{
					prodesc->arg_is_rowtype[i] = false;
					perm_fmgr_info(typeStruct->typoutput,
								   &(prodesc->arg_out_func[i]));
				}
1341 1342 1343 1344

				ReleaseSysCache(typeTup);
			}
		}
1345

1346 1347 1348 1349 1350
		/************************************************************
		 * create the text of the anonymous subroutine.
		 * we do not use a named subroutine so that we can call directly
		 * through the reference.
		 ************************************************************/
1351 1352 1353 1354
		prosrcdatum = SysCacheGetAttr(PROCOID, procTup,
									  Anum_pg_proc_prosrc, &isnull);
		if (isnull)
			elog(ERROR, "null prosrc");
1355
		proc_source = DatumGetCString(DirectFunctionCall1(textout,
1356
														  prosrcdatum));
1357 1358

		/************************************************************
1359
		 * Create the procedure in the interpreter
1360
		 ************************************************************/
1361 1362
		prodesc->reference = plperl_create_sub(proc_source, prodesc->lanpltrusted);
		pfree(proc_source);
1363
		if (!prodesc->reference) /* can this happen? */
1364 1365 1366
		{
			free(prodesc->proname);
			free(prodesc);
1367
			elog(ERROR, "could not create internal procedure \"%s\"",
1368
				 internal_proname);
1369 1370
		}

1371 1372
		hv_store(plperl_proc_hash, internal_proname, proname_len,
				 newSViv((IV) prodesc), 0);
1373 1374
	}

1375
	ReleaseSysCache(procTup);
1376

1377 1378
	return prodesc;
}
1379 1380


1381 1382
/* Build a hash from all attributes of a given tuple. */

B
Bruce Momjian 已提交
1383
static SV  *
1384
plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc)
1385
{
1386
	HV		   *hv;
1387
	int			i;
1388

1389
	hv = newHV();
1390 1391 1392

	for (i = 0; i < tupdesc->natts; i++)
	{
1393 1394 1395 1396 1397 1398 1399
		Datum		attr;
		bool		isnull;
		char	   *attname;
		char	   *outputstr;
		Oid			typoutput;
		bool		typisvarlena;
		int			namelen;
1400
		SV			*sv;
1401

1402 1403 1404
		if (tupdesc->attrs[i]->attisdropped)
			continue;

1405
		attname = NameStr(tupdesc->attrs[i]->attname);
1406
		namelen = strlen(attname);
1407 1408
		attr = heap_getattr(tuple, i + 1, tupdesc, &isnull);

1409 1410 1411
		if (isnull) {
			/* Store (attname => undef) and move on. */
			hv_store(hv, attname, namelen, newSV(0), 0);
1412 1413 1414
			continue;
		}

1415
		/* XXX should have a way to cache these lookups */
1416

1417
		getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
1418
						  &typoutput, &typisvarlena);
1419

1420
		outputstr = DatumGetCString(OidFunctionCall1(typoutput, attr));
1421

1422 1423
		sv = newSVpv(outputstr, 0);
#if PERL_BCDVERSION >= 0x5006000L
1424 1425
		if (GetDatabaseEncoding() == PG_UTF8)
			SvUTF8_on(sv);
1426 1427
#endif
		hv_store(hv, attname, namelen, sv, 0);
1428 1429

		pfree(outputstr);
1430
	}
1431

1432
	return newRV_noinc((SV *) hv);
1433
}
1434 1435 1436 1437 1438 1439 1440


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

1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
	/*
	 * 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();
	{
		int			spi_rv;

		spi_rv = SPI_execute(query, plperl_current_prodesc->fn_readonly,
							 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;
		/*
		 * 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();
1499 1500 1501 1502

	return ret_hv;
}

1503

1504
static HV  *
1505 1506
plperl_spi_execute_fetch_result(SPITupleTable *tuptable, int processed,
								int status)
1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
{
	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)
	{
1519
		AV		   *rows;
1520
		SV		   *row;
1521
		int			i;
1522

1523 1524 1525 1526
		rows = newAV();
		for (i = 0; i < processed; i++)
		{
			row = plperl_hash_from_tuple(tuptable->vals[i], tuptable->tupdesc);
1527
			av_push(rows, row);
1528
		}
1529 1530
		hv_store(result, "rows", strlen("rows"),
				 newRV_noinc((SV *) rows), 0);
1531 1532 1533 1534 1535 1536
	}

	SPI_freetuptable(tuptable);

	return result;
}
1537 1538 1539 1540 1541 1542


void
plperl_return_next(SV *sv)
{
	plperl_proc_desc *prodesc = plperl_current_prodesc;
1543
	FunctionCallInfo fcinfo = plperl_current_caller_info;
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569
	ReturnSetInfo *rsi = (ReturnSetInfo *)fcinfo->resultinfo;
	MemoryContext cxt;
	HeapTuple tuple;
	TupleDesc tupdesc;

	if (!sv)
		return;

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

	cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);

1570 1571 1572
	if (!plperl_current_tuple_store)
		plperl_current_tuple_store = 
			tuplestore_begin_heap(true, false, work_mem);
1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607

	if (prodesc->fn_retistuple)
	{
		TypeFuncClass rettype;
		AttInMetadata *attinmeta;

		rettype = get_call_result_type(fcinfo, NULL, &tupdesc);
		tupdesc = CreateTupleDescCopy(tupdesc);
		attinmeta = TupleDescGetAttInMetadata(tupdesc);
		tuple = plperl_build_tuple_result((HV *)SvRV(sv), attinmeta);
	}
	else
	{
		Datum ret;
		bool isNull;

		tupdesc = CreateTupleDescCopy(rsi->expectedDesc);

		if (SvOK(sv) && SvTYPE(sv) != SVt_NULL)
		{
			char *val = SvPV(sv, PL_na);
			ret = FunctionCall3(&prodesc->result_in_func,
								PointerGetDatum(val),
								ObjectIdGetDatum(prodesc->result_typioparam),
								Int32GetDatum(-1));
			isNull = false;
		}
		else {
			ret = (Datum)0;
			isNull = true;
		}

		tuple = heap_form_tuple(tupdesc, &ret, &isNull);
	}

1608 1609
	if (!plperl_current_tuple_desc)
		plperl_current_tuple_desc = tupdesc;
1610

1611
	tuplestore_puttuple(plperl_current_tuple_store, tuple);
1612 1613 1614
	heap_freetuple(tuple);
	MemoryContextSwitchTo(cxt);
}
1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688


SV *
plperl_spi_query(char *query)
{
	SV *cursor;

	MemoryContext oldcontext = CurrentMemoryContext;
	ResourceOwner oldowner = CurrentResourceOwner;

	BeginInternalSubTransaction(NULL);
	MemoryContextSwitchTo(oldcontext);

	PG_TRY();
	{
		void *plan;
		Portal portal = NULL;

		plan = SPI_prepare(query, 0, NULL);
		if (plan)
			portal = SPI_cursor_open(NULL, plan, NULL, NULL, false);
		if (portal)
			cursor = newSVpv(portal->name, 0);
		else
			cursor = newSV(0);

		ReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;
		SPI_restore_connection();
	}
	PG_CATCH();
	{
		ErrorData  *edata;

		MemoryContextSwitchTo(oldcontext);
		edata = CopyErrorData();
		FlushErrorState();

		RollbackAndReleaseCurrentSubTransaction();
		MemoryContextSwitchTo(oldcontext);
		CurrentResourceOwner = oldowner;

		SPI_restore_connection();
		croak("%s", edata->message);
		return NULL;
	}
	PG_END_TRY();

	return cursor;
}


SV *
plperl_spi_fetchrow(char *cursor)
{
	SV *row = newSV(0);
	Portal p = SPI_cursor_find(cursor);

	if (!p)
		return row;

	SPI_cursor_fetch(p, true, 1);
	if (SPI_processed == 0) {
		SPI_cursor_close(p);
		return row;
	}

	row = plperl_hash_from_tuple(SPI_tuptable->vals[0],
								 SPI_tuptable->tupdesc);
	SPI_freetuptable(SPI_tuptable);

	return row;
}