pg_query 6.1.0 → 6.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +38 -1
- data/README.md +1 -1
- data/Rakefile +3 -2
- data/ext/pg_query/extconf.rb +2 -2
- data/ext/pg_query/include/pg_query.h +32 -2
- data/ext/pg_query/include/postgres/access/amapi.h +1 -1
- data/ext/pg_query/include/postgres/access/slru.h +1 -1
- data/ext/pg_query/include/postgres/access/tableam.h +11 -4
- data/ext/pg_query/include/postgres/access/xlog.h +1 -0
- data/ext/pg_query/include/postgres/access/xlogdefs.h +2 -1
- data/ext/pg_query/include/postgres/commands/defrem.h +1 -1
- data/ext/pg_query/include/postgres/commands/trigger.h +18 -0
- data/ext/pg_query/include/postgres/executor/executor.h +4 -0
- data/ext/pg_query/include/postgres/mb/pg_wchar.h +2 -0
- data/ext/pg_query/include/postgres/miscadmin.h +2 -1
- data/ext/pg_query/include/postgres/nodes/execnodes.h +6 -8
- data/ext/pg_query/include/postgres/nodes/pathnodes.h +1 -2
- data/ext/pg_query/include/postgres/pg_config.h +10 -9
- data/ext/pg_query/include/postgres/pg_config_manual.h +2 -0
- data/ext/pg_query/include/postgres/port/atomics/generic-gcc.h +10 -2
- data/ext/pg_query/include/postgres/port/pg_iovec.h +9 -3
- data/ext/pg_query/include/postgres/replication/reorderbuffer.h +29 -9
- data/ext/pg_query/include/postgres/replication/slot.h +2 -0
- data/ext/pg_query/include/postgres/utils/elog.h +1 -0
- data/ext/pg_query/include/postgres/utils/guc.h +1 -1
- data/ext/pg_query/include/postgres/utils/guc_hooks.h +0 -2
- data/ext/pg_query/include/postgres/utils/pg_locale.h +5 -0
- data/ext/pg_query/include/postgres_deparse.h +34 -0
- data/ext/pg_query/include/protobuf/pg_query.pb-c.h +673 -516
- data/ext/pg_query/pg_query.pb-c.c +488 -0
- data/ext/pg_query/pg_query_deparse.c +148 -15
- data/ext/pg_query/pg_query_internal.h +9 -8
- data/ext/pg_query/pg_query_is_utility_stmt.c +70 -0
- data/ext/pg_query/pg_query_normalize.c +3 -0
- data/ext/pg_query/pg_query_raw_tree_walker_supports.c +117 -0
- data/ext/pg_query/pg_query_ruby.c +150 -0
- data/ext/pg_query/pg_query_summary.c +941 -0
- data/ext/pg_query/pg_query_summary.h +109 -0
- data/ext/pg_query/pg_query_summary_statement_type.c +797 -0
- data/ext/pg_query/pg_query_summary_truncate.c +530 -0
- data/ext/pg_query/postgres_deparse.c +4481 -3870
- data/ext/pg_query/src_backend_catalog_namespace.c +29 -0
- data/ext/pg_query/src_backend_nodes_bitmapset.c +84 -1
- data/ext/pg_query/src_backend_nodes_list.c +60 -1
- data/ext/pg_query/src_backend_parser_gram.c +739 -732
- data/ext/pg_query/src_backend_utils_activity_pgstat_database.c +2 -2
- data/ext/pg_query/src_backend_utils_error_elog.c +11 -0
- data/ext/pg_query/src_backend_utils_mb_mbutils.c +43 -4
- data/ext/pg_query/src_backend_utils_mmgr_alignedalloc.c +22 -7
- data/ext/pg_query/src_backend_utils_mmgr_aset.c +3 -3
- data/ext/pg_query/src_backend_utils_mmgr_bump.c +1 -1
- data/ext/pg_query/src_common_stringinfo.c +20 -0
- data/ext/pg_query/src_common_wchar.c +46 -6
- data/lib/pg_query/deparse.rb +29 -8
- data/lib/pg_query/parse.rb +19 -0
- data/lib/pg_query/pg_query_pb.rb +7 -2
- data/lib/pg_query/split.rb +20 -0
- data/lib/pg_query/treewalker.rb +9 -7
- data/lib/pg_query/version.rb +1 -1
- data/lib/pg_query.rb +1 -0
- metadata +10 -3
- data/ext/pg_query/postgres_deparse.h +0 -9
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
#include "pg_query.h"
|
|
2
|
+
#include "pg_query_internal.h"
|
|
3
|
+
#include "pg_query_summary.h"
|
|
4
|
+
|
|
5
|
+
#include "nodes/pg_list.h"
|
|
6
|
+
#include "nodes/nodeFuncs.h"
|
|
7
|
+
|
|
8
|
+
#include "mb/pg_wchar.h"
|
|
9
|
+
|
|
10
|
+
enum TruncationAttr
|
|
11
|
+
{
|
|
12
|
+
TRUNCATION_TARGET_LIST,
|
|
13
|
+
TRUNCATION_WHERE_CLAUSE,
|
|
14
|
+
TRUNCATION_VALUES_LISTS,
|
|
15
|
+
TRUNCATION_COLS,
|
|
16
|
+
TRUNCATION_CTE_QUERY,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
typedef struct
|
|
20
|
+
{
|
|
21
|
+
List *truncations;
|
|
22
|
+
int32_t depth;
|
|
23
|
+
} TruncationState;
|
|
24
|
+
|
|
25
|
+
typedef struct
|
|
26
|
+
{
|
|
27
|
+
enum TruncationAttr attr;
|
|
28
|
+
Node *node;
|
|
29
|
+
int32_t depth;
|
|
30
|
+
int32_t length;
|
|
31
|
+
} PossibleTruncation;
|
|
32
|
+
|
|
33
|
+
static bool generate_possible_truncations(Node *tree, TruncationState * state);
|
|
34
|
+
static void apply_truncations(Summary * summary, Node *tree, TruncationState * state, int truncate_limit);
|
|
35
|
+
static int cmp_possible_truncations(const ListCell *a, const ListCell *b);
|
|
36
|
+
|
|
37
|
+
static int32_t select_target_list_len(List *nodes);
|
|
38
|
+
static int32_t select_values_lists_len(List *nodes);
|
|
39
|
+
static int32_t update_target_list_len(List *nodes);
|
|
40
|
+
static int32_t where_clause_len(Node *node);
|
|
41
|
+
static int32_t cols_len(List *nodes);
|
|
42
|
+
|
|
43
|
+
static ColumnRef *dummy_column(void);
|
|
44
|
+
static ResTarget *dummy_target(void);
|
|
45
|
+
static Node *dummy_select(List *targetList, Node *whereClause, List *valuesLists);
|
|
46
|
+
static Node *dummy_insert(List *cols);
|
|
47
|
+
static Node *dummy_update(List *targetList);
|
|
48
|
+
|
|
49
|
+
static size_t deparse_stmt_len(Node *node);
|
|
50
|
+
static StringInfo deparse_raw_stmt_list(List *stmts);
|
|
51
|
+
|
|
52
|
+
/* Given a walked parse tree and summary, store the truncated version in `summary`. */
|
|
53
|
+
void
|
|
54
|
+
pg_query_summary_truncate(Summary * summary, Node *tree, int truncate_limit)
|
|
55
|
+
{
|
|
56
|
+
TruncationState state = {NULL, 0};
|
|
57
|
+
|
|
58
|
+
StringInfo output = deparse_raw_stmt_list((List *) tree);
|
|
59
|
+
|
|
60
|
+
if (output->len <= truncate_limit)
|
|
61
|
+
{
|
|
62
|
+
summary->truncated_query = output->data;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
destroyStringInfo(output);
|
|
67
|
+
|
|
68
|
+
generate_possible_truncations(tree, &state);
|
|
69
|
+
|
|
70
|
+
list_sort(state.truncations, cmp_possible_truncations);
|
|
71
|
+
apply_truncations(summary, tree, &state, truncate_limit);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static void
|
|
75
|
+
truncate_mbstr(char *mbstr, size_t max_chars)
|
|
76
|
+
{
|
|
77
|
+
/* Determine the number of characters in mbstr. */
|
|
78
|
+
int n_chars = pg_mbstrlen(mbstr);
|
|
79
|
+
|
|
80
|
+
/* If we don't need to truncate the string, return immediately. */
|
|
81
|
+
if (n_chars <= max_chars)
|
|
82
|
+
return;
|
|
83
|
+
|
|
84
|
+
/* Determine how many bytes hold `max_chars - 3`. */
|
|
85
|
+
int n_bytes = pg_mbcharcliplen(mbstr, n_chars, max_chars - 3);
|
|
86
|
+
|
|
87
|
+
/* Actually truncate it. */
|
|
88
|
+
strncpy(mbstr + n_bytes, "...", 4);
|
|
89
|
+
mbstr[n_bytes + 3] = '\0';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static void
|
|
93
|
+
add_truncation(TruncationState * state, enum TruncationAttr attr,
|
|
94
|
+
Node *node, int32_t length)
|
|
95
|
+
{
|
|
96
|
+
/* Don't bother truncating if it won't become shorter. */
|
|
97
|
+
if (length <= 3)
|
|
98
|
+
return;
|
|
99
|
+
|
|
100
|
+
PossibleTruncation *truncation = palloc(sizeof(PossibleTruncation));
|
|
101
|
+
|
|
102
|
+
truncation->attr = attr;
|
|
103
|
+
truncation->node = node;
|
|
104
|
+
truncation->depth = state->depth;
|
|
105
|
+
truncation->length = length;
|
|
106
|
+
|
|
107
|
+
state->truncations = lappend(state->truncations, truncation);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static void
|
|
111
|
+
add_truncation_where_clause(TruncationState * state, Node *node, Node *whereClause)
|
|
112
|
+
{
|
|
113
|
+
if (whereClause == NULL)
|
|
114
|
+
return;
|
|
115
|
+
|
|
116
|
+
add_truncation(state,
|
|
117
|
+
TRUNCATION_WHERE_CLAUSE,
|
|
118
|
+
node,
|
|
119
|
+
where_clause_len(whereClause));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
static bool
|
|
123
|
+
generate_possible_truncations(Node *node, TruncationState * state)
|
|
124
|
+
{
|
|
125
|
+
if (node == NULL)
|
|
126
|
+
return false;
|
|
127
|
+
|
|
128
|
+
switch (nodeTag(node))
|
|
129
|
+
{
|
|
130
|
+
case T_RawStmt:
|
|
131
|
+
return generate_possible_truncations(castNode(RawStmt, node)->stmt, state);
|
|
132
|
+
|
|
133
|
+
case T_SelectStmt:
|
|
134
|
+
{
|
|
135
|
+
SelectStmt *stmt = castNode(SelectStmt, node);
|
|
136
|
+
|
|
137
|
+
if (stmt->targetList != NULL)
|
|
138
|
+
add_truncation(state,
|
|
139
|
+
TRUNCATION_TARGET_LIST,
|
|
140
|
+
node,
|
|
141
|
+
select_target_list_len(stmt->targetList));
|
|
142
|
+
|
|
143
|
+
add_truncation_where_clause(state, node, stmt->whereClause);
|
|
144
|
+
|
|
145
|
+
if (stmt->valuesLists != NULL)
|
|
146
|
+
add_truncation(state,
|
|
147
|
+
TRUNCATION_VALUES_LISTS,
|
|
148
|
+
node,
|
|
149
|
+
select_values_lists_len(stmt->valuesLists));
|
|
150
|
+
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
case T_InsertStmt:
|
|
155
|
+
{
|
|
156
|
+
InsertStmt *stmt = castNode(InsertStmt, node);
|
|
157
|
+
|
|
158
|
+
if (stmt->cols != NULL)
|
|
159
|
+
add_truncation(state, TRUNCATION_COLS, node, cols_len(stmt->cols));
|
|
160
|
+
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
case T_UpdateStmt:
|
|
165
|
+
{
|
|
166
|
+
UpdateStmt *stmt = castNode(UpdateStmt, node);
|
|
167
|
+
|
|
168
|
+
if (stmt->targetList != NULL)
|
|
169
|
+
add_truncation(state,
|
|
170
|
+
TRUNCATION_TARGET_LIST,
|
|
171
|
+
node,
|
|
172
|
+
update_target_list_len(stmt->targetList));
|
|
173
|
+
|
|
174
|
+
add_truncation_where_clause(state, node, stmt->whereClause);
|
|
175
|
+
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
case T_DeleteStmt:
|
|
180
|
+
{
|
|
181
|
+
DeleteStmt *stmt = castNode(DeleteStmt, node);
|
|
182
|
+
|
|
183
|
+
add_truncation_where_clause(state, node, stmt->whereClause);
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
case T_CopyStmt:
|
|
188
|
+
{
|
|
189
|
+
CopyStmt *stmt = castNode(CopyStmt, node);
|
|
190
|
+
|
|
191
|
+
add_truncation_where_clause(state, node, stmt->whereClause);
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
case T_IndexStmt:
|
|
196
|
+
{
|
|
197
|
+
IndexStmt *stmt = castNode(IndexStmt, node);
|
|
198
|
+
|
|
199
|
+
add_truncation_where_clause(state, node, stmt->whereClause);
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
case T_RuleStmt:
|
|
204
|
+
{
|
|
205
|
+
RuleStmt *stmt = castNode(RuleStmt, node);
|
|
206
|
+
|
|
207
|
+
add_truncation_where_clause(state, node, stmt->whereClause);
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
case T_CommonTableExpr:
|
|
212
|
+
{
|
|
213
|
+
CommonTableExpr *stmt = castNode(CommonTableExpr, node);
|
|
214
|
+
|
|
215
|
+
if (stmt->ctequery != NULL)
|
|
216
|
+
{
|
|
217
|
+
size_t query_len = deparse_stmt_len((Node *) stmt->ctequery);
|
|
218
|
+
|
|
219
|
+
add_truncation(state,
|
|
220
|
+
TRUNCATION_CTE_QUERY,
|
|
221
|
+
node,
|
|
222
|
+
query_len);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
case T_InferClause:
|
|
229
|
+
{
|
|
230
|
+
InferClause *stmt = castNode(InferClause, node);
|
|
231
|
+
|
|
232
|
+
add_truncation_where_clause(state, node, stmt->whereClause);
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
case T_OnConflictClause:
|
|
237
|
+
{
|
|
238
|
+
OnConflictClause *stmt = castNode(OnConflictClause, node);
|
|
239
|
+
|
|
240
|
+
if (stmt->targetList != NULL)
|
|
241
|
+
add_truncation(state,
|
|
242
|
+
TRUNCATION_TARGET_LIST,
|
|
243
|
+
node,
|
|
244
|
+
update_target_list_len(stmt->targetList));
|
|
245
|
+
|
|
246
|
+
add_truncation_where_clause(state, node, stmt->whereClause);
|
|
247
|
+
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
default:
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (!pg_query_raw_tree_walker_supports(node))
|
|
256
|
+
return false;
|
|
257
|
+
|
|
258
|
+
int old_depth = state->depth;
|
|
259
|
+
|
|
260
|
+
state->depth++;
|
|
261
|
+
|
|
262
|
+
bool result = raw_expression_tree_walker(node, generate_possible_truncations, (void *) state);
|
|
263
|
+
|
|
264
|
+
/* Restore old depth value, since the current node (or its parents) may */
|
|
265
|
+
/* have sibling elements. */
|
|
266
|
+
state->depth = old_depth;
|
|
267
|
+
|
|
268
|
+
return result;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
static int
|
|
272
|
+
cmp_possible_truncations(const ListCell *a, const ListCell *b)
|
|
273
|
+
{
|
|
274
|
+
const PossibleTruncation *pt_a = lfirst(a);
|
|
275
|
+
const PossibleTruncation *pt_b = lfirst(b);
|
|
276
|
+
|
|
277
|
+
int depth_cmp = pt_b->depth - pt_a->depth;
|
|
278
|
+
|
|
279
|
+
if (depth_cmp != 0)
|
|
280
|
+
return depth_cmp;
|
|
281
|
+
|
|
282
|
+
return pt_b->length - pt_a->length;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
static void
|
|
286
|
+
global_replace(char *str, char *pattern, char *replacement)
|
|
287
|
+
{
|
|
288
|
+
size_t plen = strlen(pattern);
|
|
289
|
+
size_t rlen = strlen(replacement);
|
|
290
|
+
char *s = str;
|
|
291
|
+
|
|
292
|
+
Assert(plen >= rlen);
|
|
293
|
+
|
|
294
|
+
while ((s = strstr(s, pattern)) != NULL)
|
|
295
|
+
{
|
|
296
|
+
memcpy(s, replacement, rlen);
|
|
297
|
+
|
|
298
|
+
/* Shift remainder of the string if needed */
|
|
299
|
+
if (plen > rlen)
|
|
300
|
+
memmove(s + rlen, s + plen, strlen(s + plen) + 1);
|
|
301
|
+
|
|
302
|
+
s += rlen;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
static void
|
|
307
|
+
apply_truncations(Summary * summary, Node *tree, TruncationState * state, int truncation_limit)
|
|
308
|
+
{
|
|
309
|
+
List *truncations = state->truncations;
|
|
310
|
+
StringInfo output = NULL;
|
|
311
|
+
ListCell *lc;
|
|
312
|
+
|
|
313
|
+
foreach(lc, state->truncations)
|
|
314
|
+
{
|
|
315
|
+
PossibleTruncation *truncation = lfirst(lc);
|
|
316
|
+
|
|
317
|
+
Node *node = truncation->node;
|
|
318
|
+
enum TruncationAttr attr = truncation->attr;
|
|
319
|
+
|
|
320
|
+
if (IsA(node, SelectStmt) && attr == TRUNCATION_TARGET_LIST)
|
|
321
|
+
castNode(SelectStmt, node)->targetList = list_make1(dummy_target());
|
|
322
|
+
else if (IsA(node, SelectStmt) && attr == TRUNCATION_WHERE_CLAUSE)
|
|
323
|
+
castNode(SelectStmt, node)->whereClause = (Node *) dummy_column();
|
|
324
|
+
else if (IsA(node, SelectStmt) && attr == TRUNCATION_VALUES_LISTS)
|
|
325
|
+
castNode(SelectStmt, node)->valuesLists = list_make1(list_make1(dummy_column()));
|
|
326
|
+
else if (IsA(node, UpdateStmt) && attr == TRUNCATION_TARGET_LIST)
|
|
327
|
+
castNode(UpdateStmt, node)->targetList = list_make1(dummy_target());
|
|
328
|
+
else if (IsA(node, InsertStmt) && attr == TRUNCATION_COLS)
|
|
329
|
+
castNode(InsertStmt, node)->cols = list_make1(dummy_target());
|
|
330
|
+
else if (IsA(node, UpdateStmt) && attr == TRUNCATION_WHERE_CLAUSE)
|
|
331
|
+
castNode(UpdateStmt, node)->whereClause = (Node *) dummy_column();
|
|
332
|
+
else if (IsA(node, DeleteStmt) && attr == TRUNCATION_WHERE_CLAUSE)
|
|
333
|
+
castNode(DeleteStmt, node)->whereClause = (Node *) dummy_column();
|
|
334
|
+
else if (IsA(node, CopyStmt) && attr == TRUNCATION_WHERE_CLAUSE)
|
|
335
|
+
castNode(CopyStmt, node)->whereClause = (Node *) dummy_column();
|
|
336
|
+
else if (IsA(node, IndexStmt) && attr == TRUNCATION_WHERE_CLAUSE)
|
|
337
|
+
castNode(IndexStmt, node)->whereClause = (Node *) dummy_column();
|
|
338
|
+
else if (IsA(node, RuleStmt) && attr == TRUNCATION_WHERE_CLAUSE)
|
|
339
|
+
castNode(RuleStmt, node)->whereClause = (Node *) dummy_column();
|
|
340
|
+
else if (IsA(node, CommonTableExpr) && attr == TRUNCATION_CTE_QUERY)
|
|
341
|
+
castNode(CommonTableExpr, node)->ctequery = dummy_select(NULL, (Node *) dummy_column(), NULL);
|
|
342
|
+
else if (IsA(node, InferClause) && attr == TRUNCATION_WHERE_CLAUSE)
|
|
343
|
+
castNode(InferClause, node)->whereClause = (Node *) dummy_column();
|
|
344
|
+
else if (IsA(node, OnConflictClause) && attr == TRUNCATION_TARGET_LIST)
|
|
345
|
+
castNode(OnConflictClause, node)->targetList = list_make1(dummy_target());
|
|
346
|
+
else if (IsA(node, OnConflictClause) && attr == TRUNCATION_WHERE_CLAUSE)
|
|
347
|
+
castNode(OnConflictClause, node)->whereClause = (Node *) dummy_column();
|
|
348
|
+
else
|
|
349
|
+
elog(ERROR, "apply_truncations() got unknown truncation type");
|
|
350
|
+
|
|
351
|
+
if (output)
|
|
352
|
+
destroyStringInfo(output);
|
|
353
|
+
output = deparse_raw_stmt_list((List *) tree);
|
|
354
|
+
|
|
355
|
+
global_replace(output->data, "SELECT \"…\" AS \"…\"", "SELECT \"…\"");
|
|
356
|
+
global_replace(output->data, "SELECT WHERE \"…\"", "\"…\"");
|
|
357
|
+
global_replace(output->data, "\"…\"", "...");
|
|
358
|
+
|
|
359
|
+
if (strlen(output->data) <= truncation_limit)
|
|
360
|
+
{
|
|
361
|
+
summary->truncated_query = output->data;
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (!output)
|
|
367
|
+
output = deparse_raw_stmt_list((List *) tree);
|
|
368
|
+
|
|
369
|
+
truncate_mbstr(output->data, truncation_limit);
|
|
370
|
+
summary->truncated_query = output->data;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
static ColumnRef *
|
|
374
|
+
dummy_column(void)
|
|
375
|
+
{
|
|
376
|
+
ColumnRef *colref = makeNode(ColumnRef);
|
|
377
|
+
|
|
378
|
+
colref->fields = list_make1(makeString(pstrdup("…")));
|
|
379
|
+
colref->location = 0;
|
|
380
|
+
|
|
381
|
+
return colref;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
static ResTarget *
|
|
385
|
+
dummy_target(void)
|
|
386
|
+
{
|
|
387
|
+
ResTarget *target = makeNode(ResTarget);
|
|
388
|
+
|
|
389
|
+
target->name = pstrdup("…");
|
|
390
|
+
target->val = (Node *) dummy_column();
|
|
391
|
+
|
|
392
|
+
/*
|
|
393
|
+
* TODO:docs for ResTarget say "-1 if unknown"-- would that be more
|
|
394
|
+
* correct ? (see also, dummy_column())
|
|
395
|
+
*/
|
|
396
|
+
target->location = 0;
|
|
397
|
+
|
|
398
|
+
return target;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
static Node *
|
|
402
|
+
dummy_select(List *targetList, Node *whereClause, List *valuesLists)
|
|
403
|
+
{
|
|
404
|
+
SelectStmt *stmt = makeNode(SelectStmt);
|
|
405
|
+
|
|
406
|
+
stmt->targetList = targetList;
|
|
407
|
+
stmt->whereClause = whereClause;
|
|
408
|
+
stmt->valuesLists = valuesLists;
|
|
409
|
+
|
|
410
|
+
return (Node *) stmt;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
static Node *
|
|
414
|
+
dummy_insert(List *cols)
|
|
415
|
+
{
|
|
416
|
+
RangeVar *rv = makeNode(RangeVar);
|
|
417
|
+
|
|
418
|
+
rv->relname = pstrdup("x");
|
|
419
|
+
rv->inh = true;
|
|
420
|
+
rv->relpersistence = 'p';
|
|
421
|
+
rv->location = 0;
|
|
422
|
+
|
|
423
|
+
InsertStmt *stmt = makeNode(InsertStmt);
|
|
424
|
+
|
|
425
|
+
stmt->relation = rv;
|
|
426
|
+
stmt->cols = cols;
|
|
427
|
+
stmt->override = 1;
|
|
428
|
+
|
|
429
|
+
return (Node *) stmt;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
static Node *
|
|
433
|
+
dummy_update(List *targetList)
|
|
434
|
+
{
|
|
435
|
+
RangeVar *rv = makeNode(RangeVar);
|
|
436
|
+
|
|
437
|
+
rv->relname = pstrdup("x");
|
|
438
|
+
rv->inh = true;
|
|
439
|
+
rv->relpersistence = 'p';
|
|
440
|
+
rv->location = 0;
|
|
441
|
+
|
|
442
|
+
UpdateStmt *stmt = makeNode(UpdateStmt);
|
|
443
|
+
|
|
444
|
+
stmt->relation = rv;
|
|
445
|
+
stmt->targetList = targetList;
|
|
446
|
+
|
|
447
|
+
return (Node *) stmt;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
static int32_t
|
|
451
|
+
select_target_list_len(List *nodes)
|
|
452
|
+
{
|
|
453
|
+
size_t result_len = deparse_stmt_len(dummy_select(nodes, NULL, NULL));
|
|
454
|
+
size_t dummy_len = 7; /* "SELECT " */
|
|
455
|
+
|
|
456
|
+
return (int32_t) result_len - dummy_len;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
static int32_t
|
|
460
|
+
select_values_lists_len(List *nodes)
|
|
461
|
+
{
|
|
462
|
+
size_t result_len = deparse_stmt_len(dummy_select(NULL, NULL, nodes));
|
|
463
|
+
size_t dummy_len = 9; /* "VALUES ()" */
|
|
464
|
+
|
|
465
|
+
return (int32_t) result_len - dummy_len;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
static int32_t
|
|
469
|
+
update_target_list_len(List *nodes)
|
|
470
|
+
{
|
|
471
|
+
size_t result_len = deparse_stmt_len(dummy_update(nodes));
|
|
472
|
+
size_t dummy_len = 13; /* "UPDATE x SET " */
|
|
473
|
+
|
|
474
|
+
return (int32_t) result_len - dummy_len;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
static int32_t
|
|
478
|
+
where_clause_len(Node *node)
|
|
479
|
+
{
|
|
480
|
+
size_t result_len = deparse_stmt_len(dummy_select(NULL, node, NULL));
|
|
481
|
+
size_t dummy_len = 13; /* "SELECT WHERE " */
|
|
482
|
+
|
|
483
|
+
return (int32_t) result_len - dummy_len;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
static int32_t
|
|
487
|
+
cols_len(List *nodes)
|
|
488
|
+
{
|
|
489
|
+
size_t result_len = deparse_stmt_len(dummy_insert(nodes));
|
|
490
|
+
size_t dummy_len = 31; /* "INSERT INTO x () DEFAULT VALUES" */
|
|
491
|
+
|
|
492
|
+
return (int32_t) result_len - dummy_len;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
static size_t
|
|
496
|
+
deparse_stmt_len(Node *node)
|
|
497
|
+
{
|
|
498
|
+
if (!IsA(node, RawStmt))
|
|
499
|
+
{
|
|
500
|
+
RawStmt *raw = makeNode(RawStmt);
|
|
501
|
+
|
|
502
|
+
raw->stmt = node;
|
|
503
|
+
raw->stmt_location = -1;
|
|
504
|
+
raw->stmt_len = 0;
|
|
505
|
+
node = (Node *) raw;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
StringInfo str = deparse_raw_stmt_list(list_make1(node));
|
|
509
|
+
size_t len = str->len;
|
|
510
|
+
|
|
511
|
+
destroyStringInfo(str);
|
|
512
|
+
return len;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
static StringInfo
|
|
516
|
+
deparse_raw_stmt_list(List *stmts)
|
|
517
|
+
{
|
|
518
|
+
PostgresDeparseOpts opts = {0};
|
|
519
|
+
StringInfo str = makeStringInfo();
|
|
520
|
+
ListCell *lc;
|
|
521
|
+
|
|
522
|
+
foreach(lc, stmts)
|
|
523
|
+
{
|
|
524
|
+
deparseRawStmtOpts(str, castNode(RawStmt, lfirst(lc)), opts);
|
|
525
|
+
if (lnext(stmts, lc))
|
|
526
|
+
appendStringInfoString(str, "; ");
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return str;
|
|
530
|
+
}
|