Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update sql_builder.AfterPrevValues. #1480

Merged
merged 4 commits into from
Feb 9, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Update sql_builder.AfterPrevValues.
Use tuple-comparison instead of complex boolean expression. Add
helper classes TupleGreater, TupleGreaterEqual, TupleLess, TupleLessEqual.
  • Loading branch information
dumbunny committed Feb 3, 2016
commit af7ceff0b88afbf7453be3876a8aa4867a863e6a
104 changes: 76 additions & 28 deletions py/vtdb/sql_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -956,25 +956,25 @@ 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".
"(x, y, z) > (3, 5, 7)".
"""

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 @@ -994,34 +994,82 @@ def build_where_sql(self, column_name, counter):
"""
if column_name:
raise ValueError('column_name should be None.')
where_clause = None
is_complex = False
bind_vars = {}
for column, prev_value in reversed(self.prev_value_pairs):
bind_name = choose_bind_name(column, counter)
if isinstance(prev_value, (list, tuple, set)):
column_list = []
token_list = []
for column, value in self.starting_point:
column_list.append(column)
bind_var = choose_bind_name(column, counter)
update_bind_vars(bind_vars, {bind_var: value})
if isinstance(value, (list, tuple, set)):
raise ValueError(
'Column=%s value=%s should be a single value.' %
(column, prev_value))
update_bind_vars(bind_vars, {bind_name: prev_value})
eq_part = '%s = %%(%s)s' % (column, bind_name)
if where_clause is None and self.inclusive:
op = '>=' if self.asc else '<='
else:
op = '>' if self.asc else '<'
ineq_part = '%s %s %%(%s)s' % (column, op, bind_name)
if where_clause:
if is_complex:
where_clause = '%s AND (%s) OR %s' % (
eq_part, where_clause, ineq_part)
else:
where_clause = '%s AND %s OR %s' % (eq_part, where_clause, ineq_part)
is_complex = True
else:
where_clause = ineq_part
(column, value))
token_list.append('%%(%s)s' % (bind_var,))

parts = ['(%s)' % ', '.join(column_list)]
if self.asc:
op = '>=' if self.inclusive else '>'
else:
op = '<=' if self.inclusive else '<'
parts.append(op)
parts.append('(%s)' % ', '.join(token for token in token_list))
where_clause = ' '.join(parts)
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
29 changes: 15 additions & 14 deletions test/sql_builder_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,25 +556,26 @@ 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',
dict(x_5=3, y_4=5, z_3=7),
sql_builder.TupleGreater([('x', 3), ('y', 5), ('z', 7)]),
'(x, y, z) > (%(x_3)s, %(y_4)s, %(z_5)s)',
dict(x_3=3, y_4=5, z_5=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',
dict(x_5=3, y_4=5, z_3=7),
sql_builder.TupleGreaterEqual([('x', 3), ('y', 5), ('z', 7)]),
'(x, y, z) >= (%(x_3)s, %(y_4)s, %(z_5)s)',
dict(x_3=3, y_4=5, z_5=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',
dict(x_5=3, y_4=5, z_3=7),
sql_builder.TupleLess([('x', 3), ('y', 5), ('z', 7)]),
'(x, y, z) < (%(x_3)s, %(y_4)s, %(z_5)s)',
dict(x_3=3, y_4=5, z_5=7),
column_name=None)
self._check_build_where_sql(
sql_builder.TupleLessEqual([('x', 3), ('y', 5), ('z', 7)]),
'(x, y, z) <= (%(x_3)s, %(y_4)s, %(z_5)s)',
dict(x_3=3, y_4=5, z_5=7),
column_name=None)

def test_greater_than(self):
Expand Down