pg_query 0.12.1 → 0.13.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
2
  SHA1:
3
- metadata.gz: f2003b8ff36a429c1dc6dd4e03104971ccca6671
4
- data.tar.gz: 77271fe0ac1d22f96949c48775279782cb400539
3
+ metadata.gz: 5f0df7ee01a2554fa3035b89da592b08aa486d9e
4
+ data.tar.gz: e1dcd57c5189a191cc33d8964e777db63cf43c75
5
5
  SHA512:
6
- metadata.gz: 4f3cfb7076a1fe2377205a9aca86b7d4d934c60b1b276e3a9bf06e140d61e3aeaa3fab86db3aef55bd00266b837a8290a459cd4c33b016c61d639fb2e4a74c3c
7
- data.tar.gz: 2d94d792fc9fd3627f42a31a4f8f6341a618ed92ed95b25d45bdef17dcfa962a67bde3b934a60088044d57d759bf82e39ce0253e61992e51e96faad6700a97ef
6
+ metadata.gz: 7c71b98b9786a4910d2386ce1a6251e367465be747a66d698487f140f407ee749e3a2c3a0a2d7e1a71fe6a2074eda4f06eea2de59adf60c527e3a107f2a7dfc4
7
+ data.tar.gz: 8f47e665e94b53bf80c1d9cfb434145ce2f7a0d01ebf190698d1340a35848dc02ed4f6782dede20833832634d9d60799209013b58e78ffb694436184549a22d7
@@ -1,9 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.13.0 2017-07-30
4
+
5
+ * Introduce split between SELECT/DML/DDL for tables method [#65](https://github.com/lfittl/pg_query/pull/65) [@chrisfrommann](https://github.com/chrisfrommann)
6
+ * Backwards compatible, use the new select_tables/dml_tables/ddl_tables to
7
+ access the categorized table references
8
+ * Update libpg_query to 9.5-1.6.2
9
+ * Update to Fingerprinting Version 1.3
10
+ * Attributes to be ignored:
11
+ * RangeVar.relname (if node also has RangeVar.relpersistence = "t")
12
+ * Special cases: List nodes where parent field name is valuesLists
13
+ * Follow same logic described for fromClause/targetList/cols/rexpr
14
+
15
+
3
16
  ## 0.12.1 2017-07-29
4
17
 
5
18
  * Update libpg_query to 9.5-1.6.1
6
- * Update Fingerprinting Version 1.2
19
+ * Update to Fingerprinting Version 1.2
7
20
  * Ignore portalname in DeclareCursorStmt, FetchStmt and ClosePortalStmt
8
21
 
9
22
 
data/README.md CHANGED
@@ -75,12 +75,12 @@ Note: The deparsing feature is experimental and does not support outputting all
75
75
  ### Parsing a normalized query
76
76
 
77
77
  ```ruby
78
- # Normalizing a query (like pg_stat_statements)
78
+ # Normalizing a query (like pg_stat_statements in Postgres 10+)
79
79
  PgQuery.normalize("SELECT 1 FROM x WHERE y = 'foo'")
80
80
 
81
- => "SELECT ? FROM x WHERE y = ?"
81
+ => "SELECT $1 FROM x WHERE y = $2"
82
82
 
83
- # Parsing a normalized query
83
+ # Parsing a normalized query (pre-Postgres 10 style)
84
84
  PgQuery.parse("SELECT ? FROM x WHERE y = ?")
85
85
 
86
86
  => #<PgQuery:0x007fb99455a438
@@ -151,12 +151,10 @@ to support parsing normalized queries containing `?` replacement characters.
151
151
 
152
152
  Currently tested and officially supported Ruby versions:
153
153
 
154
- * MRI 1.9
155
- * MRI 2.0
156
154
  * MRI 2.1
157
155
  * MRI 2.2
158
156
  * MRI 2.3
159
- * Rubinius 3.20
157
+ * MRI 2.4
160
158
 
161
159
 
162
160
  ## Resources
@@ -167,12 +165,15 @@ Products, tools and libraries built on pg_query:
167
165
  * [hsql](https://github.com/JackDanger/hsql)
168
166
  * [sqlint](https://github.com/purcell/sqlint)
169
167
  * [pghero](https://github.com/ankane/pghero)
168
+ * [dexter](https://github.com/ankane/dexter)
170
169
 
171
170
  pg_query for other languages:
172
171
 
173
172
  * C: [libpg_query](https://github.com/lfittl/libpg_query)
174
173
  * Go: [pg_query_go](https://github.com/lfittl/pg_query_go)
175
- * Javascript: [pg-query-parser](https://github.com/zhm/pg-query-parser)
174
+ * Javascript (Node): [pg-query-parser](https://github.com/zhm/pg-query-parser)
175
+ * Javascript (Browser): [pg-query-emscripten](https://github.com/lfittl/pg-query-emscripten)
176
+ * Python: [psqlparse](https://github.com/alculquicondor/psqlparse)
176
177
 
177
178
  Please feel free to [open a PR](https://github.com/lfittl/pg_query/pull/new/master) to add yours! :)
178
179
 
@@ -3,7 +3,7 @@
3
3
  require 'mkmf'
4
4
  require 'open-uri'
5
5
 
6
- LIB_PG_QUERY_TAG = '9.5-1.6.1'.freeze
6
+ LIB_PG_QUERY_TAG = '9.5-1.6.2'.freeze
7
7
 
8
8
  workdir = Dir.pwd
9
9
  libdir = File.join(workdir, 'libpg_query-' + LIB_PG_QUERY_TAG)
@@ -58,7 +58,8 @@ class PgQuery
58
58
 
59
59
  hash.update node_name
60
60
 
61
- node.values.first.sort_by { |k, _| k }.each do |field_name, val|
61
+ fields = node.values.first
62
+ fields.sort_by { |k, _| k }.each do |field_name, val|
62
63
  next if ignored_fingerprint_value?(val)
63
64
 
64
65
  case field_name
@@ -73,6 +74,8 @@ class PgQuery
73
74
  next if node_name == TRANSACTION_STMT
74
75
  when 'portalname'
75
76
  next if [DECLARE_CURSOR_STMT, FETCH_STMT, CLOSE_PORTAL_STMT].include?(node_name)
77
+ when 'relname'
78
+ next if node_name == RANGE_VAR && fields[RELPERSISTENCE_FIELD] == 't'
76
79
  end
77
80
 
78
81
  fingerprint_value(val, hash, node_name, field_name, true)
@@ -80,7 +83,7 @@ class PgQuery
80
83
  end
81
84
 
82
85
  def fingerprint_list(values, hash, parent_node_name, parent_field_name)
83
- if [FROM_CLAUSE_FIELD, TARGET_LIST_FIELD, COLS_FIELD, REXPR_FIELD].include?(parent_field_name)
86
+ if [FROM_CLAUSE_FIELD, TARGET_LIST_FIELD, COLS_FIELD, REXPR_FIELD, VALUES_LISTS_FIELD].include?(parent_field_name)
84
87
  values_subhashes = values.map do |val|
85
88
  subhash = FingerprintSubHash.new
86
89
  fingerprint_value(val, subhash, parent_node_name, parent_field_name, false)
@@ -85,10 +85,12 @@ class PgQuery
85
85
 
86
86
  # FIELDS
87
87
 
88
- FROM_CLAUSE_FIELD = 'fromClause'.freeze
89
- TARGET_LIST_FIELD = 'targetList'.freeze
90
88
  COLS_FIELD = 'cols'.freeze
89
+ FROM_CLAUSE_FIELD = 'fromClause'.freeze
90
+ RELPERSISTENCE_FIELD = 'relpersistence'.freeze
91
91
  REXPR_FIELD = 'rexpr'.freeze
92
+ TARGET_LIST_FIELD = 'targetList'.freeze
93
+ VALUES_LISTS_FIELD = 'valuesLists'.freeze
92
94
 
93
95
  # ENUMS
94
96
 
@@ -30,8 +30,19 @@ class PgQuery
30
30
  end
31
31
 
32
32
  def tables
33
- load_tables_and_aliases! if @tables.nil?
34
- @tables
33
+ tables_with_types.map { |t| t[:table] }
34
+ end
35
+
36
+ def select_tables
37
+ tables_with_types.select { |t| t[:type] == :select }.map { |t| t[:table] }
38
+ end
39
+
40
+ def dml_tables
41
+ tables_with_types.select { |t| t[:type] == :dml }.map { |t| t[:table] }
42
+ end
43
+
44
+ def ddl_tables
45
+ tables_with_types.select { |t| t[:type] == :ddl }.map { |t| t[:table] }
35
46
  end
36
47
 
37
48
  def cte_names
@@ -44,21 +55,28 @@ class PgQuery
44
55
  @aliases
45
56
  end
46
57
 
58
+ def tables_with_types
59
+ load_tables_and_aliases! if @tables.nil?
60
+ @tables
61
+ end
62
+
47
63
  protected
48
64
 
49
65
  def load_tables_and_aliases! # rubocop:disable Metrics/CyclomaticComplexity
50
- @tables = []
66
+ @tables = [] # types: select, dml, ddl
51
67
  @cte_names = []
52
68
  @aliases = {}
53
69
 
54
70
  statements = @tree.dup
55
- from_clause_items = []
71
+ from_clause_items = [] # types: select, dml, ddl
56
72
  subselect_items = []
57
73
 
58
74
  loop do
59
75
  statement = statements.shift
60
76
  if statement
61
77
  case statement.keys[0]
78
+ # The following statement types do not modify tables and are added to from_clause_items
79
+ # (and subsequently @tables)
62
80
  when SELECT_STMT
63
81
  case statement[SELECT_STMT]['op']
64
82
  when 0
@@ -66,7 +84,7 @@ class PgQuery
66
84
  if item[RANGE_SUBSELECT]
67
85
  statements << item[RANGE_SUBSELECT]['subquery']
68
86
  else
69
- from_clause_items << item
87
+ from_clause_items << { item: item, type: :select }
70
88
  end
71
89
  end
72
90
 
@@ -83,39 +101,48 @@ class PgQuery
83
101
  statements << statement[SELECT_STMT]['larg'] if statement[SELECT_STMT]['larg']
84
102
  statements << statement[SELECT_STMT]['rarg'] if statement[SELECT_STMT]['rarg']
85
103
  end
86
- when INSERT_STMT, UPDATE_STMT, DELETE_STMT, VACUUM_STMT, COPY_STMT, ALTER_TABLE_STMT, CREATE_STMT, INDEX_STMT, RULE_STMT, CREATE_TRIG_STMT
87
- from_clause_items << statement.values[0]['relation']
104
+ # The following statements modify the contents of a table
105
+ when INSERT_STMT, UPDATE_STMT, DELETE_STMT, COPY_STMT
106
+ from_clause_items << { item: statement.values[0]['relation'], type: :dml }
107
+ # The following statement types are DDL (changing table structure)
108
+ when ALTER_TABLE_STMT, CREATE_STMT
109
+ from_clause_items << { item: statement.values[0]['relation'], type: :ddl }
110
+ when CREATE_TABLE_AS_STMT
111
+ if statement[CREATE_TABLE_AS_STMT]['into'] && statement[CREATE_TABLE_AS_STMT]['into'][INTO_CLAUSE]['rel']
112
+ from_clause_items << { item: statement[CREATE_TABLE_AS_STMT]['into'][INTO_CLAUSE]['rel'], type: :ddl }
113
+ end
114
+ when TRUNCATE_STMT
115
+ from_clause_items += statement.values[0]['relations'].map { |r| { item: r, type: :ddl } }
88
116
  when VIEW_STMT
89
- from_clause_items << statement[VIEW_STMT]['view']
117
+ from_clause_items << { item: statement[VIEW_STMT]['view'], type: :ddl }
90
118
  statements << statement[VIEW_STMT]['query']
119
+ when VACUUM_STMT, INDEX_STMT, CREATE_TRIG_STMT, RULE_STMT
120
+ from_clause_items << { item: statement.values[0]['relation'], type: :ddl }
91
121
  when REFRESH_MAT_VIEW_STMT
92
- from_clause_items << statement[REFRESH_MAT_VIEW_STMT]['relation']
93
- when EXPLAIN_STMT
94
- statements << statement[EXPLAIN_STMT]['query']
95
- when CREATE_TABLE_AS_STMT
96
- if statement[CREATE_TABLE_AS_STMT]['into'] && statement[CREATE_TABLE_AS_STMT]['into'][INTO_CLAUSE]['rel']
97
- from_clause_items << statement[CREATE_TABLE_AS_STMT]['into'][INTO_CLAUSE]['rel']
122
+ from_clause_items << { item: statement[REFRESH_MAT_VIEW_STMT]['relation'], type: :ddl }
123
+ when DROP_STMT
124
+ objects = statement[DROP_STMT]['objects'].map { |list| list.map { |obj| obj['String'] && obj['String']['str'] } }
125
+ case statement[DROP_STMT]['removeType']
126
+ when OBJECT_TYPE_TABLE
127
+ @tables += objects.map { |r| { table: r.join('.'), type: :ddl } }
128
+ when OBJECT_TYPE_RULE, OBJECT_TYPE_TRIGGER
129
+ @tables += objects.map { |r| { table: r[0..-2].join('.'), type: :ddl } }
98
130
  end
99
- when LOCK_STMT, TRUNCATE_STMT
100
- from_clause_items += statement.values[0]['relations']
101
131
  when GRANT_STMT
102
132
  objects = statement[GRANT_STMT]['objects']
103
133
  case statement[GRANT_STMT]['objtype']
104
134
  when 0 # Column # rubocop:disable Lint/EmptyWhen
105
135
  # FIXME
106
136
  when 1 # Table
107
- from_clause_items += objects
137
+ from_clause_items += objects.map { |o| { item: o, type: :ddl } }
108
138
  when 2 # Sequence # rubocop:disable Lint/EmptyWhen
109
139
  # FIXME
110
140
  end
111
- when DROP_STMT
112
- objects = statement[DROP_STMT]['objects'].map { |list| list.map { |obj| obj['String'] && obj['String']['str'] } }
113
- case statement[DROP_STMT]['removeType']
114
- when OBJECT_TYPE_TABLE
115
- @tables += objects.map { |r| r.join('.') }
116
- when OBJECT_TYPE_RULE, OBJECT_TYPE_TRIGGER
117
- @tables += objects.map { |r| r[0..-2].join('.') }
118
- end
141
+ when LOCK_STMT
142
+ from_clause_items += statement.values[0]['relations'].map { |r| { item: r, type: :ddl } }
143
+ # The following are other statements that don't fit into query/DML/DDL
144
+ when EXPLAIN_STMT
145
+ statements << statement[EXPLAIN_STMT]['query']
119
146
  end
120
147
 
121
148
  statement_value = statement.values[0]
@@ -157,19 +184,19 @@ class PgQuery
157
184
  next_item = from_clause_items.shift
158
185
  break unless next_item
159
186
 
160
- case next_item.keys[0]
187
+ case next_item[:item].keys[0]
161
188
  when JOIN_EXPR
162
189
  %w[larg rarg].each do |side|
163
- from_clause_items << next_item[JOIN_EXPR][side]
190
+ from_clause_items << { item: next_item[:item][JOIN_EXPR][side], type: next_item[:type] }
164
191
  end
165
192
  when ROW_EXPR
166
- from_clause_items += next_item[ROW_EXPR]['args']
193
+ from_clause_items += next_item[:item][ROW_EXPR]['args'].map { |a| { item: a, type: next_item[:type] } }
167
194
  when RANGE_VAR
168
- rangevar = next_item[RANGE_VAR]
195
+ rangevar = next_item[:item][RANGE_VAR]
169
196
  next if !rangevar['schemaname'] && @cte_names.include?(rangevar['relname'])
170
197
 
171
198
  table = [rangevar['schemaname'], rangevar['relname']].compact.join('.')
172
- @tables << table
199
+ @tables << { table: table, type: next_item[:type] }
173
200
  @aliases[rangevar['alias'][ALIAS]['aliasname']] = table if rangevar['alias']
174
201
  end
175
202
  end
@@ -1,3 +1,3 @@
1
1
  class PgQuery
2
- VERSION = '0.12.1'.freeze
2
+ VERSION = '0.13.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: 0.12.1
4
+ version: 0.13.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: 2017-07-30 00:00:00.000000000 Z
11
+ date: 2017-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler