Skip to content

Commit

Permalink
Merge pull request #1480 from dumbunny/v2v3
Browse files Browse the repository at this point in the history
Update sql_builder.AfterPrevValues.
  • Loading branch information
dumbunny committed Feb 9, 2016
2 parents d371351 + 036cc3f commit 5be7ca8
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 17 deletions.
69 changes: 63 additions & 6 deletions py/vtdb/sql_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -956,25 +956,30 @@ def build_update_value_sql(self, column_name):
return clause, bind_vars


class AfterPrevValues(BaseWhereExpr):
class TupleCompare(BaseWhereExpr):
"""Create SQL for an after clause in a multi-dimensional scan.
Example: If reading values ordered by columns (x, y, z) starting at
Example: If reading values ordered by columns (x, y, z) starting after
the point (3, 5, 7), build the SQL:
"x = 3 AND (y = 5 AND z > 7 OR y > 5) OR x > 3".
NOTE: MySQL supports "(x, y, z) > (3, 5, 7)" to do the same thing,
but we have found that the optimizer frequently does not recognize
this as an indexed, range query. Surprisingly, it has a better chance
of efficiently using with the above inequality.
"""

def __init__(self, prev_value_pairs, asc=True, inclusive=False):
def __init__(self, starting_point, asc=True, inclusive=False):
"""Constructor.
Args:
prev_value_pairs: Ordered list of (column, prev_value) pairs.
starting_point: Ordered list of (column, start_value) pairs.
Example - [('x', 3), ('y', 5), ('z', 7)].
asc: If True, scan forward.
inclusive: If True, also include starting point.
"""
self.prev_value_pairs = prev_value_pairs
self.starting_point = starting_point
self.asc = asc
self.inclusive = inclusive

Expand All @@ -997,7 +1002,7 @@ def build_where_sql(self, column_name, counter):
where_clause = None
is_complex = False
bind_vars = {}
for column, prev_value in reversed(self.prev_value_pairs):
for column, prev_value in reversed(self.starting_point):
bind_name = choose_bind_name(column, counter)
if isinstance(prev_value, (list, tuple, set)):
raise ValueError(
Expand All @@ -1022,6 +1027,58 @@ def build_where_sql(self, column_name, counter):
return where_clause, bind_vars


class TupleGreater(TupleCompare):
"""WHERE expr for tuple > values expr.
starting_point=[('x', 3), ('y', 5)] makes: '(x, y) > (3, 5)'.
See TupleCompare.
"""

def __init__(self, starting_point):
super(TupleGreater, self).__init__(
starting_point, asc=True, inclusive=False)


class TupleGreaterEqual(TupleCompare):
"""WHERE expr for tuple >= values expr.
starting_point=[('x', 3), ('y', 5)] makes: '(x, y) >= (3, 5)'.
See TupleCompare.
"""

def __init__(self, starting_point):
super(TupleGreaterEqual, self).__init__(
starting_point, asc=True, inclusive=True)


class TupleLess(TupleCompare):
"""WHERE expr for tuple < values expr.
starting_point=[('x', 3), ('y', 5)] makes: '(x, y) < (3, 5)'.
See TupleCompare.
"""

def __init__(self, starting_point):
super(TupleLess, self).__init__(
starting_point, asc=False, inclusive=False)


class TupleLessEqual(TupleCompare):
"""WHERE expr for tuple <= values expr.
starting_point=[('x', 3), ('y', 5)] makes: '(x, y) <= (3, 5)'.
See TupleCompare.
"""

def __init__(self, starting_point):
super(TupleLessEqual, self).__init__(
starting_point, asc=False, inclusive=True)


def make_flags(flag_mask, value):
if value:
return Flags(flags_present=flag_mask)
Expand Down
27 changes: 16 additions & 11 deletions test/sql_builder_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,24 +556,29 @@ def test_or_exprs(self):
'(col_a = %(col_a_5)s))',
dict(col_a_3=11, col_a_4=20, col_a_5=30))

def test_after_prev__values(self):
def test_tuple_compare(self):
self._check_build_where_sql(
sql_builder.AfterPrevValues([('x', 3), ('y', 5), ('z', 7)]),
'x = %(x_5)s AND (y = %(y_4)s AND z > %(z_3)s OR y > %(y_4)s) '
'OR x > %(x_5)s',
sql_builder.TupleGreater([('x', 3), ('y', 5), ('z', 7)]),
'x = %(x_5)s AND '
'(y = %(y_4)s AND z > %(z_3)s OR y > %(y_4)s) OR x > %(x_5)s',
dict(x_5=3, y_4=5, z_3=7),
column_name=None)
self._check_build_where_sql(
sql_builder.AfterPrevValues(
[('x', 3), ('y', 5), ('z', 7)], inclusive=True),
'x = %(x_5)s AND (y = %(y_4)s AND z >= %(z_3)s OR y > %(y_4)s) '
'OR x > %(x_5)s',
sql_builder.TupleGreaterEqual([('x', 3), ('y', 5), ('z', 7)]),
'x = %(x_5)s AND '
'(y = %(y_4)s AND z >= %(z_3)s OR y > %(y_4)s) OR x > %(x_5)s',
dict(x_5=3, y_4=5, z_3=7),
column_name=None)
self._check_build_where_sql(
sql_builder.AfterPrevValues([('x', 3), ('y', 5), ('z', 7)], asc=False),
'x = %(x_5)s AND (y = %(y_4)s AND z < %(z_3)s OR y < %(y_4)s) '
'OR x < %(x_5)s',
sql_builder.TupleLess([('x', 3), ('y', 5), ('z', 7)]),
'x = %(x_5)s AND '
'(y = %(y_4)s AND z < %(z_3)s OR y < %(y_4)s) OR x < %(x_5)s',
dict(x_5=3, y_4=5, z_3=7),
column_name=None)
self._check_build_where_sql(
sql_builder.TupleLessEqual([('x', 3), ('y', 5), ('z', 7)]),
'x = %(x_5)s AND '
'(y = %(y_4)s AND z <= %(z_3)s OR y < %(y_4)s) OR x < %(x_5)s',
dict(x_5=3, y_4=5, z_3=7),
column_name=None)

Expand Down

0 comments on commit 5be7ca8

Please sign in to comment.