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 +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
|