pg_query 1.3.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -52
  3. data/README.md +72 -65
  4. data/Rakefile +82 -1
  5. data/ext/pg_query/extconf.rb +2 -39
  6. data/ext/pg_query/guc-file.c +0 -0
  7. data/ext/pg_query/pg_query.c +104 -0
  8. data/ext/pg_query/pg_query.pb-c.c +37628 -0
  9. data/ext/pg_query/pg_query_deparse.c +9953 -0
  10. data/ext/pg_query/pg_query_fingerprint.c +292 -0
  11. data/ext/pg_query/pg_query_fingerprint.h +8 -0
  12. data/ext/pg_query/pg_query_internal.h +24 -0
  13. data/ext/pg_query/pg_query_json_plpgsql.c +738 -0
  14. data/ext/pg_query/pg_query_json_plpgsql.h +9 -0
  15. data/ext/pg_query/pg_query_normalize.c +437 -0
  16. data/ext/pg_query/pg_query_outfuncs.h +10 -0
  17. data/ext/pg_query/pg_query_outfuncs_json.c +297 -0
  18. data/ext/pg_query/pg_query_outfuncs_protobuf.c +237 -0
  19. data/ext/pg_query/pg_query_parse.c +148 -0
  20. data/ext/pg_query/pg_query_parse_plpgsql.c +460 -0
  21. data/ext/pg_query/pg_query_readfuncs.h +11 -0
  22. data/ext/pg_query/pg_query_readfuncs_protobuf.c +142 -0
  23. data/ext/pg_query/pg_query_ruby.c +108 -12
  24. data/ext/pg_query/pg_query_scan.c +173 -0
  25. data/ext/pg_query/pg_query_split.c +221 -0
  26. data/ext/pg_query/protobuf-c.c +3660 -0
  27. data/ext/pg_query/src_backend_catalog_namespace.c +1051 -0
  28. data/ext/pg_query/src_backend_catalog_pg_proc.c +142 -0
  29. data/ext/pg_query/src_backend_commands_define.c +117 -0
  30. data/ext/pg_query/src_backend_libpq_pqcomm.c +651 -0
  31. data/ext/pg_query/src_backend_nodes_bitmapset.c +513 -0
  32. data/ext/pg_query/src_backend_nodes_copyfuncs.c +6013 -0
  33. data/ext/pg_query/src_backend_nodes_equalfuncs.c +4003 -0
  34. data/ext/pg_query/src_backend_nodes_extensible.c +99 -0
  35. data/ext/pg_query/src_backend_nodes_list.c +922 -0
  36. data/ext/pg_query/src_backend_nodes_makefuncs.c +417 -0
  37. data/ext/pg_query/src_backend_nodes_nodeFuncs.c +1363 -0
  38. data/ext/pg_query/src_backend_nodes_value.c +84 -0
  39. data/ext/pg_query/src_backend_parser_gram.c +47456 -0
  40. data/ext/pg_query/src_backend_parser_parse_expr.c +313 -0
  41. data/ext/pg_query/src_backend_parser_parser.c +497 -0
  42. data/ext/pg_query/src_backend_parser_scan.c +7091 -0
  43. data/ext/pg_query/src_backend_parser_scansup.c +160 -0
  44. data/ext/pg_query/src_backend_postmaster_postmaster.c +2230 -0
  45. data/ext/pg_query/src_backend_storage_ipc_ipc.c +192 -0
  46. data/ext/pg_query/src_backend_storage_lmgr_s_lock.c +370 -0
  47. data/ext/pg_query/src_backend_tcop_postgres.c +776 -0
  48. data/ext/pg_query/src_backend_utils_adt_datum.c +326 -0
  49. data/ext/pg_query/src_backend_utils_adt_expandeddatum.c +98 -0
  50. data/ext/pg_query/src_backend_utils_adt_format_type.c +136 -0
  51. data/ext/pg_query/src_backend_utils_adt_ruleutils.c +1683 -0
  52. data/ext/pg_query/src_backend_utils_error_assert.c +74 -0
  53. data/ext/pg_query/src_backend_utils_error_elog.c +1748 -0
  54. data/ext/pg_query/src_backend_utils_fmgr_fmgr.c +570 -0
  55. data/ext/pg_query/src_backend_utils_hash_dynahash.c +1086 -0
  56. data/ext/pg_query/src_backend_utils_init_globals.c +168 -0
  57. data/ext/pg_query/src_backend_utils_mb_mbutils.c +839 -0
  58. data/ext/pg_query/src_backend_utils_misc_guc.c +1831 -0
  59. data/ext/pg_query/src_backend_utils_mmgr_aset.c +1560 -0
  60. data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +1006 -0
  61. data/ext/pg_query/src_common_encnames.c +158 -0
  62. data/ext/pg_query/src_common_keywords.c +39 -0
  63. data/ext/pg_query/src_common_kwlist_d.h +1081 -0
  64. data/ext/pg_query/src_common_kwlookup.c +91 -0
  65. data/ext/pg_query/src_common_psprintf.c +158 -0
  66. data/ext/pg_query/src_common_string.c +86 -0
  67. data/ext/pg_query/src_common_stringinfo.c +336 -0
  68. data/ext/pg_query/src_common_wchar.c +1651 -0
  69. data/ext/pg_query/src_pl_plpgsql_src_pl_comp.c +1133 -0
  70. data/ext/pg_query/src_pl_plpgsql_src_pl_funcs.c +877 -0
  71. data/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +6533 -0
  72. data/ext/pg_query/src_pl_plpgsql_src_pl_handler.c +107 -0
  73. data/ext/pg_query/src_pl_plpgsql_src_pl_reserved_kwlist_d.h +123 -0
  74. data/ext/pg_query/src_pl_plpgsql_src_pl_scanner.c +671 -0
  75. data/ext/pg_query/src_pl_plpgsql_src_pl_unreserved_kwlist_d.h +255 -0
  76. data/ext/pg_query/src_port_erand48.c +127 -0
  77. data/ext/pg_query/src_port_pg_bitutils.c +246 -0
  78. data/ext/pg_query/src_port_pgsleep.c +69 -0
  79. data/ext/pg_query/src_port_pgstrcasecmp.c +83 -0
  80. data/ext/pg_query/src_port_qsort.c +240 -0
  81. data/ext/pg_query/src_port_random.c +31 -0
  82. data/ext/pg_query/src_port_snprintf.c +1449 -0
  83. data/ext/pg_query/src_port_strerror.c +324 -0
  84. data/ext/pg_query/src_port_strnlen.c +39 -0
  85. data/ext/pg_query/xxhash.c +43 -0
  86. data/lib/pg_query.rb +7 -4
  87. data/lib/pg_query/constants.rb +21 -0
  88. data/lib/pg_query/deparse.rb +15 -1673
  89. data/lib/pg_query/filter_columns.rb +86 -85
  90. data/lib/pg_query/fingerprint.rb +122 -87
  91. data/lib/pg_query/json_field_names.rb +1402 -0
  92. data/lib/pg_query/node.rb +31 -0
  93. data/lib/pg_query/param_refs.rb +42 -37
  94. data/lib/pg_query/parse.rb +220 -203
  95. data/lib/pg_query/parse_error.rb +1 -1
  96. data/lib/pg_query/pg_query_pb.rb +3211 -0
  97. data/lib/pg_query/scan.rb +23 -0
  98. data/lib/pg_query/treewalker.rb +24 -40
  99. data/lib/pg_query/truncate.rb +64 -43
  100. data/lib/pg_query/version.rb +2 -2
  101. metadata +101 -11
  102. data/ext/pg_query/pg_query_ruby.h +0 -10
  103. data/lib/pg_query/deep_dup.rb +0 -16
  104. data/lib/pg_query/deparse/alter_table.rb +0 -42
  105. data/lib/pg_query/deparse/interval.rb +0 -105
  106. data/lib/pg_query/deparse/keywords.rb +0 -159
  107. data/lib/pg_query/deparse/rename.rb +0 -41
  108. data/lib/pg_query/legacy_parsetree.rb +0 -109
  109. data/lib/pg_query/node_types.rb +0 -297
@@ -0,0 +1,1133 @@
1
+ /*--------------------------------------------------------------------
2
+ * Symbols referenced in this file:
3
+ * - plpgsql_compile_inline
4
+ * - plpgsql_error_funcname
5
+ * - plpgsql_check_syntax
6
+ * - plpgsql_curr_compile
7
+ * - plpgsql_compile_tmp_cxt
8
+ * - plpgsql_DumpExecTree
9
+ * - plpgsql_start_datums
10
+ * - plpgsql_nDatums
11
+ * - plpgsql_Datums
12
+ * - datums_alloc
13
+ * - datums_last
14
+ * - plpgsql_build_variable
15
+ * - plpgsql_adddatum
16
+ * - plpgsql_build_record
17
+ * - plpgsql_build_datatype
18
+ * - plpgsql_parse_tripword
19
+ * - plpgsql_build_recfield
20
+ * - plpgsql_parse_dblword
21
+ * - plpgsql_parse_word
22
+ * - plpgsql_add_initdatums
23
+ * - plpgsql_recognize_err_condition
24
+ * - exception_label_map
25
+ * - plpgsql_parse_err_condition
26
+ * - plpgsql_parse_wordtype
27
+ * - plpgsql_parse_wordrowtype
28
+ * - plpgsql_parse_cwordtype
29
+ * - plpgsql_parse_cwordrowtype
30
+ * - plpgsql_parse_result
31
+ * - plpgsql_finish_datums
32
+ * - plpgsql_compile_error_callback
33
+ * - add_dummy_return
34
+ *--------------------------------------------------------------------
35
+ */
36
+
37
+ /*-------------------------------------------------------------------------
38
+ *
39
+ * pl_comp.c - Compiler part of the PL/pgSQL
40
+ * procedural language
41
+ *
42
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
43
+ * Portions Copyright (c) 1994, Regents of the University of California
44
+ *
45
+ *
46
+ * IDENTIFICATION
47
+ * src/pl/plpgsql/src/pl_comp.c
48
+ *
49
+ *-------------------------------------------------------------------------
50
+ */
51
+
52
+ #include "postgres.h"
53
+
54
+ #include <ctype.h>
55
+
56
+ #include "access/htup_details.h"
57
+ #include "catalog/namespace.h"
58
+ #include "catalog/pg_proc.h"
59
+ #include "catalog/pg_type.h"
60
+ #include "funcapi.h"
61
+ #include "nodes/makefuncs.h"
62
+ #include "parser/parse_type.h"
63
+ #include "plpgsql.h"
64
+ #include "utils/builtins.h"
65
+ #include "utils/guc.h"
66
+ #include "utils/lsyscache.h"
67
+ #include "utils/memutils.h"
68
+ #include "utils/regproc.h"
69
+ #include "utils/rel.h"
70
+ #include "utils/syscache.h"
71
+ #include "utils/typcache.h"
72
+
73
+ /* ----------
74
+ * Our own local and global variables
75
+ * ----------
76
+ */
77
+ __thread PLpgSQL_stmt_block *plpgsql_parse_result;
78
+
79
+
80
+ static __thread int datums_alloc;
81
+
82
+ __thread int plpgsql_nDatums;
83
+
84
+ __thread PLpgSQL_datum **plpgsql_Datums;
85
+
86
+ static __thread int datums_last;
87
+
88
+
89
+ __thread char *plpgsql_error_funcname;
90
+
91
+ __thread bool plpgsql_DumpExecTree = false;
92
+
93
+ __thread bool plpgsql_check_syntax = false;
94
+
95
+
96
+ __thread PLpgSQL_function *plpgsql_curr_compile;
97
+
98
+
99
+ /* A context appropriate for short-term allocs during compilation */
100
+ __thread MemoryContext plpgsql_compile_tmp_cxt;
101
+
102
+
103
+ /* ----------
104
+ * Hash table for compiled functions
105
+ * ----------
106
+ */
107
+
108
+
109
+ typedef struct plpgsql_hashent
110
+ {
111
+ PLpgSQL_func_hashkey key;
112
+ PLpgSQL_function *function;
113
+ } plpgsql_HashEnt;
114
+
115
+ #define FUNCS_PER_USER 128 /* initial table size */
116
+
117
+ /* ----------
118
+ * Lookup table for EXCEPTION condition names
119
+ * ----------
120
+ */
121
+ typedef struct
122
+ {
123
+ const char *label;
124
+ int sqlerrstate;
125
+ } ExceptionLabelMap;
126
+
127
+ static const ExceptionLabelMap exception_label_map[] = {
128
+ #include "plerrcodes.h" /* pgrminclude ignore */
129
+ {NULL, 0}
130
+ };
131
+
132
+
133
+ /* ----------
134
+ * static prototypes
135
+ * ----------
136
+ */
137
+ static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo,
138
+ HeapTuple procTup,
139
+ PLpgSQL_function *function,
140
+ PLpgSQL_func_hashkey *hashkey,
141
+ bool forValidator);
142
+ static void plpgsql_compile_error_callback(void *arg);
143
+ static void add_parameter_name(PLpgSQL_nsitem_type itemtype, int itemno, const char *name);
144
+ static void add_dummy_return(PLpgSQL_function *function);
145
+ static Node *plpgsql_pre_column_ref(ParseState *pstate, ColumnRef *cref);
146
+ static Node *plpgsql_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var);
147
+ static Node *plpgsql_param_ref(ParseState *pstate, ParamRef *pref);
148
+ static Node *resolve_column_ref(ParseState *pstate, PLpgSQL_expr *expr,
149
+ ColumnRef *cref, bool error_if_no_field);
150
+ static Node *make_datum_param(PLpgSQL_expr *expr, int dno, int location);
151
+ static PLpgSQL_row *build_row_from_vars(PLpgSQL_variable **vars, int numvars);
152
+ static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod,
153
+ Oid collation, TypeName *origtypname);
154
+ static void compute_function_hashkey(FunctionCallInfo fcinfo,
155
+ Form_pg_proc procStruct,
156
+ PLpgSQL_func_hashkey *hashkey,
157
+ bool forValidator);
158
+ static void plpgsql_resolve_polymorphic_argtypes(int numargs,
159
+ Oid *argtypes, char *argmodes,
160
+ Node *call_expr, bool forValidator,
161
+ const char *proname);
162
+ static PLpgSQL_function *plpgsql_HashTableLookup(PLpgSQL_func_hashkey *func_key);
163
+ static void plpgsql_HashTableInsert(PLpgSQL_function *function,
164
+ PLpgSQL_func_hashkey *func_key);
165
+ static void plpgsql_HashTableDelete(PLpgSQL_function *function);
166
+ static void delete_function(PLpgSQL_function *func);
167
+
168
+ /* ----------
169
+ * plpgsql_compile Make an execution tree for a PL/pgSQL function.
170
+ *
171
+ * If forValidator is true, we're only compiling for validation purposes,
172
+ * and so some checks are skipped.
173
+ *
174
+ * Note: it's important for this to fall through quickly if the function
175
+ * has already been compiled.
176
+ * ----------
177
+ */
178
+
179
+
180
+ /*
181
+ * This is the slow part of plpgsql_compile().
182
+ *
183
+ * The passed-in "function" pointer is either NULL or an already-allocated
184
+ * function struct to overwrite.
185
+ *
186
+ * While compiling a function, the CurrentMemoryContext is the
187
+ * per-function memory context of the function we are compiling. That
188
+ * means a palloc() will allocate storage with the same lifetime as
189
+ * the function itself.
190
+ *
191
+ * Because palloc()'d storage will not be immediately freed, temporary
192
+ * allocations should either be performed in a short-lived memory
193
+ * context or explicitly pfree'd. Since not all backend functions are
194
+ * careful about pfree'ing their allocations, it is also wise to
195
+ * switch into a short-term context before calling into the
196
+ * backend. An appropriate context for performing short-term
197
+ * allocations is the plpgsql_compile_tmp_cxt.
198
+ *
199
+ * NB: this code is not re-entrant. We assume that nothing we do here could
200
+ * result in the invocation of another plpgsql function.
201
+ */
202
+
203
+
204
+ /* ----------
205
+ * plpgsql_compile_inline Make an execution tree for an anonymous code block.
206
+ *
207
+ * Note: this is generally parallel to do_compile(); is it worth trying to
208
+ * merge the two?
209
+ *
210
+ * Note: we assume the block will be thrown away so there is no need to build
211
+ * persistent data structures.
212
+ * ----------
213
+ */
214
+ PLpgSQL_function *
215
+ plpgsql_compile_inline(char *proc_source)
216
+ {
217
+ char *func_name = "inline_code_block";
218
+ PLpgSQL_function *function;
219
+ ErrorContextCallback plerrcontext;
220
+ PLpgSQL_variable *var;
221
+ int parse_rc;
222
+ MemoryContext func_cxt;
223
+
224
+ /*
225
+ * Setup the scanner input and error info. We assume that this function
226
+ * cannot be invoked recursively, so there's no need to save and restore
227
+ * the static variables used here.
228
+ */
229
+ plpgsql_scanner_init(proc_source);
230
+
231
+ plpgsql_error_funcname = func_name;
232
+
233
+ /*
234
+ * Setup error traceback support for ereport()
235
+ */
236
+ plerrcontext.callback = plpgsql_compile_error_callback;
237
+ plerrcontext.arg = proc_source;
238
+ plerrcontext.previous = error_context_stack;
239
+ error_context_stack = &plerrcontext;
240
+
241
+ /* Do extra syntax checking if check_function_bodies is on */
242
+ plpgsql_check_syntax = check_function_bodies;
243
+
244
+ /* Function struct does not live past current statement */
245
+ function = (PLpgSQL_function *) palloc0(sizeof(PLpgSQL_function));
246
+
247
+ plpgsql_curr_compile = function;
248
+
249
+ /*
250
+ * All the rest of the compile-time storage (e.g. parse tree) is kept in
251
+ * its own memory context, so it can be reclaimed easily.
252
+ */
253
+ func_cxt = AllocSetContextCreate(CurrentMemoryContext,
254
+ "PL/pgSQL inline code context",
255
+ ALLOCSET_DEFAULT_SIZES);
256
+ plpgsql_compile_tmp_cxt = MemoryContextSwitchTo(func_cxt);
257
+
258
+ function->fn_signature = pstrdup(func_name);
259
+ function->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
260
+ function->fn_input_collation = InvalidOid;
261
+ function->fn_cxt = func_cxt;
262
+ function->out_param_varno = -1; /* set up for no OUT param */
263
+ function->resolve_option = plpgsql_variable_conflict;
264
+ function->print_strict_params = plpgsql_print_strict_params;
265
+
266
+ /*
267
+ * don't do extra validation for inline code as we don't want to add spam
268
+ * at runtime
269
+ */
270
+ function->extra_warnings = 0;
271
+ function->extra_errors = 0;
272
+
273
+ function->nstatements = 0;
274
+
275
+ plpgsql_ns_init();
276
+ plpgsql_ns_push(func_name, PLPGSQL_LABEL_BLOCK);
277
+ plpgsql_DumpExecTree = false;
278
+ plpgsql_start_datums();
279
+
280
+ /* Set up as though in a function returning VOID */
281
+ function->fn_rettype = VOIDOID;
282
+ function->fn_retset = false;
283
+ function->fn_retistuple = false;
284
+ function->fn_retisdomain = false;
285
+ function->fn_prokind = PROKIND_FUNCTION;
286
+ /* a bit of hardwired knowledge about type VOID here */
287
+ function->fn_retbyval = true;
288
+ function->fn_rettyplen = sizeof(int32);
289
+
290
+ /*
291
+ * Remember if function is STABLE/IMMUTABLE. XXX would it be better to
292
+ * set this true inside a read-only transaction? Not clear.
293
+ */
294
+ function->fn_readonly = false;
295
+
296
+ /*
297
+ * Create the magic FOUND variable.
298
+ */
299
+ var = plpgsql_build_variable("found", 0,
300
+ plpgsql_build_datatype(BOOLOID,
301
+ -1,
302
+ InvalidOid,
303
+ NULL),
304
+ true);
305
+ function->found_varno = var->dno;
306
+
307
+ /*
308
+ * Now parse the function's text
309
+ */
310
+ parse_rc = plpgsql_yyparse();
311
+ if (parse_rc != 0)
312
+ elog(ERROR, "plpgsql parser returned %d", parse_rc);
313
+ function->action = plpgsql_parse_result;
314
+
315
+ plpgsql_scanner_finish();
316
+
317
+ /*
318
+ * If it returns VOID (always true at the moment), we allow control to
319
+ * fall off the end without an explicit RETURN statement.
320
+ */
321
+ if (function->fn_rettype == VOIDOID)
322
+ add_dummy_return(function);
323
+
324
+ /*
325
+ * Complete the function's info
326
+ */
327
+ function->fn_nargs = 0;
328
+
329
+ plpgsql_finish_datums(function);
330
+
331
+ /*
332
+ * Pop the error context stack
333
+ */
334
+ error_context_stack = plerrcontext.previous;
335
+ plpgsql_error_funcname = NULL;
336
+
337
+ plpgsql_check_syntax = false;
338
+
339
+ MemoryContextSwitchTo(plpgsql_compile_tmp_cxt);
340
+ plpgsql_compile_tmp_cxt = NULL;
341
+ return function;
342
+ }
343
+
344
+
345
+ /*
346
+ * error context callback to let us supply a call-stack traceback.
347
+ * If we are validating or executing an anonymous code block, the function
348
+ * source text is passed as an argument.
349
+ */
350
+ static void
351
+ plpgsql_compile_error_callback(void *arg)
352
+ {
353
+ if (arg)
354
+ {
355
+ /*
356
+ * Try to convert syntax error position to reference text of original
357
+ * CREATE FUNCTION or DO command.
358
+ */
359
+ if (function_parse_error_transpose((const char *) arg))
360
+ return;
361
+
362
+ /*
363
+ * Done if a syntax error position was reported; otherwise we have to
364
+ * fall back to a "near line N" report.
365
+ */
366
+ }
367
+
368
+ if (plpgsql_error_funcname)
369
+ errcontext("compilation of PL/pgSQL function \"%s\" near line %d",
370
+ plpgsql_error_funcname, plpgsql_latest_lineno());
371
+ }
372
+
373
+
374
+ /*
375
+ * Add a name for a function parameter to the function's namespace
376
+ */
377
+
378
+
379
+ /*
380
+ * Add a dummy RETURN statement to the given function's body
381
+ */
382
+ static void
383
+ add_dummy_return(PLpgSQL_function *function)
384
+ {
385
+ /*
386
+ * If the outer block has an EXCEPTION clause, we need to make a new outer
387
+ * block, since the added RETURN shouldn't act like it is inside the
388
+ * EXCEPTION clause.
389
+ */
390
+ if (function->action->exceptions != NULL)
391
+ {
392
+ PLpgSQL_stmt_block *new;
393
+
394
+ new = palloc0(sizeof(PLpgSQL_stmt_block));
395
+ new->cmd_type = PLPGSQL_STMT_BLOCK;
396
+ new->stmtid = ++function->nstatements;
397
+ new->body = list_make1(function->action);
398
+
399
+ function->action = new;
400
+ }
401
+ if (function->action->body == NIL ||
402
+ ((PLpgSQL_stmt *) llast(function->action->body))->cmd_type != PLPGSQL_STMT_RETURN)
403
+ {
404
+ PLpgSQL_stmt_return *new;
405
+
406
+ new = palloc0(sizeof(PLpgSQL_stmt_return));
407
+ new->cmd_type = PLPGSQL_STMT_RETURN;
408
+ new->stmtid = ++function->nstatements;
409
+ new->expr = NULL;
410
+ new->retvarno = function->out_param_varno;
411
+
412
+ function->action->body = lappend(function->action->body, new);
413
+ }
414
+ }
415
+
416
+
417
+ /*
418
+ * plpgsql_parser_setup set up parser hooks for dynamic parameters
419
+ *
420
+ * Note: this routine, and the hook functions it prepares for, are logically
421
+ * part of plpgsql parsing. But they actually run during function execution,
422
+ * when we are ready to evaluate a SQL query or expression that has not
423
+ * previously been parsed and planned.
424
+ */
425
+
426
+
427
+ /*
428
+ * plpgsql_pre_column_ref parser callback before parsing a ColumnRef
429
+ */
430
+
431
+
432
+ /*
433
+ * plpgsql_post_column_ref parser callback after parsing a ColumnRef
434
+ */
435
+
436
+
437
+ /*
438
+ * plpgsql_param_ref parser callback for ParamRefs ($n symbols)
439
+ */
440
+
441
+
442
+ /*
443
+ * resolve_column_ref attempt to resolve a ColumnRef as a plpgsql var
444
+ *
445
+ * Returns the translated node structure, or NULL if name not found
446
+ *
447
+ * error_if_no_field tells whether to throw error or quietly return NULL if
448
+ * we are able to match a record/row name but don't find a field name match.
449
+ */
450
+
451
+
452
+ /*
453
+ * Helper for columnref parsing: build a Param referencing a plpgsql datum,
454
+ * and make sure that that datum is listed in the expression's paramnos.
455
+ */
456
+
457
+
458
+
459
+ /* ----------
460
+ * plpgsql_parse_word The scanner calls this to postparse
461
+ * any single word that is not a reserved keyword.
462
+ *
463
+ * word1 is the downcased/dequoted identifier; it must be palloc'd in the
464
+ * function's long-term memory context.
465
+ *
466
+ * yytxt is the original token text; we need this to check for quoting,
467
+ * so that later checks for unreserved keywords work properly.
468
+ *
469
+ * We attempt to recognize the token as a variable only if lookup is true
470
+ * and the plpgsql_IdentifierLookup context permits it.
471
+ *
472
+ * If recognized as a variable, fill in *wdatum and return true;
473
+ * if not recognized, fill in *word and return false.
474
+ * (Note: those two pointers actually point to members of the same union,
475
+ * but for notational reasons we pass them separately.)
476
+ * ----------
477
+ */
478
+ bool
479
+ plpgsql_parse_word(char *word1, const char *yytxt, bool lookup,
480
+ PLwdatum *wdatum, PLword *word)
481
+ {
482
+ PLpgSQL_nsitem *ns;
483
+
484
+ /*
485
+ * We should not lookup variables in DECLARE sections. In SQL
486
+ * expressions, there's no need to do so either --- lookup will happen
487
+ * when the expression is compiled.
488
+ */
489
+ if (lookup && plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_NORMAL)
490
+ {
491
+ /*
492
+ * Do a lookup in the current namespace stack
493
+ */
494
+ ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
495
+ word1, NULL, NULL,
496
+ NULL);
497
+
498
+ if (ns != NULL)
499
+ {
500
+ switch (ns->itemtype)
501
+ {
502
+ case PLPGSQL_NSTYPE_VAR:
503
+ case PLPGSQL_NSTYPE_REC:
504
+ wdatum->datum = plpgsql_Datums[ns->itemno];
505
+ wdatum->ident = word1;
506
+ wdatum->quoted = (yytxt[0] == '"');
507
+ wdatum->idents = NIL;
508
+ return true;
509
+
510
+ default:
511
+ /* plpgsql_ns_lookup should never return anything else */
512
+ elog(ERROR, "unrecognized plpgsql itemtype: %d",
513
+ ns->itemtype);
514
+ }
515
+ }
516
+ }
517
+
518
+ /*
519
+ * Nothing found - up to now it's a word without any special meaning for
520
+ * us.
521
+ */
522
+ word->ident = word1;
523
+ word->quoted = (yytxt[0] == '"');
524
+ return false;
525
+ }
526
+
527
+
528
+ /* ----------
529
+ * plpgsql_parse_dblword Same lookup for two words
530
+ * separated by a dot.
531
+ * ----------
532
+ */
533
+ bool
534
+ plpgsql_parse_dblword(char *word1, char *word2,
535
+ PLwdatum *wdatum, PLcword *cword)
536
+ {
537
+ PLpgSQL_nsitem *ns;
538
+ List *idents;
539
+ int nnames;
540
+
541
+ idents = list_make2(makeString(word1),
542
+ makeString(word2));
543
+
544
+ /*
545
+ * We should do nothing in DECLARE sections. In SQL expressions, we
546
+ * really only need to make sure that RECFIELD datums are created when
547
+ * needed.
548
+ */
549
+ if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE)
550
+ {
551
+ /*
552
+ * Do a lookup in the current namespace stack
553
+ */
554
+ ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
555
+ word1, word2, NULL,
556
+ &nnames);
557
+ if (ns != NULL)
558
+ {
559
+ switch (ns->itemtype)
560
+ {
561
+ case PLPGSQL_NSTYPE_VAR:
562
+ /* Block-qualified reference to scalar variable. */
563
+ wdatum->datum = plpgsql_Datums[ns->itemno];
564
+ wdatum->ident = NULL;
565
+ wdatum->quoted = false; /* not used */
566
+ wdatum->idents = idents;
567
+ return true;
568
+
569
+ case PLPGSQL_NSTYPE_REC:
570
+ if (nnames == 1)
571
+ {
572
+ /*
573
+ * First word is a record name, so second word could
574
+ * be a field in this record. We build a RECFIELD
575
+ * datum whether it is or not --- any error will be
576
+ * detected later.
577
+ */
578
+ PLpgSQL_rec *rec;
579
+ PLpgSQL_recfield *new;
580
+
581
+ rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);
582
+ new = plpgsql_build_recfield(rec, word2);
583
+
584
+ wdatum->datum = (PLpgSQL_datum *) new;
585
+ }
586
+ else
587
+ {
588
+ /* Block-qualified reference to record variable. */
589
+ wdatum->datum = plpgsql_Datums[ns->itemno];
590
+ }
591
+ wdatum->ident = NULL;
592
+ wdatum->quoted = false; /* not used */
593
+ wdatum->idents = idents;
594
+ return true;
595
+
596
+ default:
597
+ break;
598
+ }
599
+ }
600
+ }
601
+
602
+ /* Nothing found */
603
+ cword->idents = idents;
604
+ return false;
605
+ }
606
+
607
+
608
+ /* ----------
609
+ * plpgsql_parse_tripword Same lookup for three words
610
+ * separated by dots.
611
+ * ----------
612
+ */
613
+ bool
614
+ plpgsql_parse_tripword(char *word1, char *word2, char *word3,
615
+ PLwdatum *wdatum, PLcword *cword)
616
+ {
617
+ PLpgSQL_nsitem *ns;
618
+ List *idents;
619
+ int nnames;
620
+
621
+ idents = list_make3(makeString(word1),
622
+ makeString(word2),
623
+ makeString(word3));
624
+
625
+ /*
626
+ * We should do nothing in DECLARE sections. In SQL expressions, we
627
+ * really only need to make sure that RECFIELD datums are created when
628
+ * needed.
629
+ */
630
+ if (plpgsql_IdentifierLookup != IDENTIFIER_LOOKUP_DECLARE)
631
+ {
632
+ /*
633
+ * Do a lookup in the current namespace stack. Must find a qualified
634
+ * reference, else ignore.
635
+ */
636
+ ns = plpgsql_ns_lookup(plpgsql_ns_top(), false,
637
+ word1, word2, word3,
638
+ &nnames);
639
+ if (ns != NULL && nnames == 2)
640
+ {
641
+ switch (ns->itemtype)
642
+ {
643
+ case PLPGSQL_NSTYPE_REC:
644
+ {
645
+ /*
646
+ * words 1/2 are a record name, so third word could be
647
+ * a field in this record.
648
+ */
649
+ PLpgSQL_rec *rec;
650
+ PLpgSQL_recfield *new;
651
+
652
+ rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);
653
+ new = plpgsql_build_recfield(rec, word3);
654
+
655
+ wdatum->datum = (PLpgSQL_datum *) new;
656
+ wdatum->ident = NULL;
657
+ wdatum->quoted = false; /* not used */
658
+ wdatum->idents = idents;
659
+ return true;
660
+ }
661
+
662
+ default:
663
+ break;
664
+ }
665
+ }
666
+ }
667
+
668
+ /* Nothing found */
669
+ cword->idents = idents;
670
+ return false;
671
+ }
672
+
673
+
674
+ /* ----------
675
+ * plpgsql_parse_wordtype The scanner found word%TYPE. word can be
676
+ * a variable name or a basetype.
677
+ *
678
+ * Returns datatype struct, or NULL if no match found for word.
679
+ * ----------
680
+ */
681
+ PLpgSQL_type * plpgsql_parse_wordtype(char *ident) { return NULL; }
682
+
683
+
684
+
685
+ /* ----------
686
+ * plpgsql_parse_cwordtype Same lookup for compositeword%TYPE
687
+ * ----------
688
+ */
689
+ PLpgSQL_type * plpgsql_parse_cwordtype(List *idents) { return NULL; }
690
+
691
+
692
+ /* ----------
693
+ * plpgsql_parse_wordrowtype Scanner found word%ROWTYPE.
694
+ * So word must be a table name.
695
+ * ----------
696
+ */
697
+ PLpgSQL_type * plpgsql_parse_wordrowtype(char *ident) { return NULL; }
698
+
699
+
700
+ /* ----------
701
+ * plpgsql_parse_cwordrowtype Scanner found compositeword%ROWTYPE.
702
+ * So word must be a namespace qualified table name.
703
+ * ----------
704
+ */
705
+ PLpgSQL_type * plpgsql_parse_cwordrowtype(List *idents) { return NULL; }
706
+
707
+
708
+ /*
709
+ * plpgsql_build_variable - build a datum-array entry of a given
710
+ * datatype
711
+ *
712
+ * The returned struct may be a PLpgSQL_var or PLpgSQL_rec
713
+ * depending on the given datatype, and is allocated via
714
+ * palloc. The struct is automatically added to the current datum
715
+ * array, and optionally to the current namespace.
716
+ */
717
+ PLpgSQL_variable *
718
+ plpgsql_build_variable(const char *refname, int lineno, PLpgSQL_type *dtype,
719
+ bool add2namespace)
720
+ {
721
+ PLpgSQL_variable *result;
722
+
723
+ switch (dtype->ttype)
724
+ {
725
+ case PLPGSQL_TTYPE_SCALAR:
726
+ {
727
+ /* Ordinary scalar datatype */
728
+ PLpgSQL_var *var;
729
+
730
+ var = palloc0(sizeof(PLpgSQL_var));
731
+ var->dtype = PLPGSQL_DTYPE_VAR;
732
+ var->refname = pstrdup(refname);
733
+ var->lineno = lineno;
734
+ var->datatype = dtype;
735
+ /* other fields are left as 0, might be changed by caller */
736
+
737
+ /* preset to NULL */
738
+ var->value = 0;
739
+ var->isnull = true;
740
+ var->freeval = false;
741
+
742
+ plpgsql_adddatum((PLpgSQL_datum *) var);
743
+ if (add2namespace)
744
+ plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR,
745
+ var->dno,
746
+ refname);
747
+ result = (PLpgSQL_variable *) var;
748
+ break;
749
+ }
750
+ case PLPGSQL_TTYPE_REC:
751
+ {
752
+ /* Composite type -- build a record variable */
753
+ PLpgSQL_rec *rec;
754
+
755
+ rec = plpgsql_build_record(refname, lineno,
756
+ dtype, dtype->typoid,
757
+ add2namespace);
758
+ result = (PLpgSQL_variable *) rec;
759
+ break;
760
+ }
761
+ case PLPGSQL_TTYPE_PSEUDO:
762
+ ereport(ERROR,
763
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
764
+ errmsg("variable \"%s\" has pseudo-type %s",
765
+ refname, format_type_be(dtype->typoid))));
766
+ result = NULL; /* keep compiler quiet */
767
+ break;
768
+ default:
769
+ elog(ERROR, "unrecognized ttype: %d", dtype->ttype);
770
+ result = NULL; /* keep compiler quiet */
771
+ break;
772
+ }
773
+
774
+ return result;
775
+ }
776
+
777
+ /*
778
+ * Build empty named record variable, and optionally add it to namespace
779
+ */
780
+ PLpgSQL_rec *
781
+ plpgsql_build_record(const char *refname, int lineno,
782
+ PLpgSQL_type *dtype, Oid rectypeid,
783
+ bool add2namespace)
784
+ {
785
+ PLpgSQL_rec *rec;
786
+
787
+ rec = palloc0(sizeof(PLpgSQL_rec));
788
+ rec->dtype = PLPGSQL_DTYPE_REC;
789
+ rec->refname = pstrdup(refname);
790
+ rec->lineno = lineno;
791
+ /* other fields are left as 0, might be changed by caller */
792
+ rec->datatype = dtype;
793
+ rec->rectypeid = rectypeid;
794
+ rec->firstfield = -1;
795
+ rec->erh = NULL;
796
+ plpgsql_adddatum((PLpgSQL_datum *) rec);
797
+ if (add2namespace)
798
+ plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->dno, rec->refname);
799
+
800
+ return rec;
801
+ }
802
+
803
+ /*
804
+ * Build a row-variable data structure given the component variables.
805
+ * Include a rowtupdesc, since we will need to materialize the row result.
806
+ */
807
+
808
+
809
+ /*
810
+ * Build a RECFIELD datum for the named field of the specified record variable
811
+ *
812
+ * If there's already such a datum, just return it; we don't need duplicates.
813
+ */
814
+ PLpgSQL_recfield *
815
+ plpgsql_build_recfield(PLpgSQL_rec *rec, const char *fldname)
816
+ {
817
+ PLpgSQL_recfield *recfield;
818
+ int i;
819
+
820
+ /* search for an existing datum referencing this field */
821
+ i = rec->firstfield;
822
+ while (i >= 0)
823
+ {
824
+ PLpgSQL_recfield *fld = (PLpgSQL_recfield *) plpgsql_Datums[i];
825
+
826
+ Assert(fld->dtype == PLPGSQL_DTYPE_RECFIELD &&
827
+ fld->recparentno == rec->dno);
828
+ if (strcmp(fld->fieldname, fldname) == 0)
829
+ return fld;
830
+ i = fld->nextfield;
831
+ }
832
+
833
+ /* nope, so make a new one */
834
+ recfield = palloc0(sizeof(PLpgSQL_recfield));
835
+ recfield->dtype = PLPGSQL_DTYPE_RECFIELD;
836
+ recfield->fieldname = pstrdup(fldname);
837
+ recfield->recparentno = rec->dno;
838
+ recfield->rectupledescid = INVALID_TUPLEDESC_IDENTIFIER;
839
+
840
+ plpgsql_adddatum((PLpgSQL_datum *) recfield);
841
+
842
+ /* now we can link it into the parent's chain */
843
+ recfield->nextfield = rec->firstfield;
844
+ rec->firstfield = recfield->dno;
845
+
846
+ return recfield;
847
+ }
848
+
849
+ /*
850
+ * plpgsql_build_datatype
851
+ * Build PLpgSQL_type struct given type OID, typmod, collation,
852
+ * and type's parsed name.
853
+ *
854
+ * If collation is not InvalidOid then it overrides the type's default
855
+ * collation. But collation is ignored if the datatype is non-collatable.
856
+ *
857
+ * origtypname is the parsed form of what the user wrote as the type name.
858
+ * It can be NULL if the type could not be a composite type, or if it was
859
+ * identified by OID to begin with (e.g., it's a function argument type).
860
+ */
861
+ PLpgSQL_type * plpgsql_build_datatype(Oid typeOid, int32 typmod, Oid collation, TypeName *origtypname) { PLpgSQL_type *typ; typ = (PLpgSQL_type *) palloc0(sizeof(PLpgSQL_type)); typ->typname = pstrdup("UNKNOWN"); typ->ttype = PLPGSQL_TTYPE_SCALAR; return typ; }
862
+
863
+
864
+ /*
865
+ * Utility subroutine to make a PLpgSQL_type struct given a pg_type entry
866
+ * and additional details (see comments for plpgsql_build_datatype).
867
+ */
868
+
869
+
870
+ /*
871
+ * plpgsql_recognize_err_condition
872
+ * Check condition name and translate it to SQLSTATE.
873
+ *
874
+ * Note: there are some cases where the same condition name has multiple
875
+ * entries in the table. We arbitrarily return the first match.
876
+ */
877
+ int
878
+ plpgsql_recognize_err_condition(const char *condname, bool allow_sqlstate)
879
+ {
880
+ int i;
881
+
882
+ if (allow_sqlstate)
883
+ {
884
+ if (strlen(condname) == 5 &&
885
+ strspn(condname, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") == 5)
886
+ return MAKE_SQLSTATE(condname[0],
887
+ condname[1],
888
+ condname[2],
889
+ condname[3],
890
+ condname[4]);
891
+ }
892
+
893
+ for (i = 0; exception_label_map[i].label != NULL; i++)
894
+ {
895
+ if (strcmp(condname, exception_label_map[i].label) == 0)
896
+ return exception_label_map[i].sqlerrstate;
897
+ }
898
+
899
+ ereport(ERROR,
900
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
901
+ errmsg("unrecognized exception condition \"%s\"",
902
+ condname)));
903
+ return 0; /* keep compiler quiet */
904
+ }
905
+
906
+ /*
907
+ * plpgsql_parse_err_condition
908
+ * Generate PLpgSQL_condition entry(s) for an exception condition name
909
+ *
910
+ * This has to be able to return a list because there are some duplicate
911
+ * names in the table of error code names.
912
+ */
913
+ PLpgSQL_condition *
914
+ plpgsql_parse_err_condition(char *condname)
915
+ {
916
+ int i;
917
+ PLpgSQL_condition *new;
918
+ PLpgSQL_condition *prev;
919
+
920
+ /*
921
+ * XXX Eventually we will want to look for user-defined exception names
922
+ * here.
923
+ */
924
+
925
+ /*
926
+ * OTHERS is represented as code 0 (which would map to '00000', but we
927
+ * have no need to represent that as an exception condition).
928
+ */
929
+ if (strcmp(condname, "others") == 0)
930
+ {
931
+ new = palloc(sizeof(PLpgSQL_condition));
932
+ new->sqlerrstate = 0;
933
+ new->condname = condname;
934
+ new->next = NULL;
935
+ return new;
936
+ }
937
+
938
+ prev = NULL;
939
+ for (i = 0; exception_label_map[i].label != NULL; i++)
940
+ {
941
+ if (strcmp(condname, exception_label_map[i].label) == 0)
942
+ {
943
+ new = palloc(sizeof(PLpgSQL_condition));
944
+ new->sqlerrstate = exception_label_map[i].sqlerrstate;
945
+ new->condname = condname;
946
+ new->next = prev;
947
+ prev = new;
948
+ }
949
+ }
950
+
951
+ if (!prev)
952
+ ereport(ERROR,
953
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
954
+ errmsg("unrecognized exception condition \"%s\"",
955
+ condname)));
956
+
957
+ return prev;
958
+ }
959
+
960
+ /* ----------
961
+ * plpgsql_start_datums Initialize datum list at compile startup.
962
+ * ----------
963
+ */
964
+ void
965
+ plpgsql_start_datums(void)
966
+ {
967
+ datums_alloc = 128;
968
+ plpgsql_nDatums = 0;
969
+ /* This is short-lived, so needn't allocate in function's cxt */
970
+ plpgsql_Datums = MemoryContextAlloc(plpgsql_compile_tmp_cxt,
971
+ sizeof(PLpgSQL_datum *) * datums_alloc);
972
+ /* datums_last tracks what's been seen by plpgsql_add_initdatums() */
973
+ datums_last = 0;
974
+ }
975
+
976
+ /* ----------
977
+ * plpgsql_adddatum Add a variable, record or row
978
+ * to the compiler's datum list.
979
+ * ----------
980
+ */
981
+ void
982
+ plpgsql_adddatum(PLpgSQL_datum *newdatum)
983
+ {
984
+ if (plpgsql_nDatums == datums_alloc)
985
+ {
986
+ datums_alloc *= 2;
987
+ plpgsql_Datums = repalloc(plpgsql_Datums, sizeof(PLpgSQL_datum *) * datums_alloc);
988
+ }
989
+
990
+ newdatum->dno = plpgsql_nDatums;
991
+ plpgsql_Datums[plpgsql_nDatums++] = newdatum;
992
+ }
993
+
994
+ /* ----------
995
+ * plpgsql_finish_datums Copy completed datum info into function struct.
996
+ * ----------
997
+ */
998
+ void
999
+ plpgsql_finish_datums(PLpgSQL_function *function)
1000
+ {
1001
+ Size copiable_size = 0;
1002
+ int i;
1003
+
1004
+ function->ndatums = plpgsql_nDatums;
1005
+ function->datums = palloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
1006
+ for (i = 0; i < plpgsql_nDatums; i++)
1007
+ {
1008
+ function->datums[i] = plpgsql_Datums[i];
1009
+
1010
+ /* This must agree with copy_plpgsql_datums on what is copiable */
1011
+ switch (function->datums[i]->dtype)
1012
+ {
1013
+ case PLPGSQL_DTYPE_VAR:
1014
+ case PLPGSQL_DTYPE_PROMISE:
1015
+ copiable_size += MAXALIGN(sizeof(PLpgSQL_var));
1016
+ break;
1017
+ case PLPGSQL_DTYPE_REC:
1018
+ copiable_size += MAXALIGN(sizeof(PLpgSQL_rec));
1019
+ break;
1020
+ default:
1021
+ break;
1022
+ }
1023
+ }
1024
+ function->copiable_size = copiable_size;
1025
+ }
1026
+
1027
+
1028
+ /* ----------
1029
+ * plpgsql_add_initdatums Make an array of the datum numbers of
1030
+ * all the initializable datums created since the last call
1031
+ * to this function.
1032
+ *
1033
+ * If varnos is NULL, we just forget any datum entries created since the
1034
+ * last call.
1035
+ *
1036
+ * This is used around a DECLARE section to create a list of the datums
1037
+ * that have to be initialized at block entry. Note that datums can also
1038
+ * be created elsewhere than DECLARE, eg by a FOR-loop, but it is then
1039
+ * the responsibility of special-purpose code to initialize them.
1040
+ * ----------
1041
+ */
1042
+ int
1043
+ plpgsql_add_initdatums(int **varnos)
1044
+ {
1045
+ int i;
1046
+ int n = 0;
1047
+
1048
+ /*
1049
+ * The set of dtypes recognized here must match what exec_stmt_block()
1050
+ * cares about (re)initializing at block entry.
1051
+ */
1052
+ for (i = datums_last; i < plpgsql_nDatums; i++)
1053
+ {
1054
+ switch (plpgsql_Datums[i]->dtype)
1055
+ {
1056
+ case PLPGSQL_DTYPE_VAR:
1057
+ case PLPGSQL_DTYPE_REC:
1058
+ n++;
1059
+ break;
1060
+
1061
+ default:
1062
+ break;
1063
+ }
1064
+ }
1065
+
1066
+ if (varnos != NULL)
1067
+ {
1068
+ if (n > 0)
1069
+ {
1070
+ *varnos = (int *) palloc(sizeof(int) * n);
1071
+
1072
+ n = 0;
1073
+ for (i = datums_last; i < plpgsql_nDatums; i++)
1074
+ {
1075
+ switch (plpgsql_Datums[i]->dtype)
1076
+ {
1077
+ case PLPGSQL_DTYPE_VAR:
1078
+ case PLPGSQL_DTYPE_REC:
1079
+ (*varnos)[n++] = plpgsql_Datums[i]->dno;
1080
+
1081
+ default:
1082
+ break;
1083
+ }
1084
+ }
1085
+ }
1086
+ else
1087
+ *varnos = NULL;
1088
+ }
1089
+
1090
+ datums_last = plpgsql_nDatums;
1091
+ return n;
1092
+ }
1093
+
1094
+
1095
+ /*
1096
+ * Compute the hashkey for a given function invocation
1097
+ *
1098
+ * The hashkey is returned into the caller-provided storage at *hashkey.
1099
+ */
1100
+
1101
+
1102
+ /*
1103
+ * This is the same as the standard resolve_polymorphic_argtypes() function,
1104
+ * but with a special case for validation: assume that polymorphic arguments
1105
+ * are integer, integer-array or integer-range. Also, we go ahead and report
1106
+ * the error if we can't resolve the types.
1107
+ */
1108
+
1109
+
1110
+ /*
1111
+ * delete_function - clean up as much as possible of a stale function cache
1112
+ *
1113
+ * We can't release the PLpgSQL_function struct itself, because of the
1114
+ * possibility that there are fn_extra pointers to it. We can release
1115
+ * the subsidiary storage, but only if there are no active evaluations
1116
+ * in progress. Otherwise we'll just leak that storage. Since the
1117
+ * case would only occur if a pg_proc update is detected during a nested
1118
+ * recursive call on the function, a leak seems acceptable.
1119
+ *
1120
+ * Note that this can be called more than once if there are multiple fn_extra
1121
+ * pointers to the same function cache. Hence be careful not to do things
1122
+ * twice.
1123
+ */
1124
+
1125
+
1126
+ /* exported so we can call it from _PG_init() */
1127
+
1128
+
1129
+
1130
+
1131
+
1132
+
1133
+