sql-parser-tl 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,383 @@
1
+ module SQLParser
2
+
3
+ class SQLVisitor
4
+
5
+ def initialize
6
+ @negated = false
7
+ end
8
+
9
+ def visit(node)
10
+ node.accept(self)
11
+ end
12
+
13
+ def visit_Insert(o)
14
+ name = visit(o.table_reference)
15
+ columns = ' ' + visit(o.column_list) if o.column_list
16
+ values = ' VALUES ' + visit(o.in_value_list)
17
+ "INSERT INTO #{name}#{columns}#{values}"
18
+ end
19
+
20
+ def visit_DirectSelect(o)
21
+ [
22
+ o.query_expression,
23
+ o.order_by,
24
+ o.limit_clause
25
+ ].compact.collect { |e| visit(e) }.join(' ')
26
+ end
27
+
28
+ def visit_OrderBy(o)
29
+ "ORDER BY #{arrayize(o.sort_specification)}"
30
+ end
31
+
32
+ def visit_LimitClause(o)
33
+ "LIMIT #{o.limit} OFFSET #{o.offset}"
34
+ end
35
+
36
+ def visit_Subquery(o)
37
+ "(#{visit(o.query_specification)})"
38
+ end
39
+
40
+ def visit_Select(o)
41
+ # FIXME: This feels like a hack
42
+ initialize
43
+
44
+ "SELECT #{visit_all([o.list, o.table_expression].compact).join(' ')}"
45
+ end
46
+
47
+ def visit_SelectList(o)
48
+ arrayize(o.columns)
49
+ end
50
+
51
+ def visit_Distinct(o)
52
+ "DISTINCT(#{visit(o.column)})"
53
+ end
54
+
55
+ def visit_All(o)
56
+ '*'
57
+ end
58
+
59
+ def visit_TableExpression(o)
60
+ [
61
+ o.from_clause,
62
+ o.where_clause,
63
+ o.group_by_clause,
64
+ o.having_clause
65
+ ].compact.collect { |e| visit(e) }.join(' ')
66
+ end
67
+
68
+ def visit_FromClause(o)
69
+ "FROM #{arrayize(o.tables)}"
70
+ end
71
+
72
+ def visit_OrderClause(o)
73
+ "ORDER BY #{arrayize(o.columns)}"
74
+ end
75
+
76
+ def visit_Ascending(o)
77
+ "#{visit(o.column)} ASC"
78
+ end
79
+
80
+ def visit_Descending(o)
81
+ "#{visit(o.column)} DESC"
82
+ end
83
+
84
+ def visit_HavingClause(o)
85
+ "HAVING #{visit(o.search_condition)}"
86
+ end
87
+
88
+ def visit_GroupByClause(o)
89
+ "GROUP BY #{arrayize(o.columns)}"
90
+ end
91
+
92
+ def visit_WhereClause(o)
93
+ "WHERE #{visit(o.search_condition)}"
94
+ end
95
+
96
+ def visit_On(o)
97
+ "ON #{visit(o.search_condition)}"
98
+ end
99
+
100
+ def visit_Using(o)
101
+ "USING (#{arrayize(o.columns)})"
102
+ end
103
+
104
+ def visit_Or(o)
105
+ search_condition('OR', o)
106
+ end
107
+
108
+ def visit_And(o)
109
+ search_condition('AND', o)
110
+ end
111
+
112
+ def visit_Exists(o)
113
+ if @negated
114
+ "NOT EXISTS #{visit(o.table_subquery)}"
115
+ else
116
+ "EXISTS #{visit(o.table_subquery)}"
117
+ end
118
+ end
119
+
120
+ def visit_Is(o)
121
+ if @negated
122
+ comparison('IS NOT', o)
123
+ else
124
+ comparison('IS', o)
125
+ end
126
+ end
127
+
128
+ def visit_Like(o)
129
+ if @negated
130
+ comparison('NOT LIKE', o)
131
+ else
132
+ comparison('LIKE', o)
133
+ end
134
+ end
135
+
136
+ def visit_In(o)
137
+ if @negated
138
+ comparison('NOT IN', o)
139
+ else
140
+ comparison('IN', o)
141
+ end
142
+ end
143
+
144
+ def visit_InColumnList(o)
145
+ "(#{arrayize(o.columns)})"
146
+ end
147
+
148
+ def visit_InValueList(o)
149
+ "(#{arrayize(o.values)})"
150
+ end
151
+
152
+ def visit_Between(o)
153
+ if @negated
154
+ comparison('NOT BETWEEN', o)
155
+ else
156
+ comparison('BETWEEN', o)
157
+ end
158
+ end
159
+
160
+ def visit_BetweenRange(o)
161
+ "#{visit(o.min)} AND #{visit(o.max)}"
162
+ end
163
+
164
+ def visit_GreaterOrEquals(o)
165
+ comparison('>=', o)
166
+ end
167
+
168
+ def visit_LessOrEquals(o)
169
+ comparison('<=', o)
170
+ end
171
+
172
+ def visit_Greater(o)
173
+ comparison('>', o)
174
+ end
175
+
176
+ def visit_Less(o)
177
+ comparison('<', o)
178
+ end
179
+
180
+ def visit_Equals(o)
181
+ if @negated
182
+ comparison('<>', o)
183
+ else
184
+ comparison('=', o)
185
+ end
186
+ end
187
+
188
+ def visit_Sum(o)
189
+ aggregate('SUM', o)
190
+ end
191
+
192
+ def visit_Minimum(o)
193
+ aggregate('MIN', o)
194
+ end
195
+
196
+ def visit_Maximum(o)
197
+ aggregate('MAX', o)
198
+ end
199
+
200
+ def visit_Average(o)
201
+ aggregate('AVG', o)
202
+ end
203
+
204
+ def visit_Count(o)
205
+ aggregate('COUNT', o)
206
+ end
207
+
208
+ def visit_CrossJoin(o)
209
+ "#{visit(o.left)} CROSS JOIN #{visit(o.right)}"
210
+ end
211
+
212
+ def visit_InnerJoin(o)
213
+ qualified_join('INNER', o)
214
+ end
215
+
216
+ def visit_LeftJoin(o)
217
+ qualified_join('LEFT', o)
218
+ end
219
+
220
+ def visit_LeftOuterJoin(o)
221
+ qualified_join('LEFT OUTER', o)
222
+ end
223
+
224
+ def visit_RightJoin(o)
225
+ qualified_join('RIGHT', o)
226
+ end
227
+
228
+ def visit_RightOuterJoin(o)
229
+ qualified_join('RIGHT OUTER', o)
230
+ end
231
+
232
+ def visit_FullJoin(o)
233
+ qualified_join('FULL', o)
234
+ end
235
+
236
+ def visit_FullOuterJoin(o)
237
+ qualified_join('FULL OUTER', o)
238
+ end
239
+
240
+ def visit_Table(o)
241
+ quote(o.name)
242
+ end
243
+
244
+ def visit_QualifiedColumn(o)
245
+ "#{visit(o.table)}.#{visit(o.column)}"
246
+ end
247
+
248
+ def visit_Column(o)
249
+ quote(o.name)
250
+ end
251
+
252
+ def visit_As(o)
253
+ "#{visit(o.original)} AS #{visit(o.alias)}"
254
+ end
255
+
256
+ def visit_ForceIndex(o)
257
+ "#{visit(o.table)} FORCE INDEX (`#{o.index}`)"
258
+ end
259
+
260
+ def visit_UseIndex(o)
261
+ "#{visit(o.table)} USE INDEX (`#{o.index}`)"
262
+ end
263
+
264
+ def visit_IgnoreIndex(o)
265
+ "#{visit(o.table)} IGNORE INDEX (`#{o.index}`)"
266
+ end
267
+
268
+ def visit_Multiply(o)
269
+ arithmetic('*', o)
270
+ end
271
+
272
+ def visit_Divide(o)
273
+ arithmetic('/', o)
274
+ end
275
+
276
+ def visit_Add(o)
277
+ arithmetic('+', o)
278
+ end
279
+
280
+ def visit_Subtract(o)
281
+ arithmetic('-', o)
282
+ end
283
+
284
+ def visit_Not(o)
285
+ negate { visit(o.value) }
286
+ end
287
+
288
+ def visit_UnaryPlus(o)
289
+ "+#{visit(o.value)}"
290
+ end
291
+
292
+ def visit_UnaryMinus(o)
293
+ "-#{visit(o.value)}"
294
+ end
295
+
296
+ def visit_True(o)
297
+ 'TRUE'
298
+ end
299
+
300
+ def visit_False(o)
301
+ 'FALSE'
302
+ end
303
+
304
+ def visit_Null(o)
305
+ 'NULL'
306
+ end
307
+
308
+ def visit_CurrentUser(o)
309
+ 'CURRENT_USER'
310
+ end
311
+
312
+ def visit_DateTime(o)
313
+ "'%s'" % escape(o.value.strftime('%Y-%m-%d %H:%M:%S'))
314
+ end
315
+
316
+ def visit_Date(o)
317
+ "DATE '%s'" % escape(o.value.strftime('%Y-%m-%d'))
318
+ end
319
+
320
+ def visit_String(o)
321
+ "'%s'" % escape(o.value)
322
+ end
323
+
324
+ def visit_ApproximateFloat(o)
325
+ "#{visit(o.mantissa)}E#{visit(o.exponent)}"
326
+ end
327
+
328
+ def visit_Float(o)
329
+ o.value.to_s
330
+ end
331
+
332
+ def visit_Integer(o)
333
+ o.value.to_s
334
+ end
335
+
336
+ private
337
+
338
+ def negate
339
+ @negated = true
340
+ yield
341
+ ensure
342
+ @negated = false
343
+ end
344
+
345
+ def quote(str)
346
+ "`#{str}`"
347
+ end
348
+
349
+ def escape(str)
350
+ str.gsub(/'/, "''")
351
+ end
352
+
353
+ def arithmetic(operator, o)
354
+ search_condition(operator, o)
355
+ end
356
+
357
+ def comparison(operator, o)
358
+ [visit(o.left), operator, visit(o.right)].join(' ')
359
+ end
360
+
361
+ def search_condition(operator, o)
362
+ "(#{visit(o.left)} #{operator} #{visit(o.right)})"
363
+ end
364
+
365
+ def visit_all(nodes)
366
+ nodes.collect { |e| visit(e) }
367
+ end
368
+
369
+ def arrayize(arr)
370
+ visit_all(arr).join(', ')
371
+ end
372
+
373
+ def aggregate(function_name, o)
374
+ "#{function_name}(#{visit(o.column)})"
375
+ end
376
+
377
+ def qualified_join(join_type, o)
378
+ "#{visit(o.left)} #{join_type} JOIN #{visit(o.right)} #{visit(o.search_condition)}"
379
+ end
380
+
381
+ end
382
+
383
+ end