00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "plpgsql.h"
00017
00018 #include <ctype.h>
00019
00020 #include "access/htup_details.h"
00021 #include "catalog/namespace.h"
00022 #include "catalog/pg_proc.h"
00023 #include "catalog/pg_proc_fn.h"
00024 #include "catalog/pg_type.h"
00025 #include "funcapi.h"
00026 #include "nodes/makefuncs.h"
00027 #include "parser/parse_type.h"
00028 #include "utils/builtins.h"
00029 #include "utils/guc.h"
00030 #include "utils/lsyscache.h"
00031 #include "utils/memutils.h"
00032 #include "utils/rel.h"
00033 #include "utils/syscache.h"
00034
00035
00036
00037
00038
00039
00040 PLpgSQL_stmt_block *plpgsql_parse_result;
00041
00042 static int datums_alloc;
00043 int plpgsql_nDatums;
00044 PLpgSQL_datum **plpgsql_Datums;
00045 static int datums_last = 0;
00046
00047 char *plpgsql_error_funcname;
00048 bool plpgsql_DumpExecTree = false;
00049 bool plpgsql_check_syntax = false;
00050
00051 PLpgSQL_function *plpgsql_curr_compile;
00052
00053
00054 MemoryContext compile_tmp_cxt;
00055
00056
00057
00058
00059
00060 static HTAB *plpgsql_HashTable = NULL;
00061
00062 typedef struct plpgsql_hashent
00063 {
00064 PLpgSQL_func_hashkey key;
00065 PLpgSQL_function *function;
00066 } plpgsql_HashEnt;
00067
00068 #define FUNCS_PER_USER 128
00069
00070
00071
00072
00073
00074 typedef struct
00075 {
00076 const char *label;
00077 int sqlerrstate;
00078 } ExceptionLabelMap;
00079
00080 static const ExceptionLabelMap exception_label_map[] = {
00081 #include "plerrcodes.h"
00082 {NULL, 0}
00083 };
00084
00085
00086
00087
00088
00089
00090 static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo,
00091 HeapTuple procTup,
00092 PLpgSQL_function *function,
00093 PLpgSQL_func_hashkey *hashkey,
00094 bool forValidator);
00095 static void plpgsql_compile_error_callback(void *arg);
00096 static void add_parameter_name(int itemtype, int itemno, const char *name);
00097 static void add_dummy_return(PLpgSQL_function *function);
00098 static Node *plpgsql_pre_column_ref(ParseState *pstate, ColumnRef *cref);
00099 static Node *plpgsql_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var);
00100 static Node *plpgsql_param_ref(ParseState *pstate, ParamRef *pref);
00101 static Node *resolve_column_ref(ParseState *pstate, PLpgSQL_expr *expr,
00102 ColumnRef *cref, bool error_if_no_field);
00103 static Node *make_datum_param(PLpgSQL_expr *expr, int dno, int location);
00104 static PLpgSQL_row *build_row_from_class(Oid classOid);
00105 static PLpgSQL_row *build_row_from_vars(PLpgSQL_variable **vars, int numvars);
00106 static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod, Oid collation);
00107 static void compute_function_hashkey(FunctionCallInfo fcinfo,
00108 Form_pg_proc procStruct,
00109 PLpgSQL_func_hashkey *hashkey,
00110 bool forValidator);
00111 static void plpgsql_resolve_polymorphic_argtypes(int numargs,
00112 Oid *argtypes, char *argmodes,
00113 Node *call_expr, bool forValidator,
00114 const char *proname);
00115 static PLpgSQL_function *plpgsql_HashTableLookup(PLpgSQL_func_hashkey *func_key);
00116 static void plpgsql_HashTableInsert(PLpgSQL_function *function,
00117 PLpgSQL_func_hashkey *func_key);
00118 static void plpgsql_HashTableDelete(PLpgSQL_function *function);
00119 static void delete_function(PLpgSQL_function *func);
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131 PLpgSQL_function *
00132 plpgsql_compile(FunctionCallInfo fcinfo, bool forValidator)
00133 {
00134 Oid funcOid = fcinfo->flinfo->fn_oid;
00135 HeapTuple procTup;
00136 Form_pg_proc procStruct;
00137 PLpgSQL_function *function;
00138 PLpgSQL_func_hashkey hashkey;
00139 bool function_valid = false;
00140 bool hashkey_valid = false;
00141
00142
00143
00144
00145 procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
00146 if (!HeapTupleIsValid(procTup))
00147 elog(ERROR, "cache lookup failed for function %u", funcOid);
00148 procStruct = (Form_pg_proc) GETSTRUCT(procTup);
00149
00150
00151
00152
00153
00154 function = (PLpgSQL_function *) fcinfo->flinfo->fn_extra;
00155
00156 recheck:
00157 if (!function)
00158 {
00159
00160 compute_function_hashkey(fcinfo, procStruct, &hashkey, forValidator);
00161 hashkey_valid = true;
00162
00163
00164 function = plpgsql_HashTableLookup(&hashkey);
00165 }
00166
00167 if (function)
00168 {
00169
00170 if (function->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
00171 ItemPointerEquals(&function->fn_tid, &procTup->t_self))
00172 function_valid = true;
00173 else
00174 {
00175
00176
00177
00178
00179 delete_function(function);
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 if (function->use_count != 0)
00196 {
00197 function = NULL;
00198 if (!hashkey_valid)
00199 goto recheck;
00200 }
00201 }
00202 }
00203
00204
00205
00206
00207 if (!function_valid)
00208 {
00209
00210
00211
00212
00213 if (!hashkey_valid)
00214 compute_function_hashkey(fcinfo, procStruct, &hashkey,
00215 forValidator);
00216
00217
00218
00219
00220 function = do_compile(fcinfo, procTup, function,
00221 &hashkey, forValidator);
00222 }
00223
00224 ReleaseSysCache(procTup);
00225
00226
00227
00228
00229 fcinfo->flinfo->fn_extra = (void *) function;
00230
00231
00232
00233
00234 return function;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 static PLpgSQL_function *
00260 do_compile(FunctionCallInfo fcinfo,
00261 HeapTuple procTup,
00262 PLpgSQL_function *function,
00263 PLpgSQL_func_hashkey *hashkey,
00264 bool forValidator)
00265 {
00266 Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup);
00267 bool is_dml_trigger = CALLED_AS_TRIGGER(fcinfo);
00268 bool is_event_trigger = CALLED_AS_EVENT_TRIGGER(fcinfo);
00269 Datum prosrcdatum;
00270 bool isnull;
00271 char *proc_source;
00272 HeapTuple typeTup;
00273 Form_pg_type typeStruct;
00274 PLpgSQL_variable *var;
00275 PLpgSQL_rec *rec;
00276 int i;
00277 ErrorContextCallback plerrcontext;
00278 int parse_rc;
00279 Oid rettypeid;
00280 int numargs;
00281 int num_in_args = 0;
00282 int num_out_args = 0;
00283 Oid *argtypes;
00284 char **argnames;
00285 char *argmodes;
00286 int *in_arg_varnos = NULL;
00287 PLpgSQL_variable **out_arg_variables;
00288 MemoryContext func_cxt;
00289
00290
00291
00292
00293
00294
00295 prosrcdatum = SysCacheGetAttr(PROCOID, procTup,
00296 Anum_pg_proc_prosrc, &isnull);
00297 if (isnull)
00298 elog(ERROR, "null prosrc");
00299 proc_source = TextDatumGetCString(prosrcdatum);
00300 plpgsql_scanner_init(proc_source);
00301
00302 plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
00303
00304
00305
00306
00307 plerrcontext.callback = plpgsql_compile_error_callback;
00308 plerrcontext.arg = forValidator ? proc_source : NULL;
00309 plerrcontext.previous = error_context_stack;
00310 error_context_stack = &plerrcontext;
00311
00312
00313
00314
00315
00316
00317 plpgsql_check_syntax = forValidator;
00318
00319
00320
00321
00322
00323 if (function == NULL)
00324 {
00325 function = (PLpgSQL_function *)
00326 MemoryContextAllocZero(TopMemoryContext, sizeof(PLpgSQL_function));
00327 }
00328 else
00329 {
00330
00331 memset(function, 0, sizeof(PLpgSQL_function));
00332 }
00333 plpgsql_curr_compile = function;
00334
00335
00336
00337
00338
00339 func_cxt = AllocSetContextCreate(TopMemoryContext,
00340 "PL/pgSQL function context",
00341 ALLOCSET_DEFAULT_MINSIZE,
00342 ALLOCSET_DEFAULT_INITSIZE,
00343 ALLOCSET_DEFAULT_MAXSIZE);
00344 compile_tmp_cxt = MemoryContextSwitchTo(func_cxt);
00345
00346 function->fn_signature = format_procedure(fcinfo->flinfo->fn_oid);
00347 function->fn_oid = fcinfo->flinfo->fn_oid;
00348 function->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
00349 function->fn_tid = procTup->t_self;
00350 function->fn_input_collation = fcinfo->fncollation;
00351 function->fn_cxt = func_cxt;
00352 function->out_param_varno = -1;
00353 function->resolve_option = plpgsql_variable_conflict;
00354
00355 if (is_dml_trigger)
00356 function->fn_is_trigger = PLPGSQL_DML_TRIGGER;
00357 else if (is_event_trigger)
00358 function->fn_is_trigger = PLPGSQL_EVENT_TRIGGER;
00359 else
00360 function->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
00361
00362
00363
00364
00365
00366
00367 plpgsql_ns_init();
00368 plpgsql_ns_push(NameStr(procStruct->proname));
00369 plpgsql_DumpExecTree = false;
00370
00371 datums_alloc = 128;
00372 plpgsql_nDatums = 0;
00373
00374 plpgsql_Datums = MemoryContextAlloc(compile_tmp_cxt,
00375 sizeof(PLpgSQL_datum *) * datums_alloc);
00376 datums_last = 0;
00377
00378 switch (function->fn_is_trigger)
00379 {
00380 case PLPGSQL_NOT_TRIGGER:
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390 MemoryContextSwitchTo(compile_tmp_cxt);
00391
00392 numargs = get_func_arg_info(procTup,
00393 &argtypes, &argnames, &argmodes);
00394
00395 plpgsql_resolve_polymorphic_argtypes(numargs, argtypes, argmodes,
00396 fcinfo->flinfo->fn_expr,
00397 forValidator,
00398 plpgsql_error_funcname);
00399
00400 in_arg_varnos = (int *) palloc(numargs * sizeof(int));
00401 out_arg_variables = (PLpgSQL_variable **) palloc(numargs * sizeof(PLpgSQL_variable *));
00402
00403 MemoryContextSwitchTo(func_cxt);
00404
00405
00406
00407
00408 for (i = 0; i < numargs; i++)
00409 {
00410 char buf[32];
00411 Oid argtypeid = argtypes[i];
00412 char argmode = argmodes ? argmodes[i] : PROARGMODE_IN;
00413 PLpgSQL_type *argdtype;
00414 PLpgSQL_variable *argvariable;
00415 int argitemtype;
00416
00417
00418 snprintf(buf, sizeof(buf), "$%d", i + 1);
00419
00420
00421 argdtype = plpgsql_build_datatype(argtypeid,
00422 -1,
00423 function->fn_input_collation);
00424
00425
00426
00427
00428 if (argdtype->ttype != PLPGSQL_TTYPE_SCALAR &&
00429 argdtype->ttype != PLPGSQL_TTYPE_ROW)
00430 ereport(ERROR,
00431 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00432 errmsg("PL/pgSQL functions cannot accept type %s",
00433 format_type_be(argtypeid))));
00434
00435
00436 argvariable = plpgsql_build_variable(buf, 0,
00437 argdtype, false);
00438
00439 if (argvariable->dtype == PLPGSQL_DTYPE_VAR)
00440 {
00441 argitemtype = PLPGSQL_NSTYPE_VAR;
00442 }
00443 else
00444 {
00445 Assert(argvariable->dtype == PLPGSQL_DTYPE_ROW);
00446 argitemtype = PLPGSQL_NSTYPE_ROW;
00447 }
00448
00449
00450 if (argmode == PROARGMODE_IN ||
00451 argmode == PROARGMODE_INOUT ||
00452 argmode == PROARGMODE_VARIADIC)
00453 in_arg_varnos[num_in_args++] = argvariable->dno;
00454 if (argmode == PROARGMODE_OUT ||
00455 argmode == PROARGMODE_INOUT ||
00456 argmode == PROARGMODE_TABLE)
00457 out_arg_variables[num_out_args++] = argvariable;
00458
00459
00460 add_parameter_name(argitemtype, argvariable->dno, buf);
00461
00462
00463 if (argnames && argnames[i][0] != '\0')
00464 add_parameter_name(argitemtype, argvariable->dno,
00465 argnames[i]);
00466 }
00467
00468
00469
00470
00471
00472
00473 if (num_out_args == 1)
00474 function->out_param_varno = out_arg_variables[0]->dno;
00475 else if (num_out_args > 1)
00476 {
00477 PLpgSQL_row *row = build_row_from_vars(out_arg_variables,
00478 num_out_args);
00479
00480 plpgsql_adddatum((PLpgSQL_datum *) row);
00481 function->out_param_varno = row->dno;
00482 }
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494 rettypeid = procStruct->prorettype;
00495 if (IsPolymorphicType(rettypeid))
00496 {
00497 if (forValidator)
00498 {
00499 if (rettypeid == ANYARRAYOID)
00500 rettypeid = INT4ARRAYOID;
00501 else if (rettypeid == ANYRANGEOID)
00502 rettypeid = INT4RANGEOID;
00503 else
00504 rettypeid = INT4OID;
00505
00506 }
00507 else
00508 {
00509 rettypeid = get_fn_expr_rettype(fcinfo->flinfo);
00510 if (!OidIsValid(rettypeid))
00511 ereport(ERROR,
00512 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00513 errmsg("could not determine actual return type "
00514 "for polymorphic function \"%s\"",
00515 plpgsql_error_funcname)));
00516 }
00517 }
00518
00519
00520
00521
00522 function->fn_rettype = rettypeid;
00523 function->fn_retset = procStruct->proretset;
00524
00525
00526
00527
00528 typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettypeid));
00529 if (!HeapTupleIsValid(typeTup))
00530 elog(ERROR, "cache lookup failed for type %u", rettypeid);
00531 typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
00532
00533
00534
00535 if (typeStruct->typtype == TYPTYPE_PSEUDO)
00536 {
00537 if (rettypeid == VOIDOID ||
00538 rettypeid == RECORDOID)
00539 ;
00540 else if (rettypeid == TRIGGEROID || rettypeid == EVTTRIGGEROID)
00541 ereport(ERROR,
00542 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00543 errmsg("trigger functions can only be called as triggers")));
00544 else
00545 ereport(ERROR,
00546 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00547 errmsg("PL/pgSQL functions cannot return type %s",
00548 format_type_be(rettypeid))));
00549 }
00550
00551 if (typeStruct->typrelid != InvalidOid ||
00552 rettypeid == RECORDOID)
00553 function->fn_retistuple = true;
00554 else
00555 {
00556 function->fn_retbyval = typeStruct->typbyval;
00557 function->fn_rettyplen = typeStruct->typlen;
00558 function->fn_rettypioparam = getTypeIOParam(typeTup);
00559 fmgr_info(typeStruct->typinput, &(function->fn_retinput));
00560
00561
00562
00563
00564
00565
00566 if (IsPolymorphicType(procStruct->prorettype) &&
00567 num_out_args == 0)
00568 {
00569 (void) plpgsql_build_variable("$0", 0,
00570 build_datatype(typeTup,
00571 -1,
00572 function->fn_input_collation),
00573 true);
00574 }
00575 }
00576 ReleaseSysCache(typeTup);
00577 break;
00578
00579 case PLPGSQL_DML_TRIGGER:
00580
00581 function->fn_rettype = InvalidOid;
00582 function->fn_retbyval = false;
00583 function->fn_retistuple = true;
00584 function->fn_retset = false;
00585
00586
00587 if (procStruct->pronargs != 0)
00588 ereport(ERROR,
00589 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00590 errmsg("trigger functions cannot have declared arguments"),
00591 errhint("The arguments of the trigger can be accessed through TG_NARGS and TG_ARGV instead.")));
00592
00593
00594 rec = plpgsql_build_record("new", 0, true);
00595 function->new_varno = rec->dno;
00596
00597
00598 rec = plpgsql_build_record("old", 0, true);
00599 function->old_varno = rec->dno;
00600
00601
00602 var = plpgsql_build_variable("tg_name", 0,
00603 plpgsql_build_datatype(NAMEOID,
00604 -1,
00605 InvalidOid),
00606 true);
00607 function->tg_name_varno = var->dno;
00608
00609
00610 var = plpgsql_build_variable("tg_when", 0,
00611 plpgsql_build_datatype(TEXTOID,
00612 -1,
00613 function->fn_input_collation),
00614 true);
00615 function->tg_when_varno = var->dno;
00616
00617
00618 var = plpgsql_build_variable("tg_level", 0,
00619 plpgsql_build_datatype(TEXTOID,
00620 -1,
00621 function->fn_input_collation),
00622 true);
00623 function->tg_level_varno = var->dno;
00624
00625
00626 var = plpgsql_build_variable("tg_op", 0,
00627 plpgsql_build_datatype(TEXTOID,
00628 -1,
00629 function->fn_input_collation),
00630 true);
00631 function->tg_op_varno = var->dno;
00632
00633
00634 var = plpgsql_build_variable("tg_relid", 0,
00635 plpgsql_build_datatype(OIDOID,
00636 -1,
00637 InvalidOid),
00638 true);
00639 function->tg_relid_varno = var->dno;
00640
00641
00642 var = plpgsql_build_variable("tg_relname", 0,
00643 plpgsql_build_datatype(NAMEOID,
00644 -1,
00645 InvalidOid),
00646 true);
00647 function->tg_relname_varno = var->dno;
00648
00649
00650 var = plpgsql_build_variable("tg_table_name", 0,
00651 plpgsql_build_datatype(NAMEOID,
00652 -1,
00653 InvalidOid),
00654 true);
00655 function->tg_table_name_varno = var->dno;
00656
00657
00658 var = plpgsql_build_variable("tg_table_schema", 0,
00659 plpgsql_build_datatype(NAMEOID,
00660 -1,
00661 InvalidOid),
00662 true);
00663 function->tg_table_schema_varno = var->dno;
00664
00665
00666 var = plpgsql_build_variable("tg_nargs", 0,
00667 plpgsql_build_datatype(INT4OID,
00668 -1,
00669 InvalidOid),
00670 true);
00671 function->tg_nargs_varno = var->dno;
00672
00673
00674 var = plpgsql_build_variable("tg_argv", 0,
00675 plpgsql_build_datatype(TEXTARRAYOID,
00676 -1,
00677 function->fn_input_collation),
00678 true);
00679 function->tg_argv_varno = var->dno;
00680
00681 break;
00682
00683 case PLPGSQL_EVENT_TRIGGER:
00684 function->fn_rettype = VOIDOID;
00685 function->fn_retbyval = false;
00686 function->fn_retistuple = true;
00687 function->fn_retset = false;
00688
00689
00690 if (procStruct->pronargs != 0)
00691 ereport(ERROR,
00692 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00693 errmsg("event trigger functions cannot have declared arguments")));
00694
00695
00696 var = plpgsql_build_variable("tg_event", 0,
00697 plpgsql_build_datatype(TEXTOID,
00698 -1,
00699 function->fn_input_collation),
00700 true);
00701 function->tg_event_varno = var->dno;
00702
00703
00704 var = plpgsql_build_variable("tg_tag", 0,
00705 plpgsql_build_datatype(TEXTOID,
00706 -1,
00707 function->fn_input_collation),
00708 true);
00709 function->tg_tag_varno = var->dno;
00710
00711 break;
00712
00713 default:
00714 elog(ERROR, "unrecognized function typecode: %d",
00715 (int) function->fn_is_trigger);
00716 break;
00717 }
00718
00719
00720 function->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
00721
00722
00723
00724
00725 var = plpgsql_build_variable("found", 0,
00726 plpgsql_build_datatype(BOOLOID,
00727 -1,
00728 InvalidOid),
00729 true);
00730 function->found_varno = var->dno;
00731
00732
00733
00734
00735 parse_rc = plpgsql_yyparse();
00736 if (parse_rc != 0)
00737 elog(ERROR, "plpgsql parser returned %d", parse_rc);
00738 function->action = plpgsql_parse_result;
00739
00740 plpgsql_scanner_finish();
00741 pfree(proc_source);
00742
00743
00744
00745
00746
00747
00748
00749 if (num_out_args > 0 || function->fn_rettype == VOIDOID ||
00750 function->fn_retset)
00751 add_dummy_return(function);
00752
00753
00754
00755
00756 function->fn_nargs = procStruct->pronargs;
00757 for (i = 0; i < function->fn_nargs; i++)
00758 function->fn_argvarnos[i] = in_arg_varnos[i];
00759 function->ndatums = plpgsql_nDatums;
00760 function->datums = palloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
00761 for (i = 0; i < plpgsql_nDatums; i++)
00762 function->datums[i] = plpgsql_Datums[i];
00763
00764
00765 if (plpgsql_DumpExecTree)
00766 plpgsql_dumptree(function);
00767
00768
00769
00770
00771 plpgsql_HashTableInsert(function, hashkey);
00772
00773
00774
00775
00776 error_context_stack = plerrcontext.previous;
00777 plpgsql_error_funcname = NULL;
00778
00779 plpgsql_check_syntax = false;
00780
00781 MemoryContextSwitchTo(compile_tmp_cxt);
00782 compile_tmp_cxt = NULL;
00783 return function;
00784 }
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796 PLpgSQL_function *
00797 plpgsql_compile_inline(char *proc_source)
00798 {
00799 char *func_name = "inline_code_block";
00800 PLpgSQL_function *function;
00801 ErrorContextCallback plerrcontext;
00802 Oid typinput;
00803 PLpgSQL_variable *var;
00804 int parse_rc;
00805 MemoryContext func_cxt;
00806 int i;
00807
00808
00809
00810
00811
00812
00813 plpgsql_scanner_init(proc_source);
00814
00815 plpgsql_error_funcname = func_name;
00816
00817
00818
00819
00820 plerrcontext.callback = plpgsql_compile_error_callback;
00821 plerrcontext.arg = proc_source;
00822 plerrcontext.previous = error_context_stack;
00823 error_context_stack = &plerrcontext;
00824
00825
00826 plpgsql_check_syntax = check_function_bodies;
00827
00828
00829 function = (PLpgSQL_function *) palloc0(sizeof(PLpgSQL_function));
00830
00831 plpgsql_curr_compile = function;
00832
00833
00834
00835
00836
00837 func_cxt = AllocSetContextCreate(CurrentMemoryContext,
00838 "PL/pgSQL function context",
00839 ALLOCSET_DEFAULT_MINSIZE,
00840 ALLOCSET_DEFAULT_INITSIZE,
00841 ALLOCSET_DEFAULT_MAXSIZE);
00842 compile_tmp_cxt = MemoryContextSwitchTo(func_cxt);
00843
00844 function->fn_signature = pstrdup(func_name);
00845 function->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
00846 function->fn_input_collation = InvalidOid;
00847 function->fn_cxt = func_cxt;
00848 function->out_param_varno = -1;
00849 function->resolve_option = plpgsql_variable_conflict;
00850
00851 plpgsql_ns_init();
00852 plpgsql_ns_push(func_name);
00853 plpgsql_DumpExecTree = false;
00854
00855 datums_alloc = 128;
00856 plpgsql_nDatums = 0;
00857 plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc);
00858 datums_last = 0;
00859
00860
00861 function->fn_rettype = VOIDOID;
00862 function->fn_retset = false;
00863 function->fn_retistuple = false;
00864
00865 function->fn_retbyval = true;
00866 function->fn_rettyplen = sizeof(int32);
00867 getTypeInputInfo(VOIDOID, &typinput, &function->fn_rettypioparam);
00868 fmgr_info(typinput, &(function->fn_retinput));
00869
00870
00871
00872
00873
00874 function->fn_readonly = false;
00875
00876
00877
00878
00879 var = plpgsql_build_variable("found", 0,
00880 plpgsql_build_datatype(BOOLOID,
00881 -1,
00882 InvalidOid),
00883 true);
00884 function->found_varno = var->dno;
00885
00886
00887
00888
00889 parse_rc = plpgsql_yyparse();
00890 if (parse_rc != 0)
00891 elog(ERROR, "plpgsql parser returned %d", parse_rc);
00892 function->action = plpgsql_parse_result;
00893
00894 plpgsql_scanner_finish();
00895
00896
00897
00898
00899
00900 if (function->fn_rettype == VOIDOID)
00901 add_dummy_return(function);
00902
00903
00904
00905
00906 function->fn_nargs = 0;
00907 function->ndatums = plpgsql_nDatums;
00908 function->datums = palloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
00909 for (i = 0; i < plpgsql_nDatums; i++)
00910 function->datums[i] = plpgsql_Datums[i];
00911
00912
00913
00914
00915 error_context_stack = plerrcontext.previous;
00916 plpgsql_error_funcname = NULL;
00917
00918 plpgsql_check_syntax = false;
00919
00920 MemoryContextSwitchTo(compile_tmp_cxt);
00921 compile_tmp_cxt = NULL;
00922 return function;
00923 }
00924
00925
00926
00927
00928
00929
00930
00931 static void
00932 plpgsql_compile_error_callback(void *arg)
00933 {
00934 if (arg)
00935 {
00936
00937
00938
00939
00940 if (function_parse_error_transpose((const char *) arg))
00941 return;
00942
00943
00944
00945
00946
00947 }
00948
00949 if (plpgsql_error_funcname)
00950 errcontext("compilation of PL/pgSQL function \"%s\" near line %d",
00951 plpgsql_error_funcname, plpgsql_latest_lineno());
00952 }
00953
00954
00955
00956
00957
00958 static void
00959 add_parameter_name(int itemtype, int itemno, const char *name)
00960 {
00961
00962
00963
00964
00965
00966
00967
00968 if (plpgsql_ns_lookup(plpgsql_ns_top(), true,
00969 name, NULL, NULL,
00970 NULL) != NULL)
00971 ereport(ERROR,
00972 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
00973 errmsg("parameter name \"%s\" used more than once",
00974 name)));
00975
00976
00977 plpgsql_ns_additem(itemtype, itemno, name);
00978 }
00979
00980
00981
00982
00983 static void
00984 add_dummy_return(PLpgSQL_function *function)
00985 {
00986
00987
00988
00989
00990
00991 if (function->action->exceptions != NULL)
00992 {
00993 PLpgSQL_stmt_block *new;
00994
00995 new = palloc0(sizeof(PLpgSQL_stmt_block));
00996 new->cmd_type = PLPGSQL_STMT_BLOCK;
00997 new->body = list_make1(function->action);
00998
00999 function->action = new;
01000 }
01001 if (function->action->body == NIL ||
01002 ((PLpgSQL_stmt *) llast(function->action->body))->cmd_type != PLPGSQL_STMT_RETURN)
01003 {
01004 PLpgSQL_stmt_return *new;
01005
01006 new = palloc0(sizeof(PLpgSQL_stmt_return));
01007 new->cmd_type = PLPGSQL_STMT_RETURN;
01008 new->expr = NULL;
01009 new->retvarno = function->out_param_varno;
01010
01011 function->action->body = lappend(function->action->body, new);
01012 }
01013 }
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024 void
01025 plpgsql_parser_setup(struct ParseState *pstate, PLpgSQL_expr *expr)
01026 {
01027 pstate->p_pre_columnref_hook = plpgsql_pre_column_ref;
01028 pstate->p_post_columnref_hook = plpgsql_post_column_ref;
01029 pstate->p_paramref_hook = plpgsql_param_ref;
01030
01031 pstate->p_ref_hook_state = (void *) expr;
01032 }
01033
01034
01035
01036
01037 static Node *
01038 plpgsql_pre_column_ref(ParseState *pstate, ColumnRef *cref)
01039 {
01040 PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
01041
01042 if (expr->func->resolve_option == PLPGSQL_RESOLVE_VARIABLE)
01043 return resolve_column_ref(pstate, expr, cref, false);
01044 else
01045 return NULL;
01046 }
01047
01048
01049
01050
01051 static Node *
01052 plpgsql_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var)
01053 {
01054 PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
01055 Node *myvar;
01056
01057 if (expr->func->resolve_option == PLPGSQL_RESOLVE_VARIABLE)
01058 return NULL;
01059
01060 if (expr->func->resolve_option == PLPGSQL_RESOLVE_COLUMN && var != NULL)
01061 return NULL;
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073 myvar = resolve_column_ref(pstate, expr, cref, (var == NULL));
01074
01075 if (myvar != NULL && var != NULL)
01076 {
01077
01078
01079
01080
01081 ereport(ERROR,
01082 (errcode(ERRCODE_AMBIGUOUS_COLUMN),
01083 errmsg("column reference \"%s\" is ambiguous",
01084 NameListToString(cref->fields)),
01085 errdetail("It could refer to either a PL/pgSQL variable or a table column."),
01086 parser_errposition(pstate, cref->location)));
01087 }
01088
01089 return myvar;
01090 }
01091
01092
01093
01094
01095 static Node *
01096 plpgsql_param_ref(ParseState *pstate, ParamRef *pref)
01097 {
01098 PLpgSQL_expr *expr = (PLpgSQL_expr *) pstate->p_ref_hook_state;
01099 char pname[32];
01100 PLpgSQL_nsitem *nse;
01101
01102 snprintf(pname, sizeof(pname), "$%d", pref->number);
01103
01104 nse = plpgsql_ns_lookup(expr->ns, false,
01105 pname, NULL, NULL,
01106 NULL);
01107
01108 if (nse == NULL)
01109 return NULL;
01110
01111 return make_datum_param(expr, nse->itemno, pref->location);
01112 }
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122 static Node *
01123 resolve_column_ref(ParseState *pstate, PLpgSQL_expr *expr,
01124 ColumnRef *cref, bool error_if_no_field)
01125 {
01126 PLpgSQL_execstate *estate;
01127 PLpgSQL_nsitem *nse;
01128 const char *name1;
01129 const char *name2 = NULL;
01130 const char *name3 = NULL;
01131 const char *colname = NULL;
01132 int nnames;
01133 int nnames_scalar = 0;
01134 int nnames_wholerow = 0;
01135 int nnames_field = 0;
01136
01137
01138
01139
01140
01141
01142 estate = expr->func->cur_estate;
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154 switch (list_length(cref->fields))
01155 {
01156 case 1:
01157 {
01158 Node *field1 = (Node *) linitial(cref->fields);
01159
01160 Assert(IsA(field1, String));
01161 name1 = strVal(field1);
01162 nnames_scalar = 1;
01163 nnames_wholerow = 1;
01164 break;
01165 }
01166 case 2:
01167 {
01168 Node *field1 = (Node *) linitial(cref->fields);
01169 Node *field2 = (Node *) lsecond(cref->fields);
01170
01171 Assert(IsA(field1, String));
01172 name1 = strVal(field1);
01173
01174
01175 if (IsA(field2, A_Star))
01176 {
01177
01178 name2 = "*";
01179 nnames_wholerow = 1;
01180 break;
01181 }
01182
01183 Assert(IsA(field2, String));
01184 name2 = strVal(field2);
01185 colname = name2;
01186 nnames_scalar = 2;
01187 nnames_wholerow = 2;
01188 nnames_field = 1;
01189 break;
01190 }
01191 case 3:
01192 {
01193 Node *field1 = (Node *) linitial(cref->fields);
01194 Node *field2 = (Node *) lsecond(cref->fields);
01195 Node *field3 = (Node *) lthird(cref->fields);
01196
01197 Assert(IsA(field1, String));
01198 name1 = strVal(field1);
01199 Assert(IsA(field2, String));
01200 name2 = strVal(field2);
01201
01202
01203 if (IsA(field3, A_Star))
01204 {
01205
01206 name3 = "*";
01207 nnames_wholerow = 2;
01208 break;
01209 }
01210
01211 Assert(IsA(field3, String));
01212 name3 = strVal(field3);
01213 colname = name3;
01214 nnames_field = 2;
01215 break;
01216 }
01217 default:
01218
01219 return NULL;
01220 }
01221
01222 nse = plpgsql_ns_lookup(expr->ns, false,
01223 name1, name2, name3,
01224 &nnames);
01225
01226 if (nse == NULL)
01227 return NULL;
01228
01229 switch (nse->itemtype)
01230 {
01231 case PLPGSQL_NSTYPE_VAR:
01232 if (nnames == nnames_scalar)
01233 return make_datum_param(expr, nse->itemno, cref->location);
01234 break;
01235 case PLPGSQL_NSTYPE_REC:
01236 if (nnames == nnames_wholerow)
01237 return make_datum_param(expr, nse->itemno, cref->location);
01238 if (nnames == nnames_field)
01239 {
01240
01241 int i;
01242
01243
01244 for (i = 0; i < estate->ndatums; i++)
01245 {
01246 PLpgSQL_recfield *fld = (PLpgSQL_recfield *) estate->datums[i];
01247
01248 if (fld->dtype == PLPGSQL_DTYPE_RECFIELD &&
01249 fld->recparentno == nse->itemno &&
01250 strcmp(fld->fieldname, colname) == 0)
01251 {
01252 return make_datum_param(expr, i, cref->location);
01253 }
01254 }
01255
01256
01257
01258
01259
01260
01261
01262 if (error_if_no_field)
01263 ereport(ERROR,
01264 (errcode(ERRCODE_UNDEFINED_COLUMN),
01265 errmsg("record \"%s\" has no field \"%s\"",
01266 (nnames_field == 1) ? name1 : name2,
01267 colname),
01268 parser_errposition(pstate, cref->location)));
01269 }
01270 break;
01271 case PLPGSQL_NSTYPE_ROW:
01272 if (nnames == nnames_wholerow)
01273 return make_datum_param(expr, nse->itemno, cref->location);
01274 if (nnames == nnames_field)
01275 {
01276
01277 PLpgSQL_row *row = (PLpgSQL_row *) estate->datums[nse->itemno];
01278 int i;
01279
01280 for (i = 0; i < row->nfields; i++)
01281 {
01282 if (row->fieldnames[i] &&
01283 strcmp(row->fieldnames[i], colname) == 0)
01284 {
01285 return make_datum_param(expr, row->varnos[i],
01286 cref->location);
01287 }
01288 }
01289
01290 if (error_if_no_field)
01291 ereport(ERROR,
01292 (errcode(ERRCODE_UNDEFINED_COLUMN),
01293 errmsg("record \"%s\" has no field \"%s\"",
01294 (nnames_field == 1) ? name1 : name2,
01295 colname),
01296 parser_errposition(pstate, cref->location)));
01297 }
01298 break;
01299 default:
01300 elog(ERROR, "unrecognized plpgsql itemtype: %d", nse->itemtype);
01301 }
01302
01303
01304 return NULL;
01305 }
01306
01307
01308
01309
01310
01311 static Node *
01312 make_datum_param(PLpgSQL_expr *expr, int dno, int location)
01313 {
01314 PLpgSQL_execstate *estate;
01315 PLpgSQL_datum *datum;
01316 Param *param;
01317 MemoryContext oldcontext;
01318
01319
01320 estate = expr->func->cur_estate;
01321 Assert(dno >= 0 && dno < estate->ndatums);
01322 datum = estate->datums[dno];
01323
01324
01325
01326
01327 oldcontext = MemoryContextSwitchTo(expr->func->fn_cxt);
01328 expr->paramnos = bms_add_member(expr->paramnos, dno);
01329 MemoryContextSwitchTo(oldcontext);
01330
01331 param = makeNode(Param);
01332 param->paramkind = PARAM_EXTERN;
01333 param->paramid = dno + 1;
01334 exec_get_datum_type_info(estate,
01335 datum,
01336 ¶m->paramtype,
01337 ¶m->paramtypmod,
01338 ¶m->paramcollid);
01339 param->location = location;
01340
01341 return (Node *) param;
01342 }
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361 bool
01362 plpgsql_parse_word(char *word1, const char *yytxt,
01363 PLwdatum *wdatum, PLword *word)
01364 {
01365 PLpgSQL_nsitem *ns;
01366
01367
01368
01369
01370
01371
01372 if (plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_NORMAL)
01373 {
01374
01375
01376
01377 ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
01378 word1, NULL, NULL,
01379 NULL);
01380
01381 if (ns != NULL)
01382 {
01383 switch (ns->itemtype)
01384 {
01385 case PLPGSQL_NSTYPE_VAR:
01386 case PLPGSQL_NSTYPE_ROW:
01387 case PLPGSQL_NSTYPE_REC:
01388 wdatum->datum = plpgsql_Datums[ns->itemno];
01389 wdatum->ident = word1;
01390 wdatum->quoted = (yytxt[0] == '"');
01391 wdatum->idents = NIL;
01392 return true;
01393
01394 default:
01395
01396 elog(ERROR, "unrecognized plpgsql itemtype: %d",
01397 ns->itemtype);
01398 }
01399 }
01400 }
01401
01402
01403
01404
01405
01406 word->ident = word1;
01407 word->quoted = (yytxt[0] == '"');
01408 return false;
01409 }
01410
01411
01412
01413
01414
01415
01416
01417 bool
01418 plpgsql_parse_dblword(char *word1, char *word2,
01419 PLwdatum *wdatum, PLcword *cword)
01420 {
01421 PLpgSQL_nsitem *ns;
01422 List *idents;
01423 int nnames;
01424
01425 idents = list_make2(makeString(word1),
01426 makeString(word2));
01427
01428
01429
01430
01431
01432
01433 if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE)
01434 {
01435
01436
01437
01438 ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
01439 word1, word2, NULL,
01440 &nnames);
01441 if (ns != NULL)
01442 {
01443 switch (ns->itemtype)
01444 {
01445 case PLPGSQL_NSTYPE_VAR:
01446
01447 wdatum->datum = plpgsql_Datums[ns->itemno];
01448 wdatum->ident = NULL;
01449 wdatum->quoted = false;
01450 wdatum->idents = idents;
01451 return true;
01452
01453 case PLPGSQL_NSTYPE_REC:
01454 if (nnames == 1)
01455 {
01456
01457
01458
01459
01460
01461
01462 PLpgSQL_recfield *new;
01463
01464 new = palloc(sizeof(PLpgSQL_recfield));
01465 new->dtype = PLPGSQL_DTYPE_RECFIELD;
01466 new->fieldname = pstrdup(word2);
01467 new->recparentno = ns->itemno;
01468
01469 plpgsql_adddatum((PLpgSQL_datum *) new);
01470
01471 wdatum->datum = (PLpgSQL_datum *) new;
01472 }
01473 else
01474 {
01475
01476 wdatum->datum = plpgsql_Datums[ns->itemno];
01477 }
01478 wdatum->ident = NULL;
01479 wdatum->quoted = false;
01480 wdatum->idents = idents;
01481 return true;
01482
01483 case PLPGSQL_NSTYPE_ROW:
01484 if (nnames == 1)
01485 {
01486
01487
01488
01489
01490
01491 PLpgSQL_row *row;
01492 int i;
01493
01494 row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
01495 for (i = 0; i < row->nfields; i++)
01496 {
01497 if (row->fieldnames[i] &&
01498 strcmp(row->fieldnames[i], word2) == 0)
01499 {
01500 wdatum->datum = plpgsql_Datums[row->varnos[i]];
01501 wdatum->ident = NULL;
01502 wdatum->quoted = false;
01503 wdatum->idents = idents;
01504 return true;
01505 }
01506 }
01507
01508 }
01509 else
01510 {
01511
01512 wdatum->datum = plpgsql_Datums[ns->itemno];
01513 wdatum->ident = NULL;
01514 wdatum->quoted = false;
01515 wdatum->idents = idents;
01516 return true;
01517 }
01518 break;
01519
01520 default:
01521 break;
01522 }
01523 }
01524 }
01525
01526
01527 cword->idents = idents;
01528 return false;
01529 }
01530
01531
01532
01533
01534
01535
01536
01537 bool
01538 plpgsql_parse_tripword(char *word1, char *word2, char *word3,
01539 PLwdatum *wdatum, PLcword *cword)
01540 {
01541 PLpgSQL_nsitem *ns;
01542 List *idents;
01543 int nnames;
01544
01545 idents = list_make3(makeString(word1),
01546 makeString(word2),
01547 makeString(word3));
01548
01549
01550
01551
01552
01553
01554 if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE)
01555 {
01556
01557
01558
01559
01560 ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
01561 word1, word2, word3,
01562 &nnames);
01563 if (ns != NULL && nnames == 2)
01564 {
01565 switch (ns->itemtype)
01566 {
01567 case PLPGSQL_NSTYPE_REC:
01568 {
01569
01570
01571
01572
01573 PLpgSQL_recfield *new;
01574
01575 new = palloc(sizeof(PLpgSQL_recfield));
01576 new->dtype = PLPGSQL_DTYPE_RECFIELD;
01577 new->fieldname = pstrdup(word3);
01578 new->recparentno = ns->itemno;
01579
01580 plpgsql_adddatum((PLpgSQL_datum *) new);
01581
01582 wdatum->datum = (PLpgSQL_datum *) new;
01583 wdatum->ident = NULL;
01584 wdatum->quoted = false;
01585 wdatum->idents = idents;
01586 return true;
01587 }
01588
01589 case PLPGSQL_NSTYPE_ROW:
01590 {
01591
01592
01593
01594
01595 PLpgSQL_row *row;
01596 int i;
01597
01598 row = (PLpgSQL_row *) (plpgsql_Datums[ns->itemno]);
01599 for (i = 0; i < row->nfields; i++)
01600 {
01601 if (row->fieldnames[i] &&
01602 strcmp(row->fieldnames[i], word3) == 0)
01603 {
01604 wdatum->datum = plpgsql_Datums[row->varnos[i]];
01605 wdatum->ident = NULL;
01606 wdatum->quoted = false;
01607 wdatum->idents = idents;
01608 return true;
01609 }
01610 }
01611
01612 break;
01613 }
01614
01615 default:
01616 break;
01617 }
01618 }
01619 }
01620
01621
01622 cword->idents = idents;
01623 return false;
01624 }
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634 PLpgSQL_type *
01635 plpgsql_parse_wordtype(char *ident)
01636 {
01637 PLpgSQL_type *dtype;
01638 PLpgSQL_nsitem *nse;
01639 HeapTuple typeTup;
01640
01641
01642
01643
01644 nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
01645 ident, NULL, NULL,
01646 NULL);
01647
01648 if (nse != NULL)
01649 {
01650 switch (nse->itemtype)
01651 {
01652 case PLPGSQL_NSTYPE_VAR:
01653 return ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
01654
01655
01656
01657 default:
01658 return NULL;
01659 }
01660 }
01661
01662
01663
01664
01665
01666 typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL);
01667 if (typeTup)
01668 {
01669 Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
01670
01671 if (!typeStruct->typisdefined ||
01672 typeStruct->typrelid != InvalidOid)
01673 {
01674 ReleaseSysCache(typeTup);
01675 return NULL;
01676 }
01677
01678 dtype = build_datatype(typeTup, -1,
01679 plpgsql_curr_compile->fn_input_collation);
01680
01681 ReleaseSysCache(typeTup);
01682 return dtype;
01683 }
01684
01685
01686
01687
01688
01689 return NULL;
01690 }
01691
01692
01693
01694
01695
01696
01697 PLpgSQL_type *
01698 plpgsql_parse_cwordtype(List *idents)
01699 {
01700 PLpgSQL_type *dtype = NULL;
01701 PLpgSQL_nsitem *nse;
01702 const char *fldname;
01703 Oid classOid;
01704 HeapTuple classtup = NULL;
01705 HeapTuple attrtup = NULL;
01706 HeapTuple typetup = NULL;
01707 Form_pg_class classStruct;
01708 Form_pg_attribute attrStruct;
01709 MemoryContext oldCxt;
01710
01711
01712 oldCxt = MemoryContextSwitchTo(compile_tmp_cxt);
01713
01714 if (list_length(idents) == 2)
01715 {
01716
01717
01718
01719
01720
01721 nse = plpgsql_ns_lookup(plpgsql_ns_top(), false,
01722 strVal(linitial(idents)),
01723 strVal(lsecond(idents)),
01724 NULL,
01725 NULL);
01726
01727 if (nse != NULL && nse->itemtype == PLPGSQL_NSTYPE_VAR)
01728 {
01729 dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
01730 goto done;
01731 }
01732
01733
01734
01735
01736 classOid = RelnameGetRelid(strVal(linitial(idents)));
01737 if (!OidIsValid(classOid))
01738 goto done;
01739 fldname = strVal(lsecond(idents));
01740 }
01741 else if (list_length(idents) == 3)
01742 {
01743 RangeVar *relvar;
01744
01745 relvar = makeRangeVar(strVal(linitial(idents)),
01746 strVal(lsecond(idents)),
01747 -1);
01748
01749 classOid = RangeVarGetRelid(relvar, NoLock, true);
01750 if (!OidIsValid(classOid))
01751 goto done;
01752 fldname = strVal(lthird(idents));
01753 }
01754 else
01755 goto done;
01756
01757 classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classOid));
01758 if (!HeapTupleIsValid(classtup))
01759 goto done;
01760 classStruct = (Form_pg_class) GETSTRUCT(classtup);
01761
01762
01763
01764
01765
01766 if (classStruct->relkind != RELKIND_RELATION &&
01767 classStruct->relkind != RELKIND_SEQUENCE &&
01768 classStruct->relkind != RELKIND_VIEW &&
01769 classStruct->relkind != RELKIND_MATVIEW &&
01770 classStruct->relkind != RELKIND_COMPOSITE_TYPE &&
01771 classStruct->relkind != RELKIND_FOREIGN_TABLE)
01772 goto done;
01773
01774
01775
01776
01777 attrtup = SearchSysCacheAttName(classOid, fldname);
01778 if (!HeapTupleIsValid(attrtup))
01779 goto done;
01780 attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
01781
01782 typetup = SearchSysCache1(TYPEOID,
01783 ObjectIdGetDatum(attrStruct->atttypid));
01784 if (!HeapTupleIsValid(typetup))
01785 elog(ERROR, "cache lookup failed for type %u", attrStruct->atttypid);
01786
01787
01788
01789
01790
01791 MemoryContextSwitchTo(oldCxt);
01792 dtype = build_datatype(typetup,
01793 attrStruct->atttypmod,
01794 attrStruct->attcollation);
01795 MemoryContextSwitchTo(compile_tmp_cxt);
01796
01797 done:
01798 if (HeapTupleIsValid(classtup))
01799 ReleaseSysCache(classtup);
01800 if (HeapTupleIsValid(attrtup))
01801 ReleaseSysCache(attrtup);
01802 if (HeapTupleIsValid(typetup))
01803 ReleaseSysCache(typetup);
01804
01805 MemoryContextSwitchTo(oldCxt);
01806 return dtype;
01807 }
01808
01809
01810
01811
01812
01813
01814 PLpgSQL_type *
01815 plpgsql_parse_wordrowtype(char *ident)
01816 {
01817 Oid classOid;
01818
01819
01820 classOid = RelnameGetRelid(ident);
01821 if (!OidIsValid(classOid))
01822 ereport(ERROR,
01823 (errcode(ERRCODE_UNDEFINED_TABLE),
01824 errmsg("relation \"%s\" does not exist", ident)));
01825
01826
01827 return plpgsql_build_datatype(get_rel_type_id(classOid), -1, InvalidOid);
01828 }
01829
01830
01831
01832
01833
01834
01835 PLpgSQL_type *
01836 plpgsql_parse_cwordrowtype(List *idents)
01837 {
01838 Oid classOid;
01839 RangeVar *relvar;
01840 MemoryContext oldCxt;
01841
01842 if (list_length(idents) != 2)
01843 return NULL;
01844
01845
01846 oldCxt = MemoryContextSwitchTo(compile_tmp_cxt);
01847
01848
01849 relvar = makeRangeVar(strVal(linitial(idents)),
01850 strVal(lsecond(idents)),
01851 -1);
01852 classOid = RangeVarGetRelid(relvar, NoLock, false);
01853
01854 MemoryContextSwitchTo(oldCxt);
01855
01856
01857 return plpgsql_build_datatype(get_rel_type_id(classOid), -1, InvalidOid);
01858 }
01859
01860
01861
01862
01863
01864
01865
01866
01867
01868
01869 PLpgSQL_variable *
01870 plpgsql_build_variable(const char *refname, int lineno, PLpgSQL_type *dtype,
01871 bool add2namespace)
01872 {
01873 PLpgSQL_variable *result;
01874
01875 switch (dtype->ttype)
01876 {
01877 case PLPGSQL_TTYPE_SCALAR:
01878 {
01879
01880 PLpgSQL_var *var;
01881
01882 var = palloc0(sizeof(PLpgSQL_var));
01883 var->dtype = PLPGSQL_DTYPE_VAR;
01884 var->refname = pstrdup(refname);
01885 var->lineno = lineno;
01886 var->datatype = dtype;
01887
01888
01889
01890 var->value = 0;
01891 var->isnull = true;
01892 var->freeval = false;
01893
01894 plpgsql_adddatum((PLpgSQL_datum *) var);
01895 if (add2namespace)
01896 plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR,
01897 var->dno,
01898 refname);
01899 result = (PLpgSQL_variable *) var;
01900 break;
01901 }
01902 case PLPGSQL_TTYPE_ROW:
01903 {
01904
01905 PLpgSQL_row *row;
01906
01907 row = build_row_from_class(dtype->typrelid);
01908
01909 row->dtype = PLPGSQL_DTYPE_ROW;
01910 row->refname = pstrdup(refname);
01911 row->lineno = lineno;
01912
01913 plpgsql_adddatum((PLpgSQL_datum *) row);
01914 if (add2namespace)
01915 plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW,
01916 row->dno,
01917 refname);
01918 result = (PLpgSQL_variable *) row;
01919 break;
01920 }
01921 case PLPGSQL_TTYPE_REC:
01922 {
01923
01924 PLpgSQL_rec *rec;
01925
01926 rec = plpgsql_build_record(refname, lineno, add2namespace);
01927 result = (PLpgSQL_variable *) rec;
01928 break;
01929 }
01930 case PLPGSQL_TTYPE_PSEUDO:
01931 ereport(ERROR,
01932 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01933 errmsg("variable \"%s\" has pseudo-type %s",
01934 refname, format_type_be(dtype->typoid))));
01935 result = NULL;
01936 break;
01937 default:
01938 elog(ERROR, "unrecognized ttype: %d", dtype->ttype);
01939 result = NULL;
01940 break;
01941 }
01942
01943 return result;
01944 }
01945
01946
01947
01948
01949 PLpgSQL_rec *
01950 plpgsql_build_record(const char *refname, int lineno, bool add2namespace)
01951 {
01952 PLpgSQL_rec *rec;
01953
01954 rec = palloc0(sizeof(PLpgSQL_rec));
01955 rec->dtype = PLPGSQL_DTYPE_REC;
01956 rec->refname = pstrdup(refname);
01957 rec->lineno = lineno;
01958 rec->tup = NULL;
01959 rec->tupdesc = NULL;
01960 rec->freetup = false;
01961 plpgsql_adddatum((PLpgSQL_datum *) rec);
01962 if (add2namespace)
01963 plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->dno, rec->refname);
01964
01965 return rec;
01966 }
01967
01968
01969
01970
01971 static PLpgSQL_row *
01972 build_row_from_class(Oid classOid)
01973 {
01974 PLpgSQL_row *row;
01975 Relation rel;
01976 Form_pg_class classStruct;
01977 const char *relname;
01978 int i;
01979
01980
01981
01982
01983 rel = relation_open(classOid, AccessShareLock);
01984 classStruct = RelationGetForm(rel);
01985 relname = RelationGetRelationName(rel);
01986
01987
01988
01989
01990
01991 if (classStruct->relkind != RELKIND_RELATION &&
01992 classStruct->relkind != RELKIND_SEQUENCE &&
01993 classStruct->relkind != RELKIND_VIEW &&
01994 classStruct->relkind != RELKIND_MATVIEW &&
01995 classStruct->relkind != RELKIND_COMPOSITE_TYPE &&
01996 classStruct->relkind != RELKIND_FOREIGN_TABLE)
01997 ereport(ERROR,
01998 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
01999 errmsg("relation \"%s\" is not a table", relname)));
02000
02001
02002
02003
02004
02005 row = palloc0(sizeof(PLpgSQL_row));
02006 row->dtype = PLPGSQL_DTYPE_ROW;
02007 row->rowtupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
02008 row->nfields = classStruct->relnatts;
02009 row->fieldnames = palloc(sizeof(char *) * row->nfields);
02010 row->varnos = palloc(sizeof(int) * row->nfields);
02011
02012 for (i = 0; i < row->nfields; i++)
02013 {
02014 Form_pg_attribute attrStruct;
02015
02016
02017
02018
02019 attrStruct = row->rowtupdesc->attrs[i];
02020
02021 if (!attrStruct->attisdropped)
02022 {
02023 char *attname;
02024 char refname[(NAMEDATALEN * 2) + 100];
02025 PLpgSQL_variable *var;
02026
02027 attname = NameStr(attrStruct->attname);
02028 snprintf(refname, sizeof(refname), "%s.%s", relname, attname);
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039
02040 var = plpgsql_build_variable(refname, 0,
02041 plpgsql_build_datatype(attrStruct->atttypid,
02042 attrStruct->atttypmod,
02043 attrStruct->attcollation),
02044 false);
02045
02046
02047 row->fieldnames[i] = attname;
02048 row->varnos[i] = var->dno;
02049 }
02050 else
02051 {
02052
02053 row->fieldnames[i] = NULL;
02054 row->varnos[i] = -1;
02055 }
02056 }
02057
02058 relation_close(rel, AccessShareLock);
02059
02060 return row;
02061 }
02062
02063
02064
02065
02066 static PLpgSQL_row *
02067 build_row_from_vars(PLpgSQL_variable **vars, int numvars)
02068 {
02069 PLpgSQL_row *row;
02070 int i;
02071
02072 row = palloc0(sizeof(PLpgSQL_row));
02073 row->dtype = PLPGSQL_DTYPE_ROW;
02074 row->rowtupdesc = CreateTemplateTupleDesc(numvars, false);
02075 row->nfields = numvars;
02076 row->fieldnames = palloc(numvars * sizeof(char *));
02077 row->varnos = palloc(numvars * sizeof(int));
02078
02079 for (i = 0; i < numvars; i++)
02080 {
02081 PLpgSQL_variable *var = vars[i];
02082 Oid typoid = RECORDOID;
02083 int32 typmod = -1;
02084 Oid typcoll = InvalidOid;
02085
02086 switch (var->dtype)
02087 {
02088 case PLPGSQL_DTYPE_VAR:
02089 typoid = ((PLpgSQL_var *) var)->datatype->typoid;
02090 typmod = ((PLpgSQL_var *) var)->datatype->atttypmod;
02091 typcoll = ((PLpgSQL_var *) var)->datatype->collation;
02092 break;
02093
02094 case PLPGSQL_DTYPE_REC:
02095 break;
02096
02097 case PLPGSQL_DTYPE_ROW:
02098 if (((PLpgSQL_row *) var)->rowtupdesc)
02099 {
02100 typoid = ((PLpgSQL_row *) var)->rowtupdesc->tdtypeid;
02101 typmod = ((PLpgSQL_row *) var)->rowtupdesc->tdtypmod;
02102
02103 }
02104 break;
02105
02106 default:
02107 elog(ERROR, "unrecognized dtype: %d", var->dtype);
02108 }
02109
02110 row->fieldnames[i] = var->refname;
02111 row->varnos[i] = var->dno;
02112
02113 TupleDescInitEntry(row->rowtupdesc, i + 1,
02114 var->refname,
02115 typoid, typmod,
02116 0);
02117 TupleDescInitEntryCollation(row->rowtupdesc, i + 1, typcoll);
02118 }
02119
02120 return row;
02121 }
02122
02123
02124
02125
02126
02127
02128
02129
02130 PLpgSQL_type *
02131 plpgsql_build_datatype(Oid typeOid, int32 typmod, Oid collation)
02132 {
02133 HeapTuple typeTup;
02134 PLpgSQL_type *typ;
02135
02136 typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeOid));
02137 if (!HeapTupleIsValid(typeTup))
02138 elog(ERROR, "cache lookup failed for type %u", typeOid);
02139
02140 typ = build_datatype(typeTup, typmod, collation);
02141
02142 ReleaseSysCache(typeTup);
02143
02144 return typ;
02145 }
02146
02147
02148
02149
02150 static PLpgSQL_type *
02151 build_datatype(HeapTuple typeTup, int32 typmod, Oid collation)
02152 {
02153 Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
02154 PLpgSQL_type *typ;
02155
02156 if (!typeStruct->typisdefined)
02157 ereport(ERROR,
02158 (errcode(ERRCODE_UNDEFINED_OBJECT),
02159 errmsg("type \"%s\" is only a shell",
02160 NameStr(typeStruct->typname))));
02161
02162 typ = (PLpgSQL_type *) palloc(sizeof(PLpgSQL_type));
02163
02164 typ->typname = pstrdup(NameStr(typeStruct->typname));
02165 typ->typoid = HeapTupleGetOid(typeTup);
02166 switch (typeStruct->typtype)
02167 {
02168 case TYPTYPE_BASE:
02169 case TYPTYPE_DOMAIN:
02170 case TYPTYPE_ENUM:
02171 case TYPTYPE_RANGE:
02172 typ->ttype = PLPGSQL_TTYPE_SCALAR;
02173 break;
02174 case TYPTYPE_COMPOSITE:
02175 Assert(OidIsValid(typeStruct->typrelid));
02176 typ->ttype = PLPGSQL_TTYPE_ROW;
02177 break;
02178 case TYPTYPE_PSEUDO:
02179 if (typ->typoid == RECORDOID)
02180 typ->ttype = PLPGSQL_TTYPE_REC;
02181 else
02182 typ->ttype = PLPGSQL_TTYPE_PSEUDO;
02183 break;
02184 default:
02185 elog(ERROR, "unrecognized typtype: %d",
02186 (int) typeStruct->typtype);
02187 break;
02188 }
02189 typ->typlen = typeStruct->typlen;
02190 typ->typbyval = typeStruct->typbyval;
02191 typ->typrelid = typeStruct->typrelid;
02192 typ->typioparam = getTypeIOParam(typeTup);
02193 typ->collation = typeStruct->typcollation;
02194 if (OidIsValid(collation) && OidIsValid(typ->collation))
02195 typ->collation = collation;
02196 fmgr_info(typeStruct->typinput, &(typ->typinput));
02197 typ->atttypmod = typmod;
02198
02199 return typ;
02200 }
02201
02202
02203
02204
02205
02206
02207
02208
02209 int
02210 plpgsql_recognize_err_condition(const char *condname, bool allow_sqlstate)
02211 {
02212 int i;
02213
02214 if (allow_sqlstate)
02215 {
02216 if (strlen(condname) == 5 &&
02217 strspn(condname, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") == 5)
02218 return MAKE_SQLSTATE(condname[0],
02219 condname[1],
02220 condname[2],
02221 condname[3],
02222 condname[4]);
02223 }
02224
02225 for (i = 0; exception_label_map[i].label != NULL; i++)
02226 {
02227 if (strcmp(condname, exception_label_map[i].label) == 0)
02228 return exception_label_map[i].sqlerrstate;
02229 }
02230
02231 ereport(ERROR,
02232 (errcode(ERRCODE_UNDEFINED_OBJECT),
02233 errmsg("unrecognized exception condition \"%s\"",
02234 condname)));
02235 return 0;
02236 }
02237
02238
02239
02240
02241
02242
02243
02244
02245 PLpgSQL_condition *
02246 plpgsql_parse_err_condition(char *condname)
02247 {
02248 int i;
02249 PLpgSQL_condition *new;
02250 PLpgSQL_condition *prev;
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261 if (strcmp(condname, "others") == 0)
02262 {
02263 new = palloc(sizeof(PLpgSQL_condition));
02264 new->sqlerrstate = 0;
02265 new->condname = condname;
02266 new->next = NULL;
02267 return new;
02268 }
02269
02270 prev = NULL;
02271 for (i = 0; exception_label_map[i].label != NULL; i++)
02272 {
02273 if (strcmp(condname, exception_label_map[i].label) == 0)
02274 {
02275 new = palloc(sizeof(PLpgSQL_condition));
02276 new->sqlerrstate = exception_label_map[i].sqlerrstate;
02277 new->condname = condname;
02278 new->next = prev;
02279 prev = new;
02280 }
02281 }
02282
02283 if (!prev)
02284 ereport(ERROR,
02285 (errcode(ERRCODE_UNDEFINED_OBJECT),
02286 errmsg("unrecognized exception condition \"%s\"",
02287 condname)));
02288
02289 return prev;
02290 }
02291
02292
02293
02294
02295
02296
02297 void
02298 plpgsql_adddatum(PLpgSQL_datum *new)
02299 {
02300 if (plpgsql_nDatums == datums_alloc)
02301 {
02302 datums_alloc *= 2;
02303 plpgsql_Datums = repalloc(plpgsql_Datums, sizeof(PLpgSQL_datum *) * datums_alloc);
02304 }
02305
02306 new->dno = plpgsql_nDatums;
02307 plpgsql_Datums[plpgsql_nDatums++] = new;
02308 }
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325 int
02326 plpgsql_add_initdatums(int **varnos)
02327 {
02328 int i;
02329 int n = 0;
02330
02331 for (i = datums_last; i < plpgsql_nDatums; i++)
02332 {
02333 switch (plpgsql_Datums[i]->dtype)
02334 {
02335 case PLPGSQL_DTYPE_VAR:
02336 n++;
02337 break;
02338
02339 default:
02340 break;
02341 }
02342 }
02343
02344 if (varnos != NULL)
02345 {
02346 if (n > 0)
02347 {
02348 *varnos = (int *) palloc(sizeof(int) * n);
02349
02350 n = 0;
02351 for (i = datums_last; i < plpgsql_nDatums; i++)
02352 {
02353 switch (plpgsql_Datums[i]->dtype)
02354 {
02355 case PLPGSQL_DTYPE_VAR:
02356 (*varnos)[n++] = plpgsql_Datums[i]->dno;
02357
02358 default:
02359 break;
02360 }
02361 }
02362 }
02363 else
02364 *varnos = NULL;
02365 }
02366
02367 datums_last = plpgsql_nDatums;
02368 return n;
02369 }
02370
02371
02372
02373
02374
02375
02376
02377 static void
02378 compute_function_hashkey(FunctionCallInfo fcinfo,
02379 Form_pg_proc procStruct,
02380 PLpgSQL_func_hashkey *hashkey,
02381 bool forValidator)
02382 {
02383
02384 MemSet(hashkey, 0, sizeof(PLpgSQL_func_hashkey));
02385
02386
02387 hashkey->funcOid = fcinfo->flinfo->fn_oid;
02388
02389
02390 hashkey->isTrigger = CALLED_AS_TRIGGER(fcinfo);
02391
02392
02393
02394
02395
02396
02397 if (hashkey->isTrigger && !forValidator)
02398 {
02399 TriggerData *trigdata = (TriggerData *) fcinfo->context;
02400
02401 hashkey->trigrelOid = RelationGetRelid(trigdata->tg_relation);
02402 }
02403
02404
02405 hashkey->inputCollation = fcinfo->fncollation;
02406
02407 if (procStruct->pronargs > 0)
02408 {
02409
02410 memcpy(hashkey->argtypes, procStruct->proargtypes.values,
02411 procStruct->pronargs * sizeof(Oid));
02412
02413
02414 plpgsql_resolve_polymorphic_argtypes(procStruct->pronargs,
02415 hashkey->argtypes,
02416 NULL,
02417 fcinfo->flinfo->fn_expr,
02418 forValidator,
02419 NameStr(procStruct->proname));
02420 }
02421 }
02422
02423
02424
02425
02426
02427
02428
02429 static void
02430 plpgsql_resolve_polymorphic_argtypes(int numargs,
02431 Oid *argtypes, char *argmodes,
02432 Node *call_expr, bool forValidator,
02433 const char *proname)
02434 {
02435 int i;
02436
02437 if (!forValidator)
02438 {
02439
02440 if (!resolve_polymorphic_argtypes(numargs, argtypes, argmodes,
02441 call_expr))
02442 ereport(ERROR,
02443 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02444 errmsg("could not determine actual argument "
02445 "type for polymorphic function \"%s\"",
02446 proname)));
02447 }
02448 else
02449 {
02450
02451 for (i = 0; i < numargs; i++)
02452 {
02453 switch (argtypes[i])
02454 {
02455 case ANYELEMENTOID:
02456 case ANYNONARRAYOID:
02457 case ANYENUMOID:
02458 argtypes[i] = INT4OID;
02459 break;
02460 case ANYARRAYOID:
02461 argtypes[i] = INT4ARRAYOID;
02462 break;
02463 case ANYRANGEOID:
02464 argtypes[i] = INT4RANGEOID;
02465 break;
02466 default:
02467 break;
02468 }
02469 }
02470 }
02471 }
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487 static void
02488 delete_function(PLpgSQL_function *func)
02489 {
02490
02491 plpgsql_HashTableDelete(func);
02492
02493
02494 if (func->use_count == 0)
02495 plpgsql_free_function_memory(func);
02496 }
02497
02498
02499 void
02500 plpgsql_HashTableInit(void)
02501 {
02502 HASHCTL ctl;
02503
02504
02505 Assert(plpgsql_HashTable == NULL);
02506
02507 memset(&ctl, 0, sizeof(ctl));
02508 ctl.keysize = sizeof(PLpgSQL_func_hashkey);
02509 ctl.entrysize = sizeof(plpgsql_HashEnt);
02510 ctl.hash = tag_hash;
02511 plpgsql_HashTable = hash_create("PLpgSQL function cache",
02512 FUNCS_PER_USER,
02513 &ctl,
02514 HASH_ELEM | HASH_FUNCTION);
02515 }
02516
02517 static PLpgSQL_function *
02518 plpgsql_HashTableLookup(PLpgSQL_func_hashkey *func_key)
02519 {
02520 plpgsql_HashEnt *hentry;
02521
02522 hentry = (plpgsql_HashEnt *) hash_search(plpgsql_HashTable,
02523 (void *) func_key,
02524 HASH_FIND,
02525 NULL);
02526 if (hentry)
02527 return hentry->function;
02528 else
02529 return NULL;
02530 }
02531
02532 static void
02533 plpgsql_HashTableInsert(PLpgSQL_function *function,
02534 PLpgSQL_func_hashkey *func_key)
02535 {
02536 plpgsql_HashEnt *hentry;
02537 bool found;
02538
02539 hentry = (plpgsql_HashEnt *) hash_search(plpgsql_HashTable,
02540 (void *) func_key,
02541 HASH_ENTER,
02542 &found);
02543 if (found)
02544 elog(WARNING, "trying to insert a function that already exists");
02545
02546 hentry->function = function;
02547
02548 function->fn_hashkey = &hentry->key;
02549 }
02550
02551 static void
02552 plpgsql_HashTableDelete(PLpgSQL_function *function)
02553 {
02554 plpgsql_HashEnt *hentry;
02555
02556
02557 if (function->fn_hashkey == NULL)
02558 return;
02559
02560 hentry = (plpgsql_HashEnt *) hash_search(plpgsql_HashTable,
02561 (void *) function->fn_hashkey,
02562 HASH_REMOVE,
02563 NULL);
02564 if (hentry == NULL)
02565 elog(WARNING, "trying to delete function that does not exist");
02566
02567
02568 function->fn_hashkey = NULL;
02569 }