plperl.c 41.3 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
36
 *	  $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.83 2005/07/10 15:32:47 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

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

71 72 73 74 75 76 77

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


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

106 107
static bool plperl_use_strict = false;

108 109 110
/* this is saved and restored by plperl_call_handler */
static plperl_proc_desc *plperl_current_prodesc = NULL;

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

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

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

124
static Datum plperl_func_handler(PG_FUNCTION_ARGS);
125

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

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

133
void plperl_return_next(SV *);
134

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

152 153 154

/* Perform initialization during postmaster startup. */

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

161 162 163 164 165 166 167 168 169
	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");
170

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

175 176 177

/* Perform initialization during backend startup. */

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

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

187 188

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

220

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

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

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

240
	plperl_proc_hash = newHV();
241 242
}

243 244 245 246

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

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

260 261 262 263 264 265 266 267 268 269 270 271
	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 已提交
272 273
	static char *safe_bad =
	"use vars qw($PLContainer); $PLContainer = new Safe('PLPerl');"
274 275
	"$PLContainer->permit_only(':default');"
	"$PLContainer->share(qw[&elog &ERROR ]);"
B
Bruce Momjian 已提交
276
	"sub ::mksafefunc { return $PLContainer->reval(qq[sub { "
277
	"elog(ERROR,'trusted Perl functions disabled - "
278
	"please upgrade Perl Safe module to version 2.09 or later');}]); }"
B
Bruce Momjian 已提交
279
			   ;
280

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

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

	safe_version = SvNV(res);

288 289 290 291 292
	/*
	 * 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.
	 */
293 294 295 296 297 298 299 300 301 302
	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);
	}
303 304 305 306

	plperl_safe_init_done = true;
}

307

308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
/*
 * 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;
}


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

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

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

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

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

	tup = BuildTupleFromCStrings(attinmeta, values);
	pfree(values);
	return tup;
355 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
/*
 * 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;
}

385

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

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

400
	hv = newHV();
401 402 403 404

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

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

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

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

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

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

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

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

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

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


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

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

496 497 498 499 500
	TupleDesc	tupdesc;

	tupdesc = tdata->tg_relation->rd_att;

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

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

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

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

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

	pfree(modattrs);
	pfree(modvalues);
	pfree(modnulls);
558

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

	return rtup;
}
565

566

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

Datum
575
plperl_call_handler(PG_FUNCTION_ARGS)
576
{
577
	Datum retval;
578
	plperl_proc_desc *save_prodesc;
579

580
	plperl_init_all();
581

582
	save_prodesc = plperl_current_prodesc;
583

584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
	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;
		PG_RE_THROW();
	}
	PG_END_TRY();

	plperl_current_prodesc = save_prodesc;
599 600 601 602

	return retval;
}

603 604 605 606 607 608 609 610 611 612 613 614 615 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
/*
 * 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();
}

641

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

B
Bruce Momjian 已提交
645
static SV  *
646
plperl_create_sub(char *s, bool trusted)
647
{
648
	dSP;
649
	SV		   *subref;
B
Bruce Momjian 已提交
650
	int			count;
651

B
Bruce Momjian 已提交
652
	if (trusted && !plperl_safe_init_done)
653
	{
654
		plperl_safe_init();
655 656
		SPAGAIN;
	}
657

658 659 660
	ENTER;
	SAVETMPS;
	PUSHMARK(SP);
661
	XPUSHs(sv_2mortal(newSVpv("my $_TD=$_[0]; shift;", 0)));
B
Bruce Momjian 已提交
662
	XPUSHs(sv_2mortal(newSVpv(s, 0)));
B
Bruce Momjian 已提交
663
	PUTBACK;
B
Bruce Momjian 已提交
664

665 666
	/*
	 * G_KEEPERR seems to be needed here, else we don't recognize compile
B
Bruce Momjian 已提交
667 668
	 * errors properly.  Perhaps it's because there's another level of
	 * eval inside mksafefunc?
669
	 */
670 671
	count = perl_call_pv((trusted ? "mksafefunc" : "mkunsafefunc"),
						 G_SCALAR | G_EVAL | G_KEEPERR);
672 673
	SPAGAIN;

674 675 676 677 678
	if (count != 1)
	{
		PUTBACK;
		FREETMPS;
		LEAVE;
679
		elog(ERROR, "didn't get a return item from mksafefunc");
680 681
	}

682
	if (SvTRUE(ERRSV))
683
	{
684
		(void) POPs;
685 686 687
		PUTBACK;
		FREETMPS;
		LEAVE;
688 689 690 691
		ereport(ERROR,
				(errcode(ERRCODE_SYNTAX_ERROR),
				 errmsg("creation of Perl function failed: %s",
						strip_trailing_ws(SvPV(ERRSV, PL_na)))));
692 693 694
	}

	/*
695 696
	 * need to make a deep copy of the return. it comes off the stack as a
	 * temporary.
697 698 699
	 */
	subref = newSVsv(POPs);

700
	if (!SvROK(subref) || SvTYPE(SvRV(subref)) != SVt_PVCV)
701
	{
702 703 704
		PUTBACK;
		FREETMPS;
		LEAVE;
705

706 707 708 709
		/*
		 * subref is our responsibility because it is not mortal
		 */
		SvREFCNT_dec(subref);
710
		elog(ERROR, "didn't get a code ref");
711 712 713 714 715
	}

	PUTBACK;
	FREETMPS;
	LEAVE;
716

717 718 719
	return subref;
}

720

721
/**********************************************************************
722
 * plperl_init_shared_libs()		-
723 724 725 726
 *
 * 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.
727
 *
728 729
 **********************************************************************/

730 731
EXTERN_C void boot_DynaLoader(pTHX_ CV *cv);
EXTERN_C void boot_SPI(pTHX_ CV *cv);
732

733
static void
734
plperl_init_shared_libs(pTHX)
735
{
736 737
	char	   *file = __FILE__;

738
	newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
739
	newXS("SPI::bootstrap", boot_SPI, file);
740 741
}

742

B
Bruce Momjian 已提交
743
static SV  *
744
plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
745 746
{
	dSP;
747 748 749
	SV		   *retval;
	int			i;
	int			count;
750
	SV			*sv;
751 752 753 754

	ENTER;
	SAVETMPS;

755
	PUSHMARK(SP);
756

757
	XPUSHs(&PL_sv_undef); /* no trigger data */
758

759 760
	for (i = 0; i < desc->nargs; i++)
	{
761 762 763
		if (fcinfo->argnull[i])
			XPUSHs(&PL_sv_undef);
		else if (desc->arg_is_rowtype[i])
764
		{
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
			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;

781 782
			hashref = plperl_hash_from_tuple(&tmptup, tupdesc);
			XPUSHs(sv_2mortal(hashref));
783 784 785
		}
		else
		{
786 787
			char	   *tmp;

788 789
			tmp = DatumGetCString(FunctionCall1(&(desc->arg_out_func[i]),
												fcinfo->arg[i]));
790 791 792 793 794
			sv = newSVpv(tmp, 0);
#if PERL_BCDVERSION >= 0x5006000L
			if (GetDatabaseEncoding() == PG_UTF8) SvUTF8_on(sv);
#endif
			XPUSHs(sv_2mortal(sv));
795
			pfree(tmp);
796 797 798
		}
	}
	PUTBACK;
799 800 801

	/* Do NOT use G_KEEPERR here */
	count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL);
802 803 804

	SPAGAIN;

805 806 807 808
	if (count != 1)
	{
		PUTBACK;
		FREETMPS;
809
		LEAVE;
810
		elog(ERROR, "didn't get a return item from function");
811 812
	}

813
	if (SvTRUE(ERRSV))
814
	{
815
		(void) POPs;
816 817
		PUTBACK;
		FREETMPS;
818
		LEAVE;
819 820 821 822
		/* 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)))));
823 824 825 826
	}

	retval = newSVsv(POPs);

827 828 829
	PUTBACK;
	FREETMPS;
	LEAVE;
830 831 832 833

	return retval;
}

834

835
static SV  *
836 837
plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo,
							  SV *td)
838 839 840
{
	dSP;
	SV		   *retval;
841
	Trigger    *tg_trigger;
842 843 844 845 846 847 848
	int			i;
	int			count;

	ENTER;
	SAVETMPS;

	PUSHMARK(sp);
849

850
	XPUSHs(td);
851

852 853 854
	tg_trigger = ((TriggerData *) fcinfo->context)->tg_trigger;
	for (i = 0; i < tg_trigger->tgnargs; i++)
		XPUSHs(sv_2mortal(newSVpv(tg_trigger->tgargs[i], 0)));
855 856
	PUTBACK;

857 858
	/* Do NOT use G_KEEPERR here */
	count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL);
859 860 861 862 863 864 865 866

	SPAGAIN;

	if (count != 1)
	{
		PUTBACK;
		FREETMPS;
		LEAVE;
867
		elog(ERROR, "didn't get a return item from trigger function");
868 869 870 871
	}

	if (SvTRUE(ERRSV))
	{
872
		(void) POPs;
873 874 875
		PUTBACK;
		FREETMPS;
		LEAVE;
876 877 878 879
		/* 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)))));
880 881 882 883 884 885 886 887 888 889
	}

	retval = newSVsv(POPs);

	PUTBACK;
	FREETMPS;
	LEAVE;

	return retval;
}
890

891

892
static Datum
893
plperl_func_handler(PG_FUNCTION_ARGS)
894 895
{
	plperl_proc_desc *prodesc;
896 897
	SV		   *perlret;
	Datum		retval;
898
	ReturnSetInfo *rsi;
899

900 901 902
	if (SPI_connect() != SPI_OK_CONNECT)
		elog(ERROR, "could not connect to SPI manager");

903
	prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, false);
904 905

	plperl_current_prodesc = prodesc;
906 907 908
	prodesc->caller_info = fcinfo;
	prodesc->tuple_store = 0;
	prodesc->tuple_desc = 0;
909

910
	perlret = plperl_call_perl_func(prodesc, fcinfo);
911 912 913 914 915 916 917 918

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

921
	rsi = (ReturnSetInfo *)fcinfo->resultinfo;
922

923 924
	if (prodesc->fn_retisset) 
	{
925 926 927
		if (!rsi || !IsA(rsi, ReturnSetInfo) ||
			(rsi->allowedModes & SFRM_Materialize) == 0 ||
			rsi->expectedDesc == NULL)
928
		{
929 930 931 932
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
					 errmsg("set-valued function called in context that "
							"cannot accept a set")));
933 934
		}

935 936 937 938 939 940
		/* 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)
941
		{
942 943 944
			int i = 0;
			SV **svp = 0;
			AV *rav = (AV *)SvRV(perlret);
945 946
			while ((svp = av_fetch(rav, i, FALSE)) != NULL) 
			{
947 948 949
				plperl_return_next(*svp);
				i++;
			}
950
		}
951
		else if (SvTYPE(perlret) != SVt_NULL)
952
		{
953 954
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
955 956
					 errmsg("set-returning Perl function must return "
							"reference to array or use return_next")));
957
		}
B
Bruce Momjian 已提交
958

959
		rsi->returnMode = SFRM_Materialize;
960 961
		if (prodesc->tuple_store) 
		{
962 963
			rsi->setResult = prodesc->tuple_store;
			rsi->setDesc = prodesc->tuple_desc;
964
		}
965 966 967 968 969 970 971 972 973
		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 已提交
974
	}
975
	else if (prodesc->fn_retistuple)
976
	{
977 978
		/* Return a perl hash converted to a Datum */
		TupleDesc td;
979
		AttInMetadata *attinmeta;
980
		HeapTuple tup;
981

982 983 984
		if (!SvOK(perlret) || SvTYPE(perlret) != SVt_RV ||
			SvTYPE(SvRV(perlret)) != SVt_PVHV)
		{
985 986
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
987 988 989
					 errmsg("composite-returning Perl function "
							"must return reference to hash")));
		}
990

991 992 993 994 995 996 997 998
		/* 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")));
		}
999

1000 1001
		attinmeta = TupleDescGetAttInMetadata(td);
		tup = plperl_build_tuple_result((HV *)SvRV(perlret), attinmeta);
1002 1003 1004 1005
		retval = HeapTupleGetDatum(tup);
	}
	else
	{
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
        /* Return a perl string converted to a Datum */
        char *val;
        SV* array_ret;
 

        if (prodesc->fn_retisarray && SvTYPE(SvRV(perlret)) == SVt_PVAV)
        {
            array_ret = plperl_convert_to_pg_array(perlret);
            SvREFCNT_dec(perlret);
            perlret = array_ret;
        }

		val = SvPV(perlret, PL_na);

1020 1021 1022 1023
		retval = FunctionCall3(&prodesc->result_in_func,
							   CStringGetDatum(val),
							   ObjectIdGetDatum(prodesc->result_typioparam),
							   Int32GetDatum(-1));
1024
	}
1025 1026 1027 1028 1029

	SvREFCNT_dec(perlret);
	return retval;
}

1030

1031 1032 1033 1034 1035 1036 1037 1038 1039
static Datum
plperl_trigger_handler(PG_FUNCTION_ARGS)
{
	plperl_proc_desc *prodesc;
	SV		   *perlret;
	Datum		retval;
	SV		   *svTD;
	HV		   *hvTD;

1040 1041 1042 1043
	/* Connect to SPI manager */
	if (SPI_connect() != SPI_OK_CONNECT)
		elog(ERROR, "could not connect to SPI manager");

1044 1045 1046
	/* Find or compile the function */
	prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, true);

1047 1048
	plperl_current_prodesc = prodesc;

1049 1050
	svTD = plperl_trigger_build_args(fcinfo);
	perlret = plperl_call_perl_trigger_func(prodesc, fcinfo, svTD);
1051
	hvTD = (HV *) SvRV(svTD);
1052 1053 1054 1055 1056 1057 1058 1059

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

1062
	if (!(perlret && SvOK(perlret) && SvTYPE(perlret) != SVt_NULL))
1063
	{
1064
		/* undef result means go ahead with original tuple */
1065 1066 1067 1068 1069 1070 1071 1072
		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;
1073 1074
		else
			retval = (Datum) 0;	/* can this happen? */
1075 1076 1077
	}
	else
	{
1078 1079
		HeapTuple	trv;
		char	   *tmp;
1080

1081
		tmp = SvPV(perlret, PL_na);
1082

1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
		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);
1095 1096
			else
			{
1097 1098 1099
				ereport(WARNING,
						(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
						 errmsg("ignoring modified tuple in DELETE trigger")));
1100 1101 1102
				trv = NULL;
			}
		}
1103
		else
1104
		{
1105 1106
			ereport(ERROR,
					(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
1107 1108
					 errmsg("result of Perl trigger function must be undef, "
							"\"SKIP\" or \"MODIFY\"")));
1109 1110 1111
			trv = NULL;
		}
		retval = PointerGetDatum(trv);
1112 1113
	}

1114 1115 1116
	SvREFCNT_dec(svTD);
	if (perlret)
		SvREFCNT_dec(perlret);
1117 1118 1119

	return retval;
}
1120

1121

1122 1123
static plperl_proc_desc *
compile_plperl_function(Oid fn_oid, bool is_trigger)
1124
{
1125 1126 1127 1128 1129
	HeapTuple	procTup;
	Form_pg_proc procStruct;
	char		internal_proname[64];
	int			proname_len;
	plperl_proc_desc *prodesc = NULL;
1130
	int			i;
1131
	SV			**svp;
1132

1133 1134 1135 1136 1137
	/* We'll need the pg_proc tuple in any case... */
	procTup = SearchSysCache(PROCOID,
							 ObjectIdGetDatum(fn_oid),
							 0, 0, 0);
	if (!HeapTupleIsValid(procTup))
1138
		elog(ERROR, "cache lookup failed for function %u", fn_oid);
1139
	procStruct = (Form_pg_proc) GETSTRUCT(procTup);
1140 1141 1142 1143

	/************************************************************
	 * Build our internal proc name from the functions Oid
	 ************************************************************/
1144 1145 1146 1147
	if (!is_trigger)
		sprintf(internal_proname, "__PLPerl_proc_%u", fn_oid);
	else
		sprintf(internal_proname, "__PLPerl_proc_%u_trigger", fn_oid);
1148

1149
	proname_len = strlen(internal_proname);
1150 1151 1152 1153

	/************************************************************
	 * Lookup the internal proc name in the hashtable
	 ************************************************************/
1154 1155
	svp = hv_fetch(plperl_proc_hash, internal_proname, proname_len, FALSE);
	if (svp)
1156
	{
1157 1158
		bool		uptodate;

1159
		prodesc = (plperl_proc_desc *) SvIV(*svp);
1160

1161
		/************************************************************
1162 1163 1164
		 * 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.
1165
		 ************************************************************/
1166
		uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
B
Bruce Momjian 已提交
1167
			prodesc->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data));
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189

		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;
1190 1191
		Datum		prosrcdatum;
		bool		isnull;
1192 1193 1194 1195 1196 1197
		char	   *proc_source;

		/************************************************************
		 * Allocate a new procedure description block
		 ************************************************************/
		prodesc = (plperl_proc_desc *) malloc(sizeof(plperl_proc_desc));
1198
		if (prodesc == NULL)
1199 1200 1201
			ereport(ERROR,
					(errcode(ERRCODE_OUT_OF_MEMORY),
					 errmsg("out of memory")));
1202 1203
		MemSet(prodesc, 0, sizeof(plperl_proc_desc));
		prodesc->proname = strdup(internal_proname);
1204 1205
		prodesc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
		prodesc->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);
1206

1207 1208 1209 1210
		/* Remember if function is STABLE/IMMUTABLE */
		prodesc->fn_readonly =
			(procStruct->provolatile != PROVOLATILE_VOLATILE);

1211
		/************************************************************
1212
		 * Lookup the pg_language tuple by Oid
1213
		 ************************************************************/
1214 1215
		langTup = SearchSysCache(LANGOID,
								 ObjectIdGetDatum(procStruct->prolang),
1216
								 0, 0, 0);
1217
		if (!HeapTupleIsValid(langTup))
1218 1219 1220
		{
			free(prodesc->proname);
			free(prodesc);
1221
			elog(ERROR, "cache lookup failed for language %u",
1222
				 procStruct->prolang);
1223
		}
1224 1225 1226
		langStruct = (Form_pg_language) GETSTRUCT(langTup);
		prodesc->lanpltrusted = langStruct->lanpltrusted;
		ReleaseSysCache(langTup);
1227 1228

		/************************************************************
1229 1230
		 * Get the required information for input conversion of the
		 * return value.
1231
		 ************************************************************/
1232 1233 1234
		if (!is_trigger)
		{
			typeTup = SearchSysCache(TYPEOID,
1235
								ObjectIdGetDatum(procStruct->prorettype),
1236 1237 1238 1239 1240
									 0, 0, 0);
			if (!HeapTupleIsValid(typeTup))
			{
				free(prodesc->proname);
				free(prodesc);
1241
				elog(ERROR, "cache lookup failed for type %u",
1242
					 procStruct->prorettype);
1243 1244 1245
			}
			typeStruct = (Form_pg_type) GETSTRUCT(typeTup);

1246
			/* Disallow pseudotype result, except VOID or RECORD */
1247 1248
			if (typeStruct->typtype == 'p')
			{
1249 1250
				if (procStruct->prorettype == VOIDOID ||
					procStruct->prorettype == RECORDOID)
B
Bruce Momjian 已提交
1251
					 /* okay */ ;
1252
				else if (procStruct->prorettype == TRIGGEROID)
1253 1254 1255
				{
					free(prodesc->proname);
					free(prodesc);
1256 1257
					ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1258 1259
							 errmsg("trigger functions may only be called "
									"as triggers")));
1260 1261 1262 1263 1264
				}
				else
				{
					free(prodesc->proname);
					free(prodesc);
1265 1266
					ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
B
Bruce Momjian 已提交
1267 1268
						 errmsg("plperl functions cannot return type %s",
								format_type_be(procStruct->prorettype))));
1269 1270 1271
				}
			}

1272 1273 1274 1275
			prodesc->result_oid = procStruct->prorettype;
			prodesc->fn_retisset = procStruct->proretset;
			prodesc->fn_retistuple = (typeStruct->typtype == 'c' ||
									  procStruct->prorettype == RECORDOID);
1276

1277 1278 1279
			prodesc->fn_retisarray = 
				(typeStruct->typlen == -1 && typeStruct->typelem) ;

1280
			perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
1281
			prodesc->result_typioparam = getTypeIOParam(typeTup);
1282 1283 1284

			ReleaseSysCache(typeTup);
		}
1285 1286

		/************************************************************
1287 1288
		 * Get the required information for output conversion
		 * of all procedure arguments
1289
		 ************************************************************/
1290 1291 1292 1293 1294 1295
		if (!is_trigger)
		{
			prodesc->nargs = procStruct->pronargs;
			for (i = 0; i < prodesc->nargs; i++)
			{
				typeTup = SearchSysCache(TYPEOID,
1296
							ObjectIdGetDatum(procStruct->proargtypes.values[i]),
1297 1298 1299 1300 1301
										 0, 0, 0);
				if (!HeapTupleIsValid(typeTup))
				{
					free(prodesc->proname);
					free(prodesc);
1302
					elog(ERROR, "cache lookup failed for type %u",
1303
						 procStruct->proargtypes.values[i]);
1304 1305 1306
				}
				typeStruct = (Form_pg_type) GETSTRUCT(typeTup);

1307 1308 1309 1310 1311
				/* Disallow pseudotype argument */
				if (typeStruct->typtype == 'p')
				{
					free(prodesc->proname);
					free(prodesc);
1312 1313
					ereport(ERROR,
							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
B
Bruce Momjian 已提交
1314
						   errmsg("plperl functions cannot take type %s",
1315
						   format_type_be(procStruct->proargtypes.values[i]))));
1316 1317
				}

1318 1319
				if (typeStruct->typtype == 'c')
					prodesc->arg_is_rowtype[i] = true;
1320
				else
1321 1322 1323 1324 1325
				{
					prodesc->arg_is_rowtype[i] = false;
					perm_fmgr_info(typeStruct->typoutput,
								   &(prodesc->arg_out_func[i]));
				}
1326 1327 1328 1329

				ReleaseSysCache(typeTup);
			}
		}
1330

1331 1332 1333 1334 1335
		/************************************************************
		 * create the text of the anonymous subroutine.
		 * we do not use a named subroutine so that we can call directly
		 * through the reference.
		 ************************************************************/
1336 1337 1338 1339
		prosrcdatum = SysCacheGetAttr(PROCOID, procTup,
									  Anum_pg_proc_prosrc, &isnull);
		if (isnull)
			elog(ERROR, "null prosrc");
1340
		proc_source = DatumGetCString(DirectFunctionCall1(textout,
1341
														  prosrcdatum));
1342 1343

		/************************************************************
1344
		 * Create the procedure in the interpreter
1345
		 ************************************************************/
1346 1347
		prodesc->reference = plperl_create_sub(proc_source, prodesc->lanpltrusted);
		pfree(proc_source);
1348
		if (!prodesc->reference) /* can this happen? */
1349 1350 1351
		{
			free(prodesc->proname);
			free(prodesc);
1352
			elog(ERROR, "could not create internal procedure \"%s\"",
1353
				 internal_proname);
1354 1355
		}

1356 1357
		hv_store(plperl_proc_hash, internal_proname, proname_len,
				 newSViv((IV) prodesc), 0);
1358 1359
	}

1360
	ReleaseSysCache(procTup);
1361

1362 1363
	return prodesc;
}
1364 1365


1366 1367
/* Build a hash from all attributes of a given tuple. */

B
Bruce Momjian 已提交
1368
static SV  *
1369
plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc)
1370
{
1371
	HV		   *hv;
1372
	int			i;
1373

1374
	hv = newHV();
1375 1376 1377

	for (i = 0; i < tupdesc->natts; i++)
	{
1378 1379 1380 1381 1382 1383 1384
		Datum		attr;
		bool		isnull;
		char	   *attname;
		char	   *outputstr;
		Oid			typoutput;
		bool		typisvarlena;
		int			namelen;
1385
		SV			*sv;
1386

1387 1388 1389
		if (tupdesc->attrs[i]->attisdropped)
			continue;

1390
		attname = NameStr(tupdesc->attrs[i]->attname);
1391
		namelen = strlen(attname);
1392 1393
		attr = heap_getattr(tuple, i + 1, tupdesc, &isnull);

1394 1395 1396
		if (isnull) {
			/* Store (attname => undef) and move on. */
			hv_store(hv, attname, namelen, newSV(0), 0);
1397 1398 1399
			continue;
		}

1400
		/* XXX should have a way to cache these lookups */
1401

1402
		getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
1403
						  &typoutput, &typisvarlena);
1404

1405
		outputstr = DatumGetCString(OidFunctionCall1(typoutput, attr));
1406

1407 1408
		sv = newSVpv(outputstr, 0);
#if PERL_BCDVERSION >= 0x5006000L
1409 1410
		if (GetDatabaseEncoding() == PG_UTF8)
			SvUTF8_on(sv);
1411 1412
#endif
		hv_store(hv, attname, namelen, sv, 0);
1413 1414

		pfree(outputstr);
1415
	}
1416

1417
	return newRV_noinc((SV *) hv);
1418
}
1419 1420 1421 1422 1423 1424 1425


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

1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 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
	/*
	 * 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();
1484 1485 1486 1487

	return ret_hv;
}

1488

1489
static HV  *
1490 1491
plperl_spi_execute_fetch_result(SPITupleTable *tuptable, int processed,
								int status)
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503
{
	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)
	{
1504
		AV		   *rows;
1505
		SV		   *row;
1506
		int			i;
1507

1508 1509 1510 1511
		rows = newAV();
		for (i = 0; i < processed; i++)
		{
			row = plperl_hash_from_tuple(tuptable->vals[i], tuptable->tupdesc);
1512
			av_push(rows, row);
1513
		}
1514 1515
		hv_store(result, "rows", strlen("rows"),
				 newRV_noinc((SV *) rows), 0);
1516 1517 1518 1519 1520 1521
	}

	SPI_freetuptable(tuptable);

	return result;
}
1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 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 1570 1571 1572 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


void
plperl_return_next(SV *sv)
{
	plperl_proc_desc *prodesc = plperl_current_prodesc;
	FunctionCallInfo fcinfo = prodesc->caller_info;
	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);

	if (!prodesc->tuple_store)
		prodesc->tuple_store = tuplestore_begin_heap(true, false, work_mem);

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

	if (!prodesc->tuple_desc)
		prodesc->tuple_desc = tupdesc;

	tuplestore_puttuple(prodesc->tuple_store, tuple);
	heap_freetuple(tuple);
	MemoryContextSwitchTo(cxt);
}
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 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


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