/src/libpg_query/src/pg_query_outfuncs_protobuf.c
Line | Count | Source |
1 | | #include "pg_query_outfuncs.h" |
2 | | |
3 | | #include "postgres.h" |
4 | | #include <ctype.h> |
5 | | #include "access/relation.h" |
6 | | #include "nodes/parsenodes.h" |
7 | | #include "nodes/plannodes.h" |
8 | | #include "nodes/value.h" |
9 | | #include "utils/datum.h" |
10 | | |
11 | | #include "protobuf/pg_query.pb-c.h" |
12 | | |
13 | | #define OUT_TYPE(typename, typename_c) PgQuery__##typename_c* |
14 | | |
15 | | #define OUT_NODE(typename, typename_c, typename_underscore, typename_underscore_upcase, typename_cast, fldname) \ |
16 | | { \ |
17 | | PgQuery__##typename_c *__node = palloc(sizeof(PgQuery__##typename_c)); \ |
18 | | pg_query__##typename_underscore##__init(__node); \ |
19 | | _out##typename_c(__node, (const typename_cast *) obj); \ |
20 | | out->fldname = __node; \ |
21 | | out->node_case = PG_QUERY__NODE__NODE_##typename_underscore_upcase; \ |
22 | | } |
23 | | |
24 | 0 | #define WRITE_INT_FIELD(outname, outname_json, fldname) out->outname = node->fldname; |
25 | 0 | #define WRITE_UINT_FIELD(outname, outname_json, fldname) out->outname = node->fldname; |
26 | 0 | #define WRITE_UINT64_FIELD(outname, outname_json, fldname) out->outname = node->fldname; |
27 | 0 | #define WRITE_LONG_FIELD(outname, outname_json, fldname) out->outname = node->fldname; |
28 | 0 | #define WRITE_FLOAT_FIELD(outname, outname_json, fldname) out->outname = node->fldname; |
29 | 0 | #define WRITE_BOOL_FIELD(outname, outname_json, fldname) out->outname = node->fldname; |
30 | | |
31 | | #define WRITE_CHAR_FIELD(outname, outname_json, fldname) \ |
32 | 0 | if (node->fldname != 0) { \ |
33 | 0 | out->outname = palloc(sizeof(char) * 2); \ |
34 | 0 | out->outname[0] = node->fldname; \ |
35 | 0 | out->outname[1] = '\0'; \ |
36 | 0 | } |
37 | | #define WRITE_STRING_FIELD(outname, outname_json, fldname) \ |
38 | 0 | if (node->fldname != NULL) { \ |
39 | 0 | out->outname = pstrdup(node->fldname); \ |
40 | 0 | } |
41 | | |
42 | | #define WRITE_ENUM_FIELD(typename, outname, outname_json, fldname) \ |
43 | 0 | out->outname = _enumToInt##typename(node->fldname); |
44 | | |
45 | | #define WRITE_LIST_FIELD(outname, outname_json, fldname) \ |
46 | 0 | if (node->fldname != NULL) { \ |
47 | 0 | out->n_##outname = list_length(node->fldname); \ |
48 | 0 | out->outname = palloc(sizeof(PgQuery__Node*) * out->n_##outname); \ |
49 | 0 | for (int i = 0; i < out->n_##outname; i++) \ |
50 | 0 | { \ |
51 | 0 | PgQuery__Node *__node = palloc(sizeof(PgQuery__Node)); \ |
52 | 0 | pg_query__node__init(__node); \ |
53 | 0 | out->outname[i] = __node; \ |
54 | 0 | _outNode(out->outname[i], list_nth(node->fldname, i)); \ |
55 | 0 | } \ |
56 | 0 | } |
57 | | |
58 | | #define WRITE_BITMAPSET_FIELD(outname, outname_json, fldname) \ |
59 | 0 | if (!bms_is_empty(node->fldname)) \ |
60 | 0 | { \ |
61 | 0 | int x = -1; \ |
62 | 0 | int i = 0; \ |
63 | 0 | out->n_##outname = bms_num_members(node->fldname); \ |
64 | 0 | out->outname = palloc(sizeof(PgQuery__Node*) * out->n_##outname); \ |
65 | 0 | while ((x = bms_next_member(node->fldname, x)) >= 0) \ |
66 | 0 | out->outname[i++] = x; \ |
67 | 0 | } |
68 | | |
69 | | #define WRITE_NODE_FIELD(outname, outname_json, fldname) \ |
70 | | { \ |
71 | | PgQuery__Node *__node = palloc(sizeof(PgQuery__Node)); \ |
72 | | pg_query__node__init(__node); \ |
73 | | out->outname = __node; \ |
74 | | _outNode(out->outname, &node->fldname); \ |
75 | | } |
76 | | |
77 | | #define WRITE_NODE_PTR_FIELD(outname, outname_json, fldname) \ |
78 | 0 | if (node->fldname != NULL) { \ |
79 | 0 | PgQuery__Node *__node = palloc(sizeof(PgQuery__Node)); \ |
80 | 0 | pg_query__node__init(__node); \ |
81 | 0 | out->outname = __node; \ |
82 | 0 | _outNode(out->outname, node->fldname); \ |
83 | 0 | } |
84 | | |
85 | | #define WRITE_SPECIFIC_NODE_FIELD(typename, typename_underscore, outname, outname_json, fldname) \ |
86 | 0 | { \ |
87 | 0 | PgQuery__##typename *__node = palloc(sizeof(PgQuery__##typename)); \ |
88 | 0 | pg_query__##typename_underscore##__init(__node); \ |
89 | 0 | _out##typename(__node, &node->fldname); \ |
90 | 0 | out->outname = __node; \ |
91 | 0 | } |
92 | | |
93 | | #define WRITE_SPECIFIC_NODE_PTR_FIELD(typename, typename_underscore, outname, outname_json, fldname) \ |
94 | 0 | if (node->fldname != NULL) { \ |
95 | 0 | PgQuery__##typename *__node = palloc(sizeof(PgQuery__##typename)); \ |
96 | 0 | pg_query__##typename_underscore##__init(__node); \ |
97 | 0 | _out##typename(__node, node->fldname); \ |
98 | 0 | out->outname = __node; \ |
99 | 0 | } |
100 | | |
101 | | static void _outNode(PgQuery__Node* out, const void *obj); |
102 | | |
103 | | static void |
104 | | _outList(PgQuery__List* out, const List *node) |
105 | 0 | { |
106 | 0 | const ListCell *lc; |
107 | 0 | int i = 0; |
108 | 0 | out->n_items = list_length(node); |
109 | 0 | out->items = palloc(sizeof(PgQuery__Node*) * out->n_items); |
110 | 0 | foreach(lc, node) |
111 | 0 | { |
112 | 0 | out->items[i] = palloc(sizeof(PgQuery__Node)); |
113 | 0 | pg_query__node__init(out->items[i]); |
114 | 0 | _outNode(out->items[i], lfirst(lc)); |
115 | 0 | i++; |
116 | 0 | } |
117 | 0 | } |
118 | | |
119 | | static void |
120 | | _outIntList(PgQuery__IntList* out, const List *node) |
121 | 0 | { |
122 | 0 | const ListCell *lc; |
123 | 0 | int i = 0; |
124 | 0 | out->n_items = list_length(node); |
125 | 0 | out->items = palloc(sizeof(PgQuery__Node*) * out->n_items); |
126 | 0 | foreach(lc, node) |
127 | 0 | { |
128 | 0 | out->items[i] = palloc(sizeof(PgQuery__Node)); |
129 | 0 | pg_query__node__init(out->items[i]); |
130 | 0 | _outNode(out->items[i], lfirst(lc)); |
131 | 0 | i++; |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | | static void |
136 | | _outOidList(PgQuery__OidList* out, const List *node) |
137 | 0 | { |
138 | 0 | const ListCell *lc; |
139 | 0 | int i = 0; |
140 | 0 | out->n_items = list_length(node); |
141 | 0 | out->items = palloc(sizeof(PgQuery__Node*) * out->n_items); |
142 | 0 | foreach(lc, node) |
143 | 0 | { |
144 | 0 | out->items[i] = palloc(sizeof(PgQuery__Node)); |
145 | 0 | pg_query__node__init(out->items[i]); |
146 | 0 | _outNode(out->items[i], lfirst(lc)); |
147 | 0 | i++; |
148 | 0 | } |
149 | 0 | } |
150 | | |
151 | | // TODO: Add Bitmapset |
152 | | |
153 | | static void |
154 | | _outInteger(PgQuery__Integer* out, const Integer *node) |
155 | 0 | { |
156 | 0 | out->ival = node->ival; |
157 | 0 | } |
158 | | |
159 | | static void |
160 | | _outFloat(PgQuery__Float* out, const Float *node) |
161 | 0 | { |
162 | 0 | out->fval = node->fval; |
163 | 0 | } |
164 | | |
165 | | static void |
166 | | _outBoolean(PgQuery__Boolean* out, const Boolean *node) |
167 | 0 | { |
168 | 0 | out->boolval = node->boolval; |
169 | 0 | } |
170 | | |
171 | | static void |
172 | | _outString(PgQuery__String* out, const String *node) |
173 | 0 | { |
174 | 0 | out->sval = node->sval; |
175 | 0 | } |
176 | | |
177 | | static void |
178 | | _outBitString(PgQuery__BitString* out, const BitString *node) |
179 | 0 | { |
180 | 0 | out->bsval = node->bsval; |
181 | 0 | } |
182 | | |
183 | | static void |
184 | | _outAConst(PgQuery__AConst* out, const A_Const *node) |
185 | 0 | { |
186 | 0 | out->isnull = node->isnull; |
187 | 0 | out->location = node->location; |
188 | |
|
189 | 0 | if (!node->isnull) { |
190 | 0 | switch (nodeTag(&node->val.node)) { |
191 | 0 | case T_Integer: { |
192 | 0 | PgQuery__Integer *value = palloc(sizeof(PgQuery__Integer)); |
193 | 0 | pg_query__integer__init(value); |
194 | 0 | value->ival = node->val.ival.ival; |
195 | |
|
196 | 0 | out->val_case = PG_QUERY__A__CONST__VAL_IVAL; |
197 | 0 | out->ival = value; |
198 | 0 | break; |
199 | 0 | } |
200 | 0 | case T_Float: { |
201 | 0 | PgQuery__Float *value = palloc(sizeof(PgQuery__Float)); |
202 | 0 | pg_query__float__init(value); |
203 | 0 | value->fval = pstrdup(node->val.fval.fval); |
204 | |
|
205 | 0 | out->val_case = PG_QUERY__A__CONST__VAL_FVAL; |
206 | 0 | out->fval = value; |
207 | 0 | break; |
208 | 0 | } |
209 | 0 | case T_Boolean: { |
210 | 0 | PgQuery__Boolean *value = palloc(sizeof(PgQuery__Boolean)); |
211 | 0 | pg_query__boolean__init(value); |
212 | 0 | value->boolval = node->val.boolval.boolval; |
213 | |
|
214 | 0 | out->val_case = PG_QUERY__A__CONST__VAL_BOOLVAL; |
215 | 0 | out->boolval = value; |
216 | 0 | break; |
217 | 0 | } |
218 | 0 | case T_String: { |
219 | 0 | PgQuery__String *value = palloc(sizeof(PgQuery__String)); |
220 | 0 | pg_query__string__init(value); |
221 | 0 | value->sval = pstrdup(node->val.sval.sval); |
222 | |
|
223 | 0 | out->val_case = PG_QUERY__A__CONST__VAL_SVAL; |
224 | 0 | out->sval = value; |
225 | 0 | break; |
226 | 0 | } |
227 | 0 | case T_BitString: { |
228 | 0 | PgQuery__BitString *value = palloc(sizeof(PgQuery__BitString)); |
229 | 0 | pg_query__bit_string__init(value); |
230 | 0 | value->bsval = pstrdup(node->val.bsval.bsval); |
231 | |
|
232 | 0 | out->val_case = PG_QUERY__A__CONST__VAL_BSVAL; |
233 | 0 | out->bsval = value; |
234 | 0 | break; |
235 | 0 | } |
236 | 0 | default: |
237 | | // Unreachable |
238 | 0 | Assert(false); |
239 | 0 | } |
240 | 0 | } |
241 | 0 | } |
242 | | |
243 | | #include "pg_query_enum_defs.c" |
244 | | #include "pg_query_outfuncs_defs.c" |
245 | | |
246 | | static void |
247 | | _outNode(PgQuery__Node* out, const void *obj) |
248 | | { |
249 | | if (obj == NULL) |
250 | | return; // Keep out as NULL |
251 | | |
252 | | switch (nodeTag(obj)) |
253 | | { |
254 | | #include "pg_query_outfuncs_conds.c" |
255 | | |
256 | | default: |
257 | | printf("could not dump unrecognized node type: %d", (int) nodeTag(obj)); |
258 | | elog(WARNING, "could not dump unrecognized node type: %d", |
259 | | (int) nodeTag(obj)); |
260 | | |
261 | | return; |
262 | | } |
263 | | } |
264 | | |
265 | | PgQueryProtobuf |
266 | | pg_query_nodes_to_protobuf(const void *obj) |
267 | 0 | { |
268 | 0 | PgQueryProtobuf protobuf; |
269 | 0 | const ListCell *lc; |
270 | 0 | int i = 0; |
271 | 0 | PgQuery__ParseResult parse_result = PG_QUERY__PARSE_RESULT__INIT; |
272 | |
|
273 | 0 | parse_result.version = PG_VERSION_NUM; |
274 | |
|
275 | 0 | if (obj == NULL) { |
276 | 0 | parse_result.n_stmts = 0; |
277 | 0 | parse_result.stmts = NULL; |
278 | 0 | } |
279 | 0 | else |
280 | 0 | { |
281 | 0 | parse_result.n_stmts = list_length(obj); |
282 | 0 | parse_result.stmts = palloc(sizeof(PgQuery__RawStmt*) * parse_result.n_stmts); |
283 | 0 | foreach(lc, obj) |
284 | 0 | { |
285 | 0 | parse_result.stmts[i] = palloc(sizeof(PgQuery__RawStmt)); |
286 | 0 | pg_query__raw_stmt__init(parse_result.stmts[i]); |
287 | 0 | _outRawStmt(parse_result.stmts[i], lfirst(lc)); |
288 | 0 | i++; |
289 | 0 | } |
290 | 0 | } |
291 | |
|
292 | 0 | protobuf.len = pg_query__parse_result__get_packed_size(&parse_result); |
293 | | // Note: This is intentionally malloc so exiting the memory context doesn't free this |
294 | 0 | protobuf.data = malloc(sizeof(char) * protobuf.len); |
295 | 0 | pg_query__parse_result__pack(&parse_result, (void*) protobuf.data); |
296 | |
|
297 | 0 | return protobuf; |
298 | 0 | } |