oracle-sql-parser 0.1.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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +4 -0
  5. data/README.md +58 -0
  6. data/Rakefile +41 -0
  7. data/bin/console +14 -0
  8. data/bin/setup +8 -0
  9. data/lib/oracle-sql-parser.rb +7 -0
  10. data/lib/oracle-sql-parser/ast.rb +38 -0
  11. data/lib/oracle-sql-parser/ast/array.rb +37 -0
  12. data/lib/oracle-sql-parser/ast/base.rb +89 -0
  13. data/lib/oracle-sql-parser/ast/between_condition.rb +4 -0
  14. data/lib/oracle-sql-parser/ast/current_of.rb +4 -0
  15. data/lib/oracle-sql-parser/ast/delete_statement.rb +5 -0
  16. data/lib/oracle-sql-parser/ast/delete_target.rb +6 -0
  17. data/lib/oracle-sql-parser/ast/exists_condition.rb +4 -0
  18. data/lib/oracle-sql-parser/ast/for_update_clause.rb +4 -0
  19. data/lib/oracle-sql-parser/ast/function_expression.rb +4 -0
  20. data/lib/oracle-sql-parser/ast/group_by_clause.rb +4 -0
  21. data/lib/oracle-sql-parser/ast/hash.rb +44 -0
  22. data/lib/oracle-sql-parser/ast/identifier.rb +7 -0
  23. data/lib/oracle-sql-parser/ast/in_condition.rb +4 -0
  24. data/lib/oracle-sql-parser/ast/insert_statement.rb +5 -0
  25. data/lib/oracle-sql-parser/ast/keyword.rb +8 -0
  26. data/lib/oracle-sql-parser/ast/like_condition.rb +4 -0
  27. data/lib/oracle-sql-parser/ast/logical_condition.rb +4 -0
  28. data/lib/oracle-sql-parser/ast/null_condition.rb +4 -0
  29. data/lib/oracle-sql-parser/ast/number_literal.rb +8 -0
  30. data/lib/oracle-sql-parser/ast/order_by_clause.rb +4 -0
  31. data/lib/oracle-sql-parser/ast/order_by_clause_item.rb +4 -0
  32. data/lib/oracle-sql-parser/ast/query_block.rb +17 -0
  33. data/lib/oracle-sql-parser/ast/regexp_condition.rb +4 -0
  34. data/lib/oracle-sql-parser/ast/rollup_cube_clause.rb +4 -0
  35. data/lib/oracle-sql-parser/ast/searched_case_expression.rb +8 -0
  36. data/lib/oracle-sql-parser/ast/select_statement.rb +5 -0
  37. data/lib/oracle-sql-parser/ast/simple_case_expression.rb +7 -0
  38. data/lib/oracle-sql-parser/ast/simple_comparision_condition.rb +4 -0
  39. data/lib/oracle-sql-parser/ast/subquery.rb +5 -0
  40. data/lib/oracle-sql-parser/ast/text_literal.rb +7 -0
  41. data/lib/oracle-sql-parser/ast/update_set_column.rb +4 -0
  42. data/lib/oracle-sql-parser/ast/update_statement.rb +4 -0
  43. data/lib/oracle-sql-parser/ast/where_clause.rb +4 -0
  44. data/lib/oracle-sql-parser/grammar.rb +10 -0
  45. data/lib/oracle-sql-parser/grammar/condition.treetop +224 -0
  46. data/lib/oracle-sql-parser/grammar/delete.treetop +68 -0
  47. data/lib/oracle-sql-parser/grammar/expression.treetop +236 -0
  48. data/lib/oracle-sql-parser/grammar/grammar.treetop +166 -0
  49. data/lib/oracle-sql-parser/grammar/insert.treetop +112 -0
  50. data/lib/oracle-sql-parser/grammar/reserved_word_generator.rb +233 -0
  51. data/lib/oracle-sql-parser/grammar/select.treetop +388 -0
  52. data/lib/oracle-sql-parser/grammar/update.treetop +113 -0
  53. data/lib/oracle-sql-parser/treetop_ext.rb +11 -0
  54. data/lib/oracle-sql-parser/version.rb +3 -0
  55. data/oracle-sql-parser.gemspec +28 -0
  56. metadata +176 -0
@@ -0,0 +1,233 @@
1
+ module OracleSqlParser
2
+ module Grammar
3
+ class ReservedWordGenerator
4
+ def self.generate_grammer
5
+ filename = ARGV[1] || File.expand_path("./reserved_word.treetop", File.dirname(__FILE__))
6
+ File.open(filename, 'w') do |f|
7
+ f.write self.generate_grammer_string(filename)
8
+ end
9
+ end
10
+
11
+ class KeywordRule
12
+ attr_reader :keyword
13
+ def initialize(keyword)
14
+ @keyword = keyword
15
+ end
16
+
17
+ def to_s
18
+ content = []
19
+ content << " rule #{rule_name}"
20
+ content << " #{matcher} {"
21
+ content << " def ast"
22
+ content << " OracleSqlParser::Ast::Keyword.new(:name => text_value)"
23
+ content << " end"
24
+ content << " }"
25
+ content << " end"
26
+ content.join("\n")
27
+ end
28
+
29
+ def rule_name
30
+ "#{@keyword.downcase}_keyword"
31
+ end
32
+
33
+ def matcher
34
+ matcher = []
35
+ keyword.each_char do |ch|
36
+ if ch.match(/[A-Z]/)
37
+ matcher << "[#{ch.downcase}#{ch.upcase}]"
38
+ else
39
+ matcher << "'#{ch}'"
40
+ end
41
+ end
42
+ matcher << '( ![A-Za-z0-9] )'
43
+ matcher.join(' ')
44
+ end
45
+ end
46
+
47
+ class MatchKeyword < Array
48
+ attr_reader :rule_name
49
+ def initialize(rule_name)
50
+ @rule_name = rule_name
51
+ end
52
+
53
+ def to_s
54
+ content = []
55
+ content << " rule #{rule_name}"
56
+ content << " [a-zA-Z0-9_]+ ![a-zA-Z0-9] &{|w| #{self.to_a.to_s}.include? w.first.text_value.upcase}"
57
+ content << " end"
58
+ content.join("\n")
59
+ end
60
+ end
61
+
62
+ def self.generate_grammer_string(filename)
63
+ header = <<EOS
64
+ #
65
+ # #{File.basename(filename)} generated by #{__FILE__} at #{Time.now}
66
+ #
67
+ module OracleSqlParser::Grammar
68
+ grammar ReservedWord
69
+ EOS
70
+ content = []
71
+
72
+ footer = <<EOS
73
+ end
74
+ end
75
+ EOS
76
+ not_match_keyword = MatchKeyword.new 'keyword'
77
+ self.keywords.each do |keyword|
78
+ rule = KeywordRule.new(keyword)
79
+ content << rule.to_s
80
+ not_match_keyword << keyword
81
+ end
82
+
83
+ content.unshift not_match_keyword.to_s
84
+ header + content.join("\n") + footer
85
+ end
86
+
87
+ def self.keywords
88
+ [
89
+ 'ACCESS',
90
+ 'ADD',
91
+ 'ALL',
92
+ 'ALTER',
93
+ 'AND',
94
+ 'ANY',
95
+ 'AS',
96
+ 'ASC',
97
+ 'AUDIT',
98
+ 'BETWEEN',
99
+ 'BY',
100
+ 'CASE',
101
+ 'CHAR',
102
+ 'CHECK',
103
+ 'CLUSTER',
104
+ 'CURRENT_OF',
105
+ 'COLUMN',
106
+ 'COLUMN_VALUE',
107
+ 'COMMENT',
108
+ 'COMPRESS',
109
+ 'CONNECT',
110
+ 'CREATE',
111
+ 'CROSS',
112
+ 'CUBE',
113
+ 'CURRENT',
114
+ 'CURRVAL',
115
+ 'DATE',
116
+ 'DECIMAL',
117
+ 'DEFAULT',
118
+ 'DELETE',
119
+ 'DESC',
120
+ 'DISTINCT',
121
+ 'DROP',
122
+ 'ELSE',
123
+ 'END',
124
+ 'ESCAPE',
125
+ 'EXCLUSIVE',
126
+ 'EXISTS',
127
+ 'FILE',
128
+ 'FIRST',
129
+ 'FLOAT',
130
+ 'FOR',
131
+ 'FROM',
132
+ 'FULL',
133
+ 'GRANT',
134
+ 'GROUP',
135
+ 'HAVING',
136
+ 'IDENTIFIED',
137
+ 'IMMEDIATE',
138
+ 'IN',
139
+ 'INCREMENT',
140
+ 'INDEX',
141
+ 'INITIAL',
142
+ 'INNER',
143
+ 'INSERT',
144
+ 'INTEGER',
145
+ 'INTERSECT',
146
+ 'INTO',
147
+ 'IS',
148
+ 'JOIN',
149
+ 'LAST',
150
+ 'LEFT',
151
+ 'LEVEL',
152
+ 'LIKE',
153
+ 'LIKE2',
154
+ 'LIKE4',
155
+ 'LIKEC',
156
+ 'LOCK',
157
+ 'LONG',
158
+ 'MAXEXTENTS',
159
+ 'MINUS',
160
+ 'MLSLABEL',
161
+ 'MODE',
162
+ 'MODIFY',
163
+ 'NATURAL',
164
+ 'NESTED_TABLE_ID',
165
+ 'NEXTVAL',
166
+ 'NOAUDIT',
167
+ 'NOCOMPRESS',
168
+ 'NOT',
169
+ 'NOWAIT',
170
+ 'NULL',
171
+ 'NULLS',
172
+ 'NUMBER',
173
+ 'OF',
174
+ 'OFFLINE',
175
+ 'ON',
176
+ 'ONLINE',
177
+ 'OPTION',
178
+ 'OR',
179
+ 'ORDER',
180
+ 'OUTER',
181
+ 'PCTFREE',
182
+ 'PRIOR',
183
+ 'PRIVILEGES',
184
+ 'PUBLIC',
185
+ 'RAW',
186
+ 'REGEXP_LIKE',
187
+ 'RENAME',
188
+ 'RESOURCE',
189
+ 'REVOKE',
190
+ 'RIGHT',
191
+ 'ROLLUP',
192
+ 'ROW',
193
+ 'ROWID',
194
+ 'ROWNUM',
195
+ 'ROWS',
196
+ 'SELECT',
197
+ 'SESSION',
198
+ 'SET',
199
+ 'SHARE',
200
+ 'SIZE',
201
+ 'SIBLINGS',
202
+ 'SMALLINT',
203
+ 'START',
204
+ 'SUCCESSFUL',
205
+ 'SYNONYM',
206
+ 'SYSDATE',
207
+ 'SYSTIMESTAMP',
208
+ 'TABLE',
209
+ 'THEN',
210
+ 'TO',
211
+ 'TRIGGER',
212
+ 'UID',
213
+ 'UNION',
214
+ 'UNIQUE',
215
+ 'UPDATE',
216
+ 'USER',
217
+ 'USING',
218
+ 'VALIDATE',
219
+ 'VALUES',
220
+ 'VARCHAR',
221
+ 'VARCHAR2',
222
+ 'VIEW',
223
+ 'WAIT',
224
+ 'WHEN',
225
+ 'WHENEVER',
226
+ 'WHERE',
227
+ ]
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ OracleSqlParser::Grammar::ReservedWordGenerator.generate_grammer
@@ -0,0 +1,388 @@
1
+ module OracleSqlParser::Grammar
2
+ grammar Select
3
+ rule select_statement
4
+ subquery for_update_clause:for_update_clause? {
5
+ def ast
6
+ OracleSqlParser::Ast::SelectStatement[
7
+ :subquery => subquery.ast,
8
+ :for_update_clause => for_update_clause.ast]
9
+ end
10
+ }
11
+ end
12
+
13
+ rule subquery
14
+ query_block
15
+ (
16
+ more_queries:(
17
+ union_keyword (space all_keyword?) /
18
+ intersect_keyword /
19
+ minus_keyword
20
+ ) space? subquery )?
21
+ order_by_clause:order_by_clause? {
22
+ def ast
23
+ OracleSqlParser::Ast::Subquery[
24
+ :query_block => query_block.ast,
25
+ :order_by_clause => order_by_clause.ast]
26
+ end
27
+ }
28
+ end
29
+
30
+ rule query_block
31
+ (subquery_factoring_clause:subquery_factoring_clause space)?
32
+ select_keyword space
33
+ hint:hint?
34
+ mod:(modifier:(all_keyword / distinct_keyword / unique_keyword) space)?
35
+ select_list space?
36
+ from_keyword space?
37
+ select_sources space?
38
+ where_clause:where_clause? space?
39
+ group_by_clause:group_by_clause? space?
40
+ model_clause:model_clause? space? {
41
+ def ast
42
+ OracleSqlParser::Ast::QueryBlock[
43
+ :hint => hint.ast,
44
+ :modifier => modifier.ast,
45
+ :select_list => select_list.ast,
46
+ :select_sources => select_sources.ast,
47
+ :where_clause => where_clause.ast,
48
+ :group_by_clause => group_by_clause.ast,
49
+ :model_clause => model_clause.ast]
50
+ end
51
+
52
+ def modifier
53
+ mod.modifier if mod.respond_to? :modifier
54
+ end
55
+ }
56
+ end
57
+
58
+ rule select_sources
59
+ join_clause /
60
+ '(' space? join_clause space? ')' /
61
+ table_reference {
62
+ def ast
63
+ if respond_to? :join_clause
64
+ join_clause.ast
65
+ else
66
+ super
67
+ end
68
+ end
69
+ }
70
+ end
71
+
72
+ rule join_clause
73
+ table_reference space
74
+ (
75
+ outer_join_clause /
76
+ inner_cross_join_clause {
77
+ def ast
78
+ super
79
+ end
80
+ }
81
+ )
82
+ end
83
+
84
+ rule inner_cross_join_clause
85
+ inner_join_clause /
86
+ cross_join_clause {
87
+ def ast
88
+ super
89
+ end
90
+ }
91
+ end
92
+
93
+ rule inner_join_clause
94
+ inner_keyword space? join_keyword space? table_reference space?
95
+ (
96
+ on_keyword space? condition /
97
+ using_keyword space? '(' space? column_list space? ')'
98
+ ) {
99
+ def ast
100
+ 'inner_join_clause'
101
+ end
102
+ }
103
+ end
104
+
105
+ rule cross_join_clause
106
+ (
107
+ cross_keyword /
108
+ natural_keyword (space inner_keyword)?
109
+ ) space join_keyword space table_reference {
110
+ def ast
111
+ 'cross_join_clause'
112
+ end
113
+ }
114
+ end
115
+
116
+ rule column_list
117
+ column_name (space? ',' space? column_name)* {
118
+ def ast
119
+ 'column_list'
120
+ end
121
+ }
122
+ end
123
+
124
+ rule outer_join_clause
125
+ query_partition_clause?
126
+ (
127
+ outer_join_type space? join_keyword /
128
+ natural_keyword space? outer_join_type? space? join_keyword
129
+ ) space
130
+ table_reference space
131
+ (query_partition_clause space)?
132
+ (
133
+ on_keyword space? condition /
134
+ using_keyword space '(' space? column_list space? ')'
135
+ ) {
136
+ def ast
137
+ 'outer_join_clause'
138
+ end
139
+ }
140
+ end
141
+
142
+ rule query_partition_clause
143
+ 'query_partition_clause' {
144
+ def ast
145
+ 'query_partition_clause'
146
+ end
147
+ }
148
+ end
149
+
150
+ rule outer_join_type
151
+ (
152
+ full_keyword /
153
+ left_keyword /
154
+ right_keyword
155
+ ) (space outer_keyword)? {
156
+ def ast
157
+ 'outer_join_type'
158
+ end
159
+ }
160
+ end
161
+
162
+ rule for_update_clause
163
+ for_keyword space?
164
+ update_keyword space?
165
+ f:(of_keyword space for_update_clause_columns)?
166
+ wait:(wait_with_integer / nowait_keyword)? {
167
+ def ast
168
+ OracleSqlParser::Ast::ForUpdateClause[
169
+ :columns => for_update_clause_columns.ast,
170
+ :wait => wait.ast
171
+ ].remove_nil_values!
172
+ end
173
+
174
+ def for_update_clause_columns
175
+ if f.respond_to? :for_update_clause_columns
176
+ f.for_update_clause_columns
177
+ else
178
+ nil
179
+ end
180
+ end
181
+ }
182
+ end
183
+
184
+ rule wait_with_integer
185
+ wait_keyword space? integer {
186
+ def ast
187
+ integer.ast
188
+ end
189
+ }
190
+ end
191
+
192
+ rule for_update_clause_columns
193
+ for_update_clause_column more:(space? ',' space? more_for_update_clause_columns:for_update_clause_column)* {
194
+ def ast
195
+ OracleSqlParser::Ast::Array[
196
+ for_update_clause_column.ast, *more_for_update_clause_columns.map(&:ast)
197
+ ]
198
+ end
199
+
200
+ def more_for_update_clause_columns
201
+ more.elements.map(&:more_for_update_clause_columns)
202
+ end
203
+ }
204
+ end
205
+
206
+ rule for_update_clause_column
207
+ (
208
+ schema_name space? '.' space? table_name space? '.' space? column_name /
209
+ table_name space? '.' space? column_name /
210
+ space? column_name
211
+ ) {
212
+ def ast
213
+ OracleSqlParser::Ast::Identifier[:name => text_value]
214
+ end
215
+ }
216
+ end
217
+
218
+ rule subquery_factoring_clause
219
+ 'subquery_factoring_clause' { # not implemented
220
+ def ast
221
+ 'subquery_factoring_clause'
222
+ end
223
+ }
224
+ end
225
+
226
+ rule order_by_clause
227
+ order_keyword space siblings:siblings_keyword? space? by_keyword space order_by_clause_items {
228
+ def ast
229
+ OracleSqlParser::Ast::OrderByClause[
230
+ :siblings => siblings.ast,
231
+ :items => order_by_clause_items.ast
232
+ ]
233
+ end
234
+ }
235
+ end
236
+
237
+ rule order_by_clause_items
238
+ order_by_clause_item
239
+ more:(space? ',' space? order_by_clause_item space?)* {
240
+ def ast
241
+ OracleSqlParser::Ast::Array[
242
+ order_by_clause_item.ast, *more_order_by_clause_items.map(&:ast)
243
+ ]
244
+ end
245
+
246
+ def more_order_by_clause_items
247
+ more.elements.map(&:order_by_clause_item)
248
+ end
249
+ }
250
+ end
251
+
252
+ rule order_by_clause_item
253
+ target:(expr / position / c_alias) space?
254
+ asc:(asc_keyword / desc_keyword)? space?
255
+ null:(nulls_keyword space first_or_last:(first_keyword / last_keyword))? {
256
+ def ast
257
+ OracleSqlParser::Ast::OrderByClauseItem[
258
+ :target => target.ast,
259
+ :asc => asc.ast,
260
+ :nulls => nulls.ast
261
+ ]
262
+ end
263
+
264
+ def nulls
265
+ if null.respond_to? :first_or_last
266
+ null.first_or_last
267
+ else
268
+ nil
269
+ end
270
+ end
271
+ }
272
+ end
273
+
274
+ rule select_list
275
+ select_one_column more_list:( space? ',' space? c:select_one_column space? )* {
276
+ def ast
277
+ OracleSqlParser::Ast::Array[select_one_column.ast, *more_columns.map(&:ast)]
278
+ end
279
+
280
+ def more_columns
281
+ more_list.elements.map{|element| element.c}
282
+ end
283
+ }
284
+ end
285
+
286
+ rule select_one_column
287
+ ( select_table /
288
+ expr /
289
+ select_column
290
+ ) {
291
+ def ast
292
+ super
293
+ end
294
+ }
295
+ end
296
+
297
+ rule select_table
298
+ (table_name '.')? '*' {
299
+ def ast
300
+ OracleSqlParser::Ast::Identifier[:name => text_value]
301
+ end
302
+ }
303
+ end
304
+
305
+ rule select_column
306
+ sql_expression ( space ( as_keyword space )? c_alias )? {
307
+ def ast
308
+ sql_expression.ast
309
+ end
310
+ }
311
+ end
312
+
313
+ # group
314
+ rule group_by_clause
315
+ group_keyword space by_keyword space target:group_column space?
316
+ t:(',' space? more_target:group_column space?)*
317
+ h:(having_keyword space condition:condition)? {
318
+ def ast
319
+ OracleSqlParser::Ast::GroupByClause[
320
+ :targets => OracleSqlParser::Ast::Array[
321
+ target.ast, *more_targets.map(&:ast)
322
+ ],
323
+ :having => condition.ast
324
+ ]
325
+ end
326
+
327
+ def more_targets
328
+ t.elements.map{|e| e.more_target}
329
+ end
330
+
331
+ def condition
332
+ if h.respond_to? :condition
333
+ h.condition
334
+ else
335
+ nil
336
+ end
337
+ end
338
+ }
339
+ end
340
+
341
+ rule group_column
342
+ (
343
+ expr /
344
+ rollup_cube_clause /
345
+ grouping_sets_clause
346
+ ) {
347
+ def ast
348
+ super
349
+ end
350
+ }
351
+ end
352
+
353
+ rule rollup_cube_clause
354
+ func_name:(rollup_keyword / cube_keyword) space? grouping_expression_list {
355
+ def ast
356
+ OracleSqlParser::Ast::RollupCubeClause[
357
+ :func_name => func_name.ast,
358
+ :args => grouping_expression_list.ast
359
+ ]
360
+ end
361
+ }
362
+ end
363
+
364
+ rule grouping_sets_clause
365
+ 'grouping_sets_clause' { # not implemented
366
+ def ast
367
+ 'grouping_sets_clause'
368
+ end
369
+ }
370
+ end
371
+
372
+ rule grouping_expression_list
373
+ expression_list {
374
+ def ast
375
+ super
376
+ end
377
+ }
378
+ end
379
+
380
+ rule model_clause
381
+ 'model_clause' {
382
+ def ast
383
+ 'model_clause'
384
+ end
385
+ }
386
+ end
387
+ end
388
+ end