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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -1
  3. data/README.md +1 -1
  4. data/Rakefile +3 -2
  5. data/ext/pg_query/extconf.rb +2 -2
  6. data/ext/pg_query/include/pg_query.h +32 -2
  7. data/ext/pg_query/include/postgres/access/amapi.h +1 -1
  8. data/ext/pg_query/include/postgres/access/slru.h +1 -1
  9. data/ext/pg_query/include/postgres/access/tableam.h +11 -4
  10. data/ext/pg_query/include/postgres/access/xlog.h +1 -0
  11. data/ext/pg_query/include/postgres/access/xlogdefs.h +2 -1
  12. data/ext/pg_query/include/postgres/commands/defrem.h +1 -1
  13. data/ext/pg_query/include/postgres/commands/trigger.h +18 -0
  14. data/ext/pg_query/include/postgres/executor/executor.h +4 -0
  15. data/ext/pg_query/include/postgres/mb/pg_wchar.h +2 -0
  16. data/ext/pg_query/include/postgres/miscadmin.h +2 -1
  17. data/ext/pg_query/include/postgres/nodes/execnodes.h +6 -8
  18. data/ext/pg_query/include/postgres/nodes/pathnodes.h +1 -2
  19. data/ext/pg_query/include/postgres/pg_config.h +10 -9
  20. data/ext/pg_query/include/postgres/pg_config_manual.h +2 -0
  21. data/ext/pg_query/include/postgres/port/atomics/generic-gcc.h +10 -2
  22. data/ext/pg_query/include/postgres/port/pg_iovec.h +9 -3
  23. data/ext/pg_query/include/postgres/replication/reorderbuffer.h +29 -9
  24. data/ext/pg_query/include/postgres/replication/slot.h +2 -0
  25. data/ext/pg_query/include/postgres/utils/elog.h +1 -0
  26. data/ext/pg_query/include/postgres/utils/guc.h +1 -1
  27. data/ext/pg_query/include/postgres/utils/guc_hooks.h +0 -2
  28. data/ext/pg_query/include/postgres/utils/pg_locale.h +5 -0
  29. data/ext/pg_query/include/postgres_deparse.h +34 -0
  30. data/ext/pg_query/include/protobuf/pg_query.pb-c.h +673 -516
  31. data/ext/pg_query/pg_query.pb-c.c +488 -0
  32. data/ext/pg_query/pg_query_deparse.c +148 -15
  33. data/ext/pg_query/pg_query_internal.h +9 -8
  34. data/ext/pg_query/pg_query_is_utility_stmt.c +70 -0
  35. data/ext/pg_query/pg_query_normalize.c +3 -0
  36. data/ext/pg_query/pg_query_raw_tree_walker_supports.c +117 -0
  37. data/ext/pg_query/pg_query_ruby.c +150 -0
  38. data/ext/pg_query/pg_query_summary.c +941 -0
  39. data/ext/pg_query/pg_query_summary.h +109 -0
  40. data/ext/pg_query/pg_query_summary_statement_type.c +797 -0
  41. data/ext/pg_query/pg_query_summary_truncate.c +530 -0
  42. data/ext/pg_query/postgres_deparse.c +4481 -3870
  43. data/ext/pg_query/src_backend_catalog_namespace.c +29 -0
  44. data/ext/pg_query/src_backend_nodes_bitmapset.c +84 -1
  45. data/ext/pg_query/src_backend_nodes_list.c +60 -1
  46. data/ext/pg_query/src_backend_parser_gram.c +739 -732
  47. data/ext/pg_query/src_backend_utils_activity_pgstat_database.c +2 -2
  48. data/ext/pg_query/src_backend_utils_error_elog.c +11 -0
  49. data/ext/pg_query/src_backend_utils_mb_mbutils.c +43 -4
  50. data/ext/pg_query/src_backend_utils_mmgr_alignedalloc.c +22 -7
  51. data/ext/pg_query/src_backend_utils_mmgr_aset.c +3 -3
  52. data/ext/pg_query/src_backend_utils_mmgr_bump.c +1 -1
  53. data/ext/pg_query/src_common_stringinfo.c +20 -0
  54. data/ext/pg_query/src_common_wchar.c +46 -6
  55. data/lib/pg_query/deparse.rb +29 -8
  56. data/lib/pg_query/parse.rb +19 -0
  57. data/lib/pg_query/pg_query_pb.rb +7 -2
  58. data/lib/pg_query/split.rb +20 -0
  59. data/lib/pg_query/treewalker.rb +9 -7
  60. data/lib/pg_query/version.rb +1 -1
  61. data/lib/pg_query.rb +1 -0
  62. metadata +10 -3
  63. 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
+ }