1
/**********************************************************************
2
* pl_comp.c - Compiler part of the PL/pgSQL
6
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.83 2004-11-30 03:50:29 neilc Exp $
8
* This software is copyrighted by Jan Wieck - Hamburg.
10
* The author hereby grants permission to use, copy, modify,
11
* distribute, and license this software and its documentation
12
* for any purpose, provided that existing copyright notices are
13
* retained in all copies and that this notice is included
14
* verbatim in any distributions. No written agreement, license,
15
* or royalty fee is required for any of the authorized uses.
16
* Modifications to this software may be copyrighted by their
17
* author and need not follow the licensing terms described
18
* here, provided that the new terms are clearly indicated on
19
* the first page of each file where they apply.
21
* IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY
22
* PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
23
* CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
24
* SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
25
* IF THE AUTHOR HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
28
* THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY
29
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
31
* PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON
32
* AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAVE NO
33
* OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
34
* ENHANCEMENTS, OR MODIFICATIONS.
36
**********************************************************************/
44
#include "access/heapam.h"
45
#include "catalog/catname.h"
46
#include "catalog/namespace.h"
47
#include "catalog/pg_attribute.h"
48
#include "catalog/pg_attrdef.h"
49
#include "catalog/pg_class.h"
50
#include "catalog/pg_proc.h"
51
#include "catalog/pg_type.h"
52
#include "nodes/makefuncs.h"
53
#include "parser/gramparse.h"
54
#include "parser/parse_type.h"
55
#include "tcop/tcopprot.h"
56
#include "utils/array.h"
57
#include "utils/builtins.h"
58
#include "utils/lsyscache.h"
59
#include "utils/syscache.h"
63
* Variables in the parser that shouldn't go into plpgsql.h
66
extern PLPGSQL_YYSTYPE plpgsql_yylval;
69
* Our own local and global variables
72
static int datums_alloc;
74
PLpgSQL_datum **plpgsql_Datums;
75
static int datums_last = 0;
77
int plpgsql_error_lineno;
78
char *plpgsql_error_funcname;
79
int plpgsql_DumpExecTree = 0;
81
PLpgSQL_function *plpgsql_curr_compile;
84
* Hash table for compiled functions
87
static HTAB *plpgsql_HashTable = NULL;
89
typedef struct plpgsql_hashent
91
PLpgSQL_func_hashkey key;
92
PLpgSQL_function *function;
95
#define FUNCS_PER_USER 128 /* initial table size */
98
* Lookup table for EXCEPTION condition names
107
static const ExceptionLabelMap exception_label_map[] = {
108
#include "plerrcodes.h"
117
static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo,
119
PLpgSQL_func_hashkey *hashkey,
121
static void plpgsql_compile_error_callback(void *arg);
122
static char **fetchArgNames(HeapTuple procTup, int nargs);
123
static PLpgSQL_row *build_row_var(Oid classOid);
124
static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod);
125
static void compute_function_hashkey(FunctionCallInfo fcinfo,
126
Form_pg_proc procStruct,
127
PLpgSQL_func_hashkey *hashkey,
129
static PLpgSQL_function *plpgsql_HashTableLookup(PLpgSQL_func_hashkey *func_key);
130
static void plpgsql_HashTableInsert(PLpgSQL_function *function,
131
PLpgSQL_func_hashkey *func_key);
132
static void plpgsql_HashTableDelete(PLpgSQL_function *function);
135
* This routine is a crock, and so is everyplace that calls it. The problem
136
* is that the compiled form of a plpgsql function is allocated permanently
137
* (mostly via malloc()) and never released until backend exit. Subsidiary
138
* data structures such as fmgr info records therefore must live forever
139
* as well. A better implementation would store all this stuff in a per-
140
* function memory context that could be reclaimed at need. In the meantime,
141
* fmgr_info_cxt must be called specifying TopMemoryContext so that whatever
142
* it might allocate, and whatever the eventual function might allocate using
143
* fn_mcxt, will live forever too.
146
perm_fmgr_info(Oid functionId, FmgrInfo *finfo)
148
fmgr_info_cxt(functionId, finfo, TopMemoryContext);
153
* plpgsql_compile Make an execution tree for a PL/pgSQL function.
155
* If forValidator is true, we're only compiling for validation purposes,
156
* and so some checks are skipped.
158
* Note: it's important for this to fall through quickly if the function
159
* has already been compiled.
163
plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator)
165
Oid funcOid = fcinfo->flinfo->fn_oid;
167
Form_pg_proc procStruct;
168
PLpgSQL_function *function;
169
PLpgSQL_func_hashkey hashkey;
170
bool hashkey_valid = false;
173
* Lookup the pg_proc tuple by Oid; we'll need it in any case
175
procTup = SearchSysCache(PROCOID,
176
ObjectIdGetDatum(funcOid),
178
if (!HeapTupleIsValid(procTup))
179
elog(ERROR, "cache lookup failed for function %u", funcOid);
180
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
183
* See if there's already a cache entry for the current FmgrInfo. If
184
* not, try to find one in the hash table.
186
function = (PLpgSQL_function *) fcinfo->flinfo->fn_extra;
190
/* First time through in this backend? If so, init hashtable */
191
if (!plpgsql_HashTable)
192
plpgsql_HashTableInit();
194
/* Compute hashkey using function signature and actual arg types */
195
compute_function_hashkey(fcinfo, procStruct, &hashkey, forValidator);
196
hashkey_valid = true;
198
/* And do the lookup */
199
function = plpgsql_HashTableLookup(&hashkey);
204
/* We have a compiled function, but is it still valid? */
205
if (!(function->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
206
function->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data)))
209
* Nope, drop the hashtable entry. XXX someday, free all the
210
* subsidiary storage as well.
212
plpgsql_HashTableDelete(function);
219
* If the function wasn't found or was out-of-date, we have to compile
225
* Calculate hashkey if we didn't already; we'll need it to store
226
* the completed function.
229
compute_function_hashkey(fcinfo, procStruct, &hashkey,
235
function = do_compile(fcinfo, procTup, &hashkey, forValidator);
238
ReleaseSysCache(procTup);
241
* Save pointer in FmgrInfo to avoid search on subsequent calls
243
fcinfo->flinfo->fn_extra = (void *) function;
246
* Finally return the compiled function
252
* This is the slow part of plpgsql_compile().
254
static PLpgSQL_function *
255
do_compile(FunctionCallInfo fcinfo,
257
PLpgSQL_func_hashkey *hashkey,
260
Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
261
int functype = CALLED_AS_TRIGGER(fcinfo) ? T_TRIGGER : T_FUNCTION;
262
PLpgSQL_function *function;
267
Form_pg_type typeStruct;
268
PLpgSQL_variable *var;
271
int arg_varnos[FUNC_MAX_ARGS];
272
ErrorContextCallback plerrcontext;
278
* Setup the scanner input and error info. We assume that this
279
* function cannot be invoked recursively, so there's no need to save
280
* and restore the static variables used here.
282
prosrcdatum = SysCacheGetAttr(PROCOID, procTup,
283
Anum_pg_proc_prosrc, &isnull);
285
elog(ERROR, "null prosrc");
286
proc_source = DatumGetCString(DirectFunctionCall1(textout, prosrcdatum));
287
plpgsql_scanner_init(proc_source, functype);
289
plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
290
plpgsql_error_lineno = 0;
293
* Setup error traceback support for ereport()
295
plerrcontext.callback = plpgsql_compile_error_callback;
296
plerrcontext.arg = forValidator ? proc_source : (char *) NULL;
297
plerrcontext.previous = error_context_stack;
298
error_context_stack = &plerrcontext;
301
* Initialize the compiler
304
plpgsql_ns_push(NULL);
305
plpgsql_DumpExecTree = 0;
309
plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc);
313
* Create the new function node
315
function = malloc(sizeof(PLpgSQL_function));
316
MemSet(function, 0, sizeof(PLpgSQL_function));
317
plpgsql_curr_compile = function;
319
function->fn_name = strdup(NameStr(procStruct->proname));
320
function->fn_oid = fcinfo->flinfo->fn_oid;
321
function->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
322
function->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);
323
function->fn_functype = functype;
330
* Check for a polymorphic returntype. If found, use the
331
* actual returntype type from the caller's FuncExpr node, if
332
* we have one. (In validation mode we arbitrarily assume we
333
* are dealing with integers.)
335
* Note: errcode is FEATURE_NOT_SUPPORTED because it should
336
* always work; if it doesn't we're in some context that fails
337
* to make the info available.
339
rettypeid = procStruct->prorettype;
340
if (rettypeid == ANYARRAYOID || rettypeid == ANYELEMENTOID)
344
if (rettypeid == ANYARRAYOID)
345
rettypeid = INT4ARRAYOID;
350
rettypeid = get_fn_expr_rettype(fcinfo->flinfo);
351
if (!OidIsValid(rettypeid))
353
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
354
errmsg("could not determine actual return type "
355
"for polymorphic function \"%s\"",
356
plpgsql_error_funcname)));
360
* Normal function has a defined returntype
362
function->fn_rettype = rettypeid;
363
function->fn_retset = procStruct->proretset;
366
* Lookup the function's return type
368
typeTup = SearchSysCache(TYPEOID,
369
ObjectIdGetDatum(rettypeid),
371
if (!HeapTupleIsValid(typeTup))
372
elog(ERROR, "cache lookup failed for type %u", rettypeid);
373
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
375
/* Disallow pseudotype result, except VOID or RECORD */
376
/* (note we already replaced ANYARRAY/ANYELEMENT) */
377
if (typeStruct->typtype == 'p')
379
if (rettypeid == VOIDOID ||
380
rettypeid == RECORDOID)
382
else if (rettypeid == TRIGGEROID)
384
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
385
errmsg("trigger functions may only be called as triggers")));
388
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
389
errmsg("plpgsql functions cannot return type %s",
390
format_type_be(rettypeid))));
393
if (typeStruct->typrelid != InvalidOid ||
394
rettypeid == RECORDOID)
395
function->fn_retistuple = true;
398
function->fn_retbyval = typeStruct->typbyval;
399
function->fn_rettyplen = typeStruct->typlen;
400
function->fn_rettypioparam = getTypeIOParam(typeTup);
401
perm_fmgr_info(typeStruct->typinput, &(function->fn_retinput));
404
* install $0 reference, but only for polymorphic return
407
if (procStruct->prorettype == ANYARRAYOID ||
408
procStruct->prorettype == ANYELEMENTOID)
410
(void) plpgsql_build_variable(strdup("$0"), 0,
411
build_datatype(typeTup, -1),
415
ReleaseSysCache(typeTup);
418
* Create the variables for the procedure's parameters
420
argnames = fetchArgNames(procTup, procStruct->pronargs);
422
for (i = 0; i < procStruct->pronargs; i++)
426
PLpgSQL_type *argdtype;
427
PLpgSQL_variable *argvariable;
430
/* Create $n name for variable */
431
snprintf(buf, sizeof(buf), "$%d", i + 1);
434
* Since we already did the replacement of polymorphic
435
* argument types by actual argument types while computing
436
* the hashkey, we can just use those results.
438
argtypeid = hashkey->argtypes[i];
439
argdtype = plpgsql_build_datatype(argtypeid, -1);
441
/* Disallow pseudotype argument */
442
/* (note we already replaced ANYARRAY/ANYELEMENT) */
443
/* (build_variable would do this, but wrong message) */
444
if (argdtype->ttype != PLPGSQL_TTYPE_SCALAR &&
445
argdtype->ttype != PLPGSQL_TTYPE_ROW)
447
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
448
errmsg("plpgsql functions cannot take type %s",
449
format_type_be(argtypeid))));
451
/* Build variable and add to datum list */
452
argvariable = plpgsql_build_variable(strdup(buf), 0,
455
if (argvariable->dtype == PLPGSQL_DTYPE_VAR)
457
/* argument vars are forced to be CONSTANT (why?) */
458
((PLpgSQL_var *) argvariable)->isconst = true;
459
argitemtype = PLPGSQL_NSTYPE_VAR;
463
Assert(argvariable->dtype == PLPGSQL_DTYPE_ROW);
464
argitemtype = PLPGSQL_NSTYPE_ROW;
467
/* Remember datum number */
468
arg_varnos[i] = argvariable->dno;
470
/* Add to namespace under the $n name */
471
plpgsql_ns_additem(argitemtype, argvariable->dno, buf);
473
/* If there's a name for the argument, make an alias */
474
if (argnames && argnames[i] && argnames[i][0])
475
plpgsql_ns_additem(argitemtype, argvariable->dno,
483
* Trigger procedures return type is unknown yet
485
function->fn_rettype = InvalidOid;
486
function->fn_retbyval = false;
487
function->fn_retistuple = true;
488
function->fn_retset = false;
491
* Add the record for referencing NEW
493
rec = malloc(sizeof(PLpgSQL_rec));
494
memset(rec, 0, sizeof(PLpgSQL_rec));
495
rec->dtype = PLPGSQL_DTYPE_REC;
496
rec->refname = strdup("new");
499
rec->freetup = false;
500
plpgsql_adddatum((PLpgSQL_datum *) rec);
501
plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, rec->refname);
502
function->new_varno = rec->recno;
505
* Add the record for referencing OLD
507
rec = malloc(sizeof(PLpgSQL_rec));
508
memset(rec, 0, sizeof(PLpgSQL_rec));
509
rec->dtype = PLPGSQL_DTYPE_REC;
510
rec->refname = strdup("old");
513
rec->freetup = false;
514
plpgsql_adddatum((PLpgSQL_datum *) rec);
515
plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, rec->refname);
516
function->old_varno = rec->recno;
519
* Add the variable tg_name
521
var = plpgsql_build_variable(strdup("tg_name"), 0,
522
plpgsql_build_datatype(NAMEOID, -1),
524
function->tg_name_varno = var->dno;
527
* Add the variable tg_when
529
var = plpgsql_build_variable(strdup("tg_when"), 0,
530
plpgsql_build_datatype(TEXTOID, -1),
532
function->tg_when_varno = var->dno;
535
* Add the variable tg_level
537
var = plpgsql_build_variable(strdup("tg_level"), 0,
538
plpgsql_build_datatype(TEXTOID, -1),
540
function->tg_level_varno = var->dno;
543
* Add the variable tg_op
545
var = plpgsql_build_variable(strdup("tg_op"), 0,
546
plpgsql_build_datatype(TEXTOID, -1),
548
function->tg_op_varno = var->dno;
551
* Add the variable tg_relid
553
var = plpgsql_build_variable(strdup("tg_relid"), 0,
554
plpgsql_build_datatype(OIDOID, -1),
556
function->tg_relid_varno = var->dno;
559
* Add the variable tg_relname
561
var = plpgsql_build_variable(strdup("tg_relname"), 0,
562
plpgsql_build_datatype(NAMEOID, -1),
564
function->tg_relname_varno = var->dno;
567
* Add the variable tg_nargs
569
var = plpgsql_build_variable(strdup("tg_nargs"), 0,
570
plpgsql_build_datatype(INT4OID, -1),
572
function->tg_nargs_varno = var->dno;
577
elog(ERROR, "unrecognized function typecode: %u", functype);
581
/* Remember if function is STABLE/IMMUTABLE */
582
function->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
585
* Create the magic FOUND variable.
587
var = plpgsql_build_variable(strdup("found"), 0,
588
plpgsql_build_datatype(BOOLOID, -1),
590
function->found_varno = var->dno;
593
* Forget about the above created variables
595
plpgsql_add_initdatums(NULL);
598
* Now parse the function's text
600
parse_rc = plpgsql_yyparse();
602
elog(ERROR, "plpgsql parser returned %d", parse_rc);
604
plpgsql_scanner_finish();
608
* If that was successful, complete the function's info.
610
function->fn_nargs = procStruct->pronargs;
611
for (i = 0; i < function->fn_nargs; i++)
612
function->fn_argvarnos[i] = arg_varnos[i];
613
function->ndatums = plpgsql_nDatums;
614
function->datums = malloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
615
for (i = 0; i < plpgsql_nDatums; i++)
616
function->datums[i] = plpgsql_Datums[i];
617
function->action = plpgsql_yylval.program;
619
/* Debug dump for completed functions */
620
if (plpgsql_DumpExecTree)
621
plpgsql_dumptree(function);
624
* add it to the hash table
626
plpgsql_HashTableInsert(function, hashkey);
629
* Pop the error context stack
631
error_context_stack = plerrcontext.previous;
632
plpgsql_error_funcname = NULL;
633
plpgsql_error_lineno = 0;
640
* error context callback to let us supply a call-stack traceback
642
* If we are validating, the function source is passed as argument.
645
plpgsql_compile_error_callback(void *arg)
650
* Try to convert syntax error position to reference text of
651
* original CREATE FUNCTION command.
653
if (function_parse_error_transpose((const char *) arg))
657
* Done if a syntax error position was reported; otherwise we have
658
* to fall back to a "near line N" report.
662
if (plpgsql_error_funcname)
663
errcontext("compile of PL/pgSQL function \"%s\" near line %d",
664
plpgsql_error_funcname, plpgsql_error_lineno);
669
* Fetch the argument names, if any, from the proargnames field of the
670
* pg_proc tuple. Results are palloc'd.
673
fetchArgNames(HeapTuple procTup, int nargs)
685
argnamesDatum = SysCacheGetAttr(PROCOID, procTup, Anum_pg_proc_proargnames,
690
deconstruct_array(DatumGetArrayTypeP(argnamesDatum),
691
TEXTOID, -1, false, 'i',
694
if (nelems != nargs) /* should not happen */
695
elog(ERROR, "proargnames must have the same number of elements as the function has arguments");
697
result = (char **) palloc(sizeof(char *) * nargs);
699
for (i = 0; i < nargs; i++)
700
result[i] = DatumGetCString(DirectFunctionCall1(textout, elems[i]));
707
* plpgsql_parse_word The scanner calls this to postparse
708
* any single word not found by a
713
plpgsql_parse_word(char *word)
718
/* Do case conversion and word separation */
719
plpgsql_convert_ident(word, cp, 1);
722
* Recognize tg_argv when compiling triggers
724
if (plpgsql_curr_compile->fn_functype == T_TRIGGER)
726
if (strcmp(cp[0], "tg_argv") == 0)
728
int save_spacescanned = plpgsql_SpaceScanned;
729
PLpgSQL_trigarg *trigarg;
731
trigarg = malloc(sizeof(PLpgSQL_trigarg));
732
memset(trigarg, 0, sizeof(PLpgSQL_trigarg));
733
trigarg->dtype = PLPGSQL_DTYPE_TRIGARG;
735
if (plpgsql_yylex() != '[')
736
plpgsql_yyerror("expected \"[\"");
738
trigarg->argnum = plpgsql_read_expression(']', "]");
740
plpgsql_adddatum((PLpgSQL_datum *) trigarg);
741
plpgsql_yylval.scalar = (PLpgSQL_datum *) trigarg;
743
plpgsql_SpaceScanned = save_spacescanned;
750
* Do a lookup on the compilers namestack
752
nse = plpgsql_ns_lookup(cp[0], NULL);
756
switch (nse->itemtype)
758
case PLPGSQL_NSTYPE_LABEL:
761
case PLPGSQL_NSTYPE_VAR:
762
plpgsql_yylval.scalar = plpgsql_Datums[nse->itemno];
765
case PLPGSQL_NSTYPE_REC:
766
plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]);
769
case PLPGSQL_NSTYPE_ROW:
770
plpgsql_yylval.row = (PLpgSQL_row *) (plpgsql_Datums[nse->itemno]);
779
* Nothing found - up to now it's a word without any special meaning
788
* plpgsql_parse_dblword Same lookup for two words
789
* separated by a dot.
793
plpgsql_parse_dblword(char *word)
798
/* Do case conversion and word separation */
799
plpgsql_convert_ident(word, cp, 2);
802
* Lookup the first word
804
ns = plpgsql_ns_lookup(cp[0], NULL);
812
switch (ns->itemtype)
814
case PLPGSQL_NSTYPE_LABEL:
817
* First word is a label, so second word could be a variable,
818
* record or row in that bodies namestack. Anything else could
819
* only be something in a query given to the SPI manager and
820
* T_ERROR will get eaten up by the collector routines.
822
ns = plpgsql_ns_lookup(cp[1], cp[0]);
827
switch (ns->itemtype)
829
case PLPGSQL_NSTYPE_VAR:
830
plpgsql_yylval.scalar = plpgsql_Datums[ns->itemno];
833
case PLPGSQL_NSTYPE_REC:
834
plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);
837
case PLPGSQL_NSTYPE_ROW:
838
plpgsql_yylval.row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
846
case PLPGSQL_NSTYPE_REC:
849
* First word is a record name, so second word must be a
850
* field in this record.
852
PLpgSQL_recfield *new;
854
new = malloc(sizeof(PLpgSQL_recfield));
855
new->dtype = PLPGSQL_DTYPE_RECFIELD;
856
new->fieldname = strdup(cp[1]);
857
new->recparentno = ns->itemno;
859
plpgsql_adddatum((PLpgSQL_datum *) new);
861
plpgsql_yylval.scalar = (PLpgSQL_datum *) new;
868
case PLPGSQL_NSTYPE_ROW:
871
* First word is a row name, so second word must be a
877
row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
878
for (i = 0; i < row->nfields; i++)
880
if (row->fieldnames[i] &&
881
strcmp(row->fieldnames[i], cp[1]) == 0)
883
plpgsql_yylval.scalar = plpgsql_Datums[row->varnos[i]];
890
(errcode(ERRCODE_UNDEFINED_COLUMN),
891
errmsg("row \"%s\" has no field \"%s\"",
906
* plpgsql_parse_tripword Same lookup for three words
911
plpgsql_parse_tripword(char *word)
916
/* Do case conversion and word separation */
917
plpgsql_convert_ident(word, cp, 3);
920
* Lookup the first word - it must be a label
922
ns = plpgsql_ns_lookup(cp[0], NULL);
930
if (ns->itemtype != PLPGSQL_NSTYPE_LABEL)
939
* First word is a label, so second word could be a record or row
941
ns = plpgsql_ns_lookup(cp[1], cp[0]);
950
switch (ns->itemtype)
952
case PLPGSQL_NSTYPE_REC:
955
* This word is a record name, so third word must be a
956
* field in this record.
958
PLpgSQL_recfield *new;
960
new = malloc(sizeof(PLpgSQL_recfield));
961
new->dtype = PLPGSQL_DTYPE_RECFIELD;
962
new->fieldname = strdup(cp[2]);
963
new->recparentno = ns->itemno;
965
plpgsql_adddatum((PLpgSQL_datum *) new);
967
plpgsql_yylval.scalar = (PLpgSQL_datum *) new;
976
case PLPGSQL_NSTYPE_ROW:
979
* This word is a row name, so third word must be a field
985
row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
986
for (i = 0; i < row->nfields; i++)
988
if (row->fieldnames[i] &&
989
strcmp(row->fieldnames[i], cp[2]) == 0)
991
plpgsql_yylval.scalar = plpgsql_Datums[row->varnos[i]];
1001
(errcode(ERRCODE_UNDEFINED_COLUMN),
1002
errmsg("row \"%s.%s\" has no field \"%s\"",
1003
cp[0], cp[1], cp[2])));
1018
* plpgsql_parse_wordtype The scanner found word%TYPE. word can be
1019
* a variable name or a basetype.
1023
plpgsql_parse_wordtype(char *word)
1025
PLpgSQL_nsitem *nse;
1031
/* Do case conversion and word separation */
1032
/* We convert %type to .type momentarily to keep converter happy */
1033
i = strlen(word) - 5;
1034
Assert(word[i] == '%');
1036
plpgsql_convert_ident(word, cp, 2);
1041
* Do a lookup on the compilers namestack. But ensure it moves up to
1044
old_nsstate = plpgsql_ns_setlocal(false);
1045
nse = plpgsql_ns_lookup(cp[0], NULL);
1046
plpgsql_ns_setlocal(old_nsstate);
1051
switch (nse->itemtype)
1053
case PLPGSQL_NSTYPE_VAR:
1054
plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
1057
/* XXX perhaps allow REC here? */
1065
* Word wasn't found on the namestack. Try to find a data type with
1066
* that name, but ignore pg_type entries that are in fact class types.
1068
typeOid = LookupTypeName(makeTypeName(cp[0]));
1069
if (OidIsValid(typeOid))
1073
typeTup = SearchSysCache(TYPEOID,
1074
ObjectIdGetDatum(typeOid),
1076
if (HeapTupleIsValid(typeTup))
1078
Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
1080
if (!typeStruct->typisdefined ||
1081
typeStruct->typrelid != InvalidOid)
1083
ReleaseSysCache(typeTup);
1088
plpgsql_yylval.dtype = build_datatype(typeTup, -1);
1090
ReleaseSysCache(typeTup);
1097
* Nothing found - up to now it's a word without any special meaning
1106
* plpgsql_parse_dblwordtype Same lookup for word.word%TYPE
1110
plpgsql_parse_dblwordtype(char *word)
1112
PLpgSQL_nsitem *nse;
1116
Form_pg_class classStruct;
1118
Form_pg_attribute attrStruct;
1123
/* Do case conversion and word separation */
1124
/* We convert %type to .type momentarily to keep converter happy */
1125
i = strlen(word) - 5;
1126
Assert(word[i] == '%');
1128
plpgsql_convert_ident(word, cp, 3);
1133
* Lookup the first word
1135
nse = plpgsql_ns_lookup(cp[0], NULL);
1138
* If this is a label lookup the second word in that labels namestack
1143
if (nse->itemtype == PLPGSQL_NSTYPE_LABEL)
1145
old_nsstate = plpgsql_ns_setlocal(false);
1146
nse = plpgsql_ns_lookup(cp[1], cp[0]);
1147
plpgsql_ns_setlocal(old_nsstate);
1154
switch (nse->itemtype)
1156
case PLPGSQL_NSTYPE_VAR:
1157
plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
1172
* First word could also be a table name
1174
classOid = RelnameGetRelid(cp[0]);
1175
if (!OidIsValid(classOid))
1181
classtup = SearchSysCache(RELOID,
1182
ObjectIdGetDatum(classOid),
1184
if (!HeapTupleIsValid(classtup))
1192
* It must be a relation, sequence, view, or type
1194
classStruct = (Form_pg_class) GETSTRUCT(classtup);
1195
if (classStruct->relkind != RELKIND_RELATION &&
1196
classStruct->relkind != RELKIND_SEQUENCE &&
1197
classStruct->relkind != RELKIND_VIEW &&
1198
classStruct->relkind != RELKIND_COMPOSITE_TYPE)
1200
ReleaseSysCache(classtup);
1207
* Fetch the named table field and it's type
1209
attrtup = SearchSysCacheAttName(classOid, cp[1]);
1210
if (!HeapTupleIsValid(attrtup))
1212
ReleaseSysCache(classtup);
1217
attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
1219
typetup = SearchSysCache(TYPEOID,
1220
ObjectIdGetDatum(attrStruct->atttypid),
1222
if (!HeapTupleIsValid(typetup))
1223
elog(ERROR, "cache lookup failed for type %u", attrStruct->atttypid);
1226
* Found that - build a compiler type struct and return it
1228
plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod);
1230
ReleaseSysCache(classtup);
1231
ReleaseSysCache(attrtup);
1232
ReleaseSysCache(typetup);
1239
* plpgsql_parse_tripwordtype Same lookup for word.word.word%TYPE
1242
#define TYPE_JUNK_LEN 5
1245
plpgsql_parse_tripwordtype(char *word)
1249
Form_pg_class classStruct;
1251
Form_pg_attribute attrStruct;
1255
int qualified_att_len;
1260
/* Do case conversion and word separation */
1261
qualified_att_len = strlen(word) - TYPE_JUNK_LEN;
1262
Assert(word[qualified_att_len] == '%');
1264
for (i = 0; i < qualified_att_len; i++)
1266
if (word[i] == '.' && ++numdots == 2)
1268
cp[0] = (char *) palloc((i + 1) * sizeof(char));
1269
memset(cp[0], 0, (i + 1) * sizeof(char));
1270
memcpy(cp[0], word, i * sizeof(char));
1273
* qualified_att_len - one based position + 1 (null
1276
cp[1] = (char *) palloc((qualified_att_len - i) * sizeof(char));
1277
memset(cp[1], 0, (qualified_att_len - i) * sizeof(char));
1278
memcpy(cp[1], &word[i + 1], (qualified_att_len - i - 1) * sizeof(char));
1284
relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp[0], "plpgsql_parse_tripwordtype"));
1285
classOid = RangeVarGetRelid(relvar, true);
1286
if (!OidIsValid(classOid))
1292
classtup = SearchSysCache(RELOID,
1293
ObjectIdGetDatum(classOid),
1295
if (!HeapTupleIsValid(classtup))
1303
* It must be a relation, sequence, view, or type
1305
classStruct = (Form_pg_class) GETSTRUCT(classtup);
1306
if (classStruct->relkind != RELKIND_RELATION &&
1307
classStruct->relkind != RELKIND_SEQUENCE &&
1308
classStruct->relkind != RELKIND_VIEW &&
1309
classStruct->relkind != RELKIND_COMPOSITE_TYPE)
1311
ReleaseSysCache(classtup);
1318
* Fetch the named table field and it's type
1320
plpgsql_convert_ident(cp[1], colname, 1);
1321
attrtup = SearchSysCacheAttName(classOid, colname[0]);
1324
if (!HeapTupleIsValid(attrtup))
1326
ReleaseSysCache(classtup);
1331
attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
1333
typetup = SearchSysCache(TYPEOID,
1334
ObjectIdGetDatum(attrStruct->atttypid),
1336
if (!HeapTupleIsValid(typetup))
1337
elog(ERROR, "cache lookup failed for type %u", attrStruct->atttypid);
1340
* Found that - build a compiler type struct and return it
1342
plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod);
1344
ReleaseSysCache(classtup);
1345
ReleaseSysCache(attrtup);
1346
ReleaseSysCache(typetup);
1354
* plpgsql_parse_wordrowtype Scanner found word%ROWTYPE.
1355
* So word must be a table name.
1359
plpgsql_parse_wordrowtype(char *word)
1365
/* Do case conversion and word separation */
1366
/* We convert %rowtype to .rowtype momentarily to keep converter happy */
1367
i = strlen(word) - 8;
1368
Assert(word[i] == '%');
1370
plpgsql_convert_ident(word, cp, 2);
1373
/* Lookup the relation */
1374
classOid = RelnameGetRelid(cp[0]);
1375
if (!OidIsValid(classOid))
1377
(errcode(ERRCODE_UNDEFINED_TABLE),
1378
errmsg("relation \"%s\" does not exist", cp[0])));
1381
* Build and return the row type struct
1383
plpgsql_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid),
1393
* plpgsql_parse_dblwordrowtype Scanner found word.word%ROWTYPE.
1394
* So word must be a namespace qualified table name.
1397
#define ROWTYPE_JUNK_LEN 8
1400
plpgsql_parse_dblwordrowtype(char *word)
1407
/* Do case conversion and word separation */
1408
/* We convert %rowtype to .rowtype momentarily to keep converter happy */
1409
i = strlen(word) - ROWTYPE_JUNK_LEN;
1410
Assert(word[i] == '%');
1412
cp = (char *) palloc((i + 1) * sizeof(char));
1413
memset(cp, 0, (i + 1) * sizeof(char));
1414
memcpy(cp, word, i * sizeof(char));
1416
/* Lookup the relation */
1417
relvar = makeRangeVarFromNameList(stringToQualifiedNameList(cp, "plpgsql_parse_dblwordrowtype"));
1418
classOid = RangeVarGetRelid(relvar, true);
1419
if (!OidIsValid(classOid))
1421
(errcode(ERRCODE_UNDEFINED_TABLE),
1422
errmsg("relation \"%s\" does not exist", cp)));
1425
* Build and return the row type struct
1427
plpgsql_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid),
1436
* plpgsql_build_variable - build a datum-array entry of a given datatype
1438
* The returned struct may be a PLpgSQL_var, PLpgSQL_row, or PLpgSQL_rec
1439
* depending on the given datatype. The struct is automatically added
1440
* to the current datum array, and optionally to the current namespace.
1443
plpgsql_build_variable(char *refname, int lineno, PLpgSQL_type *dtype,
1446
PLpgSQL_variable *result;
1448
switch (dtype->ttype)
1450
case PLPGSQL_TTYPE_SCALAR:
1452
/* Ordinary scalar datatype */
1455
var = malloc(sizeof(PLpgSQL_var));
1456
memset(var, 0, sizeof(PLpgSQL_var));
1458
var->dtype = PLPGSQL_DTYPE_VAR;
1459
var->refname = refname;
1460
var->lineno = lineno;
1461
var->datatype = dtype;
1462
/* other fields might be filled by caller */
1464
/* preset to NULL */
1467
var->freeval = false;
1469
plpgsql_adddatum((PLpgSQL_datum *) var);
1471
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR,
1474
result = (PLpgSQL_variable *) var;
1477
case PLPGSQL_TTYPE_ROW:
1479
/* Composite type -- build a row variable */
1482
row = build_row_var(dtype->typrelid);
1484
row->dtype = PLPGSQL_DTYPE_ROW;
1485
row->refname = refname;
1486
row->lineno = lineno;
1488
plpgsql_adddatum((PLpgSQL_datum *) row);
1490
plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW,
1493
result = (PLpgSQL_variable *) row;
1496
case PLPGSQL_TTYPE_REC:
1499
* "record" type -- build a variable-contents record
1504
rec = malloc(sizeof(PLpgSQL_rec));
1505
memset(rec, 0, sizeof(PLpgSQL_rec));
1507
rec->dtype = PLPGSQL_DTYPE_REC;
1508
rec->refname = refname;
1509
rec->lineno = lineno;
1511
plpgsql_adddatum((PLpgSQL_datum *) rec);
1513
plpgsql_ns_additem(PLPGSQL_NSTYPE_REC,
1516
result = (PLpgSQL_variable *) rec;
1519
case PLPGSQL_TTYPE_PSEUDO:
1522
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1523
errmsg("variable \"%s\" has pseudo-type %s",
1524
refname, format_type_be(dtype->typoid))));
1525
result = NULL; /* keep compiler quiet */
1529
elog(ERROR, "unrecognized ttype: %d", dtype->ttype);
1530
result = NULL; /* keep compiler quiet */
1538
* Build a row-variable data structure given the pg_class OID.
1540
static PLpgSQL_row *
1541
build_row_var(Oid classOid)
1545
Form_pg_class classStruct;
1546
const char *relname;
1548
MemoryContext oldcxt;
1551
* Open the relation to get info.
1553
rel = relation_open(classOid, AccessShareLock);
1554
classStruct = RelationGetForm(rel);
1555
relname = RelationGetRelationName(rel);
1557
/* accept relation, sequence, view, or composite type entries */
1558
if (classStruct->relkind != RELKIND_RELATION &&
1559
classStruct->relkind != RELKIND_SEQUENCE &&
1560
classStruct->relkind != RELKIND_VIEW &&
1561
classStruct->relkind != RELKIND_COMPOSITE_TYPE)
1563
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1564
errmsg("relation \"%s\" is not a table", relname)));
1567
* Create a row datum entry and all the required variables that it
1570
row = malloc(sizeof(PLpgSQL_row));
1571
memset(row, 0, sizeof(PLpgSQL_row));
1573
row->dtype = PLPGSQL_DTYPE_ROW;
1576
* This is a bit ugly --- need a permanent copy of the rel's tupdesc.
1577
* Someday all these mallocs should go away in favor of a per-function
1578
* memory context ...
1580
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
1581
row->rowtupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
1582
MemoryContextSwitchTo(oldcxt);
1584
row->nfields = classStruct->relnatts;
1585
row->fieldnames = malloc(sizeof(char *) * row->nfields);
1586
row->varnos = malloc(sizeof(int) * row->nfields);
1588
for (i = 0; i < row->nfields; i++)
1590
Form_pg_attribute attrStruct;
1593
* Get the attribute and check for dropped column
1595
attrStruct = RelationGetDescr(rel)->attrs[i];
1597
if (!attrStruct->attisdropped)
1599
const char *attname;
1601
PLpgSQL_variable *var;
1603
attname = NameStr(attrStruct->attname);
1604
refname = malloc(strlen(relname) + strlen(attname) + 2);
1605
strcpy(refname, relname);
1606
strcat(refname, ".");
1607
strcat(refname, attname);
1610
* Create the internal variable for the field
1612
* We know if the table definitions contain a default value or if
1613
* the field is declared in the table as NOT NULL. But it's
1614
* possible to create a table field as NOT NULL without a
1615
* default value and that would lead to problems later when
1616
* initializing the variables due to entering a block at
1617
* execution time. Thus we ignore this information for now.
1619
var = plpgsql_build_variable(refname, 0,
1620
plpgsql_build_datatype(attrStruct->atttypid,
1621
attrStruct->atttypmod),
1625
* Add the variable to the row.
1627
row->fieldnames[i] = strdup(attname);
1628
row->varnos[i] = var->dno;
1632
/* Leave a hole in the row structure for the dropped col */
1633
row->fieldnames[i] = NULL;
1634
row->varnos[i] = -1;
1638
relation_close(rel, AccessShareLock);
1645
* plpgsql_parse_datatype Scanner found something that should
1646
* be a datatype name.
1650
plpgsql_parse_datatype(const char *string)
1655
/* Let the main parser try to parse it under standard SQL rules */
1656
parseTypeString(string, &type_id, &typmod);
1658
/* Okay, build a PLpgSQL_type data structure for it */
1659
return plpgsql_build_datatype(type_id, typmod);
1663
* plpgsql_build_datatype
1664
* Build PLpgSQL_type struct given type OID and typmod.
1667
plpgsql_build_datatype(Oid typeOid, int32 typmod)
1672
typeTup = SearchSysCache(TYPEOID,
1673
ObjectIdGetDatum(typeOid),
1675
if (!HeapTupleIsValid(typeTup))
1676
elog(ERROR, "cache lookup failed for type %u", typeOid);
1678
typ = build_datatype(typeTup, typmod);
1680
ReleaseSysCache(typeTup);
1686
* Utility subroutine to make a PLpgSQL_type struct given a pg_type entry
1688
static PLpgSQL_type *
1689
build_datatype(HeapTuple typeTup, int32 typmod)
1691
Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
1694
if (!typeStruct->typisdefined)
1696
(errcode(ERRCODE_UNDEFINED_OBJECT),
1697
errmsg("type \"%s\" is only a shell",
1698
NameStr(typeStruct->typname))));
1700
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
1702
typ->typname = strdup(NameStr(typeStruct->typname));
1703
typ->typoid = HeapTupleGetOid(typeTup);
1704
switch (typeStruct->typtype)
1706
case 'b': /* base type */
1707
case 'd': /* domain */
1708
typ->ttype = PLPGSQL_TTYPE_SCALAR;
1710
case 'c': /* composite, ie, rowtype */
1711
Assert(OidIsValid(typeStruct->typrelid));
1712
typ->ttype = PLPGSQL_TTYPE_ROW;
1714
case 'p': /* pseudo */
1715
if (typ->typoid == RECORDOID)
1716
typ->ttype = PLPGSQL_TTYPE_REC;
1718
typ->ttype = PLPGSQL_TTYPE_PSEUDO;
1721
elog(ERROR, "unrecognized typtype: %d",
1722
(int) typeStruct->typtype);
1725
typ->typlen = typeStruct->typlen;
1726
typ->typbyval = typeStruct->typbyval;
1727
typ->typrelid = typeStruct->typrelid;
1728
typ->typioparam = getTypeIOParam(typeTup);
1729
perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
1730
typ->atttypmod = typmod;
1736
* plpgsql_parse_err_condition
1737
* Generate PLpgSQL_condition entry(s) for an exception condition name
1739
* This has to be able to return a list because there are some duplicate
1740
* names in the table of error code names.
1743
plpgsql_parse_err_condition(char *condname)
1746
PLpgSQL_condition *new;
1747
PLpgSQL_condition *prev;
1750
* XXX Eventually we will want to look for user-defined exception
1755
* OTHERS is represented as code 0 (which would map to '00000', but we
1756
* have no need to represent that as an exception condition).
1758
if (strcmp(condname, "others") == 0)
1760
new = malloc(sizeof(PLpgSQL_condition));
1761
new->sqlerrstate = 0;
1762
new->condname = condname;
1768
for (i = 0; exception_label_map[i].label != NULL; i++)
1770
if (strcmp(condname, exception_label_map[i].label) == 0)
1772
new = malloc(sizeof(PLpgSQL_condition));
1773
new->sqlerrstate = exception_label_map[i].sqlerrstate;
1774
new->condname = condname;
1782
(errcode(ERRCODE_UNDEFINED_OBJECT),
1783
errmsg("unrecognized exception condition \"%s\"",
1790
* plpgsql_adddatum Add a variable, record or row
1791
* to the compilers datum list.
1795
plpgsql_adddatum(PLpgSQL_datum *new)
1797
if (plpgsql_nDatums == datums_alloc)
1800
plpgsql_Datums = repalloc(plpgsql_Datums, sizeof(PLpgSQL_datum *) * datums_alloc);
1803
new->dno = plpgsql_nDatums;
1804
plpgsql_Datums[plpgsql_nDatums++] = new;
1809
* plpgsql_add_initdatums Put all datum entries created
1810
* since the last call into the
1811
* finishing code block so the
1812
* block knows which variables to
1813
* reinitialize when entered.
1817
plpgsql_add_initdatums(int **varnos)
1822
for (i = datums_last; i < plpgsql_nDatums; i++)
1824
switch (plpgsql_Datums[i]->dtype)
1826
case PLPGSQL_DTYPE_VAR:
1839
*varnos = (int *) malloc(sizeof(int) * n);
1842
for (i = datums_last; i < plpgsql_nDatums; i++)
1844
switch (plpgsql_Datums[i]->dtype)
1846
case PLPGSQL_DTYPE_VAR:
1847
(*varnos)[n++] = plpgsql_Datums[i]->dno;
1858
datums_last = plpgsql_nDatums;
1864
* Compute the hashkey for a given function invocation
1866
* The hashkey is returned into the caller-provided storage at *hashkey.
1869
compute_function_hashkey(FunctionCallInfo fcinfo,
1870
Form_pg_proc procStruct,
1871
PLpgSQL_func_hashkey *hashkey,
1876
/* Make sure any unused bytes of the struct are zero */
1877
MemSet(hashkey, 0, sizeof(PLpgSQL_func_hashkey));
1879
/* get function OID */
1880
hashkey->funcOid = fcinfo->flinfo->fn_oid;
1883
* if trigger, get relation OID. In validation mode we do not know
1884
* what relation is intended to be used, so we leave trigrelOid zero;
1885
* the hash entry built in this case will never really be used.
1887
if (CALLED_AS_TRIGGER(fcinfo) && !forValidator)
1889
TriggerData *trigdata = (TriggerData *) fcinfo->context;
1891
hashkey->trigrelOid = RelationGetRelid(trigdata->tg_relation);
1894
/* get the argument types */
1895
for (i = 0; i < procStruct->pronargs; i++)
1897
Oid argtypeid = procStruct->proargtypes[i];
1900
* Check for polymorphic arguments. If found, use the actual
1901
* parameter type from the caller's FuncExpr node, if we have one.
1902
* (In validation mode we arbitrarily assume we are dealing with
1903
* integers. This lets us build a valid, if possibly useless,
1904
* function hashtable entry.)
1906
* We can support arguments of type ANY the same way as normal
1907
* polymorphic arguments.
1909
if (argtypeid == ANYARRAYOID || argtypeid == ANYELEMENTOID ||
1910
argtypeid == ANYOID)
1914
if (argtypeid == ANYARRAYOID)
1915
argtypeid = INT4ARRAYOID;
1917
argtypeid = INT4OID;
1920
argtypeid = get_fn_expr_argtype(fcinfo->flinfo, i);
1921
if (!OidIsValid(argtypeid))
1923
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1924
errmsg("could not determine actual argument "
1925
"type for polymorphic function \"%s\"",
1926
NameStr(procStruct->proname))));
1929
hashkey->argtypes[i] = argtypeid;
1933
/* exported so we can call it from plpgsql_init() */
1935
plpgsql_HashTableInit(void)
1939
memset(&ctl, 0, sizeof(ctl));
1940
ctl.keysize = sizeof(PLpgSQL_func_hashkey);
1941
ctl.entrysize = sizeof(plpgsql_HashEnt);
1942
ctl.hash = tag_hash;
1943
plpgsql_HashTable = hash_create("PLpgSQL function cache",
1946
HASH_ELEM | HASH_FUNCTION);
1949
static PLpgSQL_function *
1950
plpgsql_HashTableLookup(PLpgSQL_func_hashkey *func_key)
1952
plpgsql_HashEnt *hentry;
1954
hentry = (plpgsql_HashEnt *) hash_search(plpgsql_HashTable,
1959
return hentry->function;
1965
plpgsql_HashTableInsert(PLpgSQL_function *function,
1966
PLpgSQL_func_hashkey *func_key)
1968
plpgsql_HashEnt *hentry;
1971
hentry = (plpgsql_HashEnt *) hash_search(plpgsql_HashTable,
1977
(errcode(ERRCODE_OUT_OF_MEMORY),
1978
errmsg("out of memory")));
1980
elog(WARNING, "trying to insert a function that already exists");
1982
hentry->function = function;
1983
/* prepare back link from function to hashtable key */
1984
function->fn_hashkey = &hentry->key;
1988
plpgsql_HashTableDelete(PLpgSQL_function *function)
1990
plpgsql_HashEnt *hentry;
1992
hentry = (plpgsql_HashEnt *) hash_search(plpgsql_HashTable,
1993
(void *) function->fn_hashkey,
1997
elog(WARNING, "trying to delete function that does not exist");