plperl.c 23.5 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 Weick.
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
 *	  $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.28 2002/01/24 21:40:44 tgl Exp $
37
 *
38 39
 **********************************************************************/

40
#include "postgres.h"
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

/* system stuff */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <setjmp.h>

/* postgreSQL stuff */
#include "executor/spi.h"
#include "commands/trigger.h"
#include "utils/elog.h"
#include "fmgr.h"
#include "access/heapam.h"

#include "tcop/tcopprot.h"
#include "utils/syscache.h"
60
#include "catalog/pg_language.h"
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"

/* perl stuff */
/*
 * Evil Code Alert
 *
 * both posgreSQL and perl try to do 'the right thing'
 * and provide union semun if the platform doesn't define
 * it in a system header.
 * psql uses HAVE_UNION_SEMUN
 * perl uses HAS_UNION_SEMUN
 * together, they cause compile errors.
 * If we need it, the psql headers above will provide it.
 * So we tell perl that we have it.
 */
#ifndef HAS_UNION_SEMUN
#define HAS_UNION_SEMUN
#endif
80

B
Bruce Momjian 已提交
81 82
#include "EXTERN.h"
#include "perl.h"
83
#include "XSUB.h"
84
#include "ppport.h"
85

86 87 88 89 90 91
/* just in case these symbols aren't provided */
#ifndef pTHX_
#define pTHX_
#define pTHX void
#endif

92 93 94 95 96 97 98

/**********************************************************************
 * The information we cache about loaded procedures
 **********************************************************************/
typedef struct plperl_proc_desc
{
	char	   *proname;
99 100 101
	TransactionId fn_xmin;
	CommandId	fn_cmin;
	bool		lanpltrusted;
102 103 104 105 106 107
	FmgrInfo	result_in_func;
	Oid			result_in_elem;
	int			nargs;
	FmgrInfo	arg_out_func[FUNC_MAX_ARGS];
	Oid			arg_out_elem[FUNC_MAX_ARGS];
	int			arg_is_rel[FUNC_MAX_ARGS];
108
	SV		   *reference;
109
}	plperl_proc_desc;
110 111 112 113 114 115 116 117


/**********************************************************************
 * Global data
 **********************************************************************/
static int	plperl_firstcall = 1;
static int	plperl_call_level = 0;
static int	plperl_restart_in_progress = 0;
118
static PerlInterpreter *plperl_interp = NULL;
119 120
static HV  *plperl_proc_hash = NULL;

121 122 123 124
/**********************************************************************
 * Forward declarations
 **********************************************************************/
static void plperl_init_all(void);
125
static void plperl_init_interp(void);
126

B
Bruce Momjian 已提交
127
Datum		plperl_call_handler(PG_FUNCTION_ARGS);
128

129
static Datum plperl_func_handler(PG_FUNCTION_ARGS);
130

131 132
static plperl_proc_desc *compile_plperl_function(Oid fn_oid, bool is_trigger);

133
static SV  *plperl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc);
134
static void plperl_init_shared_libs(pTHX);
135 136


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

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
/**********************************************************************
 * plperl_init_all()		- Initialize all
 **********************************************************************/
static void
plperl_init_all(void)
{

	/************************************************************
	 * Do initialization only once
	 ************************************************************/
	if (!plperl_firstcall)
		return;


	/************************************************************
169
	 * Destroy the existing Perl interpreter
170
	 ************************************************************/
171
	if (plperl_interp != NULL)
172
	{
173 174 175
		perl_destruct(plperl_interp);
		perl_free(plperl_interp);
		plperl_interp = NULL;
176 177 178 179 180 181 182 183
	}

	/************************************************************
	 * Free the proc hash table
	 ************************************************************/
	if (plperl_proc_hash != NULL)
	{
		hv_undef(plperl_proc_hash);
184
		SvREFCNT_dec((SV *) plperl_proc_hash);
185 186 187 188
		plperl_proc_hash = NULL;
	}

	/************************************************************
189
	 * Now recreate a new Perl interpreter
190
	 ************************************************************/
191
	plperl_init_interp();
192 193 194 195 196 197

	plperl_firstcall = 0;
}


/**********************************************************************
198
 * plperl_init_interp() - Create the Perl interpreter
199 200
 **********************************************************************/
static void
201
plperl_init_interp(void)
202 203
{

B
Bruce Momjian 已提交
204
	char	   *embedding[3] = {
B
Bruce Momjian 已提交
205 206 207
		"", "-e",

		/*
208
		 * no commas between the next 5 please. They are supposed to be
B
Bruce Momjian 已提交
209
		 * one string
B
Bruce Momjian 已提交
210 211
		 */
		"require Safe; SPI::bootstrap();"
212
		"sub ::mksafefunc { my $x = new Safe; $x->permit_only(':default');$x->permit(':base_math');"
T
Tom Lane 已提交
213
		"$x->share(qw[&elog &DEBUG &NOTICE &ERROR]);"
B
Bruce Momjian 已提交
214
		" return $x->reval(qq[sub { $_[0] }]); }"
215
		"sub ::mkunsafefunc {return eval(qq[ sub { $_[0] } ]); }"
B
Bruce Momjian 已提交
216
	};
217

218 219 220
	plperl_interp = perl_alloc();
	if (!plperl_interp)
		elog(ERROR, "plperl_init_interp(): could not allocate perl interpreter");
221

222 223 224
	perl_construct(plperl_interp);
	perl_parse(plperl_interp, plperl_init_shared_libs, 3, embedding, NULL);
	perl_run(plperl_interp);
225

226

227 228 229

	/************************************************************
	 * Initialize the proc and query hash tables
230
	 ************************************************************/
231
	plperl_proc_hash = newHV();
232 233 234 235 236 237 238 239 240 241 242 243

}



/**********************************************************************
 * plperl_call_handler		- This is the only visible function
 *				  of the PL interpreter. The PostgreSQL
 *				  function manager and trigger manager
 *				  call this function for execution of
 *				  perl procedures.
 **********************************************************************/
244
PG_FUNCTION_INFO_V1(plperl_call_handler);
245 246 247

/* keep non-static */
Datum
248
plperl_call_handler(PG_FUNCTION_ARGS)
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
{
	Datum		retval;

	/************************************************************
	 * Initialize interpreters on first call
	 ************************************************************/
	if (plperl_firstcall)
		plperl_init_all();

	/************************************************************
	 * Connect to SPI manager
	 ************************************************************/
	if (SPI_connect() != SPI_OK_CONNECT)
		elog(ERROR, "plperl: cannot connect to SPI manager");
	/************************************************************
264
	 * Keep track about the nesting of Perl-SPI-Perl-... calls
265 266 267 268 269 270 271
	 ************************************************************/
	plperl_call_level++;

	/************************************************************
	 * Determine if called as function or trigger and
	 * call appropriate subhandler
	 ************************************************************/
272
	if (CALLED_AS_TRIGGER(fcinfo))
273
	{
274
		elog(ERROR, "plperl: can't use perl in triggers yet.");
275

276
		/*
277
		 * retval = PointerGetDatum(plperl_trigger_handler(fcinfo));
278
		 */
279 280 281
		/* make the compiler happy */
		retval = (Datum) 0;
	}
282 283
	else
		retval = plperl_func_handler(fcinfo);
284 285 286 287 288 289 290 291 292

	plperl_call_level--;

	return retval;
}


/**********************************************************************
 * plperl_create_sub()		- calls the perl interpreter to
293 294
 *		create the anonymous subroutine whose text is in the SV.
 *		Returns the SV containing the RV to the closure.
295 296 297
 **********************************************************************/
static
SV *
298
plperl_create_sub(char *s, bool trusted)
299
{
300 301
	dSP;

302
	SV		   *subref = NULL;
B
Bruce Momjian 已提交
303
	int			count;
304 305 306 307

	ENTER;
	SAVETMPS;
	PUSHMARK(SP);
B
Bruce Momjian 已提交
308
	XPUSHs(sv_2mortal(newSVpv(s, 0)));
B
Bruce Momjian 已提交
309
	PUTBACK;
310 311
	count = perl_call_pv((trusted ? "mksafefunc" : "mkunsafefunc"),
						 G_SCALAR | G_EVAL | G_KEEPERR);
312 313
	SPAGAIN;

314
	if (SvTRUE(ERRSV))
315
	{
316 317 318 319
		POPs;
		PUTBACK;
		FREETMPS;
		LEAVE;
320
		elog(ERROR, "creation of function failed: %s", SvPV(ERRSV, PL_na));
321 322
	}

B
Bruce Momjian 已提交
323
	if (count != 1)
B
Bruce Momjian 已提交
324 325
		elog(ERROR, "creation of function failed - no return from mksafefunc");

326
	/*
327 328
	 * need to make a deep copy of the return. it comes off the stack as a
	 * temporary.
329 330 331
	 */
	subref = newSVsv(POPs);

332 333
	if (!SvROK(subref))
	{
334 335 336
		PUTBACK;
		FREETMPS;
		LEAVE;
337

338 339 340 341 342 343 344 345 346 347 348 349 350 351
		/*
		 * subref is our responsibility because it is not mortal
		 */
		SvREFCNT_dec(subref);
		elog(ERROR, "plperl_create_sub: didn't get a code ref");
	}

	PUTBACK;
	FREETMPS;
	LEAVE;
	return subref;
}

/**********************************************************************
352
 * plperl_init_shared_libs()		-
353 354 355 356
 *
 * 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.
357
 *
358 359
 **********************************************************************/

360 361
EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);
EXTERN_C void boot_SPI(pTHX_ CV* cv);
362

363
static void
364
plperl_init_shared_libs(pTHX)
365
{
366 367
	char	   *file = __FILE__;

368
	newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
369
	newXS("SPI::bootstrap", boot_SPI, file);
370 371 372 373 374 375 376
}

/**********************************************************************
 * plperl_call_perl_func()		- calls a perl function through the RV
 *			stored in the prodesc structure. massages the input parms properly
 **********************************************************************/
static
377
SV *
378
plperl_call_perl_func(plperl_proc_desc * desc, FunctionCallInfo fcinfo)
379 380 381
{
	dSP;

382 383 384
	SV		   *retval;
	int			i;
	int			count;
385 386 387 388 389 390


	ENTER;
	SAVETMPS;

	PUSHMARK(sp);
391 392 393 394
	for (i = 0; i < desc->nargs; i++)
	{
		if (desc->arg_is_rel[i])
		{
395 396
			TupleTableSlot *slot = (TupleTableSlot *) fcinfo->arg[i];
			SV		   *hashref;
397

B
Bruce Momjian 已提交
398 399
			Assert(slot != NULL && !fcinfo->argnull[i]);

400
			/*
401 402
			 * plperl_build_tuple_argument better return a mortal SV.
			 */
403
			hashref = plperl_build_tuple_argument(slot->val,
B
Bruce Momjian 已提交
404
											  slot->ttc_tupleDescriptor);
405
			XPUSHs(hashref);
406 407 408
		}
		else
		{
409 410 411 412 413 414
			if (fcinfo->argnull[i])
				XPUSHs(&PL_sv_undef);
			else
			{
				char	   *tmp;

415
				tmp = DatumGetCString(FunctionCall3(&(desc->arg_out_func[i]),
B
Bruce Momjian 已提交
416 417
													fcinfo->arg[i],
								 ObjectIdGetDatum(desc->arg_out_elem[i]),
418
													Int32GetDatum(-1)));
419 420 421
				XPUSHs(sv_2mortal(newSVpv(tmp, 0)));
				pfree(tmp);
			}
422 423 424 425 426 427 428
		}
	}
	PUTBACK;
	count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL | G_KEEPERR);

	SPAGAIN;

429 430 431 432
	if (count != 1)
	{
		PUTBACK;
		FREETMPS;
433
		LEAVE;
434
		elog(ERROR, "plperl: didn't get a return item from function");
435 436
	}

437
	if (SvTRUE(ERRSV))
438
	{
439
		POPs;
440 441
		PUTBACK;
		FREETMPS;
442
		LEAVE;
443
		elog(ERROR, "plperl: error from function: %s", SvPV(ERRSV, PL_na));
444 445 446 447 448
	}

	retval = newSVsv(POPs);


449 450 451
	PUTBACK;
	FREETMPS;
	LEAVE;
452 453 454 455 456 457 458 459 460 461

	return retval;


}

/**********************************************************************
 * plperl_func_handler()		- Handler for regular function calls
 **********************************************************************/
static Datum
462
plperl_func_handler(PG_FUNCTION_ARGS)
463 464
{
	plperl_proc_desc *prodesc;
465 466
	SV		   *perlret;
	Datum		retval;
467 468
	sigjmp_buf	save_restart;

469 470
	/* Find or compile the function */
	prodesc = compile_plperl_function(fcinfo->flinfo->fn_oid, false);
471

472
	/* Set up error handling */
473 474 475 476 477 478 479 480 481 482 483 484 485 486
	memcpy(&save_restart, &Warn_restart, sizeof(save_restart));

	if (sigsetjmp(Warn_restart, 1) != 0)
	{
		memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));
		plperl_restart_in_progress = 1;
		if (--plperl_call_level == 0)
			plperl_restart_in_progress = 0;
		siglongjmp(Warn_restart, 1);
	}

	/************************************************************
	 * Call the Perl function
	 ************************************************************/
487
	perlret = plperl_call_perl_func(prodesc, fcinfo);
488 489 490 491 492 493 494 495 496 497

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

498
	if (!(perlret && SvOK(perlret)))
499
	{
500
		/* return NULL if Perl code returned undef */
501 502 503 504 505 506
		retval = (Datum) 0;
		fcinfo->isnull = true;
	}
	else
	{
		retval = FunctionCall3(&prodesc->result_in_func,
507
							   PointerGetDatum(SvPV(perlret, PL_na)),
508
							   ObjectIdGetDatum(prodesc->result_in_elem),
509
							   Int32GetDatum(-1));
510
	}
511 512 513 514

	SvREFCNT_dec(perlret);

	memcpy(&Warn_restart, &save_restart, sizeof(Warn_restart));
515 516 517
	if (plperl_restart_in_progress)
	{
		if (--plperl_call_level == 0)
518
			plperl_restart_in_progress = 0;
519
		siglongjmp(Warn_restart, 1);
520 521 522 523 524 525 526
	}

	return retval;
}


/**********************************************************************
527
 * compile_plperl_function	- compile (or hopefully just look up) function
528
 **********************************************************************/
529 530
static plperl_proc_desc *
compile_plperl_function(Oid fn_oid, bool is_trigger)
531
{
532 533 534 535 536
	HeapTuple	procTup;
	Form_pg_proc procStruct;
	char		internal_proname[64];
	int			proname_len;
	plperl_proc_desc *prodesc = NULL;
537 538
	int			i;

539 540 541 542 543 544 545
	/* We'll need the pg_proc tuple in any case... */
	procTup = SearchSysCache(PROCOID,
							 ObjectIdGetDatum(fn_oid),
							 0, 0, 0);
	if (!HeapTupleIsValid(procTup))
		elog(ERROR, "plperl: cache lookup for proc %u failed", fn_oid);
	procStruct = (Form_pg_proc) GETSTRUCT(procTup);
546 547 548 549

	/************************************************************
	 * Build our internal proc name from the functions Oid
	 ************************************************************/
550 551 552 553 554
	if (!is_trigger)
		sprintf(internal_proname, "__PLPerl_proc_%u", fn_oid);
	else
		sprintf(internal_proname, "__PLPerl_proc_%u_trigger", fn_oid);
	proname_len = strlen(internal_proname);
555 556 557 558

	/************************************************************
	 * Lookup the internal proc name in the hashtable
	 ************************************************************/
559
	if (hv_exists(plperl_proc_hash, internal_proname, proname_len))
560
	{
561 562 563 564 565
		bool		uptodate;

		prodesc = (plperl_proc_desc *) SvIV(*hv_fetch(plperl_proc_hash,
									  internal_proname, proname_len, 0));

566
		/************************************************************
567 568 569
		 * 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.
570
		 ************************************************************/
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
		uptodate = (prodesc->fn_xmin == procTup->t_data->t_xmin &&
					prodesc->fn_cmin == procTup->t_data->t_cmin);

		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;
595 596 597 598 599 600
		char	   *proc_source;

		/************************************************************
		 * Allocate a new procedure description block
		 ************************************************************/
		prodesc = (plperl_proc_desc *) malloc(sizeof(plperl_proc_desc));
601 602 603 604 605 606
		if (prodesc == NULL)
			elog(ERROR, "plperl: out of memory");
		MemSet(prodesc, 0, sizeof(plperl_proc_desc));
		prodesc->proname = strdup(internal_proname);
		prodesc->fn_xmin = procTup->t_data->t_xmin;
		prodesc->fn_cmin = procTup->t_data->t_cmin;
607 608

		/************************************************************
609
		 * Lookup the pg_language tuple by Oid
610
		 ************************************************************/
611 612
		langTup = SearchSysCache(LANGOID,
								 ObjectIdGetDatum(procStruct->prolang),
613
								 0, 0, 0);
614
		if (!HeapTupleIsValid(langTup))
615 616 617
		{
			free(prodesc->proname);
			free(prodesc);
618 619
			elog(ERROR, "plperl: cache lookup for language %u failed",
				 procStruct->prolang);
620
		}
621 622 623
		langStruct = (Form_pg_language) GETSTRUCT(langTup);
		prodesc->lanpltrusted = langStruct->lanpltrusted;
		ReleaseSysCache(langTup);
624 625

		/************************************************************
626 627
		 * Get the required information for input conversion of the
		 * return value.
628
		 ************************************************************/
629 630 631
		if (!is_trigger)
		{
			typeTup = SearchSysCache(TYPEOID,
632
								ObjectIdGetDatum(procStruct->prorettype),
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
									 0, 0, 0);
			if (!HeapTupleIsValid(typeTup))
			{
				free(prodesc->proname);
				free(prodesc);
				if (!OidIsValid(procStruct->prorettype))
					elog(ERROR, "plperl functions cannot return type \"opaque\""
						 "\n\texcept when used as triggers");
				else
					elog(ERROR, "plperl: cache lookup for return type %u failed",
						 procStruct->prorettype);
			}
			typeStruct = (Form_pg_type) GETSTRUCT(typeTup);

			if (typeStruct->typrelid != InvalidOid)
			{
				free(prodesc->proname);
				free(prodesc);
				elog(ERROR, "plperl: return types of tuples not supported yet");
			}

			perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
			prodesc->result_in_elem = typeStruct->typelem;

			ReleaseSysCache(typeTup);
		}
659 660

		/************************************************************
661 662
		 * Get the required information for output conversion
		 * of all procedure arguments
663
		 ************************************************************/
664 665 666 667 668 669
		if (!is_trigger)
		{
			prodesc->nargs = procStruct->pronargs;
			for (i = 0; i < prodesc->nargs; i++)
			{
				typeTup = SearchSysCache(TYPEOID,
670
							ObjectIdGetDatum(procStruct->proargtypes[i]),
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
										 0, 0, 0);
				if (!HeapTupleIsValid(typeTup))
				{
					free(prodesc->proname);
					free(prodesc);
					if (!OidIsValid(procStruct->proargtypes[i]))
						elog(ERROR, "plperl functions cannot take type \"opaque\"");
					else
						elog(ERROR, "plperl: cache lookup for argument type %u failed",
							 procStruct->proargtypes[i]);
				}
				typeStruct = (Form_pg_type) GETSTRUCT(typeTup);

				if (typeStruct->typrelid != InvalidOid)
					prodesc->arg_is_rel[i] = 1;
				else
					prodesc->arg_is_rel[i] = 0;

				perm_fmgr_info(typeStruct->typoutput, &(prodesc->arg_out_func[i]));
				prodesc->arg_out_elem[i] = typeStruct->typelem;
				ReleaseSysCache(typeTup);
			}
		}
694

695 696 697 698 699 700
		/************************************************************
		 * create the text of the anonymous subroutine.
		 * we do not use a named subroutine so that we can call directly
		 * through the reference.
		 *
		 ************************************************************/
701
		proc_source = DatumGetCString(DirectFunctionCall1(textout,
B
Bruce Momjian 已提交
702
								  PointerGetDatum(&procStruct->prosrc)));
703 704

		/************************************************************
705
		 * Create the procedure in the interpreter
706
		 ************************************************************/
707 708 709
		prodesc->reference = plperl_create_sub(proc_source, prodesc->lanpltrusted);
		pfree(proc_source);
		if (!prodesc->reference)
710 711 712
		{
			free(prodesc->proname);
			free(prodesc);
713 714
			elog(ERROR, "plperl: cannot create internal procedure %s",
				 internal_proname);
715 716 717 718 719
		}

		/************************************************************
		 * Add the proc description block to the hashtable
		 ************************************************************/
720 721
		hv_store(plperl_proc_hash, internal_proname, proname_len,
				 newSViv((IV) prodesc), 0);
722 723
	}

724
	ReleaseSysCache(procTup);
725

726 727
	return prodesc;
}
728 729 730 731 732 733


/**********************************************************************
 * plperl_build_tuple_argument() - Build a string for a ref to a hash
 *				  from all attributes of a given tuple
 **********************************************************************/
734
static SV  *
735 736 737
plperl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc)
{
	int			i;
738
	SV		   *output;
739 740 741
	Datum		attr;
	bool		isnull;
	char	   *attname;
742
	char	   *outputstr;
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
	HeapTuple	typeTup;
	Oid			typoutput;
	Oid			typelem;

	output = sv_2mortal(newSVpv("{", 0));

	for (i = 0; i < tupdesc->natts; i++)
	{
		/************************************************************
		 * Get the attribute name
		 ************************************************************/
		attname = tupdesc->attrs[i]->attname.data;

		/************************************************************
		 * Get the attributes value
		 ************************************************************/
		attr = heap_getattr(tuple, i + 1, tupdesc, &isnull);

761 762 763 764 765 766 767 768 769
		/************************************************************
		 *	If it is null it will be set to undef in the hash.
		 ************************************************************/
		if (isnull)
		{
			sv_catpvf(output, "'%s' => undef,", attname);
			continue;
		}

770 771 772 773
		/************************************************************
		 * Lookup the attribute type in the syscache
		 * for the output function
		 ************************************************************/
774
		typeTup = SearchSysCache(TYPEOID,
775
						   ObjectIdGetDatum(tupdesc->attrs[i]->atttypid),
776
								 0, 0, 0);
777
		if (!HeapTupleIsValid(typeTup))
778 779
			elog(ERROR, "plperl: Cache lookup for attribute '%s' type %u failed",
				 attname, tupdesc->attrs[i]->atttypid);
780

781 782
		typoutput = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
		typelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
783
		ReleaseSysCache(typeTup);
784 785

		/************************************************************
786
		 * Append the attribute name and the value to the list.
787
		 ************************************************************/
788 789
		outputstr = DatumGetCString(OidFunctionCall3(typoutput,
													 attr,
790 791
											   ObjectIdGetDatum(typelem),
						   Int32GetDatum(tupdesc->attrs[i]->atttypmod)));
792 793
		sv_catpvf(output, "'%s' => '%s',", attname, outputstr);
		pfree(outputstr);
794
	}
795

796
	sv_catpv(output, "}");
797
	output = perl_eval_pv(SvPV(output, PL_na), TRUE);
798 799
	return output;
}