pg_query 0.12.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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