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 +4 -4
- data/CHANGELOG.md +14 -1
- data/README.md +8 -7
- data/ext/pg_query/extconf.rb +1 -1
- data/lib/pg_query/fingerprint.rb +5 -2
- data/lib/pg_query/node_types.rb +4 -2
- data/lib/pg_query/parse.rb +57 -30
- data/lib/pg_query/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f0df7ee01a2554fa3035b89da592b08aa486d9e
|
4
|
+
data.tar.gz: e1dcd57c5189a191cc33d8964e777db63cf43c75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c71b98b9786a4910d2386ce1a6251e367465be747a66d698487f140f407ee749e3a2c3a0a2d7e1a71fe6a2074eda4f06eea2de59adf60c527e3a107f2a7dfc4
|
7
|
+
data.tar.gz: 8f47e665e94b53bf80c1d9cfb434145ce2f7a0d01ebf190698d1340a35848dc02ed4f6782dede20833832634d9d60799209013b58e78ffb694436184549a22d7
|
data/CHANGELOG.md
CHANGED
@@ -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
|
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
|
-
*
|
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
|
|
data/ext/pg_query/extconf.rb
CHANGED
data/lib/pg_query/fingerprint.rb
CHANGED
@@ -58,7 +58,8 @@ class PgQuery
|
|
58
58
|
|
59
59
|
hash.update node_name
|
60
60
|
|
61
|
-
node.values.first
|
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)
|
data/lib/pg_query/node_types.rb
CHANGED
@@ -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
|
|
data/lib/pg_query/parse.rb
CHANGED
@@ -30,8 +30,19 @@ class PgQuery
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def tables
|
33
|
-
|
34
|
-
|
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
|
-
|
87
|
-
|
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
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
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
|
data/lib/pg_query/version.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2017-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|