Skip to content
This repository was archived by the owner on May 17, 2024. It is now read-only.

Commit 8b7484a

Browse files
committed
feat: use a separate render function for limited query
1 parent 94b6d93 commit 8b7484a

File tree

4 files changed

+33
-21
lines changed

4 files changed

+33
-21
lines changed

data_diff/databases/base.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,6 @@ class BaseDialect(abc.ABC):
202202
TYPE_CLASSES: ClassVar[Dict[str, Type[ColType]]] = {}
203203

204204
PLACEHOLDER_TABLE = None # Used for Oracle
205-
USE_TOP_INSTEAD_LIMIT: bool = False # True for MsSQL or Teradata
206205

207206
def parse_table_name(self, name: str) -> DbPath:
208207
"Parse the given table name into a DbPath"
@@ -472,10 +471,7 @@ def render_select(self, parent_c: Compiler, elem: Select) -> str:
472471
columns = ", ".join(map(compile_fn, elem.columns)) if elem.columns else "*"
473472
distinct = "DISTINCT " if elem.distinct else ""
474473
optimizer_hints = self.optimizer_hints(elem.optimizer_hints) if elem.optimizer_hints else ""
475-
if elem.limit_expr is not None and self.USE_TOP_INSTEAD_LIMIT:
476-
select = f"SELECT TOP {elem.limit_expr} {optimizer_hints}{distinct}{columns}"
477-
else:
478-
select = f"SELECT {optimizer_hints}{distinct}{columns}"
474+
select = f"SELECT {optimizer_hints}{distinct}{columns}"
479475

480476
if elem.table:
481477
select += " FROM " + self.compile(c, elem.table)
@@ -495,9 +491,9 @@ def render_select(self, parent_c: Compiler, elem: Select) -> str:
495491
if elem.order_by_exprs:
496492
select += " ORDER BY " + ", ".join(map(compile_fn, elem.order_by_exprs))
497493

498-
if elem.limit_expr is not None and not self.USE_TOP_INSTEAD_LIMIT:
494+
if elem.limit_expr is not None:
499495
has_order_by = bool(elem.order_by_exprs)
500-
select += " " + self.offset_limit(0, elem.limit_expr, has_order_by=has_order_by)
496+
select = self.limit_select(select_query=select, offset=0, limit=elem.limit_expr, has_order_by=has_order_by)
501497

502498
if parent_c.in_select:
503499
select = f"({select}) {c.new_unique_name()}"
@@ -609,14 +605,17 @@ def render_inserttotable(self, c: Compiler, elem: InsertToTable) -> str:
609605

610606
return f"INSERT INTO {self.compile(c, elem.path)}{columns} {expr}"
611607

612-
def offset_limit(
613-
self, offset: Optional[int] = None, limit: Optional[int] = None, has_order_by: Optional[bool] = None
608+
def limit_select(
609+
self,
610+
select_query: str,
611+
offset: Optional[int] = None,
612+
limit: Optional[int] = None,
613+
has_order_by: Optional[bool] = None,
614614
) -> str:
615-
"Provide SQL fragment for limit and offset inside a select"
616615
if offset:
617616
raise NotImplementedError("No support for OFFSET in query")
618617

619-
return f"LIMIT {limit}"
618+
return f"SELECT * FROM ({select_query}) AS LIMITED_SELECT LIMIT {limit}"
620619

621620
def concat(self, items: List[str]) -> str:
622621
"Provide SQL for concatenating a bunch of columns into a string"
@@ -1107,7 +1106,7 @@ def _query_cursor(self, c, sql_code: str) -> QueryResult:
11071106
return result
11081107
except Exception as _e:
11091108
# logger.exception(e)
1110-
# logger.error(f'Caused by SQL: {sql_code}')
1109+
logger.error(f"Caused by SQL: {sql_code}")
11111110
raise
11121111

11131112
def _query_conn(self, conn, sql_code: Union[str, ThreadLocalInterpreter]) -> QueryResult:

data_diff/databases/mssql.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,12 @@ def is_distinct_from(self, a: str, b: str) -> str:
110110
# See: https://stackoverflow.com/a/18684859/857383
111111
return f"(({a}<>{b} OR {a} IS NULL OR {b} IS NULL) AND NOT({a} IS NULL AND {b} IS NULL))"
112112

113-
def offset_limit(
114-
self, offset: Optional[int] = None, limit: Optional[int] = None, has_order_by: Optional[bool] = None
113+
def limit_select(
114+
self,
115+
select_query: str,
116+
offset: Optional[int] = None,
117+
limit: Optional[int] = None,
118+
has_order_by: Optional[bool] = None,
115119
) -> str:
116120
if offset:
117121
raise NotImplementedError("No support for OFFSET in query")
@@ -121,7 +125,7 @@ def offset_limit(
121125
result += "ORDER BY 1"
122126

123127
result += f" OFFSET 0 ROWS FETCH NEXT {limit} ROWS ONLY"
124-
return result
128+
return f"SELECT * FROM ({select_query}) AS LIMITED_SELECT {result}"
125129

126130
def constant_values(self, rows) -> str:
127131
values = ", ".join("(%s)" % ", ".join(self._constant_value(v) for v in row) for row in rows)

data_diff/databases/oracle.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,17 @@ def quote(self, s: str):
6464
def to_string(self, s: str):
6565
return f"cast({s} as varchar(1024))"
6666

67-
def offset_limit(
68-
self, offset: Optional[int] = None, limit: Optional[int] = None, has_order_by: Optional[bool] = None
67+
def limit_select(
68+
self,
69+
select_query: str,
70+
offset: Optional[int] = None,
71+
limit: Optional[int] = None,
72+
has_order_by: Optional[bool] = None,
6973
) -> str:
7074
if offset:
7175
raise NotImplementedError("No support for OFFSET in query")
7276

73-
return f"FETCH NEXT {limit} ROWS ONLY"
77+
return f"SELECT * FROM ({select_query}) FETCH NEXT {limit} ROWS ONLY"
7478

7579
def concat(self, items: List[str]) -> str:
7680
joined_exprs = " || ".join(items)

tests/test_query.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,16 @@ def current_database(self) -> str:
5050
def current_schema(self) -> str:
5151
return "current_schema()"
5252

53-
def offset_limit(
54-
self, offset: Optional[int] = None, limit: Optional[int] = None, has_order_by: Optional[bool] = None
53+
def limit_select(
54+
self,
55+
select_query: str,
56+
offset: Optional[int] = None,
57+
limit: Optional[int] = None,
58+
has_order_by: Optional[bool] = None,
5559
) -> str:
5660
x = offset and f"OFFSET {offset}", limit and f"LIMIT {limit}"
57-
return " ".join(filter(None, x))
61+
result = " ".join(filter(None, x))
62+
return f"SELECT * FROM ({select_query}) {result}"
5863

5964
def explain_as_text(self, query: str) -> str:
6065
return f"explain {query}"

0 commit comments

Comments
 (0)