pg_query 0.13.5 → 1.0.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: 130496beef8076270894c725111a261febd7b9ac
4
- data.tar.gz: 8543cfd89d821fc25109c0318c9186b19fb66898
3
+ metadata.gz: b234a246e532789199b80cfdc118cc44f45f56dc
4
+ data.tar.gz: 9f1b878a7902bfbce4a86a69d96ecdc8bdd4a659
5
5
  SHA512:
6
- metadata.gz: e93a528c33bd1fdf597d1d67a581038d7988712e6bcf5819184012118955baf881ed2d43575f71fce82486188287c95fc0115ada496898286a4b31080fa479d8
7
- data.tar.gz: a094a568c867ebd96ebcf9bc6b5fb56a711313b2317868ae065089b27b60c3563c20f5c16713c65ba276c77648f4597fb30dae1fb8d57e114097fd0f13aa0456
6
+ metadata.gz: 642d3c1c1a325d737da9252e72715a16f25dc6c2138c03ebd4503efb231604a5fd13b0265cf5637c0aa12510837560b70e8f4ad90ca94ecaf937301783bc4673
7
+ data.tar.gz: 269105c0470ee517a15f6bb613609ed0ff50a915e188b1c43510a98c02304eafee38f5c70a3ecfeefdf4bffdacbbe7331ce0c3d6d13d2336af41d8c314b746bb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0 2017-10-31
4
+
5
+ * IMPORTANT: Major version bump to indicate backwards incompatible parse tree change!
6
+ * Update to Postgres 10 parser and fingerprint version 2
7
+ - This is a backwards-incompatible change in parser output format, although it should
8
+ be relatively easy to update most programs. This can't be avoided since Postgres
9
+ does not guarantee parse trees stay the same across versions
10
+
11
+
3
12
  ## 0.13.5 2017-10-26
4
13
 
5
14
  * Update to libpg_query 9.5-1.7.1
@@ -3,7 +3,7 @@
3
3
  require 'mkmf'
4
4
  require 'open-uri'
5
5
 
6
- LIB_PG_QUERY_TAG = '9.5-1.7.1'.freeze
6
+ LIB_PG_QUERY_TAG = '10-1.0.1'.freeze
7
7
 
8
8
  workdir = Dir.pwd
9
9
  libdir = File.join(workdir, 'libpg_query-' + LIB_PG_QUERY_TAG)
@@ -116,6 +116,8 @@ class PgQuery
116
116
  deparse_rangesubselect(node)
117
117
  when RANGE_VAR
118
118
  deparse_rangevar(node)
119
+ when RAW_STMT
120
+ deparse_raw_stmt(node)
119
121
  when RENAME_STMT
120
122
  deparse_renamestmt(node)
121
123
  when RES_TARGET
@@ -171,15 +173,16 @@ class PgQuery
171
173
 
172
174
  def deparse_rangevar(node)
173
175
  output = []
174
- case node['inhOpt']
175
- when 0
176
- output << 'ONLY'
177
- end
176
+ output << 'ONLY' unless node['inh']
178
177
  output << '"' + node['relname'] + '"'
179
178
  output << deparse_item(node['alias']) if node['alias']
180
179
  output.join(' ')
181
180
  end
182
181
 
182
+ def deparse_raw_stmt(node)
183
+ deparse_item(node[STMT_FIELD])
184
+ end
185
+
183
186
  def deparse_renamestmt(node)
184
187
  output = []
185
188
 
@@ -13,7 +13,9 @@ class PgQuery
13
13
  loop do
14
14
  statement = statements.shift
15
15
  if statement
16
- if statement[SELECT_STMT]
16
+ if statement[RAW_STMT]
17
+ statements << statement[RAW_STMT][STMT_FIELD]
18
+ elsif statement[SELECT_STMT]
17
19
  case statement[SELECT_STMT]['op']
18
20
  when 0
19
21
  if statement[SELECT_STMT][FROM_CLAUSE_FIELD]
@@ -9,7 +9,7 @@ class PgQuery
9
9
 
10
10
  private
11
11
 
12
- FINGERPRINT_VERSION = 1
12
+ FINGERPRINT_VERSION = 2
13
13
 
14
14
  class FingerprintSubHash
15
15
  attr_reader :parts
@@ -76,6 +76,10 @@ class PgQuery
76
76
  next if [DECLARE_CURSOR_STMT, FETCH_STMT, CLOSE_PORTAL_STMT].include?(node_name)
77
77
  when 'relname'
78
78
  next if node_name == RANGE_VAR && fields[RELPERSISTENCE_FIELD] == 't'
79
+ when 'stmt_len'
80
+ next if node_name == RAW_STMT
81
+ when 'stmt_location'
82
+ next if node_name == RAW_STMT
79
83
  end
80
84
 
81
85
  fingerprint_value(val, hash, node_name, field_name, true)
@@ -1,7 +1,9 @@
1
1
  class PgQuery
2
2
  # Legacy parsetree from 0.7 and earlier versions - migrate to "tree" format if you can
3
3
  def parsetree # rubocop:disable Metrics/CyclomaticComplexity
4
- @parsetree ||= transform_nodes!(@tree) do |node|
4
+ @parsetree ||= transform_nodes!(@tree) do |raw_node|
5
+ node = raw_node.keys[0] == RAW_STMT ? raw_node.delete(RAW_STMT)[STMT_FIELD] : raw_node
6
+
5
7
  key = node.keys[0]
6
8
  new_key = LEGACY_NODE_NAMES[key] || key.upcase
7
9
 
@@ -9,34 +11,38 @@ class PgQuery
9
11
  when A_CONST
10
12
  transform_parsetree_a_const(node)
11
13
  when A_EXPR
12
- transform_string_list(node[A_EXPR]['name'])
14
+ node[A_EXPR]['name'] = transform_string_list(node[A_EXPR]['name'])
13
15
  node[key].delete('kind')
14
16
  when COLUMN_REF
15
- transform_string_list(node[COLUMN_REF]['fields'])
17
+ node[COLUMN_REF]['fields'] = transform_string_list(node[COLUMN_REF]['fields'])
16
18
  when CREATE_FUNCTION_STMT
17
- transform_string_list(node[CREATE_FUNCTION_STMT]['funcname'])
19
+ node[CREATE_FUNCTION_STMT]['funcname'] = transform_string_list(node[CREATE_FUNCTION_STMT]['funcname'])
18
20
  when CREATE_TRIG_STMT
19
- transform_string_list(node[CREATE_TRIG_STMT]['funcname'])
21
+ node[CREATE_TRIG_STMT]['funcname'] = transform_string_list(node[CREATE_TRIG_STMT]['funcname'])
20
22
  when CONSTRAINT
21
23
  node[CONSTRAINT]['contype'] = LEGACY_CONSTRAINT_TYPES[node[CONSTRAINT]['contype']]
22
- transform_string_list(node[CONSTRAINT]['keys'])
24
+ node[CONSTRAINT]['keys'] = transform_string_list(node[CONSTRAINT]['keys'])
23
25
  when COPY_STMT
24
- transform_string_list(node[COPY_STMT]['attlist'])
26
+ node[COPY_STMT]['attlist'] = transform_string_list(node[COPY_STMT]['attlist'])
25
27
  when DEF_ELEM
26
28
  node[DEF_ELEM]['arg'] = node[DEF_ELEM]['arg'][INTEGER]['ival'] if node[DEF_ELEM]['arg'].is_a?(Hash) && node[DEF_ELEM]['arg'].keys[0] == INTEGER
27
29
  node[DEF_ELEM]['arg'] = node[DEF_ELEM]['arg'][STRING]['str'] if node[DEF_ELEM]['arg'].is_a?(Hash) && node[DEF_ELEM]['arg'].keys[0] == STRING
28
- transform_string_list(node[DEF_ELEM]['arg']) if node[DEF_ELEM]['arg'].is_a?(Array)
30
+ node[DEF_ELEM]['arg'] = transform_string_list(node[DEF_ELEM]['arg']) if node[DEF_ELEM]['arg'].is_a?(Array)
29
31
  when DROP_STMT
30
- node[DROP_STMT]['objects'].each { |obj| transform_string_list(obj) }
32
+ node[DROP_STMT]['objects'].each_with_index do |obj, idx|
33
+ node[DROP_STMT]['objects'][idx] = transform_string_list(obj)
34
+ end
31
35
  when FUNC_CALL
32
- transform_string_list(node[FUNC_CALL]['funcname'])
36
+ node[FUNC_CALL]['funcname'] = transform_string_list(node[FUNC_CALL]['funcname'])
33
37
  when GRANT_ROLE_STMT
34
- transform_string_list(node[GRANT_ROLE_STMT]['grantee_roles'])
38
+ node[GRANT_ROLE_STMT]['grantee_roles'] = transform_string_list(node[GRANT_ROLE_STMT]['grantee_roles'])
39
+ when RANGE_VAR
40
+ node[RANGE_VAR]['inhOpt'] = node[RANGE_VAR].delete('inh') ? 2 : 0
35
41
  when TYPE_NAME
36
- transform_string_list(node[TYPE_NAME]['names'])
42
+ node[TYPE_NAME]['names'] = transform_string_list(node[TYPE_NAME]['names'])
37
43
  end
38
44
 
39
- node[new_key] = node.delete(key)
45
+ raw_node[new_key] = node.delete(key)
40
46
  end
41
47
  end
42
48
 
@@ -66,18 +72,7 @@ class PgQuery
66
72
  }.freeze
67
73
 
68
74
  LEGACY_CONSTRAINT_TYPES = {
69
- # CONSTR_TYPE_NULL = 0 # not standard SQL, but a lot of people expect it
70
- # CONSTR_TYPE_NOTNULL = 1
71
- # CONSTR_TYPE_DEFAULT = 2
72
- # CONSTR_TYPE_CHECK = 3
73
- CONSTR_TYPE_PRIMARY => 'PRIMARY_KEY',
74
- # CONSTR_TYPE_UNIQUE = 5
75
- # CONSTR_TYPE_EXCLUSION = 6
76
- # CONSTR_TYPE_FOREIGN = 7
77
- # CONSTR_TYPE_ATTR_DEFERRABLE = 8 # attributes for previous constraint node
78
- # CONSTR_TYPE_ATTR_NOT_DEFERRABLE = 9
79
- # CONSTR_TYPE_ATTR_DEFERRED = 10
80
- # CONSTR_TYPE_ATTR_IMMEDIATE = 11
75
+ CONSTR_TYPE_PRIMARY => 'PRIMARY_KEY'
81
76
  }.freeze
82
77
 
83
78
  def transform_parsetree_a_const(node)
@@ -105,6 +100,10 @@ class PgQuery
105
100
  def transform_string_list(list)
106
101
  return if list.nil?
107
102
 
108
- list.map! { |node| node.keys[0] == STRING ? node[STRING]['str'] : node }
103
+ if list.is_a?(Array)
104
+ list.map { |node| node.keys[0] == STRING ? node[STRING]['str'] : node }
105
+ else
106
+ [list.keys[0] == STRING ? list[STRING]['str'] : list]
107
+ end
109
108
  end
110
109
  end
@@ -60,6 +60,7 @@ class PgQuery
60
60
  RANGE_FUNCTION = 'RangeFunction'.freeze
61
61
  RANGE_SUBSELECT = 'RangeSubselect'.freeze
62
62
  RANGE_VAR = 'RangeVar'.freeze
63
+ RAW_STMT = 'RawStmt'.freeze
63
64
  REFRESH_MAT_VIEW_STMT = 'RefreshMatViewStmt'.freeze
64
65
  RENAME_STMT = 'RenameStmt'.freeze
65
66
  RES_TARGET = 'ResTarget'.freeze
@@ -89,6 +90,7 @@ class PgQuery
89
90
  FROM_CLAUSE_FIELD = 'fromClause'.freeze
90
91
  RELPERSISTENCE_FIELD = 'relpersistence'.freeze
91
92
  REXPR_FIELD = 'rexpr'.freeze
93
+ STMT_FIELD = 'stmt'.freeze
92
94
  TARGET_LIST_FIELD = 'targetList'.freeze
93
95
  VALUES_LISTS_FIELD = 'valuesLists'.freeze
94
96
 
@@ -97,22 +99,65 @@ class PgQuery
97
99
  CONSTR_TYPE_NULL = 0 # not standard SQL, but a lot of people expect it
98
100
  CONSTR_TYPE_NOTNULL = 1
99
101
  CONSTR_TYPE_DEFAULT = 2
100
- CONSTR_TYPE_CHECK = 3
101
- CONSTR_TYPE_PRIMARY = 4
102
- CONSTR_TYPE_UNIQUE = 5
103
- CONSTR_TYPE_EXCLUSION = 6
104
- CONSTR_TYPE_FOREIGN = 7
105
- CONSTR_TYPE_ATTR_DEFERRABLE = 8 # attributes for previous constraint node
106
- CONSTR_TYPE_ATTR_NOT_DEFERRABLE = 9
107
- CONSTR_TYPE_ATTR_DEFERRED = 10
108
- CONSTR_TYPE_ATTR_IMMEDIATE = 11
102
+ CONSTR_TYPE_IDENTITY = 3
103
+ CONSTR_TYPE_CHECK = 4
104
+ CONSTR_TYPE_PRIMARY = 5
105
+ CONSTR_TYPE_UNIQUE = 6
106
+ CONSTR_TYPE_EXCLUSION = 7
107
+ CONSTR_TYPE_FOREIGN = 8
108
+ CONSTR_TYPE_ATTR_DEFERRABLE = 9 # attributes for previous constraint node
109
+ CONSTR_TYPE_ATTR_NOT_DEFERRABLE = 10
110
+ CONSTR_TYPE_ATTR_DEFERRED = 11
111
+ CONSTR_TYPE_ATTR_IMMEDIATE = 12
109
112
 
110
- OBJECT_TYPE_INDEX = 19
111
- OBJECT_TYPE_RULE = 28
112
- OBJECT_TYPE_SCHEMA = 29
113
- OBJECT_TYPE_TABLE = 32
114
- OBJECT_TYPE_TRIGGER = 35
115
- OBJECT_TYPE_VIEW = 42
113
+ OBJECT_TYPE_ACCESS_METHOD = 0
114
+ OBJECT_TYPE_AGGREGATE = 1
115
+ OBJECT_TYPE_AMOP = 2
116
+ OBJECT_TYPE_AMPROC = 3
117
+ OBJECT_TYPE_ATTRIBUTE = 4
118
+ OBJECT_TYPE_CAST = 5
119
+ OBJECT_TYPE_COLUMN = 6
120
+ OBJECT_TYPE_COLLATION = 7
121
+ OBJECT_TYPE_CONVERSION = 8
122
+ OBJECT_TYPE_DATABASE = 9
123
+ OBJECT_TYPE_DEFAULT = 10
124
+ OBJECT_TYPE_DEFACL = 11
125
+ OBJECT_TYPE_DOMAIN = 12
126
+ OBJECT_TYPE_DOMCONSTRAINT = 13
127
+ OBJECT_TYPE_EVENT_TRIGGER = 14
128
+ OBJECT_TYPE_EXTENSION = 15
129
+ OBJECT_TYPE_FDW = 16
130
+ OBJECT_TYPE_FOREIGN_SERVER = 17
131
+ OBJECT_TYPE_FOREIGN_TABLE = 18
132
+ OBJECT_TYPE_FUNCTION = 19
133
+ OBJECT_TYPE_INDEX = 20
134
+ OBJECT_TYPE_LANGUAGE = 21
135
+ OBJECT_TYPE_LARGEOBJECT = 22
136
+ OBJECT_TYPE_MATVIEW = 23
137
+ OBJECT_TYPE_OPCLASS = 24
138
+ OBJECT_TYPE_OPERATOR = 25
139
+ OBJECT_TYPE_OPFAMILY = 26
140
+ OBJECT_TYPE_POLICY = 27
141
+ OBJECT_TYPE_PUBLICATION = 28
142
+ OBJECT_TYPE_PUBLICATION_REL = 29
143
+ OBJECT_TYPE_ROLE = 30
144
+ OBJECT_TYPE_RULE = 31
145
+ OBJECT_TYPE_SCHEMA = 32
146
+ OBJECT_TYPE_SEQUENCE = 33
147
+ OBJECT_TYPE_SUBSCRIPTION = 34
148
+ OBJECT_TYPE_STATISTIC_EXT = 35
149
+ OBJECT_TYPE_TABCONSTRAINT = 36
150
+ OBJECT_TYPE_TABLE = 37
151
+ OBJECT_TYPE_TABLESPACE = 38
152
+ OBJECT_TYPE_TRANSFORM = 39
153
+ OBJECT_TYPE_TRIGGER = 40
154
+ OBJECT_TYPE_TSCONFIGURATION = 41
155
+ OBJECT_TYPE_TSDICTIONARY = 42
156
+ OBJECT_TYPE_TSPARSER = 43
157
+ OBJECT_TYPE_TSTEMPLATE = 44
158
+ OBJECT_TYPE_TYPE = 45
159
+ OBJECT_TYPE_USER_MAPPING = 46
160
+ OBJECT_TYPE_VIEW = 47
116
161
 
117
162
  BOOL_EXPR_AND = 0
118
163
  BOOL_EXPR_OR = 1
@@ -129,17 +174,18 @@ class PgQuery
129
174
  AEXPR_OP_ANY = 1 # scalar op ANY (array)
130
175
  AEXPR_OP_ALL = 2 # scalar op ALL (array)
131
176
  AEXPR_DISTINCT = 3 # IS DISTINCT FROM - name must be "="
132
- AEXPR_NULLIF = 4 # NULLIF - name must be "="
133
- AEXPR_OF = 5 # IS [NOT] OF - name must be "=" or "<>"
134
- AEXPR_IN = 6 # [NOT] IN - name must be "=" or "<>"
135
- AEXPR_LIKE = 7 # [NOT] LIKE - name must be "~~" or "!~~"
136
- AEXPR_ILIKE = 8 # [NOT] ILIKE - name must be "~~*" or "!~~*"
137
- AEXPR_SIMILAR = 9 # [NOT] SIMILAR - name must be "~" or "!~"
138
- AEXPR_BETWEEN = 10 # name must be "BETWEEN"
139
- AEXPR_NOT_BETWEEN = 11 # name must be "NOT BETWEEN"
140
- AEXPR_BETWEEN_SYM = 12 # name must be "BETWEEN SYMMETRIC"
141
- AEXPR_NOT_BETWEEN_SYM = 13 # name must be "NOT BETWEEN SYMMETRIC"
142
- AEXPR_PAREN = 14 # nameless dummy node for parentheses
177
+ AEXPR_NOT_DISTINCT = 4 # IS NOT DISTINCT FROM - name must be "="
178
+ AEXPR_NULLIF = 5 # NULLIF - name must be "="
179
+ AEXPR_OF = 6 # IS [NOT] OF - name must be "=" or "<>"
180
+ AEXPR_IN = 7 # [NOT] IN - name must be "=" or "<>"
181
+ AEXPR_LIKE = 8 # [NOT] LIKE - name must be "~~" or "!~~"
182
+ AEXPR_ILIKE = 9 # [NOT] ILIKE - name must be "~~*" or "!~~*"
183
+ AEXPR_SIMILAR = 10 # [NOT] SIMILAR - name must be "~" or "!~"
184
+ AEXPR_BETWEEN = 11 # name must be "BETWEEN"
185
+ AEXPR_NOT_BETWEEN = 12 # name must be "NOT BETWEEN"
186
+ AEXPR_BETWEEN_SYM = 13 # name must be "BETWEEN SYMMETRIC"
187
+ AEXPR_NOT_BETWEEN_SYM = 14 # name must be "NOT BETWEEN SYMMETRIC"
188
+ AEXPR_PAREN = 15 # nameless dummy node for parentheses
143
189
 
144
190
  TRANS_STMT_BEGIN = 0
145
191
  TRANS_STMT_START = 1 # semantically identical to BEGIN
@@ -228,4 +274,9 @@ class PgQuery
228
274
  AT_ForceRowSecurity = 58 # FORCE ROW SECURITY
229
275
  AT_NoForceRowSecurity = 59 # NO FORCE ROW SECURITY
230
276
  AT_GenericOptions = 60 # OPTIONS (...)
277
+ AT_AttachPartition = 61 # ATTACH PARTITION
278
+ AT_DetachPartition = 62 # DETACH PARTITION
279
+ AT_AddIdentity = 63 # ADD IDENTITY
280
+ AT_SetIdentity = 64 # SET identity column options
281
+ AT_DropIdentity = 65 # DROP IDENTITY
231
282
  end
@@ -78,6 +78,8 @@ class PgQuery
78
78
  statement = statements.shift
79
79
  if statement
80
80
  case statement.keys[0]
81
+ when RAW_STMT
82
+ statements << statement[RAW_STMT][STMT_FIELD]
81
83
  # The following statement types do not modify tables and are added to from_clause_items
82
84
  # (and subsequently @tables)
83
85
  when SELECT_STMT
@@ -127,7 +129,13 @@ class PgQuery
127
129
  when REFRESH_MAT_VIEW_STMT
128
130
  from_clause_items << { item: statement[REFRESH_MAT_VIEW_STMT]['relation'], type: :ddl }
129
131
  when DROP_STMT
130
- objects = statement[DROP_STMT]['objects'].map { |list| list.map { |obj| obj['String'] && obj['String']['str'] } }
132
+ objects = statement[DROP_STMT]['objects'].map do |obj|
133
+ if obj.is_a?(Array)
134
+ obj.map { |obj2| obj2['String'] && obj2['String']['str'] }
135
+ else
136
+ obj['String'] && obj['String']['str']
137
+ end
138
+ end
131
139
  case statement[DROP_STMT]['removeType']
132
140
  when OBJECT_TYPE_TABLE
133
141
  @tables += objects.map { |r| { table: r.join('.'), type: :ddl } }
@@ -1,3 +1,3 @@
1
1
  class PgQuery
2
- VERSION = '0.13.5'.freeze
2
+ VERSION = '1.0.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.13.5
4
+ version: 1.0.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-10-26 00:00:00.000000000 Z
11
+ date: 2017-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler