pg_query 0.13.5 → 1.0.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 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