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
@@ -130,8 +130,8 @@ __thread SessionEndType pgStatSessionEndCause = DISCONNECT_NORMAL;
130
130
  /*
131
131
  * Flush out pending stats for the entry
132
132
  *
133
- * If nowait is true, this function returns false if lock could not
134
- * immediately acquired, otherwise true is returned.
133
+ * If nowait is true and the lock could not be immediately acquired, returns
134
+ * false without flushing the entry. Otherwise returns true.
135
135
  */
136
136
  #define PGSTAT_ACCUM_DBCOUNT(item) \
137
137
  (sharedent)->stats.item += (pendingent)->item
@@ -1939,6 +1939,17 @@ write_stderr(const char *fmt,...)
1939
1939
  }
1940
1940
 
1941
1941
 
1942
+
1943
+
1944
+ /*
1945
+ * Write errors to stderr (or by equal means when stderr is
1946
+ * not available) - va_list version
1947
+ */
1948
+ #ifdef WIN32
1949
+ #endif
1950
+ #ifndef WIN32
1951
+ #else
1952
+ #endif
1942
1953
  #ifdef WIN32
1943
1954
  __thread volatile int pg_signal_queue;
1944
1955
 
@@ -17,6 +17,8 @@
17
17
  * - pg_mbstrlen_with_len
18
18
  * - pg_mblen
19
19
  * - SetDatabaseEncoding
20
+ * - pg_mbcharcliplen
21
+ * - pg_mbstrlen
20
22
  * - GetMessageEncoding
21
23
  * - MessageEncoding
22
24
  *--------------------------------------------------------------------
@@ -386,7 +388,22 @@ pg_mblen(const char *mbstr)
386
388
 
387
389
 
388
390
  /* returns the length (counted in wchars) of a multibyte string */
391
+ int
392
+ pg_mbstrlen(const char *mbstr)
393
+ {
394
+ int len = 0;
389
395
 
396
+ /* optimization for single byte encoding */
397
+ if (pg_database_encoding_max_length() == 1)
398
+ return strlen(mbstr);
399
+
400
+ while (*mbstr)
401
+ {
402
+ mbstr += pg_mblen(mbstr);
403
+ len++;
404
+ }
405
+ return len;
406
+ }
390
407
 
391
408
  /* returns the length (counted in wchars) of a multibyte string
392
409
  * (not necessarily NULL terminated)
@@ -425,7 +442,7 @@ pg_mbcliplen(const char *mbstr, int len, int limit)
425
442
  }
426
443
 
427
444
  /*
428
- * pg_mbcliplen with specified encoding
445
+ * pg_mbcliplen with specified encoding; string must be valid in encoding
429
446
  */
430
447
  int
431
448
  pg_encoding_mbcliplen(int encoding, const char *mbstr,
@@ -459,7 +476,29 @@ pg_encoding_mbcliplen(int encoding, const char *mbstr,
459
476
  * Similar to pg_mbcliplen except the limit parameter specifies the
460
477
  * character length, not the byte length.
461
478
  */
479
+ int
480
+ pg_mbcharcliplen(const char *mbstr, int len, int limit)
481
+ {
482
+ int clen = 0;
483
+ int nch = 0;
484
+ int l;
462
485
 
486
+ /* optimization for single byte encoding */
487
+ if (pg_database_encoding_max_length() == 1)
488
+ return cliplen(mbstr, len, limit);
489
+
490
+ while (len > 0 && *mbstr)
491
+ {
492
+ l = pg_mblen(mbstr);
493
+ nch++;
494
+ if (nch > limit)
495
+ break;
496
+ clen += l;
497
+ len -= l;
498
+ mbstr += l;
499
+ }
500
+ return clen;
501
+ }
463
502
 
464
503
  /* mbcliplen for any single-byte encoding */
465
504
  static int
@@ -726,12 +765,12 @@ pg_verify_mbstr(int encoding, const char *mbstr, int len, bool noError)
726
765
  * report_invalid_encoding: complain about invalid multibyte character
727
766
  *
728
767
  * note: len is remaining length of string, not length of character;
729
- * len must be greater than zero, as we always examine the first byte.
768
+ * len must be greater than zero (or we'd neglect initializing "buf").
730
769
  */
731
770
  void
732
771
  report_invalid_encoding(int encoding, const char *mbstr, int len)
733
772
  {
734
- int l = pg_encoding_mblen(encoding, mbstr);
773
+ int l = pg_encoding_mblen_or_incomplete(encoding, mbstr, len);
735
774
  char buf[8 * 5 + 1];
736
775
  char *p = buf;
737
776
  int j,
@@ -758,7 +797,7 @@ report_invalid_encoding(int encoding, const char *mbstr, int len)
758
797
  * report_untranslatable_char: complain about untranslatable character
759
798
  *
760
799
  * note: len is remaining length of string, not length of character;
761
- * len must be greater than zero, as we always examine the first byte.
800
+ * len must be greater than zero (or we'd neglect initializing "buf").
762
801
  */
763
802
 
764
803
 
@@ -54,6 +54,7 @@ AlignedAllocFree(void *pointer)
54
54
  GetMemoryChunkContext(unaligned)->name, chunk);
55
55
  #endif
56
56
 
57
+ /* Recursively pfree the unaligned chunk */
57
58
  pfree(unaligned);
58
59
  }
59
60
 
@@ -105,18 +106,32 @@ AlignedAllocRealloc(void *pointer, Size size, int flags)
105
106
  Assert(old_size >= redirchunk->requested_size);
106
107
  #endif
107
108
 
109
+ /*
110
+ * To keep things simple, we always allocate a new aligned chunk and copy
111
+ * data into it. Because of the above inaccuracy, this may end in copying
112
+ * more data than was in the original allocation request size, but that
113
+ * should be OK.
114
+ */
108
115
  ctx = GetMemoryChunkContext(unaligned);
109
116
  newptr = MemoryContextAllocAligned(ctx, size, alignto, flags);
110
117
 
111
- /*
112
- * We may memcpy beyond the end of the original allocation request size,
113
- * so we must mark the entire allocation as defined.
114
- */
115
- if (likely(newptr != NULL))
118
+ /* Cope cleanly with OOM */
119
+ if (unlikely(newptr == NULL))
116
120
  {
117
- VALGRIND_MAKE_MEM_DEFINED(pointer, old_size);
118
- memcpy(newptr, pointer, Min(size, old_size));
121
+ VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
122
+ return MemoryContextAllocationFailure(ctx, size, flags);
119
123
  }
124
+
125
+ /*
126
+ * We may memcpy more than the original allocation request size, which
127
+ * would result in trying to copy trailing bytes that the original
128
+ * MemoryContextAllocAligned call marked NOACCESS. So we must mark the
129
+ * entire old_size as defined. That's slightly annoying, but probably not
130
+ * worth improving.
131
+ */
132
+ VALGRIND_MAKE_MEM_DEFINED(pointer, old_size);
133
+ memcpy(newptr, pointer, Min(size, old_size));
134
+
120
135
  pfree(unaligned);
121
136
 
122
137
  return newptr;
@@ -1632,9 +1632,9 @@ AllocSetCheck(MemoryContext context)
1632
1632
  prevblock = block, block = block->next)
1633
1633
  {
1634
1634
  char *bpoz = ((char *) block) + ALLOC_BLOCKHDRSZ;
1635
- long blk_used = block->freeptr - bpoz;
1636
- long blk_data = 0;
1637
- long nchunks = 0;
1635
+ Size blk_used = block->freeptr - bpoz;
1636
+ Size blk_data = 0;
1637
+ Size nchunks = 0;
1638
1638
  bool has_external_chunk = false;
1639
1639
 
1640
1640
  if (IsKeeperBlock(set, block))
@@ -236,7 +236,7 @@ BumpAllocLarge(MemoryContext context, Size size, int flags)
236
236
 
237
237
  block = (BumpBlock *) malloc(blksize);
238
238
  if (block == NULL)
239
- return NULL;
239
+ return MemoryContextAllocationFailure(context, size, flags);
240
240
 
241
241
  context->mem_allocated += blksize;
242
242
 
@@ -9,6 +9,8 @@
9
9
  * - enlargeStringInfo
10
10
  * - appendStringInfo
11
11
  * - appendStringInfoSpaces
12
+ * - makeStringInfo
13
+ * - destroyStringInfo
12
14
  *--------------------------------------------------------------------
13
15
  */
14
16
 
@@ -51,7 +53,17 @@
51
53
  *
52
54
  * Create an empty 'StringInfoData' & return a pointer to it.
53
55
  */
56
+ StringInfo
57
+ makeStringInfo(void)
58
+ {
59
+ StringInfo res;
60
+
61
+ res = (StringInfo) palloc(sizeof(StringInfoData));
54
62
 
63
+ initStringInfo(res);
64
+
65
+ return res;
66
+ }
55
67
 
56
68
  /*
57
69
  * initStringInfo
@@ -350,4 +362,12 @@ enlargeStringInfo(StringInfo str, int needed)
350
362
  * Frees a StringInfo and its buffer (opposite of makeStringInfo()).
351
363
  * This must only be called on palloc'd StringInfos.
352
364
  */
365
+ void
366
+ destroyStringInfo(StringInfo str)
367
+ {
368
+ /* don't allow destroys of read-only StringInfos */
369
+ Assert(str->maxlen != 0);
353
370
 
371
+ pfree(str->data);
372
+ pfree(str);
373
+ }
@@ -76,6 +76,7 @@
76
76
  * - pg_johab_dsplen
77
77
  * - pg_johab_verifychar
78
78
  * - pg_johab_verifystr
79
+ * - pg_encoding_mblen_or_incomplete
79
80
  * - pg_encoding_mblen
80
81
  *--------------------------------------------------------------------
81
82
  */
@@ -94,6 +95,8 @@
94
95
  */
95
96
  #include "c.h"
96
97
 
98
+ #include <limits.h>
99
+
97
100
  #include "mb/pg_wchar.h"
98
101
  #include "utils/ascii.h"
99
102
 
@@ -2182,10 +2185,27 @@ const pg_wchar_tbl pg_wchar_table[] = {
2182
2185
  /*
2183
2186
  * Returns the byte length of a multibyte character.
2184
2187
  *
2185
- * Caution: when dealing with text that is not certainly valid in the
2186
- * specified encoding, the result may exceed the actual remaining
2187
- * string length. Callers that are not prepared to deal with that
2188
- * should use pg_encoding_mblen_bounded() instead.
2188
+ * Choose "mblen" functions based on the input string characteristics.
2189
+ * pg_encoding_mblen() can be used when ANY of these conditions are met:
2190
+ *
2191
+ * - The input string is zero-terminated
2192
+ *
2193
+ * - The input string is known to be valid in the encoding (e.g., string
2194
+ * converted from database encoding)
2195
+ *
2196
+ * - The encoding is not GB18030 (e.g., when only database encodings are
2197
+ * passed to 'encoding' parameter)
2198
+ *
2199
+ * encoding==GB18030 requires examining up to two bytes to determine character
2200
+ * length. Therefore, callers satisfying none of those conditions must use
2201
+ * pg_encoding_mblen_or_incomplete() instead, as access to mbstr[1] cannot be
2202
+ * guaranteed to be within allocation bounds.
2203
+ *
2204
+ * When dealing with text that is not certainly valid in the specified
2205
+ * encoding, the result may exceed the actual remaining string length.
2206
+ * Callers that are not prepared to deal with that should use Min(remaining,
2207
+ * pg_encoding_mblen_or_incomplete()). For zero-terminated strings, that and
2208
+ * pg_encoding_mblen_bounded() are interchangeable.
2189
2209
  */
2190
2210
  int
2191
2211
  pg_encoding_mblen(int encoding, const char *mbstr)
@@ -2196,8 +2216,28 @@ pg_encoding_mblen(int encoding, const char *mbstr)
2196
2216
  }
2197
2217
 
2198
2218
  /*
2199
- * Returns the byte length of a multibyte character; but not more than
2200
- * the distance to end of string.
2219
+ * Returns the byte length of a multibyte character (possibly not
2220
+ * zero-terminated), or INT_MAX if too few bytes remain to determine a length.
2221
+ */
2222
+ int
2223
+ pg_encoding_mblen_or_incomplete(int encoding, const char *mbstr,
2224
+ size_t remaining)
2225
+ {
2226
+ /*
2227
+ * Define zero remaining as too few, even for single-byte encodings.
2228
+ * pg_gb18030_mblen() reads one or two bytes; single-byte encodings read
2229
+ * zero; others read one.
2230
+ */
2231
+ if (remaining < 1 ||
2232
+ (encoding == PG_GB18030 && IS_HIGHBIT_SET(*mbstr) && remaining < 2))
2233
+ return INT_MAX;
2234
+ return pg_encoding_mblen(encoding, mbstr);
2235
+ }
2236
+
2237
+ /*
2238
+ * Returns the byte length of a multibyte character; but not more than the
2239
+ * distance to the terminating zero byte. For input that might lack a
2240
+ * terminating zero, use Min(remaining, pg_encoding_mblen_or_incomplete()).
2201
2241
  */
2202
2242
 
2203
2243
 
@@ -1,18 +1,39 @@
1
1
  module PgQuery
2
2
  class ParserResult
3
- def deparse
4
- PgQuery.deparse(@tree)
3
+ def deparse(opts: nil)
4
+ PgQuery.deparse(@tree, opts: opts)
5
5
  end
6
6
  end
7
7
 
8
+ class DeparseComment
9
+ attr_accessor :match_location, :newlines_before_comment, :newlines_after_comment, :str
10
+ end
11
+
12
+ DeparseOpts = Struct.new(:pretty_print, :comments, :indent_size, :max_line_length,
13
+ :trailing_newline, :commas_start_of_line, keyword_init: true)
14
+
8
15
  # Reconstruct all of the parsed queries into their original form
9
- def self.deparse(tree)
10
- if PgQuery::ParseResult.method(:encode).arity == 1
11
- PgQuery.deparse_protobuf(PgQuery::ParseResult.encode(tree)).force_encoding('UTF-8')
12
- elsif PgQuery::ParseResult.method(:encode).arity == -1
13
- PgQuery.deparse_protobuf(PgQuery::ParseResult.encode(tree, recursion_limit: 1_000)).force_encoding('UTF-8')
16
+ def self.deparse(tree, opts: nil)
17
+ protobuf_encoded = if PgQuery::ParseResult.method(:encode).arity == 1
18
+ PgQuery::ParseResult.encode(tree)
19
+ elsif PgQuery::ParseResult.method(:encode).arity == -1
20
+ PgQuery::ParseResult.encode(tree, recursion_limit: 1_000)
21
+ else
22
+ raise ArgumentError, 'Unsupported protobuf Ruby API'
23
+ end
24
+
25
+ if opts
26
+ PgQuery.deparse_protobuf_opts(
27
+ protobuf_encoded,
28
+ opts.pretty_print,
29
+ opts.comments || [],
30
+ opts.indent_size || 0,
31
+ opts.max_line_length || 0,
32
+ opts.trailing_newline,
33
+ opts.commas_start_of_line
34
+ ).force_encoding('UTF-8')
14
35
  else
15
- raise ArgumentError, 'Unsupported protobuf Ruby API'
36
+ PgQuery.deparse_protobuf(protobuf_encoded).force_encoding('UTF-8')
16
37
  end
17
38
  end
18
39
 
@@ -106,6 +106,7 @@ module PgQuery
106
106
  statements = @tree.stmts.dup.to_a.map(&:stmt)
107
107
  from_clause_items = [] # types: select, dml, ddl
108
108
  subselect_items = []
109
+ call_items = [] # CALL fn()
109
110
 
110
111
  loop do
111
112
  statement = statements.shift
@@ -171,6 +172,8 @@ module PgQuery
171
172
  when :copy_stmt
172
173
  from_clause_items << { item: PgQuery::Node.new(range_var: statement.copy_stmt.relation), type: :dml } if statement.copy_stmt.relation
173
174
  statements << statement.copy_stmt.query
175
+ when :call_stmt
176
+ call_items << statement.call_stmt
174
177
  # The following statement types are DDL (changing table structure)
175
178
  when :alter_table_stmt
176
179
  case statement.alter_table_stmt.objtype
@@ -276,15 +279,20 @@ module PgQuery
276
279
  end
277
280
  when :bool_expr
278
281
  subselect_items.concat(next_item.bool_expr.args.to_ary)
282
+ when :boolean_test
283
+ subselect_items << next_item.boolean_test.arg
279
284
  when :coalesce_expr
280
285
  subselect_items.concat(next_item.coalesce_expr.args.to_ary)
281
286
  when :min_max_expr
282
287
  subselect_items.concat(next_item.min_max_expr.args.to_ary)
288
+ when :null_test
289
+ subselect_items << next_item.null_test.arg
283
290
  when :res_target
284
291
  subselect_items << next_item.res_target.val
285
292
  when :sub_link
286
293
  statements << next_item.sub_link.subselect
287
294
  when :func_call
295
+ # See also CALL below
288
296
  subselect_items.concat(next_item.func_call.args.to_ary)
289
297
  @functions << {
290
298
  function: next_item.func_call.funcname.map { |f| f.string.sval }.join('.'),
@@ -299,6 +307,17 @@ module PgQuery
299
307
  end
300
308
  end
301
309
 
310
+ # CALL fn()
311
+ next_item = call_items.shift
312
+ if next_item
313
+ # Treat as a sub-select. Note the difference in underscore in func_call versus the above.
314
+ subselect_items.concat(next_item.funccall.args.to_ary)
315
+ @functions << {
316
+ function: next_item.funccall.funcname.map { |f| f.string.sval }.join('.'),
317
+ type: :call
318
+ }
319
+ end
320
+
302
321
  next_item = from_clause_items.shift
303
322
  if next_item && next_item[:item]
304
323
  case next_item[:item].node