1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
|
from copy import copy
import sys
# --------------------------------------------------------------------
# Basic compiler infrastructure
class CompileError(Exception):
pass
class Compile(object):
"""Compiler based on the concept of generic functions."""
def __init__(self):
self._dispatch_table = {}
self._precedence = {}
def copy(self):
copy = self.__class__()
copy._dispatch_table = self._dispatch_table.copy()
copy._precedence = self._precedence.copy()
return copy
def when(self, *types):
def decorator(method):
for type in types:
self._dispatch_table[type] = method
return method
return decorator
def get_precedence(self, type):
return self._precedence.get(type, MAX_PRECEDENCE)
def set_precedence(self, precedence, *types):
for type in types:
self._precedence[type] = precedence
def _compile_single(self, state, expr, outer_precedence):
cls = expr.__class__
for class_ in cls.__mro__:
handler = self._dispatch_table.get(class_)
if handler is not None:
inner_precedence = state.precedence = \
self._precedence.get(cls, MAX_PRECEDENCE)
statement = handler(self._compile, state, expr)
if inner_precedence < outer_precedence:
statement = "(%s)" % statement
return statement
else:
raise CompileError("Don't know how to compile %r"
% expr.__class__)
def _compile(self, state, expr, join=", "):
outer_precedence = state.precedence
if type(expr) is str:
return expr
if type(expr) in (tuple, list):
compiled = []
for subexpr in expr:
if type(subexpr) is str:
statement = subexpr
elif type(subexpr) in (tuple, list):
state.precedence = outer_precedence
statement = self._compile(state, subexpr, join)
else:
statement = self._compile_single(state, subexpr,
outer_precedence)
compiled.append(statement)
statement = join.join(compiled)
else:
statement = self._compile_single(state, expr, outer_precedence)
state.precedence = outer_precedence
return statement
def __call__(self, expr):
state = State()
return self._compile(state, expr), state.parameters
Undef = object()
class State(object):
def __init__(self):
self._stack = []
self.precedence = 0
self.parameters = []
self.auto_tables = []
self.omit_column_tables = False
def push(self, attr, new_value=Undef):
old_value = getattr(self, attr, None)
self._stack.append((attr, old_value))
if new_value is Undef:
new_value = copy(old_value)
setattr(self, attr, new_value)
def pop(self):
setattr(self, *self._stack.pop(-1))
compile = Compile()
# --------------------------------------------------------------------
# Builtin type support
# Most common case. Optimized in Compile._compile.
#@compile.when(str)
#def compile_str(compile, state, expr):
# return expr
@compile.when(type(None))
def compile_none(compile, state, expr):
return "NULL"
# --------------------------------------------------------------------
# Base classes for expressions
MAX_PRECEDENCE = 1000
class Expr(object):
pass
class Comparable(object):
def __eq__(self, other):
if not isinstance(other, Expr) and other is not None:
other = Param(other)
return Eq(self, other)
def __ne__(self, other):
if not isinstance(other, Expr) and other is not None:
other = Param(other)
return Ne(self, other)
def __gt__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return Gt(self, other)
def __ge__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return Ge(self, other)
def __lt__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return Lt(self, other)
def __le__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return Le(self, other)
def __rshift__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return RShift(self, other)
def __lshift__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return LShift(self, other)
def __and__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return And(self, other)
def __or__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return Or(self, other)
def __add__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return Add(self, other)
def __sub__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return Sub(self, other)
def __mul__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return Mul(self, other)
def __div__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return Div(self, other)
def __mod__(self, other):
if not isinstance(other, Expr):
other = Param(other)
return Mod(self, other)
class ComparableExpr(Expr, Comparable):
pass
#class UnaryExpr(ComparableExpr):
#
# def __init__(self, expr):
# self.expr = expr
class BinaryExpr(ComparableExpr):
def __init__(self, expr1, expr2):
self.expr1 = expr1
self.expr2 = expr2
class CompoundExpr(ComparableExpr):
def __init__(self, *exprs):
self.exprs = exprs
# --------------------------------------------------------------------
# Statement expressions
def has_tables(state, expr):
return (expr.tables is not Undef or
expr.default_tables is not Undef or
state.auto_tables)
def build_tables(compile, state, expr):
if expr.tables is not Undef:
return compile(state, expr.tables)
elif state.auto_tables:
tables = []
for expr in state.auto_tables:
table = compile(state, expr)
if table not in tables:
tables.append(table)
return ", ".join(tables)
elif expr.default_tables is not Undef:
return compile(state, expr.default_tables)
raise CompileError("Couldn't find any tables")
def build_table(compile, state, expr):
if expr.table is not Undef:
return compile(state, expr.table)
elif state.auto_tables:
tables = []
for expr in state.auto_tables:
table = compile(state, expr)
if table not in tables:
tables.append(table)
return ", ".join(tables)
elif expr.default_table is not Undef:
return compile(state, expr.default_table)
raise CompileError("Couldn't find any table")
class Select(Expr):
def __init__(self, columns, where=Undef, tables=Undef,
default_tables=Undef, order_by=Undef, group_by=Undef,
limit=Undef, offset=Undef, distinct=False):
self.columns = columns
self.where = where
self.tables = tables
self.default_tables = default_tables
self.order_by = order_by
self.group_by = group_by
self.limit = limit
self.offset = offset
self.distinct = distinct
@compile.when(Select)
def compile_select(compile, state, select):
state.push("auto_tables", [])
tokens = ["SELECT "]
if select.distinct:
tokens.append("DISTINCT ")
tokens.append(compile(state, select.columns))
if has_tables(state, select):
tokens.append(" FROM ")
# Add a placeholder and compile later to support auto_tables.
tables_pos = len(tokens)
tokens.append(None)
else:
tables_pos = None
if select.where is not Undef:
tokens.append(" WHERE ")
tokens.append(compile(state, select.where))
if select.order_by is not Undef:
tokens.append(" ORDER BY ")
tokens.append(compile(state, select.order_by))
if select.group_by is not Undef:
tokens.append(" GROUP BY ")
tokens.append(compile(state, select.group_by))
if select.limit is not Undef:
tokens.append(" LIMIT %d" % select.limit)
if select.offset is not Undef:
tokens.append(" OFFSET %d" % select.offset)
if tables_pos is not None:
tokens[tables_pos] = build_tables(compile, state, select)
state.pop()
return "".join(tokens)
class Insert(Expr):
def __init__(self, columns, values, table=Undef, default_table=Undef):
self.columns = columns
self.values = values
self.table = table
self.default_table = default_table
@compile.when(Insert)
def compile_insert(compile, state, insert):
state.push("omit_column_tables", True)
columns = compile(state, insert.columns)
state.pop()
tokens = ["INSERT INTO ", build_table(compile, state, insert),
" (", columns, ") VALUES (", compile(state, insert.values), ")"]
return "".join(tokens)
class Update(Expr):
def __init__(self, set, where=Undef, table=Undef, default_table=Undef):
self.set = set
self.where = where
self.table = table
self.default_table = default_table
@compile.when(Update)
def compile_update(compile, state, update):
state.push("omit_column_tables", True)
set = update.set
sets = ["%s=%s" % (compile(state, col), compile(state, set[col]))
for col in set]
state.pop()
tokens = ["UPDATE ", build_table(compile, state, update),
" SET ", ", ".join(sets)]
if update.where is not Undef:
tokens.append(" WHERE ")
tokens.append(compile(state, update.where))
return "".join(tokens)
class Delete(Expr):
def __init__(self, where=Undef, table=Undef, default_table=Undef):
self.where = where
self.table = table
self.default_table = default_table
@compile.when(Delete)
def compile_delete(compile, state, delete):
tokens = ["DELETE FROM ", None]
if delete.where is not Undef:
tokens.append(" WHERE ")
tokens.append(compile(state, delete.where))
# Compile later for auto_tables support.
tokens[1] = build_table(compile, state, delete)
return "".join(tokens)
# --------------------------------------------------------------------
# Columns and parameters
class Column(ComparableExpr):
def __init__(self, name=Undef, table=Undef):
self.name = name
self.table = table
@compile.when(Column)
def compile_column(compile, state, column):
if column.table is not Undef:
state.auto_tables.append(column.table)
if column.table is Undef or state.omit_column_tables:
return column.name
return "%s.%s" % (compile(state, column.table), column.name)
class Param(ComparableExpr):
def __init__(self, value):
self.value = value
@compile.when(Param)
def compile_param(compile, state, param):
state.parameters.append(param.value)
return "?"
# --------------------------------------------------------------------
# Operators
#class UnaryOper(UnaryExpr):
# oper = " (unknown) "
class BinaryOper(BinaryExpr):
oper = " (unknown) "
@compile.when(BinaryOper)
def compile_binary_oper(compile, state, oper):
return "%s%s%s" % (compile(state, oper.expr1), oper.oper,
compile(state, oper.expr2))
class NonAssocBinaryOper(BinaryOper):
oper = " (unknown) "
@compile.when(NonAssocBinaryOper)
def compile_non_assoc_binary_oper(compile, state, oper):
expr1 = compile(state, oper.expr1)
state.precedence += 0.5
expr2 = compile(state, oper.expr2)
return "%s%s%s" % (expr1, oper.oper, expr2)
class CompoundOper(CompoundExpr):
oper = " (unknown) "
@compile.when(CompoundOper)
def compile_compound_oper(compile, state, oper):
return "%s" % compile(state, oper.exprs, oper.oper)
class Eq(BinaryOper):
oper = " = "
@compile.when(Eq)
def compile_eq(compile, state, eq):
if eq.expr2 is None:
return "%s IS NULL" % compile(state, eq.expr1)
return "%s = %s" % (compile(state, eq.expr1), compile(state, eq.expr2))
class Ne(BinaryOper):
oper = " != "
@compile.when(Ne)
def compile_ne(compile, state, ne):
if ne.expr2 is None:
return "%s IS NOT NULL" % compile(state, ne.expr1)
return "%s != %s" % (compile(state, ne.expr1), compile(state, ne.expr2))
class Gt(BinaryOper):
oper = " > "
class Ge(BinaryOper):
oper = " >= "
class Lt(BinaryOper):
oper = " < "
class Le(BinaryOper):
oper = " <= "
class RShift(BinaryOper):
oper = ">>"
class LShift(BinaryOper):
oper = "<<"
class Like(BinaryOper):
oper = " LIKE "
class In(BinaryOper):
oper = " IN "
@compile.when(In)
def compile_in(compile, state, expr):
expr1 = compile(state, expr.expr1)
state.precedence = 0 # We're forcing parenthesis here.
return "%s IN (%s)" % (expr1, compile(state, expr.expr2))
class And(CompoundOper):
oper = " AND "
class Or(CompoundOper):
oper = " OR "
class Add(CompoundOper):
oper = "+"
class Sub(NonAssocBinaryOper):
oper = "-"
class Mul(CompoundOper):
oper = "*"
class Div(NonAssocBinaryOper):
oper = "/"
class Mod(NonAssocBinaryOper):
oper = "%"
# --------------------------------------------------------------------
# Functions
class Func(ComparableExpr):
name = "(unknown)"
def __init__(self, *args):
self.args = args
@compile.when(Func)
def compile_func(compile, state, func):
return "%s(%s)" % (func.name, compile(state, func.args))
class Count(Func):
name = "COUNT"
@compile.when(Count)
def compile_count(compile, state, count):
if count.args:
return "COUNT(%s)" % compile(state, count.args)
return "COUNT(*)"
class Max(Func):
name = "MAX"
class Min(Func):
name = "MIN"
class Avg(Func):
name = "AVG"
class Sum(Func):
name = "SUM"
# --------------------------------------------------------------------
# Suffix expressions
class SuffixExpr(Expr):
suffix = "(unknown)"
def __init__(self, expr):
self.expr = expr
@compile.when(SuffixExpr)
def compile_suffix_expr(compile, state, expr):
return "%s %s" % (compile(state, expr.expr), expr.suffix)
class Asc(SuffixExpr):
suffix = "ASC"
class Desc(SuffixExpr):
suffix = "DESC"
# --------------------------------------------------------------------
# Set operator precedences and commutativity.
compile.set_precedence(10, Select, Insert, Update, Delete)
compile.set_precedence(20, Or)
compile.set_precedence(30, And)
compile.set_precedence(40, Eq, Ne, Gt, Ge, Lt, Le, Like, In)
compile.set_precedence(50, LShift, RShift)
compile.set_precedence(60, Add, Sub)
compile.set_precedence(70, Mul, Div, Mod)
|