Skip to content

Commit 6212efe

Browse files
committed
fix(cubesql): Improve Thoughtspot WHERE IN support
1 parent e67e800 commit 6212efe

File tree

2 files changed

+236
-1
lines changed

2 files changed

+236
-1
lines changed

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

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15699,4 +15699,174 @@ ORDER BY \"COUNT(count)\" DESC"
1569915699
}
1570015700
)
1570115701
}
15702+
15703+
#[tokio::test]
15704+
async fn test_thoughtspot_where_not_or() {
15705+
init_logger();
15706+
15707+
let logical_plan = convert_select_to_query_plan(
15708+
r#"
15709+
WITH "qt_0" AS (
15710+
SELECT "ta_1"."customer_gender" "ca_1"
15711+
FROM KibanaSampleDataEcommerce "ta_1"
15712+
WHERE NOT((
15713+
"ta_1"."customer_gender" IS NULL
15714+
OR LOWER("ta_1"."customer_gender") IN ('unknown')
15715+
))
15716+
GROUP BY "ca_1"
15717+
)
15718+
SELECT count(DISTINCT "ta_2"."ca_1") "ca_2"
15719+
FROM "qt_0" "ta_2"
15720+
"#
15721+
.to_string(),
15722+
DatabaseProtocol::PostgreSQL,
15723+
)
15724+
.await
15725+
.as_logical_plan();
15726+
15727+
assert_eq!(
15728+
logical_plan.find_cube_scan().request,
15729+
V1LoadRequestQuery {
15730+
measures: Some(vec![]),
15731+
dimensions: Some(vec!["KibanaSampleDataEcommerce.customer_gender".to_string()]),
15732+
segments: Some(vec![]),
15733+
time_dimensions: None,
15734+
order: None,
15735+
limit: None,
15736+
offset: None,
15737+
filters: Some(vec![
15738+
V1LoadRequestQueryFilterItem {
15739+
member: Some("KibanaSampleDataEcommerce.customer_gender".to_string()),
15740+
operator: Some("set".to_string()),
15741+
values: None,
15742+
or: None,
15743+
and: None,
15744+
},
15745+
V1LoadRequestQueryFilterItem {
15746+
member: Some("KibanaSampleDataEcommerce.customer_gender".to_string()),
15747+
operator: Some("notEquals".to_string()),
15748+
values: Some(vec!["unknown".to_string()]),
15749+
or: None,
15750+
and: None,
15751+
},
15752+
])
15753+
}
15754+
)
15755+
}
15756+
15757+
#[tokio::test]
15758+
async fn test_thoughtspot_where_binary_in_true_false() {
15759+
init_logger();
15760+
15761+
let logical_plan = convert_select_to_query_plan(
15762+
r#"
15763+
SELECT
15764+
((
15765+
LOWER("ta_1"."customer_gender") = 'female'
15766+
OR LOWER("ta_1"."customer_gender") = 'male'
15767+
)) "ca_1",
15768+
CASE
15769+
WHEN sum("ta_1"."count") IS NOT NULL THEN sum("ta_1"."count")
15770+
ELSE 0
15771+
END "ca_2"
15772+
FROM KibanaSampleDataEcommerce "ta_1"
15773+
WHERE ((
15774+
LOWER("ta_1"."customer_gender") = 'female'
15775+
OR LOWER("ta_1"."customer_gender") = 'male'
15776+
)) IN (
15777+
TRUE, FALSE
15778+
)
15779+
GROUP BY "ca_1"
15780+
ORDER BY
15781+
"ca_1" ASC,
15782+
"ca_2" ASC
15783+
"#
15784+
.to_string(),
15785+
DatabaseProtocol::PostgreSQL,
15786+
)
15787+
.await
15788+
.as_logical_plan();
15789+
15790+
assert_eq!(
15791+
logical_plan.find_cube_scan().request,
15792+
V1LoadRequestQuery {
15793+
measures: Some(vec!["KibanaSampleDataEcommerce.count".to_string()]),
15794+
dimensions: Some(vec!["KibanaSampleDataEcommerce.customer_gender".to_string()]),
15795+
segments: Some(vec![]),
15796+
time_dimensions: None,
15797+
order: None,
15798+
limit: None,
15799+
offset: None,
15800+
filters: Some(vec![
15801+
V1LoadRequestQueryFilterItem {
15802+
member: None,
15803+
operator: None,
15804+
values: None,
15805+
or: Some(vec![
15806+
json!(V1LoadRequestQueryFilterItem {
15807+
member: None,
15808+
operator: None,
15809+
values: None,
15810+
or: None,
15811+
and: Some(vec![
15812+
json!(V1LoadRequestQueryFilterItem {
15813+
member: Some(
15814+
"KibanaSampleDataEcommerce.customer_gender".to_string()
15815+
),
15816+
operator: Some("startsWith".to_string()),
15817+
values: Some(vec!["female".to_string()]),
15818+
or: None,
15819+
and: None,
15820+
}),
15821+
json!(V1LoadRequestQueryFilterItem {
15822+
member: Some(
15823+
"KibanaSampleDataEcommerce.customer_gender".to_string()
15824+
),
15825+
operator: Some("endsWith".to_string()),
15826+
values: Some(vec!["female".to_string()]),
15827+
or: None,
15828+
and: None,
15829+
}),
15830+
]),
15831+
}),
15832+
json!(V1LoadRequestQueryFilterItem {
15833+
member: None,
15834+
operator: None,
15835+
values: None,
15836+
or: None,
15837+
and: Some(vec![
15838+
json!(V1LoadRequestQueryFilterItem {
15839+
member: Some(
15840+
"KibanaSampleDataEcommerce.customer_gender".to_string()
15841+
),
15842+
operator: Some("startsWith".to_string()),
15843+
values: Some(vec!["male".to_string()]),
15844+
or: None,
15845+
and: None,
15846+
}),
15847+
json!(V1LoadRequestQueryFilterItem {
15848+
member: Some(
15849+
"KibanaSampleDataEcommerce.customer_gender".to_string()
15850+
),
15851+
operator: Some("endsWith".to_string()),
15852+
values: Some(vec!["male".to_string()]),
15853+
or: None,
15854+
and: None,
15855+
}),
15856+
]),
15857+
}),
15858+
]),
15859+
and: None,
15860+
},
15861+
V1LoadRequestQueryFilterItem {
15862+
member: Some("KibanaSampleDataEcommerce.customer_gender".to_string()),
15863+
operator: Some("set".to_string()),
15864+
values: None,
15865+
or: None,
15866+
and: None,
15867+
},
15868+
])
15869+
}
15870+
)
15871+
}
1570215872
}

rust/cubesql/cubesql/src/compile/rewrite/rules/filters.rs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
cube_scan_members, dimension_expr, expr_column_name, filter,
1010
filter_cast_unwrap_replacer, filter_member, filter_op, filter_op_filters,
1111
filter_replacer, fun_expr, fun_expr_var_arg, inlist_expr, is_not_null_expr,
12-
is_null_expr, like_expr, limit, literal_bool, literal_expr, literal_int,
12+
is_null_expr, like_expr, limit, list_expr, literal_bool, literal_expr, literal_int,
1313
literal_string, measure_expr, member_name_by_alias, negative_expr, not_expr,
1414
projection, rewrite,
1515
rewriter::RewriteRules,
@@ -400,6 +400,21 @@ impl RewriteRules for FilterRules {
400400
),
401401
self.transform_negate_inlist("?negated", "?new_negated"),
402402
),
403+
rewrite(
404+
"filter-replacer-not-or-to-not-and",
405+
filter_replacer(
406+
not_expr(binary_expr("?left", "OR", "?right")),
407+
"?alias_to_cube",
408+
"?members",
409+
"?filter_aliases",
410+
),
411+
filter_replacer(
412+
binary_expr(not_expr("?left"), "AND", not_expr("?right")),
413+
"?alias_to_cube",
414+
"?members",
415+
"?filter_aliases",
416+
),
417+
),
403418
transforming_rewrite(
404419
"filter-replacer-is-null",
405420
filter_replacer(
@@ -1465,6 +1480,56 @@ impl RewriteRules for FilterRules {
14651480
"?filter_aliases",
14661481
),
14671482
),
1483+
rewrite(
1484+
"filter-thoughtspot-lower-in-true-false",
1485+
filter_replacer(
1486+
inlist_expr(
1487+
binary_expr(
1488+
binary_expr(
1489+
fun_expr("Lower", vec![column_expr("?column")]),
1490+
"=",
1491+
literal_expr("?left_literal"),
1492+
),
1493+
"OR",
1494+
binary_expr(
1495+
fun_expr("Lower", vec![column_expr("?column")]),
1496+
"=",
1497+
literal_expr("?right_literal"),
1498+
),
1499+
),
1500+
list_expr(
1501+
"InListExprList",
1502+
vec![literal_bool(true), literal_bool(false)],
1503+
),
1504+
"InListExprNegated:false",
1505+
),
1506+
"?alias_to_cube",
1507+
"?members",
1508+
"?filter_aliases",
1509+
),
1510+
filter_replacer(
1511+
binary_expr(
1512+
binary_expr(
1513+
binary_expr(
1514+
fun_expr("Lower", vec![column_expr("?column")]),
1515+
"=",
1516+
literal_expr("?left_literal"),
1517+
),
1518+
"OR",
1519+
binary_expr(
1520+
fun_expr("Lower", vec![column_expr("?column")]),
1521+
"=",
1522+
literal_expr("?right_literal"),
1523+
),
1524+
),
1525+
"AND",
1526+
is_not_null_expr(column_expr("?column")),
1527+
),
1528+
"?alias_to_cube",
1529+
"?members",
1530+
"?filter_aliases",
1531+
),
1532+
),
14681533
transforming_rewrite(
14691534
"extract-year-equals",
14701535
filter_replacer(

0 commit comments

Comments
 (0)