sql-parser-tl 0.0.3

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.
@@ -0,0 +1,113 @@
1
+ class SQLParser::Parser
2
+
3
+ option
4
+ ignorecase
5
+
6
+ macro
7
+ DIGIT [0-9]
8
+ UINT {DIGIT}+
9
+ BLANK \s+
10
+
11
+ YEARS {UINT}
12
+ MONTHS {UINT}
13
+ DAYS {UINT}
14
+ DATE {YEARS}-{MONTHS}-{DAYS}
15
+
16
+ IDENT [\w\$]+
17
+
18
+ KW_TRAIL ([\s()]+)|$ # Keywords must trail with these characters; otherwise, aliases containing a keyword as a prefix will be misinterpreted
19
+
20
+ rule
21
+ # [:state] pattern [actions]
22
+
23
+ # literals
24
+ \"{DATE}\" { [:date_string, Date.parse(text)] }
25
+ \'{DATE}\' { [:date_string, Date.parse(text)] }
26
+
27
+ \' { @state = :STRS; [:single_quote, text] }
28
+ :STRS \' { @state = nil; [:single_quote, text] }
29
+ :STRS .*?(?=(?<!\\)\') { [:character_string_literal, text.gsub("''", "'")] }
30
+
31
+ \" { @state = :STRD; [:double_quote, text] }
32
+ :STRD \" { @state = nil; [:double_quote, text] }
33
+ :STRD .*?(?=(?<!\\)\") { [:character_string_literal, text.gsub('""', '"')] }
34
+
35
+ {UINT} { [:unsigned_integer, text.to_i] }
36
+
37
+ # skip
38
+ {BLANK} # no action
39
+
40
+ # keywords
41
+ SELECT(?={KW_TRAIL}) { [:SELECT, text] }
42
+ DATE(?={KW_TRAIL}) { [:DATE, text] }
43
+ ASC(?={KW_TRAIL}) { [:ASC, text] }
44
+ AS(?={KW_TRAIL}) { [:AS, text] }
45
+ FROM(?={KW_TRAIL}) { [:FROM, text] }
46
+ WHERE(?={KW_TRAIL}) { [:WHERE, text] }
47
+ BETWEEN(?={KW_TRAIL}) { [:BETWEEN, text] }
48
+ AND(?={KW_TRAIL}) { [:AND, text] }
49
+ NOT(?={KW_TRAIL}) { [:NOT, text] }
50
+ INNER(?={KW_TRAIL}) { [:INNER, text] }
51
+ INSERT(?={KW_TRAIL}) { [:INSERT, text] }
52
+ INTO(?={KW_TRAIL}) { [:INTO, text] }
53
+ IN(?={KW_TRAIL}) { [:IN, text] }
54
+ ORDER(?={KW_TRAIL}) { [:ORDER, text] }
55
+ OR(?={KW_TRAIL}) { [:OR, text] }
56
+ LIKE(?={KW_TRAIL}) { [:LIKE, text] }
57
+ IS(?={KW_TRAIL}) { [:IS, text] }
58
+ NULL(?={KW_TRAIL}) { [:NULL, text] }
59
+ COUNT(?={KW_TRAIL}) { [:COUNT, text] }
60
+ AVG(?={KW_TRAIL}) { [:AVG, text] }
61
+ MAX(?={KW_TRAIL}) { [:MAX, text] }
62
+ MIN(?={KW_TRAIL}) { [:MIN, text] }
63
+ SUM(?={KW_TRAIL}) { [:SUM, text] }
64
+ GROUP(?={KW_TRAIL}) { [:GROUP, text] }
65
+ BY(?={KW_TRAIL}) { [:BY, text] }
66
+ HAVING(?={KW_TRAIL}) { [:HAVING, text] }
67
+ CROSS(?={KW_TRAIL}) { [:CROSS, text] }
68
+ JOIN(?={KW_TRAIL}) { [:JOIN, text] }
69
+ ON(?={KW_TRAIL}) { [:ON, text] }
70
+ LEFT(?={KW_TRAIL}) { [:LEFT, text] }
71
+ OUTER(?={KW_TRAIL}) { [:OUTER, text] }
72
+ RIGHT(?={KW_TRAIL}) { [:RIGHT, text] }
73
+ FULL(?={KW_TRAIL}) { [:FULL, text] }
74
+ USING(?={KW_TRAIL}) { [:USING, text] }
75
+ EXISTS(?={KW_TRAIL}) { [:EXISTS, text] }
76
+ DESC(?={KW_TRAIL}) { [:DESC, text] }
77
+ CURRENT_USER(?={KW_TRAIL}) { [:CURRENT_USER, text] }
78
+ VALUES(?={KW_TRAIL}) { [:VALUES, text] }
79
+ LIMIT(?={KW_TRAIL}) { [:LIMIT, text] }
80
+ OFFSET(?={KW_TRAIL}) { [:OFFSET, text] }
81
+ DISTINCT(?={KW_TRAIL}) { [:DISTINCT, text] }
82
+ INDEX(?={KW_TRAIL}) { [:INDEX, text] }
83
+ FORCE(?={KW_TRAIL}) { [:FORCE, text] }
84
+ USE(?={KW_TRAIL}) { [:USE, text] }
85
+ IGNORE(?={KW_TRAIL}) { [:IGNORE, text] }
86
+
87
+
88
+ # tokens
89
+ E { [:E, text] }
90
+
91
+ <> { [:not_equals_operator, text] }
92
+ != { [:not_equals_operator, text] }
93
+ = { [:equals_operator, text] }
94
+ <= { [:less_than_or_equals_operator, text] }
95
+ < { [:less_than_operator, text] }
96
+ >= { [:greater_than_or_equals_operator, text] }
97
+ > { [:greater_than_operator, text] }
98
+
99
+ \( { [:left_paren, text] }
100
+ \) { [:right_paren, text] }
101
+ \* { [:asterisk, text] }
102
+ \/ { [:solidus, text] }
103
+ \+ { [:plus_sign, text] }
104
+ \- { [:minus_sign, text] }
105
+ \. { [:period, text] }
106
+ , { [:comma, text] }
107
+
108
+ # identifier
109
+ `{IDENT}` { [:identifier, text[1..-2]] }
110
+ {IDENT} { [:identifier, text] }
111
+
112
+ ---- header ----
113
+ require 'date'
@@ -0,0 +1,324 @@
1
+ #--
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by rex 1.0.5
4
+ # from lexical definition file "lib/sql-parser/parser.rex".
5
+ #++
6
+
7
+ require 'racc/parser'
8
+ class SQLParser::Parser < Racc::Parser
9
+ require 'strscan'
10
+
11
+ class ScanError < StandardError ; end
12
+
13
+ attr_reader :lineno
14
+ attr_reader :filename
15
+ attr_accessor :state
16
+
17
+ def scan_setup(str)
18
+ @ss = StringScanner.new(str)
19
+ @lineno = 1
20
+ @state = nil
21
+ end
22
+
23
+ def action
24
+ yield
25
+ end
26
+
27
+ def scan_str(str)
28
+ scan_setup(str)
29
+ do_parse
30
+ end
31
+ alias :scan :scan_str
32
+
33
+ def load_file( filename )
34
+ @filename = filename
35
+ open(filename, "r") do |f|
36
+ scan_setup(f.read)
37
+ end
38
+ end
39
+
40
+ def scan_file( filename )
41
+ load_file(filename)
42
+ do_parse
43
+ end
44
+
45
+
46
+ def next_token
47
+ return if @ss.eos?
48
+
49
+ # skips empty actions
50
+ until token = _next_token or @ss.eos?; end
51
+ token
52
+ end
53
+
54
+ def _next_token
55
+ text = @ss.peek(1)
56
+ @lineno += 1 if text == "\n"
57
+ token = case @state
58
+ when nil
59
+ case
60
+ when (text = @ss.scan(/\"[0-9]+-[0-9]+-[0-9]+\"/i))
61
+ action { [:date_string, Date.parse(text)] }
62
+
63
+ when (text = @ss.scan(/\'[0-9]+-[0-9]+-[0-9]+\'/i))
64
+ action { [:date_string, Date.parse(text)] }
65
+
66
+ when (text = @ss.scan(/\'/i))
67
+ action { @state = :STRS; [:single_quote, text] }
68
+
69
+ when (text = @ss.scan(/\"/i))
70
+ action { @state = :STRD; [:double_quote, text] }
71
+
72
+ when (text = @ss.scan(/[0-9]+/i))
73
+ action { [:unsigned_integer, text.to_i] }
74
+
75
+ when (text = @ss.scan(/\s+/i))
76
+ ;
77
+
78
+ when (text = @ss.scan(/SELECT(?=([\s()]+)|$)/i))
79
+ action { [:SELECT, text] }
80
+
81
+ when (text = @ss.scan(/DATE(?=([\s()]+)|$)/i))
82
+ action { [:DATE, text] }
83
+
84
+ when (text = @ss.scan(/ASC(?=([\s()]+)|$)/i))
85
+ action { [:ASC, text] }
86
+
87
+ when (text = @ss.scan(/AS(?=([\s()]+)|$)/i))
88
+ action { [:AS, text] }
89
+
90
+ when (text = @ss.scan(/FROM(?=([\s()]+)|$)/i))
91
+ action { [:FROM, text] }
92
+
93
+ when (text = @ss.scan(/WHERE(?=([\s()]+)|$)/i))
94
+ action { [:WHERE, text] }
95
+
96
+ when (text = @ss.scan(/BETWEEN(?=([\s()]+)|$)/i))
97
+ action { [:BETWEEN, text] }
98
+
99
+ when (text = @ss.scan(/AND(?=([\s()]+)|$)/i))
100
+ action { [:AND, text] }
101
+
102
+ when (text = @ss.scan(/NOT(?=([\s()]+)|$)/i))
103
+ action { [:NOT, text] }
104
+
105
+ when (text = @ss.scan(/INNER(?=([\s()]+)|$)/i))
106
+ action { [:INNER, text] }
107
+
108
+ when (text = @ss.scan(/INSERT(?=([\s()]+)|$)/i))
109
+ action { [:INSERT, text] }
110
+
111
+ when (text = @ss.scan(/INTO(?=([\s()]+)|$)/i))
112
+ action { [:INTO, text] }
113
+
114
+ when (text = @ss.scan(/IN(?=([\s()]+)|$)/i))
115
+ action { [:IN, text] }
116
+
117
+ when (text = @ss.scan(/ORDER(?=([\s()]+)|$)/i))
118
+ action { [:ORDER, text] }
119
+
120
+ when (text = @ss.scan(/OR(?=([\s()]+)|$)/i))
121
+ action { [:OR, text] }
122
+
123
+ when (text = @ss.scan(/LIKE(?=([\s()]+)|$)/i))
124
+ action { [:LIKE, text] }
125
+
126
+ when (text = @ss.scan(/IS(?=([\s()]+)|$)/i))
127
+ action { [:IS, text] }
128
+
129
+ when (text = @ss.scan(/NULL(?=([\s()]+)|$)/i))
130
+ action { [:NULL, text] }
131
+
132
+ when (text = @ss.scan(/COUNT(?=([\s()]+)|$)/i))
133
+ action { [:COUNT, text] }
134
+
135
+ when (text = @ss.scan(/AVG(?=([\s()]+)|$)/i))
136
+ action { [:AVG, text] }
137
+
138
+ when (text = @ss.scan(/MAX(?=([\s()]+)|$)/i))
139
+ action { [:MAX, text] }
140
+
141
+ when (text = @ss.scan(/MIN(?=([\s()]+)|$)/i))
142
+ action { [:MIN, text] }
143
+
144
+ when (text = @ss.scan(/SUM(?=([\s()]+)|$)/i))
145
+ action { [:SUM, text] }
146
+
147
+ when (text = @ss.scan(/GROUP(?=([\s()]+)|$)/i))
148
+ action { [:GROUP, text] }
149
+
150
+ when (text = @ss.scan(/BY(?=([\s()]+)|$)/i))
151
+ action { [:BY, text] }
152
+
153
+ when (text = @ss.scan(/HAVING(?=([\s()]+)|$)/i))
154
+ action { [:HAVING, text] }
155
+
156
+ when (text = @ss.scan(/CROSS(?=([\s()]+)|$)/i))
157
+ action { [:CROSS, text] }
158
+
159
+ when (text = @ss.scan(/JOIN(?=([\s()]+)|$)/i))
160
+ action { [:JOIN, text] }
161
+
162
+ when (text = @ss.scan(/ON(?=([\s()]+)|$)/i))
163
+ action { [:ON, text] }
164
+
165
+ when (text = @ss.scan(/LEFT(?=([\s()]+)|$)/i))
166
+ action { [:LEFT, text] }
167
+
168
+ when (text = @ss.scan(/OUTER(?=([\s()]+)|$)/i))
169
+ action { [:OUTER, text] }
170
+
171
+ when (text = @ss.scan(/RIGHT(?=([\s()]+)|$)/i))
172
+ action { [:RIGHT, text] }
173
+
174
+ when (text = @ss.scan(/FULL(?=([\s()]+)|$)/i))
175
+ action { [:FULL, text] }
176
+
177
+ when (text = @ss.scan(/USING(?=([\s()]+)|$)/i))
178
+ action { [:USING, text] }
179
+
180
+ when (text = @ss.scan(/EXISTS(?=([\s()]+)|$)/i))
181
+ action { [:EXISTS, text] }
182
+
183
+ when (text = @ss.scan(/DESC(?=([\s()]+)|$)/i))
184
+ action { [:DESC, text] }
185
+
186
+ when (text = @ss.scan(/CURRENT_USER(?=([\s()]+)|$)/i))
187
+ action { [:CURRENT_USER, text] }
188
+
189
+ when (text = @ss.scan(/VALUES(?=([\s()]+)|$)/i))
190
+ action { [:VALUES, text] }
191
+
192
+ when (text = @ss.scan(/LIMIT(?=([\s()]+)|$)/i))
193
+ action { [:LIMIT, text] }
194
+
195
+ when (text = @ss.scan(/OFFSET(?=([\s()]+)|$)/i))
196
+ action { [:OFFSET, text] }
197
+
198
+ when (text = @ss.scan(/DISTINCT(?=([\s()]+)|$)/i))
199
+ action { [:DISTINCT, text] }
200
+
201
+ when (text = @ss.scan(/INDEX(?=([\s()]+)|$)/i))
202
+ action { [:INDEX, text] }
203
+
204
+ when (text = @ss.scan(/FORCE(?=([\s()]+)|$)/i))
205
+ action { [:FORCE, text] }
206
+
207
+ when (text = @ss.scan(/USE(?=([\s()]+)|$)/i))
208
+ action { [:USE, text] }
209
+
210
+ when (text = @ss.scan(/IGNORE(?=([\s()]+)|$)/i))
211
+ action { [:IGNORE, text] }
212
+
213
+ when (text = @ss.scan(/E/i))
214
+ action { [:E, text] }
215
+
216
+ when (text = @ss.scan(/<>/i))
217
+ action { [:not_equals_operator, text] }
218
+
219
+ when (text = @ss.scan(/!=/i))
220
+ action { [:not_equals_operator, text] }
221
+
222
+ when (text = @ss.scan(/=/i))
223
+ action { [:equals_operator, text] }
224
+
225
+ when (text = @ss.scan(/<=/i))
226
+ action { [:less_than_or_equals_operator, text] }
227
+
228
+ when (text = @ss.scan(/</i))
229
+ action { [:less_than_operator, text] }
230
+
231
+ when (text = @ss.scan(/>=/i))
232
+ action { [:greater_than_or_equals_operator, text] }
233
+
234
+ when (text = @ss.scan(/>/i))
235
+ action { [:greater_than_operator, text] }
236
+
237
+ when (text = @ss.scan(/\(/i))
238
+ action { [:left_paren, text] }
239
+
240
+ when (text = @ss.scan(/\)/i))
241
+ action { [:right_paren, text] }
242
+
243
+ when (text = @ss.scan(/\*/i))
244
+ action { [:asterisk, text] }
245
+
246
+ when (text = @ss.scan(/\//i))
247
+ action { [:solidus, text] }
248
+
249
+ when (text = @ss.scan(/\+/i))
250
+ action { [:plus_sign, text] }
251
+
252
+ when (text = @ss.scan(/\-/i))
253
+ action { [:minus_sign, text] }
254
+
255
+ when (text = @ss.scan(/\./i))
256
+ action { [:period, text] }
257
+
258
+ when (text = @ss.scan(/,/i))
259
+ action { [:comma, text] }
260
+
261
+ when (text = @ss.scan(/`[\w\$]+`/i))
262
+ action { [:identifier, text[1..-2]] }
263
+
264
+ when (text = @ss.scan(/[\w\$]+/i))
265
+ action { [:identifier, text] }
266
+
267
+ when (text = @ss.scan(/----/i))
268
+ ;
269
+
270
+ when (text = @ss.scan(/require/i))
271
+ ;
272
+
273
+ else
274
+ text = @ss.string[@ss.pos .. -1]
275
+ raise ScanError, "can not match: '" + text + "'"
276
+ end # if
277
+
278
+ when :STRS
279
+ case
280
+ when (text = @ss.scan(/\'/i))
281
+ action { @state = nil; [:single_quote, text] }
282
+
283
+ when (text = @ss.scan(/.*?(?=(?<!\\)\')/i))
284
+ action { [:character_string_literal, text.gsub("''", "'")] }
285
+
286
+ else
287
+ text = @ss.string[@ss.pos .. -1]
288
+ raise ScanError, "can not match: '" + text + "'"
289
+ end # if
290
+
291
+ when :STRD
292
+ case
293
+ when (text = @ss.scan(/\"/i))
294
+ action { @state = nil; [:double_quote, text] }
295
+
296
+ when (text = @ss.scan(/.*?(?=(?<!\\)\")/i))
297
+ action { [:character_string_literal, text.gsub('""', '"')] }
298
+
299
+ else
300
+ text = @ss.string[@ss.pos .. -1]
301
+ raise ScanError, "can not match: '" + text + "'"
302
+ end # if
303
+
304
+ else
305
+ raise ScanError, "undefined state: '" + state.to_s + "'"
306
+ end # case state
307
+ token
308
+ end # def _next_token
309
+
310
+ end # class
311
+
312
+ if __FILE__ == $0
313
+ exit if ARGV.size != 1
314
+ filename = ARGV.shift
315
+ rex = SQLParser::Parser.new
316
+ begin
317
+ rex.load_file filename
318
+ while token = rex.next_token
319
+ p token
320
+ end
321
+ rescue
322
+ $stderr.printf "%s:%d:%s\n", rex.filename, rex.lineno, $!.message
323
+ end
324
+ end