mirror of
https://github.com/apache/superset.git
synced 2026-04-19 16:14:52 +00:00
fix(mssql): support top syntax for limiting queries (#18746)
* SQL-TOP Fix For Database Engines MSSQL is not supporting LIMIT syntax in SQLs. For limiting the rows, MSSQL having a different keyword TOP. Added fixes for handling the TOP and LIMIT clauses based on the database engines. * Teradata code for top clause handling removed from teradata.py Teradata code for top clause handling removed from teradata.py file, since we added generic section in base engine for the same. * Changes to handle CTE along with TOP in complex SQLs Added changes to handle TOP command in CTEs, for DB Engines which are not supporting inline CTEs. * Test cases for TOP unit testing in MSSQL Added multiple unit test cases for MSSQL top command handling and also along with CTEs * Corrected the select_keywords name key in basengine Corrected the select_keywords name key in basengine * Changes based on as per review. made the required corrections based on code review to keep good code readability and code cleanliness. * Review changes to correct lint and typo issues Made the changes according to the review comments. * fix linting errors * fix teradata tests * add coverage * lint * Code cleanliness Moved the top/limit flag check from sql_lab to core. * Changed for code cleanliness Changes for keeping code cleanliness * Corrected lint issue Corrected lint issue. * Code cleanliness Code cleanliness Co-authored-by: Ville Brofeldt <ville.v.brofeldt@gmail.com>
This commit is contained in:
@@ -231,6 +231,37 @@ def test_cte_query_parsing(
|
||||
assert actual == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"original,expected,top",
|
||||
[
|
||||
("SEL TOP 1000 * FROM My_table", "SEL TOP 100 * FROM My_table", 100),
|
||||
("SEL TOP 1000 * FROM My_table;", "SEL TOP 100 * FROM My_table", 100),
|
||||
("SEL TOP 1000 * FROM My_table;", "SEL TOP 1000 * FROM My_table", 10000),
|
||||
("SEL TOP 1000 * FROM My_table;", "SEL TOP 1000 * FROM My_table", 1000),
|
||||
(
|
||||
"""with abc as (select * from test union select * from test1)
|
||||
select TOP 100 * from currency""",
|
||||
"""WITH abc as (select * from test union select * from test1)
|
||||
select TOP 100 * from currency""",
|
||||
1000,
|
||||
),
|
||||
("SELECT 1 as cnt", "SELECT TOP 10 1 as cnt", 10),
|
||||
(
|
||||
"select TOP 1000 * from abc where id=1",
|
||||
"select TOP 10 * from abc where id=1",
|
||||
10,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_top_query_parsing(
|
||||
app_context: AppContext, original: TypeEngine, expected: str, top: int
|
||||
) -> None:
|
||||
from superset.db_engine_specs.mssql import MssqlEngineSpec
|
||||
|
||||
actual = MssqlEngineSpec.apply_top_to_sql(original, top)
|
||||
assert actual == expected
|
||||
|
||||
|
||||
def test_extract_errors(app_context: AppContext) -> None:
|
||||
"""
|
||||
Test that custom error messages are extracted correctly.
|
||||
|
||||
@@ -15,73 +15,28 @@
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# pylint: disable=unused-argument, import-outside-toplevel, protected-access
|
||||
|
||||
import pytest
|
||||
from flask.ctx import AppContext
|
||||
|
||||
|
||||
def test_ParsedQueryTeradata_lower_limit(app_context: AppContext) -> None:
|
||||
@pytest.mark.parametrize(
|
||||
"limit,original,expected",
|
||||
[
|
||||
(100, "SEL TOP 1000 * FROM My_table", "SEL TOP 100 * FROM My_table"),
|
||||
(100, "SEL TOP 1000 * FROM My_table;", "SEL TOP 100 * FROM My_table"),
|
||||
(10000, "SEL TOP 1000 * FROM My_table;", "SEL TOP 1000 * FROM My_table"),
|
||||
(1000, "SEL TOP 1000 * FROM My_table;", "SEL TOP 1000 * FROM My_table"),
|
||||
(100, "SELECT TOP 1000 * FROM My_table", "SELECT TOP 100 * FROM My_table"),
|
||||
(100, "SEL SAMPLE 1000 * FROM My_table", "SEL SAMPLE 100 * FROM My_table"),
|
||||
(10000, "SEL SAMPLE 1000 * FROM My_table", "SEL SAMPLE 1000 * FROM My_table"),
|
||||
],
|
||||
)
|
||||
def test_apply_top_to_sql_limit(
|
||||
app_context: AppContext, limit: int, original: str, expected: str,
|
||||
) -> None:
|
||||
"""
|
||||
Test the custom ``ParsedQueryTeradata`` that calls ``_extract_limit_from_query_td(``
|
||||
|
||||
The CLass looks for Teradata limit keywords TOP and SAMPLE vs LIMIT in
|
||||
other dialects.
|
||||
Ensure limits are applied to the query correctly
|
||||
"""
|
||||
from superset.db_engine_specs.teradata import TeradataEngineSpec
|
||||
|
||||
sql = "SEL TOP 1000 * FROM My_table;"
|
||||
limit = 100
|
||||
|
||||
assert str(TeradataEngineSpec.apply_limit_to_sql(sql, limit, "Database")) == (
|
||||
"SEL TOP 100 * FROM My_table"
|
||||
)
|
||||
|
||||
|
||||
def test_ParsedQueryTeradata_higher_limit(app_context: AppContext) -> None:
|
||||
"""
|
||||
Test the custom ``ParsedQueryTeradata`` that calls ``_extract_limit_from_query_td(``
|
||||
|
||||
The CLass looks for Teradata limit keywords TOP and SAMPLE vs LIMIT in
|
||||
other dialects.
|
||||
"""
|
||||
from superset.db_engine_specs.teradata import TeradataEngineSpec
|
||||
|
||||
sql = "SEL TOP 1000 * FROM My_table;"
|
||||
limit = 10000
|
||||
|
||||
assert str(TeradataEngineSpec.apply_limit_to_sql(sql, limit, "Database")) == (
|
||||
"SEL TOP 1000 * FROM My_table"
|
||||
)
|
||||
|
||||
|
||||
def test_ParsedQueryTeradata_equal_limit(app_context: AppContext) -> None:
|
||||
"""
|
||||
Test the custom ``ParsedQueryTeradata`` that calls ``_extract_limit_from_query_td(``
|
||||
|
||||
The CLass looks for Teradata limit keywords TOP and SAMPLE vs LIMIT in
|
||||
other dialects.
|
||||
"""
|
||||
from superset.db_engine_specs.teradata import TeradataEngineSpec
|
||||
|
||||
sql = "SEL TOP 1000 * FROM My_table;"
|
||||
limit = 1000
|
||||
|
||||
assert str(TeradataEngineSpec.apply_limit_to_sql(sql, limit, "Database")) == (
|
||||
"SEL TOP 1000 * FROM My_table"
|
||||
)
|
||||
|
||||
|
||||
def test_ParsedQueryTeradata_no_limit(app_context: AppContext) -> None:
|
||||
"""
|
||||
Test the custom ``ParsedQueryTeradata`` that calls ``_extract_limit_from_query_td(``
|
||||
|
||||
The CLass looks for Teradata limit keywords TOP and SAMPLE vs LIMIT in
|
||||
other dialects.
|
||||
"""
|
||||
from superset.db_engine_specs.teradata import TeradataEngineSpec
|
||||
|
||||
sql = "SEL * FROM My_table;"
|
||||
limit = 1000
|
||||
|
||||
assert str(TeradataEngineSpec.apply_limit_to_sql(sql, limit, "Database")) == (
|
||||
"SEL TOP 1000 * FROM My_table"
|
||||
)
|
||||
assert TeradataEngineSpec.apply_top_to_sql(original, limit) == expected
|
||||
|
||||
Reference in New Issue
Block a user