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,292 @@
1
+ #include "pg_query.h"
2
+ #include "pg_query_internal.h"
3
+ #include "pg_query_fingerprint.h"
4
+
5
+ #include "postgres.h"
6
+ #include "xxhash/xxhash.h"
7
+ #include "lib/ilist.h"
8
+
9
+ #include "parser/parser.h"
10
+ #include "parser/scanner.h"
11
+ #include "parser/scansup.h"
12
+
13
+ #include "nodes/parsenodes.h"
14
+ #include "nodes/value.h"
15
+
16
+ #include <stdio.h>
17
+ #include <unistd.h>
18
+ #include <fcntl.h>
19
+
20
+ // Definitions
21
+
22
+ typedef struct FingerprintContext
23
+ {
24
+ XXH3_state_t *xxh_state;
25
+
26
+ bool write_tokens;
27
+ dlist_head tokens;
28
+ } FingerprintContext;
29
+
30
+ typedef struct FingerprintListContext
31
+ {
32
+ XXH64_hash_t hash;
33
+ size_t list_pos;
34
+ } FingerprintListContext;
35
+
36
+ typedef struct FingerprintToken
37
+ {
38
+ char *str;
39
+ dlist_node list_node;
40
+ } FingerprintToken;
41
+
42
+ static void _fingerprintNode(FingerprintContext *ctx, const void *obj, const void *parent, char *parent_field_name, unsigned int depth);
43
+ static void _fingerprintInitContext(FingerprintContext *ctx, bool write_tokens);
44
+ static void _fingerprintFreeContext(FingerprintContext *ctx);
45
+
46
+ #define PG_QUERY_FINGERPRINT_VERSION 3
47
+
48
+ // Implementations
49
+
50
+ static void
51
+ _fingerprintString(FingerprintContext *ctx, const char *str)
52
+ {
53
+ if (ctx->xxh_state != NULL) {
54
+ XXH3_64bits_update(ctx->xxh_state, str, strlen(str));
55
+ }
56
+
57
+ if (ctx->write_tokens) {
58
+ FingerprintToken *token = palloc0(sizeof(FingerprintToken));
59
+ token->str = pstrdup(str);
60
+ dlist_push_tail(&ctx->tokens, &token->list_node);
61
+ }
62
+ }
63
+
64
+ static void
65
+ _fingerprintInteger(FingerprintContext *ctx, const Value *node)
66
+ {
67
+ if (node->val.ival != 0) {
68
+ _fingerprintString(ctx, "Integer");
69
+ _fingerprintString(ctx, "ival");
70
+ char buffer[50];
71
+ sprintf(buffer, "%d", node->val.ival);
72
+ _fingerprintString(ctx, buffer);
73
+ }
74
+ }
75
+
76
+ static void
77
+ _fingerprintFloat(FingerprintContext *ctx, const Value *node)
78
+ {
79
+ if (node->val.str != NULL) {
80
+ _fingerprintString(ctx, "Float");
81
+ _fingerprintString(ctx, "str");
82
+ _fingerprintString(ctx, node->val.str);
83
+ }
84
+ }
85
+
86
+ static void
87
+ _fingerprintBitString(FingerprintContext *ctx, const Value *node)
88
+ {
89
+ if (node->val.str != NULL) {
90
+ _fingerprintString(ctx, "BitString");
91
+ _fingerprintString(ctx, "str");
92
+ _fingerprintString(ctx, node->val.str);
93
+ }
94
+ }
95
+
96
+ static int compareFingerprintListContext(const void *a, const void *b)
97
+ {
98
+ FingerprintListContext *ca = *(FingerprintListContext**) a;
99
+ FingerprintListContext *cb = *(FingerprintListContext**) b;
100
+ if (ca->hash > cb->hash)
101
+ return 1;
102
+ else if (ca->hash < cb->hash)
103
+ return -1;
104
+ return 0;
105
+ }
106
+
107
+ static void
108
+ _fingerprintList(FingerprintContext *ctx, const List *node, const void *parent, char *field_name, unsigned int depth)
109
+ {
110
+ if (field_name != NULL && (strcmp(field_name, "fromClause") == 0 || strcmp(field_name, "targetList") == 0 ||
111
+ strcmp(field_name, "cols") == 0 || strcmp(field_name, "rexpr") == 0 || strcmp(field_name, "valuesLists") == 0 ||
112
+ strcmp(field_name, "args") == 0)) {
113
+
114
+ FingerprintListContext** listCtxArr = palloc0(node->length * sizeof(FingerprintListContext*));
115
+ size_t listCtxCount = 0;
116
+ const ListCell *lc;
117
+
118
+ foreach(lc, node)
119
+ {
120
+ FingerprintContext subCtx;
121
+ FingerprintListContext* listCtx = palloc0(sizeof(FingerprintListContext));
122
+
123
+ _fingerprintInitContext(&subCtx, false);
124
+ _fingerprintNode(&subCtx, lfirst(lc), parent, field_name, depth + 1);
125
+ listCtx->hash = XXH3_64bits_digest(subCtx.xxh_state);
126
+ listCtx->list_pos = listCtxCount;
127
+ _fingerprintFreeContext(&subCtx);
128
+
129
+ listCtxArr[listCtxCount] = listCtx;
130
+ listCtxCount += 1;
131
+ }
132
+
133
+ pg_qsort(listCtxArr, listCtxCount, sizeof(FingerprintListContext*), compareFingerprintListContext);
134
+
135
+ for (size_t i = 0; i < listCtxCount; i++)
136
+ {
137
+ if (i > 0 && listCtxArr[i - 1]->hash == listCtxArr[i]->hash)
138
+ continue; // Ignore duplicates
139
+
140
+ _fingerprintNode(ctx, lfirst(list_nth_cell(node, listCtxArr[i]->list_pos)), parent, field_name, depth + 1);
141
+ }
142
+ } else {
143
+ const ListCell *lc;
144
+
145
+ foreach(lc, node)
146
+ {
147
+ _fingerprintNode(ctx, lfirst(lc), parent, field_name, depth + 1);
148
+
149
+ lnext(node, lc);
150
+ }
151
+ }
152
+ }
153
+
154
+ static void
155
+ _fingerprintInitContext(FingerprintContext *ctx, bool write_tokens) {
156
+ ctx->xxh_state = XXH3_createState();
157
+ if (ctx->xxh_state == NULL) abort();
158
+ if (XXH3_64bits_reset_withSeed(ctx->xxh_state, PG_QUERY_FINGERPRINT_VERSION) == XXH_ERROR) abort();
159
+
160
+ if (write_tokens) {
161
+ ctx->write_tokens = true;
162
+ dlist_init(&ctx->tokens);
163
+ } else {
164
+ ctx->write_tokens = false;
165
+ }
166
+ }
167
+
168
+ static void
169
+ _fingerprintFreeContext(FingerprintContext *ctx) {
170
+ XXH3_freeState(ctx->xxh_state);
171
+ }
172
+
173
+ #include "pg_query_enum_defs.c"
174
+ #include "pg_query_fingerprint_defs.c"
175
+
176
+ void
177
+ _fingerprintNode(FingerprintContext *ctx, const void *obj, const void *parent, char *field_name, unsigned int depth)
178
+ {
179
+ // Some queries are overly complex in their parsetree - lets consistently cut them off at 100 nodes deep
180
+ if (depth >= 100) {
181
+ return;
182
+ }
183
+
184
+ if (obj == NULL)
185
+ {
186
+ return; // Ignore
187
+ }
188
+
189
+ switch (nodeTag(obj))
190
+ {
191
+ case T_List:
192
+ _fingerprintList(ctx, obj, parent, field_name, depth);
193
+ break;
194
+ case T_Integer:
195
+ _fingerprintInteger(ctx, obj);
196
+ break;
197
+ case T_Float:
198
+ _fingerprintFloat(ctx, obj);
199
+ break;
200
+ case T_String:
201
+ _fingerprintString(ctx, "String");
202
+ _fingerprintString(ctx, "str");
203
+ _fingerprintString(ctx, ((Value*) obj)->val.str);
204
+ break;
205
+ case T_BitString:
206
+ _fingerprintBitString(ctx, obj);
207
+ break;
208
+
209
+ #include "pg_query_fingerprint_conds.c"
210
+
211
+ default:
212
+ elog(WARNING, "could not fingerprint unrecognized node type: %d",
213
+ (int) nodeTag(obj));
214
+
215
+ return;
216
+ }
217
+ }
218
+
219
+ PgQueryFingerprintResult pg_query_fingerprint_with_opts(const char* input, bool printTokens)
220
+ {
221
+ MemoryContext ctx = NULL;
222
+ PgQueryInternalParsetreeAndError parsetree_and_error;
223
+ PgQueryFingerprintResult result = {0};
224
+
225
+ ctx = pg_query_enter_memory_context();
226
+
227
+ parsetree_and_error = pg_query_raw_parse(input);
228
+
229
+ // These are all malloc-ed and will survive exiting the memory context, the caller is responsible to free them now
230
+ result.stderr_buffer = parsetree_and_error.stderr_buffer;
231
+ result.error = parsetree_and_error.error;
232
+
233
+ if (parsetree_and_error.tree != NULL || result.error == NULL) {
234
+ FingerprintContext ctx;
235
+ XXH64_canonical_t chash;
236
+
237
+ _fingerprintInitContext(&ctx, printTokens);
238
+
239
+ if (parsetree_and_error.tree != NULL) {
240
+ _fingerprintNode(&ctx, parsetree_and_error.tree, NULL, NULL, 0);
241
+ }
242
+
243
+ if (printTokens) {
244
+ dlist_iter iter;
245
+
246
+ printf("[");
247
+
248
+ dlist_foreach(iter, &ctx.tokens)
249
+ {
250
+ FingerprintToken *token = dlist_container(FingerprintToken, list_node, iter.cur);
251
+
252
+ printf("\"%s\", ", token->str);
253
+ }
254
+
255
+ printf("]\n");
256
+ }
257
+
258
+ result.fingerprint = XXH3_64bits_digest(ctx.xxh_state);
259
+ _fingerprintFreeContext(&ctx);
260
+
261
+ XXH64_canonicalFromHash(&chash, result.fingerprint);
262
+ int err = asprintf(&result.fingerprint_str, "%02x%02x%02x%02x%02x%02x%02x%02x",
263
+ chash.digest[0], chash.digest[1], chash.digest[2], chash.digest[3],
264
+ chash.digest[4], chash.digest[5], chash.digest[6], chash.digest[7]);
265
+ if (err == -1) {
266
+ PgQueryError* error = malloc(sizeof(PgQueryError));
267
+ error->message = strdup("Failed to output fingerprint string due to asprintf failure");
268
+ result.error = error;
269
+ }
270
+ }
271
+
272
+ pg_query_exit_memory_context(ctx);
273
+
274
+ return result;
275
+ }
276
+
277
+ PgQueryFingerprintResult pg_query_fingerprint(const char* input)
278
+ {
279
+ return pg_query_fingerprint_with_opts(input, false);
280
+ }
281
+
282
+ void pg_query_free_fingerprint_result(PgQueryFingerprintResult result)
283
+ {
284
+ if (result.error) {
285
+ free(result.error->message);
286
+ free(result.error->filename);
287
+ free(result.error);
288
+ }
289
+
290
+ free(result.fingerprint_str);
291
+ free(result.stderr_buffer);
292
+ }
@@ -0,0 +1,8 @@
1
+ #ifndef PG_QUERY_FINGERPRINT_H
2
+ #define PG_QUERY_FINGERPRINT_H
3
+
4
+ #include <stdbool.h>
5
+
6
+ PgQueryFingerprintResult pg_query_fingerprint_with_opts(const char* input, bool printTokens);
7
+
8
+ #endif
@@ -0,0 +1,24 @@
1
+ #ifndef PG_QUERY_INTERNAL_H
2
+ #define PG_QUERY_INTERNAL_H
3
+
4
+ #include "postgres.h"
5
+ #include "utils/memutils.h"
6
+ #include "nodes/pg_list.h"
7
+
8
+ #define STDERR_BUFFER_LEN 4096
9
+ #define DEBUG
10
+
11
+ typedef struct {
12
+ List *tree;
13
+ char* stderr_buffer;
14
+ PgQueryError* error;
15
+ } PgQueryInternalParsetreeAndError;
16
+
17
+ PgQueryInternalParsetreeAndError pg_query_raw_parse(const char* input);
18
+
19
+ void pg_query_free_error(PgQueryError *error);
20
+
21
+ MemoryContext pg_query_enter_memory_context();
22
+ void pg_query_exit_memory_context(MemoryContext ctx);
23
+
24
+ #endif
@@ -0,0 +1,738 @@
1
+ #include "pg_query.h"
2
+ #include "pg_query_json_plpgsql.h"
3
+
4
+ #include "pg_query_json_helper.c"
5
+
6
+ /* Write the label for the node type */
7
+ #define WRITE_NODE_TYPE(nodelabel) \
8
+ appendStringInfoString(out, "\"" nodelabel "\":{")
9
+
10
+ /* Write an integer field */
11
+ #define WRITE_INT_FIELD(outname, outname_json, fldname) \
12
+ if (node->fldname != 0) { \
13
+ appendStringInfo(out, "\"" CppAsString(outname_json) "\":%d,", node->fldname); \
14
+ }
15
+
16
+ /* Write a long-integer field */
17
+ #define WRITE_LONG_FIELD(outname, outname_json, fldname) \
18
+ if (node->fldname != 0) { \
19
+ appendStringInfo(out, "\"" CppAsString(outname_json) "\":%ld,", node->fldname); \
20
+ }
21
+
22
+ /* Write an enumerated-type field as an integer code */
23
+ #define WRITE_ENUM_FIELD(outname, outname_json, fldname) \
24
+ appendStringInfo(out, "\"" CppAsString(outname_json) "\":%d,", \
25
+ (int) node->fldname)
26
+
27
+ /* Write a boolean field */
28
+ #define WRITE_BOOL_FIELD(outname, outname_json, fldname) \
29
+ if (node->fldname) { \
30
+ appendStringInfo(out, "\"" CppAsString(outname_json) "\":%s,", \
31
+ booltostr(node->fldname)); \
32
+ }
33
+
34
+ /* Write a character-string (possibly NULL) field */
35
+ #define WRITE_STRING_FIELD(outname, outname_json, fldname) \
36
+ if (node->fldname != NULL) { \
37
+ appendStringInfo(out, "\"" CppAsString(outname_json) "\":"); \
38
+ _outToken(out, node->fldname); \
39
+ appendStringInfo(out, ","); \
40
+ }
41
+
42
+ #define WRITE_INT_VALUE(fldname, value) \
43
+ if (value != 0) { \
44
+ appendStringInfo(out, "\"" CppAsString(fldname) "\":%d,", value); \
45
+ }
46
+
47
+ #define WRITE_STRING_VALUE(fldname, value) \
48
+ if (true) { \
49
+ appendStringInfo(out, "\"" CppAsString(fldname) "\":"); \
50
+ _outToken(out, value); \
51
+ appendStringInfo(out, ","); \
52
+ }
53
+
54
+ #define WRITE_OBJ_FIELD(fldname, outfunc) \
55
+ if (node->fldname != NULL) { \
56
+ appendStringInfo(out, "\"" CppAsString(fldname) "\":{"); \
57
+ outfunc(out, node->fldname); \
58
+ removeTrailingDelimiter(out); \
59
+ appendStringInfo(out, "}},"); \
60
+ }
61
+
62
+ #define WRITE_LIST_FIELD(fldname, fldtype, outfunc) \
63
+ if (node->fldname != NULL) { \
64
+ ListCell *lc; \
65
+ appendStringInfo(out, "\"" CppAsString(fldname) "\":["); \
66
+ foreach(lc, node->fldname) { \
67
+ appendStringInfoString(out, "{"); \
68
+ outfunc(out, (fldtype *) lfirst(lc)); \
69
+ removeTrailingDelimiter(out); \
70
+ appendStringInfoString(out, "}},"); \
71
+ } \
72
+ removeTrailingDelimiter(out); \
73
+ appendStringInfoString(out, "],"); \
74
+ }
75
+
76
+ #define WRITE_STATEMENTS_FIELD(fldname) \
77
+ if (node->fldname != NULL) { \
78
+ ListCell *lc; \
79
+ appendStringInfo(out, "\"" CppAsString(fldname) "\":["); \
80
+ foreach(lc, node->fldname) { \
81
+ dump_stmt(out, (PLpgSQL_stmt *) lfirst(lc)); \
82
+ } \
83
+ removeTrailingDelimiter(out); \
84
+ appendStringInfoString(out, "],"); \
85
+ }
86
+
87
+ #define WRITE_EXPR_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_expr)
88
+ #define WRITE_BLOCK_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_block)
89
+ #define WRITE_RECORD_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_record)
90
+ #define WRITE_ROW_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_row)
91
+ #define WRITE_VAR_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_var)
92
+ #define WRITE_VARIABLE_FIELD(fldname) WRITE_OBJ_FIELD(fldname, dump_variable);
93
+
94
+ static void dump_record(StringInfo out, PLpgSQL_rec *stmt);
95
+ static void dump_row(StringInfo out, PLpgSQL_row *stmt);
96
+ static void dump_var(StringInfo out, PLpgSQL_var *stmt);
97
+ static void dump_variable(StringInfo out, PLpgSQL_variable *stmt);
98
+ static void dump_record_field(StringInfo out, PLpgSQL_recfield *node);
99
+ static void dump_array_elem(StringInfo out, PLpgSQL_arrayelem *node);
100
+ static void dump_stmt(StringInfo out, PLpgSQL_stmt *stmt);
101
+ static void dump_block(StringInfo out, PLpgSQL_stmt_block *block);
102
+ static void dump_exception_block(StringInfo out, PLpgSQL_exception_block *node);
103
+ static void dump_assign(StringInfo out, PLpgSQL_stmt_assign *stmt);
104
+ static void dump_if(StringInfo out, PLpgSQL_stmt_if *stmt);
105
+ static void dump_if_elsif(StringInfo out, PLpgSQL_if_elsif *node);
106
+ static void dump_case(StringInfo out, PLpgSQL_stmt_case *stmt);
107
+ static void dump_case_when(StringInfo out, PLpgSQL_case_when *node);
108
+ static void dump_loop(StringInfo out, PLpgSQL_stmt_loop *stmt);
109
+ static void dump_while(StringInfo out, PLpgSQL_stmt_while *stmt);
110
+ static void dump_fori(StringInfo out, PLpgSQL_stmt_fori *stmt);
111
+ static void dump_fors(StringInfo out, PLpgSQL_stmt_fors *stmt);
112
+ static void dump_forc(StringInfo out, PLpgSQL_stmt_forc *stmt);
113
+ static void dump_foreach_a(StringInfo out, PLpgSQL_stmt_foreach_a *stmt);
114
+ static void dump_exit(StringInfo out, PLpgSQL_stmt_exit *stmt);
115
+ static void dump_return(StringInfo out, PLpgSQL_stmt_return *stmt);
116
+ static void dump_return_next(StringInfo out, PLpgSQL_stmt_return_next *stmt);
117
+ static void dump_return_query(StringInfo out, PLpgSQL_stmt_return_query *stmt);
118
+ static void dump_raise(StringInfo out, PLpgSQL_stmt_raise *stmt);
119
+ static void dump_raise_option(StringInfo out, PLpgSQL_raise_option *node);
120
+ static void dump_execsql(StringInfo out, PLpgSQL_stmt_execsql *stmt);
121
+ static void dump_dynexecute(StringInfo out, PLpgSQL_stmt_dynexecute *stmt);
122
+ static void dump_dynfors(StringInfo out, PLpgSQL_stmt_dynfors *stmt);
123
+ static void dump_getdiag(StringInfo out, PLpgSQL_stmt_getdiag *stmt);
124
+ static void dump_getdiag_item(StringInfo out, PLpgSQL_diag_item *node);
125
+ static void dump_open(StringInfo out, PLpgSQL_stmt_open *stmt);
126
+ static void dump_fetch(StringInfo out, PLpgSQL_stmt_fetch *stmt);
127
+ static void dump_close(StringInfo out, PLpgSQL_stmt_close *stmt);
128
+ static void dump_perform(StringInfo out, PLpgSQL_stmt_perform *stmt);
129
+ static void dump_expr(StringInfo out, PLpgSQL_expr *expr);
130
+ static void dump_function(StringInfo out, PLpgSQL_function *func);
131
+ static void dump_exception(StringInfo out, PLpgSQL_exception *node);
132
+ static void dump_condition(StringInfo out, PLpgSQL_condition *node);
133
+ static void dump_type(StringInfo out, PLpgSQL_type *node);
134
+
135
+ static void
136
+ dump_stmt(StringInfo out, PLpgSQL_stmt *node)
137
+ {
138
+ appendStringInfoChar(out, '{');
139
+ switch (node->cmd_type)
140
+ {
141
+ case PLPGSQL_STMT_BLOCK:
142
+ dump_block(out, (PLpgSQL_stmt_block *) node);
143
+ break;
144
+ case PLPGSQL_STMT_ASSIGN:
145
+ dump_assign(out, (PLpgSQL_stmt_assign *) node);
146
+ break;
147
+ case PLPGSQL_STMT_IF:
148
+ dump_if(out, (PLpgSQL_stmt_if *) node);
149
+ break;
150
+ case PLPGSQL_STMT_CASE:
151
+ dump_case(out, (PLpgSQL_stmt_case *) node);
152
+ break;
153
+ case PLPGSQL_STMT_LOOP:
154
+ dump_loop(out, (PLpgSQL_stmt_loop *) node);
155
+ break;
156
+ case PLPGSQL_STMT_WHILE:
157
+ dump_while(out, (PLpgSQL_stmt_while *) node);
158
+ break;
159
+ case PLPGSQL_STMT_FORI:
160
+ dump_fori(out, (PLpgSQL_stmt_fori *) node);
161
+ break;
162
+ case PLPGSQL_STMT_FORS:
163
+ dump_fors(out, (PLpgSQL_stmt_fors *) node);
164
+ break;
165
+ case PLPGSQL_STMT_FORC:
166
+ dump_forc(out, (PLpgSQL_stmt_forc *) node);
167
+ break;
168
+ case PLPGSQL_STMT_FOREACH_A:
169
+ dump_foreach_a(out, (PLpgSQL_stmt_foreach_a *) node);
170
+ break;
171
+ case PLPGSQL_STMT_EXIT:
172
+ dump_exit(out, (PLpgSQL_stmt_exit *) node);
173
+ break;
174
+ case PLPGSQL_STMT_RETURN:
175
+ dump_return(out, (PLpgSQL_stmt_return *) node);
176
+ break;
177
+ case PLPGSQL_STMT_RETURN_NEXT:
178
+ dump_return_next(out, (PLpgSQL_stmt_return_next *) node);
179
+ break;
180
+ case PLPGSQL_STMT_RETURN_QUERY:
181
+ dump_return_query(out, (PLpgSQL_stmt_return_query *) node);
182
+ break;
183
+ case PLPGSQL_STMT_RAISE:
184
+ dump_raise(out, (PLpgSQL_stmt_raise *) node);
185
+ break;
186
+ case PLPGSQL_STMT_EXECSQL:
187
+ dump_execsql(out, (PLpgSQL_stmt_execsql *) node);
188
+ break;
189
+ case PLPGSQL_STMT_DYNEXECUTE:
190
+ dump_dynexecute(out, (PLpgSQL_stmt_dynexecute *) node);
191
+ break;
192
+ case PLPGSQL_STMT_DYNFORS:
193
+ dump_dynfors(out, (PLpgSQL_stmt_dynfors *) node);
194
+ break;
195
+ case PLPGSQL_STMT_GETDIAG:
196
+ dump_getdiag(out, (PLpgSQL_stmt_getdiag *) node);
197
+ break;
198
+ case PLPGSQL_STMT_OPEN:
199
+ dump_open(out, (PLpgSQL_stmt_open *) node);
200
+ break;
201
+ case PLPGSQL_STMT_FETCH:
202
+ dump_fetch(out, (PLpgSQL_stmt_fetch *) node);
203
+ break;
204
+ case PLPGSQL_STMT_CLOSE:
205
+ dump_close(out, (PLpgSQL_stmt_close *) node);
206
+ break;
207
+ case PLPGSQL_STMT_PERFORM:
208
+ dump_perform(out, (PLpgSQL_stmt_perform *) node);
209
+ break;
210
+ default:
211
+ elog(ERROR, "unrecognized cmd_type: %d", node->cmd_type);
212
+ break;
213
+ }
214
+ removeTrailingDelimiter(out);
215
+ appendStringInfoString(out, "}},");
216
+ }
217
+
218
+ static void
219
+ dump_block(StringInfo out, PLpgSQL_stmt_block *node)
220
+ {
221
+ WRITE_NODE_TYPE("PLpgSQL_stmt_block");
222
+
223
+ WRITE_INT_FIELD(lineno, lineno, lineno);
224
+ WRITE_STRING_FIELD(label, label, label);
225
+ WRITE_STATEMENTS_FIELD(body);
226
+ WRITE_OBJ_FIELD(exceptions, dump_exception_block);
227
+
228
+ removeTrailingDelimiter(out);
229
+ }
230
+
231
+ static void
232
+ dump_exception_block(StringInfo out, PLpgSQL_exception_block *node)
233
+ {
234
+ WRITE_NODE_TYPE("PLpgSQL_exception_block");
235
+
236
+ WRITE_LIST_FIELD(exc_list, PLpgSQL_exception, dump_exception);
237
+ }
238
+
239
+ static void
240
+ dump_exception(StringInfo out, PLpgSQL_exception *node)
241
+ {
242
+ PLpgSQL_condition *cond;
243
+
244
+ WRITE_NODE_TYPE("PLpgSQL_exception");
245
+
246
+ appendStringInfo(out, "\"conditions\":[");
247
+ for (cond = node->conditions; cond; cond = cond->next)
248
+ {
249
+ appendStringInfoString(out, "{");
250
+ dump_condition(out, cond);
251
+ removeTrailingDelimiter(out);
252
+ appendStringInfoString(out, "}},");
253
+ }
254
+ removeTrailingDelimiter(out);
255
+ appendStringInfoString(out, "],");
256
+
257
+ WRITE_STATEMENTS_FIELD(action);
258
+ }
259
+
260
+ static void
261
+ dump_condition(StringInfo out, PLpgSQL_condition *node)
262
+ {
263
+ WRITE_NODE_TYPE("PLpgSQL_condition");
264
+
265
+ WRITE_STRING_FIELD(condname, condname, condname);
266
+ }
267
+
268
+ static void
269
+ dump_assign(StringInfo out, PLpgSQL_stmt_assign *node)
270
+ {
271
+ WRITE_NODE_TYPE("PLpgSQL_stmt_assign");
272
+
273
+ WRITE_INT_FIELD(lineno, lineno, lineno);
274
+ WRITE_INT_FIELD(varno, varno, varno);
275
+ WRITE_EXPR_FIELD(expr);
276
+ }
277
+
278
+ static void
279
+ dump_if(StringInfo out, PLpgSQL_stmt_if *node)
280
+ {
281
+ WRITE_NODE_TYPE("PLpgSQL_stmt_if");
282
+
283
+ WRITE_INT_FIELD(lineno, lineno, lineno);
284
+ WRITE_EXPR_FIELD(cond);
285
+ WRITE_STATEMENTS_FIELD(then_body);
286
+ WRITE_LIST_FIELD(elsif_list, PLpgSQL_if_elsif, dump_if_elsif);
287
+ WRITE_STATEMENTS_FIELD(else_body);
288
+ }
289
+
290
+ static void
291
+ dump_if_elsif(StringInfo out, PLpgSQL_if_elsif *node)
292
+ {
293
+ WRITE_NODE_TYPE("PLpgSQL_if_elsif");
294
+
295
+ WRITE_INT_FIELD(lineno, lineno, lineno);
296
+ WRITE_EXPR_FIELD(cond);
297
+ WRITE_STATEMENTS_FIELD(stmts);
298
+ }
299
+
300
+ static void
301
+ dump_case(StringInfo out, PLpgSQL_stmt_case *node)
302
+ {
303
+ ListCell *l;
304
+
305
+ WRITE_NODE_TYPE("PLpgSQL_stmt_case");
306
+
307
+ WRITE_INT_FIELD(lineno, lineno, lineno);
308
+ WRITE_EXPR_FIELD(t_expr);
309
+ WRITE_INT_FIELD(t_varno, t_varno, t_varno);
310
+ WRITE_LIST_FIELD(case_when_list, PLpgSQL_case_when, dump_case_when);
311
+ WRITE_BOOL_FIELD(have_else, have_else, have_else);
312
+ WRITE_STATEMENTS_FIELD(else_stmts);
313
+ }
314
+
315
+ static void
316
+ dump_case_when(StringInfo out, PLpgSQL_case_when *node)
317
+ {
318
+ WRITE_NODE_TYPE("PLpgSQL_case_when");
319
+
320
+ WRITE_INT_FIELD(lineno, lineno, lineno);
321
+ WRITE_EXPR_FIELD(expr);
322
+ WRITE_STATEMENTS_FIELD(stmts);
323
+ }
324
+
325
+ static void
326
+ dump_loop(StringInfo out, PLpgSQL_stmt_loop *node)
327
+ {
328
+ WRITE_NODE_TYPE("PLpgSQL_stmt_loop");
329
+
330
+ WRITE_INT_FIELD(lineno, lineno, lineno);
331
+ WRITE_STRING_FIELD(label, label, label);
332
+ WRITE_STATEMENTS_FIELD(body);
333
+ }
334
+
335
+ static void
336
+ dump_while(StringInfo out, PLpgSQL_stmt_while *node)
337
+ {
338
+ WRITE_NODE_TYPE("PLpgSQL_stmt_while");
339
+
340
+ WRITE_INT_FIELD(lineno, lineno, lineno);
341
+ WRITE_STRING_FIELD(label, label, label);
342
+ WRITE_EXPR_FIELD(cond);
343
+ WRITE_STATEMENTS_FIELD(body);
344
+ }
345
+
346
+ /* FOR statement with integer loopvar */
347
+ static void
348
+ dump_fori(StringInfo out, PLpgSQL_stmt_fori *node)
349
+ {
350
+ WRITE_NODE_TYPE("PLpgSQL_stmt_fori");
351
+
352
+ WRITE_INT_FIELD(lineno, lineno, lineno);
353
+ WRITE_STRING_FIELD(label, label, label);
354
+ WRITE_VAR_FIELD(var);
355
+ WRITE_EXPR_FIELD(lower);
356
+ WRITE_EXPR_FIELD(upper);
357
+ WRITE_EXPR_FIELD(step);
358
+ WRITE_BOOL_FIELD(reverse, reverse, reverse);
359
+ WRITE_STATEMENTS_FIELD(body);
360
+ }
361
+
362
+ static void
363
+ dump_fors(StringInfo out, PLpgSQL_stmt_fors *node)
364
+ {
365
+ WRITE_NODE_TYPE("PLpgSQL_stmt_fors");
366
+
367
+ WRITE_INT_FIELD(lineno, lineno, lineno);
368
+ WRITE_STRING_FIELD(label, label, label);
369
+ WRITE_VARIABLE_FIELD(var);
370
+ WRITE_STATEMENTS_FIELD(body);
371
+ WRITE_EXPR_FIELD(query);
372
+ }
373
+
374
+ static void
375
+ dump_forc(StringInfo out, PLpgSQL_stmt_forc *node)
376
+ {
377
+ WRITE_NODE_TYPE("PLpgSQL_stmt_forc");
378
+
379
+ WRITE_INT_FIELD(lineno, lineno, lineno);
380
+ WRITE_STRING_FIELD(label, label, label);
381
+ WRITE_VARIABLE_FIELD(var);
382
+ WRITE_STATEMENTS_FIELD(body);
383
+ WRITE_INT_FIELD(curvar, curvar, curvar);
384
+ WRITE_EXPR_FIELD(argquery);
385
+ }
386
+
387
+ static void
388
+ dump_foreach_a(StringInfo out, PLpgSQL_stmt_foreach_a *node)
389
+ {
390
+ WRITE_NODE_TYPE("PLpgSQL_stmt_foreach_a");
391
+
392
+ WRITE_INT_FIELD(lineno, lineno, lineno);
393
+ WRITE_STRING_FIELD(label, label, label);
394
+ WRITE_INT_FIELD(varno, varno, varno);
395
+ WRITE_INT_FIELD(slice, slice, slice);
396
+ WRITE_EXPR_FIELD(expr);
397
+ WRITE_STATEMENTS_FIELD(body);
398
+ }
399
+
400
+ static void
401
+ dump_open(StringInfo out, PLpgSQL_stmt_open *node)
402
+ {
403
+ WRITE_NODE_TYPE("PLpgSQL_stmt_open");
404
+
405
+ WRITE_INT_FIELD(lineno, lineno, lineno);
406
+ WRITE_INT_FIELD(curvar, curvar, curvar);
407
+ WRITE_INT_FIELD(cursor_options, cursor_options, cursor_options);
408
+ WRITE_EXPR_FIELD(argquery);
409
+ WRITE_EXPR_FIELD(query);
410
+ WRITE_EXPR_FIELD(dynquery);
411
+ WRITE_LIST_FIELD(params, PLpgSQL_expr, dump_expr);
412
+ }
413
+
414
+ static void
415
+ dump_fetch(StringInfo out, PLpgSQL_stmt_fetch *node)
416
+ {
417
+ WRITE_NODE_TYPE("PLpgSQL_stmt_fetch");
418
+
419
+ WRITE_INT_FIELD(lineno, lineno, lineno);
420
+ WRITE_VARIABLE_FIELD(target);
421
+ WRITE_INT_FIELD(curvar, curvar, curvar);
422
+ WRITE_ENUM_FIELD(direction, direction, direction);
423
+ WRITE_LONG_FIELD(how_many, how_many, how_many);
424
+ WRITE_EXPR_FIELD(expr);
425
+ WRITE_BOOL_FIELD(is_move, is_move, is_move);
426
+ WRITE_BOOL_FIELD(returns_multiple_rows, returns_multiple_rows, returns_multiple_rows);
427
+ }
428
+
429
+ static void
430
+ dump_close(StringInfo out, PLpgSQL_stmt_close *node)
431
+ {
432
+ WRITE_NODE_TYPE("PLpgSQL_stmt_close");
433
+
434
+ WRITE_INT_FIELD(lineno, lineno, lineno);
435
+ WRITE_INT_FIELD(curvar, curvar, curvar);
436
+ }
437
+
438
+ static void
439
+ dump_perform(StringInfo out, PLpgSQL_stmt_perform *node)
440
+ {
441
+ WRITE_NODE_TYPE("PLpgSQL_stmt_perform");
442
+
443
+ WRITE_INT_FIELD(lineno, lineno, lineno);
444
+ WRITE_EXPR_FIELD(expr);
445
+ }
446
+
447
+ static void
448
+ dump_exit(StringInfo out, PLpgSQL_stmt_exit *node)
449
+ {
450
+ WRITE_NODE_TYPE("PLpgSQL_stmt_exit");
451
+
452
+ WRITE_INT_FIELD(lineno, lineno, lineno);
453
+ WRITE_BOOL_FIELD(is_exit, is_exit, is_exit);
454
+ WRITE_STRING_FIELD(label, label, label);
455
+ WRITE_EXPR_FIELD(cond);
456
+ }
457
+
458
+ static void
459
+ dump_return(StringInfo out, PLpgSQL_stmt_return *node)
460
+ {
461
+ WRITE_NODE_TYPE("PLpgSQL_stmt_return");
462
+
463
+ WRITE_INT_FIELD(lineno, lineno, lineno);
464
+ WRITE_EXPR_FIELD(expr);
465
+ //WRITE_INT_FIELD(retvarno);
466
+ }
467
+
468
+ static void
469
+ dump_return_next(StringInfo out, PLpgSQL_stmt_return_next *node)
470
+ {
471
+ WRITE_NODE_TYPE("PLpgSQL_stmt_return_next");
472
+
473
+ WRITE_INT_FIELD(lineno, lineno, lineno);
474
+ WRITE_EXPR_FIELD(expr);
475
+ //WRITE_INT_FIELD(retvarno);
476
+ }
477
+
478
+ static void
479
+ dump_return_query(StringInfo out, PLpgSQL_stmt_return_query *node)
480
+ {
481
+ WRITE_NODE_TYPE("PLpgSQL_stmt_return_query");
482
+
483
+ WRITE_INT_FIELD(lineno, lineno, lineno);
484
+ WRITE_EXPR_FIELD(query);
485
+ WRITE_EXPR_FIELD(dynquery);
486
+ WRITE_LIST_FIELD(params, PLpgSQL_expr, dump_expr);
487
+ }
488
+
489
+ static void
490
+ dump_raise(StringInfo out, PLpgSQL_stmt_raise *node)
491
+ {
492
+ WRITE_NODE_TYPE("PLpgSQL_stmt_raise");
493
+
494
+ WRITE_INT_FIELD(lineno, lineno, lineno);
495
+ WRITE_INT_FIELD(elog_level, elog_level, elog_level);
496
+ WRITE_STRING_FIELD(condname, condname, condname);
497
+ WRITE_STRING_FIELD(message, message, message);
498
+ WRITE_LIST_FIELD(params, PLpgSQL_expr, dump_expr);
499
+ WRITE_LIST_FIELD(options, PLpgSQL_raise_option, dump_raise_option);
500
+ }
501
+
502
+ static void
503
+ dump_raise_option(StringInfo out, PLpgSQL_raise_option *node)
504
+ {
505
+ WRITE_NODE_TYPE("PLpgSQL_raise_option");
506
+
507
+ WRITE_ENUM_FIELD(opt_type, opt_type, opt_type);
508
+ WRITE_EXPR_FIELD(expr);
509
+ }
510
+
511
+ static void
512
+ dump_execsql(StringInfo out, PLpgSQL_stmt_execsql *node)
513
+ {
514
+ WRITE_NODE_TYPE("PLpgSQL_stmt_execsql");
515
+
516
+ WRITE_INT_FIELD(lineno, lineno, lineno);
517
+ WRITE_EXPR_FIELD(sqlstmt);
518
+ //WRITE_BOOL_FIELD(mod_stmt); // This is only populated when executing the function
519
+ WRITE_BOOL_FIELD(into, into, into);
520
+ WRITE_BOOL_FIELD(strict, strict, strict);
521
+ WRITE_VARIABLE_FIELD(target);
522
+ }
523
+
524
+ static void
525
+ dump_dynexecute(StringInfo out, PLpgSQL_stmt_dynexecute *node)
526
+ {
527
+ WRITE_NODE_TYPE("PLpgSQL_stmt_dynexecute");
528
+
529
+ WRITE_INT_FIELD(lineno, lineno, lineno);
530
+ WRITE_EXPR_FIELD(query);
531
+ WRITE_BOOL_FIELD(into, into, into);
532
+ WRITE_BOOL_FIELD(strict, strict, strict);
533
+ WRITE_VARIABLE_FIELD(target);
534
+ WRITE_LIST_FIELD(params, PLpgSQL_expr, dump_expr);
535
+ }
536
+
537
+ static void
538
+ dump_dynfors(StringInfo out, PLpgSQL_stmt_dynfors *node)
539
+ {
540
+ WRITE_NODE_TYPE("PLpgSQL_stmt_dynfors");
541
+
542
+ WRITE_INT_FIELD(lineno, lineno, lineno);
543
+ WRITE_STRING_FIELD(label, label, label);
544
+ WRITE_VARIABLE_FIELD(var);
545
+ WRITE_STATEMENTS_FIELD(body);
546
+ WRITE_EXPR_FIELD(query);
547
+ WRITE_LIST_FIELD(params, PLpgSQL_expr, dump_expr);
548
+ }
549
+
550
+ static void
551
+ dump_getdiag(StringInfo out, PLpgSQL_stmt_getdiag *node)
552
+ {
553
+ WRITE_NODE_TYPE("PLpgSQL_stmt_getdiag");
554
+
555
+ WRITE_INT_FIELD(lineno, lineno, lineno);
556
+ WRITE_BOOL_FIELD(is_stacked, is_stacked, is_stacked);
557
+ WRITE_LIST_FIELD(diag_items, PLpgSQL_diag_item, dump_getdiag_item);
558
+ }
559
+
560
+ static void
561
+ dump_getdiag_item(StringInfo out, PLpgSQL_diag_item *node)
562
+ {
563
+ WRITE_NODE_TYPE("PLpgSQL_diag_item");
564
+
565
+ WRITE_STRING_VALUE(kind, plpgsql_getdiag_kindname(node->kind));
566
+ WRITE_INT_FIELD(target, target, target);
567
+ }
568
+
569
+ static void
570
+ dump_expr(StringInfo out, PLpgSQL_expr *node)
571
+ {
572
+ WRITE_NODE_TYPE("PLpgSQL_expr");
573
+
574
+ WRITE_STRING_FIELD(query, query, query);
575
+ }
576
+
577
+ static void
578
+ dump_function(StringInfo out, PLpgSQL_function *node)
579
+ {
580
+ int i;
581
+ PLpgSQL_datum *d;
582
+
583
+ WRITE_NODE_TYPE("PLpgSQL_function");
584
+ WRITE_INT_FIELD(new_varno, new_varno, new_varno);
585
+ WRITE_INT_FIELD(old_varno, old_varno, old_varno);
586
+
587
+ appendStringInfoString(out, "\"datums\":");
588
+ appendStringInfoChar(out, '[');
589
+ for (i = 0; i < node->ndatums; i++)
590
+ {
591
+ appendStringInfoChar(out, '{');
592
+ d = node->datums[i];
593
+
594
+ switch (d->dtype)
595
+ {
596
+ case PLPGSQL_DTYPE_VAR:
597
+ dump_var(out, (PLpgSQL_var *) d);
598
+ break;
599
+ case PLPGSQL_DTYPE_ROW:
600
+ dump_row(out, (PLpgSQL_row *) d);
601
+ break;
602
+ case PLPGSQL_DTYPE_REC:
603
+ dump_record(out, (PLpgSQL_rec *) d);
604
+ break;
605
+ case PLPGSQL_DTYPE_RECFIELD:
606
+ dump_record_field(out, (PLpgSQL_recfield *) d);
607
+ break;
608
+ case PLPGSQL_DTYPE_ARRAYELEM:
609
+ dump_array_elem(out, (PLpgSQL_arrayelem *) d);
610
+ break;
611
+ default:
612
+ elog(WARNING, "could not dump unrecognized dtype: %d",
613
+ (int) d->dtype);
614
+ }
615
+ removeTrailingDelimiter(out);
616
+ appendStringInfoString(out, "}},");
617
+ }
618
+ removeTrailingDelimiter(out);
619
+ appendStringInfoString(out, "],");
620
+
621
+ WRITE_BLOCK_FIELD(action);
622
+ }
623
+
624
+ static void
625
+ dump_var(StringInfo out, PLpgSQL_var *node)
626
+ {
627
+ WRITE_NODE_TYPE("PLpgSQL_var");
628
+
629
+ WRITE_STRING_FIELD(refname, refname, refname);
630
+ WRITE_INT_FIELD(lineno, lineno, lineno);
631
+ WRITE_OBJ_FIELD(datatype, dump_type);
632
+ WRITE_BOOL_FIELD(isconst, isconst, isconst);
633
+ WRITE_BOOL_FIELD(notnull, notnull, notnull);
634
+ WRITE_EXPR_FIELD(default_val);
635
+ WRITE_EXPR_FIELD(cursor_explicit_expr);
636
+ WRITE_INT_FIELD(cursor_explicit_argrow, cursor_explicit_argrow, cursor_explicit_argrow);
637
+ WRITE_INT_FIELD(cursor_options, cursor_options, cursor_options);
638
+ }
639
+
640
+ static void
641
+ dump_variable(StringInfo out, PLpgSQL_variable *node)
642
+ {
643
+ switch (node->dtype)
644
+ {
645
+ case PLPGSQL_DTYPE_REC:
646
+ dump_record(out, (PLpgSQL_rec *) node);
647
+ break;
648
+ case PLPGSQL_DTYPE_VAR:
649
+ dump_var(out, (PLpgSQL_var *) node);
650
+ break;
651
+ case PLPGSQL_DTYPE_ROW:
652
+ dump_row(out, (PLpgSQL_row *) node);
653
+ break;
654
+ default:
655
+ elog(ERROR, "unrecognized variable type: %d", node->dtype);
656
+ break;
657
+ }
658
+ }
659
+
660
+ static void
661
+ dump_type(StringInfo out, PLpgSQL_type *node)
662
+ {
663
+ WRITE_NODE_TYPE("PLpgSQL_type");
664
+
665
+ WRITE_STRING_FIELD(typname, typname, typname);
666
+ }
667
+
668
+ static void
669
+ dump_row(StringInfo out, PLpgSQL_row *node)
670
+ {
671
+ int i = 0;
672
+
673
+ WRITE_NODE_TYPE("PLpgSQL_row");
674
+
675
+ WRITE_STRING_FIELD(refname, refname, refname);
676
+ WRITE_INT_FIELD(lineno, lineno, lineno);
677
+
678
+ appendStringInfoString(out, "\"fields\":");
679
+ appendStringInfoChar(out, '[');
680
+
681
+ for (i = 0; i < node->nfields; i++)
682
+ {
683
+ if (node->fieldnames[i]) {
684
+ appendStringInfoChar(out, '{');
685
+ WRITE_STRING_VALUE(name, node->fieldnames[i]);
686
+ WRITE_INT_VALUE(varno, node->varnos[i]);
687
+ removeTrailingDelimiter(out);
688
+ appendStringInfoString(out, "},");
689
+ } else {
690
+ appendStringInfoString(out, "null,");
691
+ }
692
+ }
693
+ removeTrailingDelimiter(out);
694
+
695
+ appendStringInfoString(out, "],");
696
+ }
697
+
698
+ static void
699
+ dump_record(StringInfo out, PLpgSQL_rec *node) {
700
+ WRITE_NODE_TYPE("PLpgSQL_rec");
701
+
702
+ WRITE_STRING_FIELD(refname, refname, refname);
703
+ WRITE_INT_FIELD(dno, dno, dno);
704
+ WRITE_INT_FIELD(lineno, lineno, lineno);
705
+ }
706
+
707
+ static void
708
+ dump_record_field(StringInfo out, PLpgSQL_recfield *node) {
709
+ WRITE_NODE_TYPE("PLpgSQL_recfield");
710
+
711
+ WRITE_STRING_FIELD(fieldname, fieldname, fieldname);
712
+ WRITE_INT_FIELD(recparentno, recparentno, recparentno);
713
+ }
714
+
715
+ static void
716
+ dump_array_elem(StringInfo out, PLpgSQL_arrayelem *node) {
717
+ WRITE_NODE_TYPE("PLpgSQL_arrayelem");
718
+
719
+ WRITE_EXPR_FIELD(subscript);
720
+ WRITE_INT_FIELD(arrayparentno, arrayparentno, arrayparentno);
721
+ }
722
+
723
+ char *
724
+ plpgsqlToJSON(PLpgSQL_function *func)
725
+ {
726
+ StringInfoData str;
727
+
728
+ initStringInfo(&str);
729
+
730
+ appendStringInfoChar(&str, '{');
731
+
732
+ dump_function(&str, func);
733
+
734
+ removeTrailingDelimiter(&str);
735
+ appendStringInfoString(&str, "}}");
736
+
737
+ return str.data;
738
+ }