pg_query 1.0.2 → 1.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9d1df6666392e194e8ac7a87086cae2e3051644a
4
- data.tar.gz: b524259660a3489556696cf0f4b75d0c5c3c91b7
2
+ SHA256:
3
+ metadata.gz: 0db8e898d08ff3642a800ab296d7ac10dd9556e3c5a626f005bae86d35273372
4
+ data.tar.gz: a869a1faeb3ae0bed9d5031f2a4d26263843fde368bfeb096c1c9f48ea30c9f8
5
5
  SHA512:
6
- metadata.gz: 61523601794ef69a4dad8e33ba3fc9b5f35f299dce42f3b924b8ccca8726d9a11266dbcbbb7c1fc6f92c98c3443a02092d006c2c9a1484a1a9b9e0875fa9b6e3
7
- data.tar.gz: 476105d1b4a3337f9ef4266452858cb70d02278ad8b564320ad9d76169425f81f2e64fc9fff070fcc9739ce3589bde93e5ea000bf062c61a7190d5f4e38eacee
6
+ metadata.gz: e0f51970e5f268d9d9d32d791288db0d7a048c4880f706ff7d483b0efacd1a355600f5b8ca8a0b57b75a05cda8c7b207402bb6680fad0fdaeaf7809fab06c441
7
+ data.tar.gz: 6281530a32add88cd8a474a8e224e817723e288e850f9d9232aba69208b1178d89b7135d613d15800176bd611b3d6fcd0600fb48c3e8c880f6aa47f5296bae45
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0 2018-10-04
4
+
5
+ * Deparsing improvements by [@herwinw](https://github.com/herwinw)
6
+ * Add NULLS FIRST/LAST to ORDER BY [#95](https://github.com/lfittl/pg_query/pull/95)
7
+ * VACUUM [#97](https://github.com/lfittl/pg_query/pull/97)
8
+ * UPDATE with multiple columns [#99](https://github.com/lfittl/pg_query/pull/99)
9
+ * DISTINCT ON [#101](https://github.com/lfittl/pg_query/pull/101)
10
+ * CREATE TABLE AS [#102](https://github.com/lfittl/pg_query/pull/102)
11
+ * SQL value functions [#103](https://github.com/lfittl/pg_query/pull/103)
12
+ * LOCK [#105](https://github.com/lfittl/pg_query/pull/105)
13
+ * EXPLAIN [#107](https://github.com/lfittl/pg_query/pull/107)
14
+ * COPY [#108](https://github.com/lfittl/pg_query/pull/108)
15
+ * DO [#109](https://github.com/lfittl/pg_query/pull/109)
16
+ * Ignore pg_query.so in git checkout [#110](https://github.com/lfittl/pg_query/pull/110) [@herwinw](https://github.com/herwinw)
17
+ * Prefer __dir__ over File.dirname(__FILE__) [#110](https://github.com/lfittl/pg_query/pull/104) [@herwinw](https://github.com/herwinw)
18
+
19
+
3
20
  ## 1.0.2 2018-04-11
4
21
 
5
22
  * Deparsing improvements
data/Rakefile CHANGED
@@ -17,7 +17,7 @@ task test: :spec
17
17
  task lint: :rubocop
18
18
 
19
19
  task :clean do
20
- FileUtils.rm_rf File.join(File.dirname(__FILE__), 'tmp/')
21
- FileUtils.rm_f Dir.glob(File.join(File.dirname(__FILE__), 'ext/pg_query/*.o'))
22
- FileUtils.rm_f File.join(File.dirname(__FILE__), 'lib/pg_query/pg_query.bundle')
20
+ FileUtils.rm_rf File.join(__dir__, 'tmp/')
21
+ FileUtils.rm_f Dir.glob(File.join(__dir__, 'ext/pg_query/*.o'))
22
+ FileUtils.rm_f File.join(__dir__, 'lib/pg_query/pg_query.bundle')
23
23
  end
@@ -7,7 +7,7 @@ LIB_PG_QUERY_TAG = '10-1.0.1'.freeze
7
7
 
8
8
  workdir = Dir.pwd
9
9
  libdir = File.join(workdir, 'libpg_query-' + LIB_PG_QUERY_TAG)
10
- gemdir = File.join(File.dirname(__FILE__), '../..')
10
+ gemdir = File.join(__dir__, '../..')
11
11
  libfile = libdir + '/libpg_query.a'
12
12
 
13
13
  unless File.exist?("#{workdir}/libpg_query.tar.gz")
@@ -36,7 +36,7 @@ $LOCAL_LIBS << '-lpg_query'
36
36
  $LIBPATH << libdir
37
37
  $CFLAGS << " -I #{libdir} -O3 -Wall -fno-strict-aliasing -fwrapv -g"
38
38
 
39
- SYMFILE = File.join(File.dirname(__FILE__), 'pg_query_ruby.sym')
39
+ SYMFILE = File.join(__dir__, 'pg_query_ruby.sym')
40
40
  if RUBY_PLATFORM =~ /darwin/
41
41
  $DLDFLAGS << " -Wl,-exported_symbols_list #{SYMFILE}" unless defined?(::Rubinius)
42
42
  else
@@ -86,16 +86,24 @@ class PgQuery
86
86
  deparse_cte(node)
87
87
  when CONSTRAINT
88
88
  deparse_constraint(node)
89
+ when COPY_STMT
90
+ deparse_copy(node)
89
91
  when CREATE_FUNCTION_STMT
90
92
  deparse_create_function(node)
91
93
  when CREATE_STMT
92
94
  deparse_create_table(node)
95
+ when CREATE_TABLE_AS_STMT
96
+ deparse_create_table_as(node)
97
+ when INTO_CLAUSE
98
+ deparse_into_clause(node)
93
99
  when DEF_ELEM
94
100
  deparse_defelem(node)
95
101
  when DELETE_STMT
96
102
  deparse_delete_from(node)
97
103
  when DROP_STMT
98
104
  deparse_drop(node)
105
+ when EXPLAIN_STMT
106
+ deparse_explain(node)
99
107
  when FUNC_CALL
100
108
  deparse_funccall(node)
101
109
  when FUNCTION_PARAMETER
@@ -104,6 +112,8 @@ class PgQuery
104
112
  deparse_insert_into(node)
105
113
  when JOIN_EXPR
106
114
  deparse_joinexpr(node)
115
+ when LOCK_STMT
116
+ deparse_lock(node)
107
117
  when LOCKING_CLAUSE
108
118
  deparse_lockingclause(node)
109
119
  when NULL_TEST
@@ -126,6 +136,8 @@ class PgQuery
126
136
  deparse_row(node)
127
137
  when SELECT_STMT
128
138
  deparse_select(node)
139
+ when SQL_VALUE_FUNCTION
140
+ deparse_sql_value_function(node)
129
141
  when SORT_BY
130
142
  deparse_sortby(node)
131
143
  when SUB_LINK
@@ -148,6 +160,10 @@ class PgQuery
148
160
  deparse_viewstmt(node)
149
161
  when VARIABLE_SET_STMT
150
162
  deparse_variable_set_stmt(node)
163
+ when VACUUM_STMT
164
+ deparse_vacuum_stmt(node)
165
+ when DO_STMT
166
+ deparse_do_stmt(node)
151
167
  when STRING
152
168
  if context == A_CONST
153
169
  format("'%s'", node['str'].gsub("'", "''"))
@@ -458,6 +474,14 @@ class PgQuery
458
474
  output.join(' ')
459
475
  end
460
476
 
477
+ def deparse_lock(node)
478
+ output = []
479
+ output << 'LOCK TABLE'
480
+ tables = node['relations'].map { |table| deparse_item(table) }
481
+ output << tables.join(', ')
482
+ output.join(' ')
483
+ end
484
+
461
485
  LOCK_CLAUSE_STRENGTH = {
462
486
  LCS_FORKEYSHARE => 'FOR KEY SHARE',
463
487
  LCS_FORSHARE => 'FOR SHARE',
@@ -481,6 +505,8 @@ class PgQuery
481
505
  output << deparse_item(node['node'])
482
506
  output << 'ASC' if node['sortby_dir'] == 1
483
507
  output << 'DESC' if node['sortby_dir'] == 2
508
+ output << 'NULLS FIRST' if node['sortby_nulls'] == 1
509
+ output << 'NULLS LAST' if node['sortby_nulls'] == 2
484
510
  output.join(' ')
485
511
  end
486
512
 
@@ -527,6 +553,35 @@ class PgQuery
527
553
  output.join(' ')
528
554
  end
529
555
 
556
+ def deparse_vacuum_stmt(node)
557
+ output = []
558
+ output << 'VACUUM'
559
+ output.concat(deparse_vacuum_options(node))
560
+ output << deparse_item(node['relation']) if node.key?('relation')
561
+ if node.key?('va_cols')
562
+ output << "(#{node['va_cols'].map(&method(:deparse_item)).join(', ')})"
563
+ end
564
+ output.join(' ')
565
+ end
566
+
567
+ def deparse_vacuum_options(node)
568
+ output = []
569
+ output << 'FULL' if node['options'][4] == 1
570
+ output << 'FREEZE' if node['options'][3] == 1
571
+ output << 'VERBOSE' if node['options'][2] == 1
572
+ output << 'ANALYZE' if node['options'][1] == 1
573
+ output
574
+ end
575
+
576
+ def deparse_do_stmt(node)
577
+ output = []
578
+ output << 'DO'
579
+ statement, *rest = node['args']
580
+ output << "$$#{statement['DefElem']['arg']['String']['str']}$$"
581
+ output += rest.map { |item| deparse_item(item) }
582
+ output.join(' ')
583
+ end
584
+
530
585
  def deparse_cte(node)
531
586
  output = []
532
587
  output << node['ctename']
@@ -601,6 +656,21 @@ class PgQuery
601
656
  output.join(' ')
602
657
  end
603
658
 
659
+ def deparse_copy(node)
660
+ output = ['COPY']
661
+ output << deparse_item(node['relation'])
662
+ columns = node.fetch('attlist', []).map { |column| deparse_item(column) }
663
+ output << "(#{columns.join(', ')})" unless columns.empty?
664
+ output << (node['is_from'] ? 'FROM' : 'TO')
665
+ output << 'PROGRAM' if node['is_program']
666
+ output << if node.key?('filename')
667
+ "'#{node['filename']}'"
668
+ else
669
+ node['is_from'] ? 'STDIN' : 'STDOUT'
670
+ end
671
+ output.join(' ')
672
+ end
673
+
604
674
  def deparse_create_function(node)
605
675
  output = []
606
676
  output << 'CREATE'
@@ -645,6 +715,19 @@ class PgQuery
645
715
  output.join(' ')
646
716
  end
647
717
 
718
+ def deparse_create_table_as(node)
719
+ output = []
720
+ output << 'CREATE TEMPORARY TABLE'
721
+ output << deparse_item(node['into'])
722
+ output << 'AS'
723
+ output << deparse_item(node['query'])
724
+ output.join(' ')
725
+ end
726
+
727
+ def deparse_into_clause(node)
728
+ deparse_item(node['rel'])
729
+ end
730
+
648
731
  def deparse_when(node)
649
732
  output = ['WHEN']
650
733
  output << deparse_item(node['expr'])
@@ -691,7 +774,13 @@ class PgQuery
691
774
 
692
775
  if node[TARGET_LIST_FIELD]
693
776
  output << 'SELECT'
694
- output << 'DISTINCT' if node['distinctClause']
777
+ if node['distinctClause']
778
+ output << 'DISTINCT'
779
+ unless node['distinctClause'].compact.empty?
780
+ columns = node['distinctClause'].map { |item| deparse_item(item, :select) }
781
+ output << "ON (#{columns.join(', ')})"
782
+ end
783
+ end
695
784
  output << node[TARGET_LIST_FIELD].map do |item|
696
785
  deparse_item(item, :select)
697
786
  end.join(', ')
@@ -754,6 +843,30 @@ class PgQuery
754
843
  output.join(' ')
755
844
  end
756
845
 
846
+ def deparse_sql_value_function(node)
847
+ output = []
848
+ lookup = [
849
+ 'current_date',
850
+ 'current_time',
851
+ 'current_time', # with precision
852
+ 'current_timestamp',
853
+ 'current_timestamp', # with precision
854
+ 'localtime',
855
+ 'localtime', # with precision
856
+ 'localtimestamp',
857
+ 'localtimestamp', # with precision
858
+ 'current_role',
859
+ 'current_user',
860
+ 'session_user',
861
+ 'user',
862
+ 'current_catalog',
863
+ 'current_schema'
864
+ ]
865
+ output << lookup[node['op']]
866
+ output << "(#{node['typmod']})" unless node.fetch('typmod', -1) == -1
867
+ output.join('')
868
+ end
869
+
757
870
  def deparse_insert_into(node)
758
871
  output = []
759
872
  output << deparse_item(node['withClause']) if node['withClause']
@@ -781,9 +894,10 @@ class PgQuery
781
894
 
782
895
  if node[TARGET_LIST_FIELD]
783
896
  output << 'SET'
784
- node[TARGET_LIST_FIELD].each do |item|
785
- output << deparse_item(item, :update)
897
+ columns = node[TARGET_LIST_FIELD].map do |item|
898
+ deparse_item(item, :update)
786
899
  end
900
+ output << columns.join(', ')
787
901
  end
788
902
 
789
903
  if node['whereClause']
@@ -984,6 +1098,18 @@ class PgQuery
984
1098
  output.join(' ')
985
1099
  end
986
1100
 
1101
+ def deparse_explain(node)
1102
+ output = ['EXPLAIN']
1103
+ options = node.fetch('options', []).map { |option| option['DefElem']['defname'].upcase }
1104
+ if options.size == 1
1105
+ output.concat(options)
1106
+ elsif options.size > 1
1107
+ output << "(#{options.join(', ')})"
1108
+ end
1109
+ output << deparse_item(node['query'])
1110
+ output.join(' ')
1111
+ end
1112
+
987
1113
  # The PG parser adds several pieces of view data onto the RANGEVAR
988
1114
  # that need to be printed before deparse_rangevar is called.
989
1115
  def relpersistence(rangevar)
@@ -34,6 +34,7 @@ class PgQuery
34
34
  DECLARE_CURSOR_STMT = 'DeclareCursorStmt'.freeze
35
35
  DEF_ELEM = 'DefElem'.freeze
36
36
  DELETE_STMT = 'DeleteStmt'.freeze
37
+ DO_STMT = 'DoStmt'.freeze
37
38
  DROP_STMT = 'DropStmt'.freeze
38
39
  EXECUTE_STMT = 'ExecuteStmt'.freeze
39
40
  EXPLAIN_STMT = 'ExplainStmt'.freeze
@@ -70,6 +71,7 @@ class PgQuery
70
71
  SELECT_STMT = 'SelectStmt'.freeze
71
72
  SET_TO_DEFAULT = 'SetToDefault'.freeze
72
73
  SORT_BY = 'SortBy'.freeze
74
+ SQL_VALUE_FUNCTION = 'SQLValueFunction'.freeze
73
75
  STRING = 'String'.freeze
74
76
  SUB_LINK = 'SubLink'.freeze
75
77
  TRANSACTION_STMT = 'TransactionStmt'.freeze
@@ -1,3 +1,3 @@
1
1
  class PgQuery
2
- VERSION = '1.0.2'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_query
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lukas Fittl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-11 00:00:00.000000000 Z
11
+ date: 2018-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -122,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
122
  version: '0'
123
123
  requirements: []
124
124
  rubyforge_project:
125
- rubygems_version: 2.6.8
125
+ rubygems_version: 2.7.6
126
126
  signing_key:
127
127
  specification_version: 4
128
128
  summary: PostgreSQL query parsing and normalization library