oracle-sql-parser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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