Skip to content

Commit 6b17731

Browse files
authored
fix: Render LIMIT 0 and OFFSET 0 properly in SQL templates (#8781)
`if limit` condition in Jinja will fail for both None and Some(0) This is more or less fine for offset, but completely wrong for limit. For consistency both are changed. Also add unit test in SQL API and smoke E2E test
1 parent 336fad4 commit 6b17731

File tree

6 files changed

+52
-8
lines changed

6 files changed

+52
-8
lines changed

packages/cubejs-schema-compiler/src/adapter/BaseQuery.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3217,8 +3217,8 @@ export class BaseQuery {
32173217
'{% if filter %}\nWHERE {{ filter }}{% endif %}' +
32183218
'{% if group_by %}\nGROUP BY {{ group_by }}{% endif %}' +
32193219
'{% if order_by %}\nORDER BY {{ order_by | map(attribute=\'expr\') | join(\', \') }}{% endif %}' +
3220-
'{% if limit %}\nLIMIT {{ limit }}{% endif %}' +
3221-
'{% if offset %}\nOFFSET {{ offset }}{% endif %}',
3220+
'{% if limit is not none %}\nLIMIT {{ limit }}{% endif %}' +
3221+
'{% if offset is not none %}\nOFFSET {{ offset }}{% endif %}',
32223222
group_by_exprs: '{{ group_by | map(attribute=\'index\') | join(\', \') }}',
32233223
},
32243224
expressions: {

packages/cubejs-schema-compiler/src/adapter/PrestodbQuery.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ export class PrestodbQuery extends BaseQuery {
116116
'FROM (\n {{ from }}\n) AS {{ from_alias }} \n' +
117117
'{% if group_by %} GROUP BY {{ group_by }}{% endif %}' +
118118
'{% if order_by %} ORDER BY {{ order_by | map(attribute=\'expr\') | join(\', \') }}{% endif %}' +
119-
'{% if offset %}\nOFFSET {{ offset }}{% endif %}' +
120-
'{% if limit %}\nLIMIT {{ limit }}{% endif %}';
119+
'{% if offset is not none %}\nOFFSET {{ offset }}{% endif %}' +
120+
'{% if limit is not none %}\nLIMIT {{ limit }}{% endif %}';
121121
templates.expressions.extract = 'EXTRACT({{ date_part }} FROM {{ expr }})';
122122
templates.expressions.interval_single_date_part = 'INTERVAL \'{{ num }}\' {{ date_part }}';
123123
templates.expressions.timestamp_literal = 'from_iso8601_timestamp(\'{{ value }}\')';

packages/cubejs-testing/test/smoke-cubesql.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,13 @@ describe('SQL API', () => {
390390
expect(res.rows).toEqual([]);
391391
});
392392

393+
test('zero limited dimension aggregated queries through wrapper', async () => {
394+
// Attempts to trigger query generation from SQL templates, not from Cube
395+
const query = 'SELECT MIN(t.maxval) FROM (SELECT MAX(createdAt) as maxval FROM Orders LIMIT 10) t LIMIT 0';
396+
const res = await connection.query(query);
397+
expect(res.rows).toEqual([]);
398+
});
399+
393400
test('select dimension agg where false', async () => {
394401
const query =
395402
'SELECT MAX("createdAt") AS "max" FROM "BigOrders" WHERE 1 = 0';

rust/cubesql/cubesql/src/compile/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15455,8 +15455,8 @@ ORDER BY "source"."str0" ASC
1545515455
r#"SELECT {{ select_concat | map(attribute='aliased') | join(', ') }}
1545615456
FROM ({{ from }}) AS {{ from_alias }}
1545715457
{% if group_by %} GROUP BY {{ group_by | map(attribute='index') | join(', ') }}{% endif %}
15458-
{% if order_by %} ORDER BY {{ order_by | map(attribute='expr') | join(', ') }}{% endif %}{% if offset %}
15459-
OFFSET {{ offset }}{% endif %}{% if limit %}
15458+
{% if order_by %} ORDER BY {{ order_by | map(attribute='expr') | join(', ') }}{% endif %}{% if offset is not none %}
15459+
OFFSET {{ offset }}{% endif %}{% if limit is not none %}
1546015460
LIMIT {{ limit }}{% endif %}"#.to_string(),
1546115461
),
1546215462
]

rust/cubesql/cubesql/src/compile/test/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,8 +506,8 @@ FROM (
506506
) AS {{ from_alias }} {% endif %} {% if filter %}
507507
WHERE {{ filter }}{% endif %}{% if group_by %}
508508
GROUP BY {{ group_by }}{% endif %}{% if order_by %}
509-
ORDER BY {{ order_by | map(attribute='expr') | join(', ') }}{% endif %}{% if limit %}
510-
LIMIT {{ limit }}{% endif %}{% if offset %}
509+
ORDER BY {{ order_by | map(attribute='expr') | join(', ') }}{% endif %}{% if limit is not none %}
510+
LIMIT {{ limit }}{% endif %}{% if offset is not none %}
511511
OFFSET {{ offset }}{% endif %}"#.to_string(),
512512
),
513513
(

rust/cubesql/cubesql/src/compile/test/test_wrapper.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,3 +964,40 @@ async fn test_case_wrapper_escaping() {
964964
// Expect 6 backslashes as output is JSON and it's escaped one more time
965965
.contains("\\\\\\\\\\\\`"));
966966
}
967+
968+
/// Test that WrappedSelect(... limit=Some(0) ...) will render it correctly
969+
#[tokio::test]
970+
async fn test_wrapper_limit_zero() {
971+
if !Rewriter::sql_push_down_enabled() {
972+
return;
973+
}
974+
init_testing_logger();
975+
976+
let query_plan = convert_select_to_query_plan(
977+
// language=PostgreSQL
978+
r#"
979+
SELECT
980+
MIN(t.a)
981+
FROM (
982+
SELECT
983+
MAX(order_date) AS a
984+
FROM
985+
KibanaSampleDataEcommerce
986+
LIMIT 10
987+
) t LIMIT 0
988+
"#
989+
.to_string(),
990+
DatabaseProtocol::PostgreSQL,
991+
)
992+
.await;
993+
994+
let logical_plan = query_plan.as_logical_plan();
995+
assert!(logical_plan
996+
.find_cube_scan_wrapper()
997+
.wrapped_sql
998+
.unwrap()
999+
.sql
1000+
.contains("LIMIT 0"));
1001+
1002+
let _physical_plan = query_plan.as_physical_plan().await.unwrap();
1003+
}

0 commit comments

Comments
 (0)