Skip to content

Commit

Permalink
fix(cubesql): WHERE Lower / Upper in list with multiply items (#5376)
Browse files Browse the repository at this point in the history
  • Loading branch information
gandronchik committed Sep 29, 2022
1 parent 6d6f359 commit 2269b2b
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 25 deletions.
114 changes: 114 additions & 0 deletions rust/cubesql/cubesql/src/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1924,7 +1924,88 @@ mod tests {
}
])
}
);

let query_plan = convert_select_to_query_plan(
"SELECT COUNT(*) as cnt FROM KibanaSampleDataEcommerce WHERE LOWER(customer_gender) IN ('female', 'male')".to_string(),
DatabaseProtocol::PostgreSQL,
)
.await;
let cube_scan = query_plan.as_logical_plan().find_cube_scan();

assert_eq!(
cube_scan.request,
V1LoadRequestQuery {
measures: Some(vec!["KibanaSampleDataEcommerce.count".to_string(),]),
segments: Some(vec![]),
dimensions: Some(vec![]),
time_dimensions: None,
order: None,
limit: None,
offset: None,
// TODO: Migrate to equalsLower operator, when it will be available in Cube?
filters: Some(vec![V1LoadRequestQueryFilterItem {
member: None,
operator: None,
values: None,
or: Some(vec![
json!(V1LoadRequestQueryFilterItem {
member: None,
operator: None,
values: None,
or: None,
and: Some(vec![
json!(V1LoadRequestQueryFilterItem {
member: Some(
"KibanaSampleDataEcommerce.customer_gender".to_string()
),
operator: Some("startsWith".to_string()),
values: Some(vec!["female".to_string()]),
or: None,
and: None
}),
json!(V1LoadRequestQueryFilterItem {
member: Some(
"KibanaSampleDataEcommerce.customer_gender".to_string()
),
operator: Some("endsWith".to_string()),
values: Some(vec!["female".to_string()]),
or: None,
and: None
}),
])
}),
json!(V1LoadRequestQueryFilterItem {
member: None,
operator: None,
values: None,
or: None,
and: Some(vec![
json!(V1LoadRequestQueryFilterItem {
member: Some(
"KibanaSampleDataEcommerce.customer_gender".to_string()
),
operator: Some("startsWith".to_string()),
values: Some(vec!["male".to_string()]),
or: None,
and: None
}),
json!(V1LoadRequestQueryFilterItem {
member: Some(
"KibanaSampleDataEcommerce.customer_gender".to_string()
),
operator: Some("endsWith".to_string()),
values: Some(vec!["male".to_string()]),
or: None,
and: None
}),
])
}),
]),
and: None,
}]),
}
);
}

#[tokio::test]
Expand Down Expand Up @@ -11983,4 +12064,37 @@ ORDER BY \"COUNT(count)\" DESC"
}
)
}

#[tokio::test]
async fn test_in_filter() {
init_logger();

let query_plan = convert_select_to_query_plan(
"SELECT COUNT(*) as cnt FROM KibanaSampleDataEcommerce WHERE customer_gender IN ('female', 'male')"
.to_string(),
DatabaseProtocol::PostgreSQL,
)
.await;
let cube_scan = query_plan.as_logical_plan().find_cube_scan();

assert_eq!(
cube_scan.request,
V1LoadRequestQuery {
measures: Some(vec!["KibanaSampleDataEcommerce.count".to_string(),]),
segments: Some(vec![]),
dimensions: Some(vec![]),
time_dimensions: None,
order: None,
limit: None,
offset: None,
filters: Some(vec![V1LoadRequestQueryFilterItem {
member: Some("KibanaSampleDataEcommerce.customer_gender".to_string()),
operator: Some("equals".to_string()),
values: Some(vec!["female".to_string(), "male".to_string()]),
or: None,
and: None,
}]),
}
);
}
}
79 changes: 54 additions & 25 deletions rust/cubesql/cubesql/src/compile/rewrite/rules/filters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,20 +287,15 @@ impl RewriteRules for FilterRules {
change_user_member("?user"),
self.transform_change_user_eq("?column", "?literal", "?user"),
),
// ?expr IN (?one_element..)
transforming_rewrite(
"in-filter-equal",
filter_replacer(
inlist_expr("?expr", "?list", "?negated"),
"?alias_to_cube",
"?members",
),
filter_replacer(
binary_expr("?expr", "=", literal_expr("?literal")),
"?alias_to_cube",
"?members",
),
self.transform_filter_in_to_equal("?list", "?negated", "?literal"),
filter_replacer("?binary_expr", "?alias_to_cube", "?members"),
self.transform_filter_in_to_equal("?expr", "?list", "?negated", "?binary_expr"),
),
rewrite(
"filter-in-place-filter-to-true-filter",
Expand Down Expand Up @@ -1960,35 +1955,69 @@ impl FilterRules {
// Transform ?expr IN (?literal) to ?expr = ?literal
fn transform_filter_in_to_equal(
&self,
expr_val: &'static str,
list_var: &'static str,
negated_var: &'static str,
return_literal_var: &'static str,
return_binary_expr_var: &'static str,
) -> impl Fn(&mut EGraph<LogicalPlanLanguage, LogicalPlanAnalysis>, &mut Subst) -> bool {
let expr_val = var!(expr_val);
let list_var = var!(list_var);
let negated_var = var!(negated_var);
let return_literal_var = var!(return_literal_var);
let return_binary_expr_var = var!(return_binary_expr_var);

move |egraph, subst| {
let expr_id = subst[expr_val];
let (list, scalar) = match &egraph[subst[list_var]].data.constant_in_list {
Some(list) if list.len() > 0 => (list.clone(), list[0].clone()),
_ => return false,
};

for negated in var_iter!(egraph[subst[negated_var]], InListExprNegated) {
if *negated {
return false;
let operator = if *negated {
Operator::NotEq
} else {
Operator::Eq
};
let operator =
egraph.add(LogicalPlanLanguage::BinaryExprOp(BinaryExprOp(operator)));

let literal_expr = egraph.add(LogicalPlanLanguage::LiteralExprValue(
LiteralExprValue(scalar),
));
let literal_expr = egraph.add(LogicalPlanLanguage::LiteralExpr([literal_expr]));

let mut return_binary_expr = egraph.add(LogicalPlanLanguage::BinaryExpr([
expr_id,
operator,
literal_expr,
]));

for scalar in list.into_iter().skip(1) {
let literal_expr = egraph.add(LogicalPlanLanguage::LiteralExprValue(
LiteralExprValue(scalar),
));
let literal_expr = egraph.add(LogicalPlanLanguage::LiteralExpr([literal_expr]));

let right_binary_expr = egraph.add(LogicalPlanLanguage::BinaryExpr([
expr_id,
operator,
literal_expr,
]));

let or = egraph.add(LogicalPlanLanguage::BinaryExprOp(BinaryExprOp(
Operator::Or,
)));

return_binary_expr = egraph.add(LogicalPlanLanguage::BinaryExpr([
return_binary_expr,
or,
right_binary_expr,
]));
}

if let Some(list) = &egraph[subst[list_var]].data.constant_in_list {
if list.len() != 1 {
return false;
}

if let Some(scalar) = list.first().cloned() {
let first_scalar = egraph.add(LogicalPlanLanguage::LiteralExprValue(
LiteralExprValue(scalar),
));

subst.insert(return_literal_var, first_scalar);
subst.insert(return_binary_expr_var, return_binary_expr);

return true;
}
}
return true;
}

false
Expand Down

0 comments on commit 2269b2b

Please sign in to comment.