pg_query 0.8.0 → 0.9.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 +13 -0
- data/README.md +47 -61
- data/ext/pg_query/extconf.rb +15 -4
- data/ext/pg_query/pg_query_ruby.c +42 -0
- data/lib/pg_query.rb +4 -0
- data/lib/pg_query/deep_dup.rb +16 -0
- data/lib/pg_query/deparse.rb +166 -116
- data/lib/pg_query/deparse/alter_table.rb +21 -122
- data/lib/pg_query/filter_columns.rb +37 -35
- data/lib/pg_query/fingerprint.rb +95 -26
- data/lib/pg_query/legacy_parsetree.rb +128 -0
- data/lib/pg_query/node_types.rb +218 -0
- data/lib/pg_query/param_refs.rb +9 -9
- data/lib/pg_query/parse.rb +48 -50
- data/lib/pg_query/treewalker.rb +17 -11
- data/lib/pg_query/truncate.rb +10 -8
- data/lib/pg_query/version.rb +1 -1
- metadata +5 -2
@@ -0,0 +1,218 @@
|
|
1
|
+
# rubocop:disable Style/ConstantName
|
2
|
+
class PgQuery
|
3
|
+
# NODE TYPES
|
4
|
+
|
5
|
+
A_ARRAY_EXPR = 'A_ArrayExpr'.freeze
|
6
|
+
A_CONST = 'A_Const'.freeze
|
7
|
+
A_EXPR = 'A_Expr'.freeze
|
8
|
+
A_INDICES = 'A_Indices'.freeze
|
9
|
+
A_INDIRECTION = 'A_Indirection'.freeze
|
10
|
+
A_STAR = 'A_Star'.freeze
|
11
|
+
ACCESS_PRIV = 'AccessPriv'.freeze
|
12
|
+
ALIAS = 'Alias'.freeze
|
13
|
+
ALTER_TABLE_CMD = 'AlterTableCmd'.freeze
|
14
|
+
ALTER_TABLE_STMT = 'AlterTableStmt'.freeze
|
15
|
+
BIT_STRING = 'BitString'.freeze
|
16
|
+
BOOL_EXPR = 'BoolExpr'.freeze
|
17
|
+
CASE_EXPR = 'CaseExpr'.freeze
|
18
|
+
CASE_WHEN = 'CaseWhen'.freeze
|
19
|
+
CHECK_POINT_STMT = 'CheckPointStmt'.freeze
|
20
|
+
COALESCE_EXPR = 'CoalesceExpr'.freeze
|
21
|
+
COLUMN_DEF = 'ColumnDef'.freeze
|
22
|
+
COLUMN_REF = 'ColumnRef'.freeze
|
23
|
+
COMMON_TABLE_EXPR = 'CommonTableExpr'.freeze
|
24
|
+
CONSTRAINT = 'Constraint'.freeze
|
25
|
+
COPY_STMT = 'CopyStmt'.freeze
|
26
|
+
CREATE_FUNCTION_STMT = 'CreateFunctionStmt'.freeze
|
27
|
+
CREATE_SCHEMA_STMT = 'CreateSchemaStmt'.freeze
|
28
|
+
CREATE_STMT = 'CreateStmt'.freeze
|
29
|
+
CREATE_TABLE_AS_STMT = 'CreateTableAsStmt'.freeze
|
30
|
+
CREATE_TRIG_STMT = 'CreateTrigStmt'.freeze
|
31
|
+
DEF_ELEM = 'DefElem'.freeze
|
32
|
+
DELETE_STMT = 'DeleteStmt'.freeze
|
33
|
+
DROP_STMT = 'DropStmt'.freeze
|
34
|
+
EXPLAIN_STMT = 'ExplainStmt'.freeze
|
35
|
+
FLOAT = 'Float'.freeze
|
36
|
+
FUNC_CALL = 'FuncCall'.freeze
|
37
|
+
FUNCTION_PARAMETER = 'FunctionParameter'.freeze
|
38
|
+
GRANT_STMT = 'GrantStmt'.freeze
|
39
|
+
GRANT_ROLE_STMT = 'GrantRoleStmt'.freeze
|
40
|
+
INDEX_ELEM = 'IndexElem'.freeze
|
41
|
+
INDEX_STMT = 'IndexStmt'.freeze
|
42
|
+
INSERT_STMT = 'InsertStmt'.freeze
|
43
|
+
INTO_CLAUSE = 'IntoClause'.freeze
|
44
|
+
JOIN_EXPR = 'JoinExpr'.freeze
|
45
|
+
LOCK_STMT = 'LockStmt'.freeze
|
46
|
+
LOCKING_CLAUSE = 'LockingClause'.freeze
|
47
|
+
NULL_TEST = 'NullTest'.freeze
|
48
|
+
RANGE_FUNCTION = 'RangeFunction'.freeze
|
49
|
+
PARAM_REF = 'ParamRef'.freeze
|
50
|
+
RANGE_SUBSELECT = 'RangeSubselect'.freeze
|
51
|
+
RANGE_VAR = 'RangeVar'.freeze
|
52
|
+
REFRESH_MAT_VIEW_STMT = 'RefreshMatViewStmt'.freeze
|
53
|
+
RENAME_STMT = 'RenameStmt'.freeze
|
54
|
+
RES_TARGET = 'ResTarget'.freeze
|
55
|
+
ROW_EXPR = 'RowExpr'.freeze
|
56
|
+
RULE_STMT = 'RuleStmt'.freeze
|
57
|
+
ROLE_SPEC = 'RoleSpec'.freeze
|
58
|
+
SELECT_STMT = 'SelectStmt'.freeze
|
59
|
+
SORT_BY = 'SortBy'.freeze
|
60
|
+
SUB_LINK = 'SubLink'.freeze
|
61
|
+
TRANSACTION_STMT = 'TransactionStmt'.freeze
|
62
|
+
TRUNCATE_STMT = 'TruncateStmt'.freeze
|
63
|
+
TYPE_CAST = 'TypeCast'.freeze
|
64
|
+
TYPE_NAME = 'TypeName'.freeze
|
65
|
+
UPDATE_STMT = 'UpdateStmt'.freeze
|
66
|
+
VACUUM_STMT = 'VacuumStmt'.freeze
|
67
|
+
VARIABLE_SET_STMT = 'VariableSetStmt'.freeze
|
68
|
+
VARIABLE_SHOW_STMT = 'VariableShowStmt'.freeze
|
69
|
+
VIEW_STMT = 'ViewStmt'.freeze
|
70
|
+
WINDOW_DEF = 'WindowDef'.freeze
|
71
|
+
WITH_CLAUSE = 'WithClause'.freeze
|
72
|
+
STRING = 'String'.freeze
|
73
|
+
INTEGER = 'Integer'.freeze
|
74
|
+
SET_TO_DEFAULT = 'SetToDefault'.freeze
|
75
|
+
PREPARE_STMT = 'PrepareStmt'.freeze
|
76
|
+
EXECUTE_STMT = 'ExecuteStmt'.freeze
|
77
|
+
DEALLOCATE_STMT = 'DeallocateStmt'.freeze
|
78
|
+
NULL = 'Null'.freeze
|
79
|
+
INT_LIST = 'IntList'.freeze
|
80
|
+
OID_LIST = 'OidList'.freeze
|
81
|
+
|
82
|
+
# FIELDS
|
83
|
+
|
84
|
+
FROM_CLAUSE_FIELD = 'fromClause'.freeze
|
85
|
+
TARGET_LIST_FIELD = 'targetList'.freeze
|
86
|
+
COLS_FIELD = 'cols'.freeze
|
87
|
+
REXPR_FIELD = 'rexpr'.freeze
|
88
|
+
|
89
|
+
# ENUMS
|
90
|
+
|
91
|
+
CONSTR_TYPE_NULL = 0 # not standard SQL, but a lot of people expect it
|
92
|
+
CONSTR_TYPE_NOTNULL = 1
|
93
|
+
CONSTR_TYPE_DEFAULT = 2
|
94
|
+
CONSTR_TYPE_CHECK = 3
|
95
|
+
CONSTR_TYPE_PRIMARY = 4
|
96
|
+
CONSTR_TYPE_UNIQUE = 5
|
97
|
+
CONSTR_TYPE_EXCLUSION = 6
|
98
|
+
CONSTR_TYPE_FOREIGN = 7
|
99
|
+
CONSTR_TYPE_ATTR_DEFERRABLE = 8 # attributes for previous constraint node
|
100
|
+
CONSTR_TYPE_ATTR_NOT_DEFERRABLE = 9
|
101
|
+
CONSTR_TYPE_ATTR_DEFERRED = 10
|
102
|
+
CONSTR_TYPE_ATTR_IMMEDIATE = 11
|
103
|
+
|
104
|
+
OBJECT_TYPE_INDEX = 19
|
105
|
+
OBJECT_TYPE_RULE = 28
|
106
|
+
OBJECT_TYPE_SCHEMA = 29
|
107
|
+
OBJECT_TYPE_TABLE = 32
|
108
|
+
OBJECT_TYPE_TRIGGER = 35
|
109
|
+
OBJECT_TYPE_VIEW = 42
|
110
|
+
|
111
|
+
BOOL_EXPR_AND = 0
|
112
|
+
BOOL_EXPR_OR = 1
|
113
|
+
BOOL_EXPR_NOT = 2
|
114
|
+
|
115
|
+
AEXPR_OP = 0 # normal operator
|
116
|
+
AEXPR_OP_ANY = 1 # scalar op ANY (array)
|
117
|
+
AEXPR_OP_ALL = 2 # scalar op ALL (array)
|
118
|
+
AEXPR_DISTINCT = 3 # IS DISTINCT FROM - name must be "="
|
119
|
+
AEXPR_NULLIF = 4 # NULLIF - name must be "="
|
120
|
+
AEXPR_OF = 5 # IS [NOT] OF - name must be "=" or "<>"
|
121
|
+
AEXPR_IN = 6 # [NOT] IN - name must be "=" or "<>"
|
122
|
+
AEXPR_LIKE = 7 # [NOT] LIKE - name must be "~~" or "!~~"
|
123
|
+
AEXPR_ILIKE = 8 # [NOT] ILIKE - name must be "~~*" or "!~~*"
|
124
|
+
AEXPR_SIMILAR = 9 # [NOT] SIMILAR - name must be "~" or "!~"
|
125
|
+
AEXPR_BETWEEN = 10 # name must be "BETWEEN"
|
126
|
+
AEXPR_NOT_BETWEEN = 11 # name must be "NOT BETWEEN"
|
127
|
+
AEXPR_BETWEEN_SYM = 12 # name must be "BETWEEN SYMMETRIC"
|
128
|
+
AEXPR_NOT_BETWEEN_SYM = 13 # name must be "NOT BETWEEN SYMMETRIC"
|
129
|
+
AEXPR_PAREN = 14 # nameless dummy node for parentheses
|
130
|
+
|
131
|
+
TRANS_STMT_BEGIN = 0
|
132
|
+
TRANS_STMT_START = 1 # semantically identical to BEGIN
|
133
|
+
TRANS_STMT_COMMIT = 2
|
134
|
+
TRANS_STMT_ROLLBACK = 3
|
135
|
+
TRANS_STMT_SAVEPOINT = 4
|
136
|
+
TRANS_STMT_RELEASE = 5
|
137
|
+
TRANS_STMT_ROLLBACK_TO = 6
|
138
|
+
TRANS_STMT_PREPARE = 7
|
139
|
+
TRANS_STMT_COMMIT_PREPARED = 8
|
140
|
+
TRANS_STMT_ROLLBACK_PREPARED = 9
|
141
|
+
|
142
|
+
SUBLINK_TYPE_EXISTS = 0 # EXISTS(SELECT ...)
|
143
|
+
SUBLINK_TYPE_ALL = 1 # (lefthand) op ALL (SELECT ...)
|
144
|
+
SUBLINK_TYPE_ANY = 2 # (lefthand) op ANY (SELECT ...)
|
145
|
+
SUBLINK_TYPE_ROWCOMPARE = 3 # (lefthand) op (SELECT ...)
|
146
|
+
SUBLINK_TYPE_EXPR = 4 # (SELECT with single targetlist item ...)
|
147
|
+
SUBLINK_TYPE_MULTIEXPR = 5 # (SELECT with multiple targetlist items ...)
|
148
|
+
SUBLINK_TYPE_ARRAY = 6 # ARRAY(SELECT with single targetlist item ...)
|
149
|
+
SUBLINK_TYPE_CTE = 7 # WITH query (never actually part of an expression), for SubPlans only
|
150
|
+
|
151
|
+
LCS_NONE = 0 # no such clause - only used in PlanRowMark
|
152
|
+
LCS_FORKEYSHARE = 1 # FOR KEY SHARE
|
153
|
+
LCS_FORSHARE = 2 # FOR SHARE
|
154
|
+
LCS_FORNOKEYUPDATE = 3 # FOR NO KEY UPDATE
|
155
|
+
LCS_FORUPDATE = 4 # FOR UPDATE
|
156
|
+
|
157
|
+
AT_AddColumn = 0 # add column
|
158
|
+
AT_AddColumnRecurse = 1 # internal to commands/tablecmds.c
|
159
|
+
AT_AddColumnToView = 2 # implicitly via CREATE OR REPLACE VIEW
|
160
|
+
AT_ColumnDefault = 3 # alter column default
|
161
|
+
AT_DropNotNull = 4 # alter column drop not null
|
162
|
+
AT_SetNotNull = 5 # alter column set not null
|
163
|
+
AT_SetStatistics = 6 # alter column set statistics
|
164
|
+
AT_SetOptions = 7 # alter column set ( options )
|
165
|
+
AT_ResetOptions = 8 # alter column reset ( options )
|
166
|
+
AT_SetStorage = 9 # alter column set storage
|
167
|
+
AT_DropColumn = 10 # drop column
|
168
|
+
AT_DropColumnRecurse = 11 # internal to commands/tablecmds.c
|
169
|
+
AT_AddIndex = 12 # add index
|
170
|
+
AT_ReAddIndex = 13 # internal to commands/tablecmds.c
|
171
|
+
AT_AddConstraint = 14 # add constraint
|
172
|
+
AT_AddConstraintRecurse = 15 # internal to commands/tablecmds.c
|
173
|
+
AT_ReAddConstraint = 16 # internal to commands/tablecmds.c
|
174
|
+
AT_AlterConstraint = 17 # alter constraint
|
175
|
+
AT_ValidateConstraint = 18 # validate constraint
|
176
|
+
AT_ValidateConstraintRecurse = 19 # internal to commands/tablecmds.c
|
177
|
+
AT_ProcessedConstraint = 20 # pre-processed add constraint (local in parser/parse_utilcmd.c)
|
178
|
+
AT_AddIndexConstraint = 21 # add constraint using existing index
|
179
|
+
AT_DropConstraint = 22 # drop constraint
|
180
|
+
AT_DropConstraintRecurse = 23 # internal to commands/tablecmds.c
|
181
|
+
AT_ReAddComment = 24 # internal to commands/tablecmds.c
|
182
|
+
AT_AlterColumnType = 25 # alter column type
|
183
|
+
AT_AlterColumnGenericOptions = 26 # alter column OPTIONS (...)
|
184
|
+
AT_ChangeOwner = 27 # change owner
|
185
|
+
AT_ClusterOn = 28 # CLUSTER ON
|
186
|
+
AT_DropCluster = 29 # SET WITHOUT CLUSTER
|
187
|
+
AT_SetLogged = 30 # SET LOGGED
|
188
|
+
AT_SetUnLogged = 31 # SET UNLOGGED
|
189
|
+
AT_AddOids = 32 # SET WITH OIDS
|
190
|
+
AT_AddOidsRecurse = 33 # internal to commands/tablecmds.c
|
191
|
+
AT_DropOids = 34 # SET WITHOUT OIDS
|
192
|
+
AT_SetTableSpace = 35 # SET TABLESPACE
|
193
|
+
AT_SetRelOptions = 36 # SET (...) -- AM specific parameters
|
194
|
+
AT_ResetRelOptions = 37 # RESET (...) -- AM specific parameters
|
195
|
+
AT_ReplaceRelOptions = 38 # replace reloption list in its entirety
|
196
|
+
AT_EnableTrig = 39 # ENABLE TRIGGER name
|
197
|
+
AT_EnableAlwaysTrig = 40 # ENABLE ALWAYS TRIGGER name
|
198
|
+
AT_EnableReplicaTrig = 41 # ENABLE REPLICA TRIGGER name
|
199
|
+
AT_DisableTrig = 42 # DISABLE TRIGGER name
|
200
|
+
AT_EnableTrigAll = 43 # ENABLE TRIGGER ALL
|
201
|
+
AT_DisableTrigAll = 44 # DISABLE TRIGGER ALL
|
202
|
+
AT_EnableTrigUser = 45 # ENABLE TRIGGER USER
|
203
|
+
AT_DisableTrigUser = 46 # DISABLE TRIGGER USER
|
204
|
+
AT_EnableRule = 47 # ENABLE RULE name
|
205
|
+
AT_EnableAlwaysRule = 48 # ENABLE ALWAYS RULE name
|
206
|
+
AT_EnableReplicaRule = 49 # ENABLE REPLICA RULE name
|
207
|
+
AT_DisableRule = 50 # DISABLE RULE name
|
208
|
+
AT_AddInherit = 51 # INHERIT parent
|
209
|
+
AT_DropInherit = 52 # NO INHERIT parent
|
210
|
+
AT_AddOf = 53 # OF <type_name>
|
211
|
+
AT_DropOf = 54 # NOT OF
|
212
|
+
AT_ReplicaIdentity = 55 # REPLICA IDENTITY
|
213
|
+
AT_EnableRowSecurity = 56 # ENABLE ROW SECURITY
|
214
|
+
AT_DisableRowSecurity = 57 # DISABLE ROW SECURITY
|
215
|
+
AT_ForceRowSecurity = 58 # FORCE ROW SECURITY
|
216
|
+
AT_NoForceRowSecurity = 59 # NO FORCE ROW SECURITY
|
217
|
+
AT_GenericOptions = 60 # OPTIONS (...)
|
218
|
+
end
|
data/lib/pg_query/param_refs.rb
CHANGED
@@ -2,22 +2,22 @@ class PgQuery
|
|
2
2
|
def param_refs # rubocop:disable Metrics/CyclomaticComplexity
|
3
3
|
results = []
|
4
4
|
|
5
|
-
treewalker!
|
5
|
+
treewalker! @tree do |_, _, v|
|
6
6
|
next unless v.is_a?(Hash)
|
7
7
|
|
8
|
-
if v[
|
9
|
-
results << { 'location' => v[
|
10
|
-
'length' => param_ref_length(v[
|
11
|
-
elsif v[
|
12
|
-
next unless v[
|
8
|
+
if v[PARAM_REF]
|
9
|
+
results << { 'location' => v[PARAM_REF]['location'],
|
10
|
+
'length' => param_ref_length(v[PARAM_REF]) }
|
11
|
+
elsif v[TYPE_CAST]
|
12
|
+
next unless v[TYPE_CAST]['arg'] && v[TYPE_CAST]['typeName']
|
13
13
|
|
14
|
-
p = v[
|
15
|
-
t = v[
|
14
|
+
p = v[TYPE_CAST]['arg'].delete(PARAM_REF)
|
15
|
+
t = v[TYPE_CAST]['typeName'].delete(TYPE_NAME)
|
16
16
|
next unless p && t
|
17
17
|
|
18
18
|
location = p['location']
|
19
19
|
typeloc = t['location']
|
20
|
-
typename = t['names']
|
20
|
+
typename = t['names']
|
21
21
|
length = param_ref_length(p)
|
22
22
|
|
23
23
|
if typeloc < location
|
data/lib/pg_query/parse.rb
CHANGED
@@ -2,10 +2,10 @@ require 'json'
|
|
2
2
|
|
3
3
|
class PgQuery
|
4
4
|
def self.parse(query)
|
5
|
-
|
5
|
+
tree, stderr = _raw_parse(query)
|
6
6
|
|
7
7
|
begin
|
8
|
-
|
8
|
+
tree = JSON.parse(tree, max_nesting: 1000)
|
9
9
|
rescue JSON::ParserError
|
10
10
|
raise ParseError.new('Failed to parse JSON', __FILE__, __LINE__, -1)
|
11
11
|
end
|
@@ -16,16 +16,16 @@ class PgQuery
|
|
16
16
|
warnings << line.strip
|
17
17
|
end
|
18
18
|
|
19
|
-
PgQuery.new(query,
|
19
|
+
PgQuery.new(query, tree, warnings)
|
20
20
|
end
|
21
21
|
|
22
22
|
attr_reader :query
|
23
|
-
attr_reader :
|
23
|
+
attr_reader :tree
|
24
24
|
attr_reader :warnings
|
25
25
|
|
26
|
-
def initialize(query,
|
26
|
+
def initialize(query, tree, warnings = [])
|
27
27
|
@query = query
|
28
|
-
@
|
28
|
+
@tree = tree
|
29
29
|
@warnings = warnings
|
30
30
|
end
|
31
31
|
|
@@ -45,7 +45,7 @@ class PgQuery
|
|
45
45
|
@tables = []
|
46
46
|
@aliases = {}
|
47
47
|
|
48
|
-
statements = @
|
48
|
+
statements = @tree.dup
|
49
49
|
from_clause_items = []
|
50
50
|
where_clause_items = []
|
51
51
|
|
@@ -53,44 +53,44 @@ class PgQuery
|
|
53
53
|
statement = statements.shift
|
54
54
|
if statement
|
55
55
|
case statement.keys[0]
|
56
|
-
when
|
57
|
-
if statement[
|
58
|
-
(statement[
|
59
|
-
if item[
|
60
|
-
statements << item[
|
56
|
+
when SELECT_STMT
|
57
|
+
if statement[SELECT_STMT]['op'] == 0
|
58
|
+
(statement[SELECT_STMT][FROM_CLAUSE_FIELD] || []).each do |item|
|
59
|
+
if item[RANGE_SUBSELECT]
|
60
|
+
statements << item[RANGE_SUBSELECT]['subquery']
|
61
61
|
else
|
62
62
|
from_clause_items << item
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
66
|
# CTEs
|
67
|
-
if statement[
|
68
|
-
statement[
|
69
|
-
statements << item[
|
67
|
+
if statement[SELECT_STMT]['withClause']
|
68
|
+
statement[SELECT_STMT]['withClause'][WITH_CLAUSE]['ctes'].each do |item|
|
69
|
+
statements << item[COMMON_TABLE_EXPR]['ctequery'] if item[COMMON_TABLE_EXPR]
|
70
70
|
end
|
71
71
|
end
|
72
|
-
elsif statement[
|
73
|
-
statements << statement[
|
74
|
-
statements << statement[
|
72
|
+
elsif statement[SELECT_STMT]['op'] == 1
|
73
|
+
statements << statement[SELECT_STMT]['larg'] if statement[SELECT_STMT]['larg']
|
74
|
+
statements << statement[SELECT_STMT]['rarg'] if statement[SELECT_STMT]['rarg']
|
75
75
|
end
|
76
|
-
when
|
76
|
+
when INSERT_STMT, UPDATE_STMT, DELETE_STMT, VACUUM_STMT, COPY_STMT, ALTER_TABLE_STMT, CREATE_STMT, INDEX_STMT, RULE_STMT, CREATE_TRIG_STMT
|
77
77
|
from_clause_items << statement.values[0]['relation']
|
78
|
-
when
|
79
|
-
from_clause_items << statement[
|
80
|
-
statements << statement[
|
81
|
-
when
|
82
|
-
from_clause_items << statement[
|
83
|
-
when
|
84
|
-
statements << statement[
|
85
|
-
when
|
86
|
-
if statement[
|
87
|
-
from_clause_items << statement[
|
78
|
+
when VIEW_STMT
|
79
|
+
from_clause_items << statement[VIEW_STMT]['view']
|
80
|
+
statements << statement[VIEW_STMT]['query']
|
81
|
+
when REFRESH_MAT_VIEW_STMT
|
82
|
+
from_clause_items << statement[REFRESH_MAT_VIEW_STMT]['relation']
|
83
|
+
when EXPLAIN_STMT
|
84
|
+
statements << statement[EXPLAIN_STMT]['query']
|
85
|
+
when CREATE_TABLE_AS_STMT
|
86
|
+
if statement[CREATE_TABLE_AS_STMT]['into'] && statement[CREATE_TABLE_AS_STMT]['into'][INTO_CLAUSE]['rel']
|
87
|
+
from_clause_items << statement[CREATE_TABLE_AS_STMT]['into'][INTO_CLAUSE]['rel']
|
88
88
|
end
|
89
|
-
when
|
89
|
+
when LOCK_STMT, TRUNCATE_STMT
|
90
90
|
from_clause_items += statement.values[0]['relations']
|
91
|
-
when
|
92
|
-
objects = statement[
|
93
|
-
case statement[
|
91
|
+
when GRANT_STMT
|
92
|
+
objects = statement[GRANT_STMT]['objects']
|
93
|
+
case statement[GRANT_STMT]['objtype']
|
94
94
|
when 0 # Column
|
95
95
|
# FIXME
|
96
96
|
when 1 # Table
|
@@ -98,14 +98,12 @@ class PgQuery
|
|
98
98
|
when 2 # Sequence
|
99
99
|
# FIXME
|
100
100
|
end
|
101
|
-
when
|
102
|
-
objects = statement['
|
103
|
-
case statement[
|
104
|
-
when
|
101
|
+
when DROP_STMT
|
102
|
+
objects = statement[DROP_STMT]['objects'].map { |list| list.map { |obj| obj['String']['str'] } }
|
103
|
+
case statement[DROP_STMT]['removeType']
|
104
|
+
when OBJECT_TYPE_TABLE
|
105
105
|
@tables += objects.map { |r| r.join('.') }
|
106
|
-
when
|
107
|
-
@tables += objects.map { |r| r[0..-2].join('.') }
|
108
|
-
when 28 # Trigger
|
106
|
+
when OBJECT_TYPE_RULE, OBJECT_TYPE_TRIGGER
|
109
107
|
@tables += objects.map { |r| r[0..-2].join('.') }
|
110
108
|
end
|
111
109
|
end
|
@@ -117,7 +115,7 @@ class PgQuery
|
|
117
115
|
next_item = where_clause_items.shift
|
118
116
|
if next_item
|
119
117
|
case next_item.keys[0]
|
120
|
-
when
|
118
|
+
when A_EXPR
|
121
119
|
%w(lexpr rexpr).each do |side|
|
122
120
|
elem = next_item.values[0][side]
|
123
121
|
next unless elem
|
@@ -127,8 +125,8 @@ class PgQuery
|
|
127
125
|
where_clause_items << elem
|
128
126
|
end
|
129
127
|
end
|
130
|
-
when
|
131
|
-
statements << next_item[
|
128
|
+
when SUB_LINK
|
129
|
+
statements << next_item[SUB_LINK]['subselect']
|
132
130
|
end
|
133
131
|
end
|
134
132
|
|
@@ -140,17 +138,17 @@ class PgQuery
|
|
140
138
|
break unless next_item
|
141
139
|
|
142
140
|
case next_item.keys[0]
|
143
|
-
when
|
141
|
+
when JOIN_EXPR
|
144
142
|
%w(larg rarg).each do |side|
|
145
|
-
from_clause_items << next_item[
|
143
|
+
from_clause_items << next_item[JOIN_EXPR][side]
|
146
144
|
end
|
147
|
-
when
|
148
|
-
from_clause_items += next_item[
|
149
|
-
when
|
150
|
-
rangevar = next_item[
|
145
|
+
when ROW_EXPR
|
146
|
+
from_clause_items += next_item[ROW_EXPR]['args']
|
147
|
+
when RANGE_VAR
|
148
|
+
rangevar = next_item[RANGE_VAR]
|
151
149
|
table = [rangevar['schemaname'], rangevar['relname']].compact.join('.')
|
152
150
|
@tables << table
|
153
|
-
@aliases[rangevar['alias'][
|
151
|
+
@aliases[rangevar['alias'][ALIAS]['aliasname']] = table if rangevar['alias']
|
154
152
|
end
|
155
153
|
end
|
156
154
|
|
data/lib/pg_query/treewalker.rb
CHANGED
@@ -30,18 +30,24 @@ class PgQuery
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
def transform_nodes!(parsetree, &block)
|
34
|
+
result = deep_dup(parsetree)
|
35
|
+
exprs = result.dup
|
36
|
+
|
37
|
+
loop do
|
38
|
+
expr = exprs.shift
|
39
|
+
|
40
|
+
if expr.is_a?(Hash)
|
41
|
+
block.call(expr) if expr.size == 1 && expr.keys[0][/^[A-Z]+/]
|
42
|
+
|
43
|
+
exprs += expr.values.compact
|
44
|
+
elsif expr.is_a?(Array)
|
45
|
+
exprs += expr
|
38
46
|
end
|
39
|
-
|
40
|
-
|
41
|
-
when NilClass, FalseClass, TrueClass, Symbol, Numeric
|
42
|
-
obj # Can't be duplicated
|
43
|
-
else
|
44
|
-
obj.dup
|
47
|
+
|
48
|
+
break if exprs.empty?
|
45
49
|
end
|
50
|
+
|
51
|
+
result
|
46
52
|
end
|
47
53
|
end
|