Skip to content

Commit

Permalink
feat(cubesql): Extend DATEDIFF push down support
Browse files Browse the repository at this point in the history
  • Loading branch information
MazterQyou committed Feb 5, 2024
1 parent 7b015b2 commit ecaaf1c
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ export class DatabricksQuery extends BaseQuery {
templates.functions.BTRIM = 'TRIM({% if args[1] is defined %}{{ args[1] }} FROM {% endif %}{{ args[0] }})';
templates.functions.LTRIM = 'LTRIM({{ args|reverse|join(", ") }})';
templates.functions.RTRIM = 'RTRIM({{ args|reverse|join(", ") }})';
// Databricks has a DATEDIFF function but produces values different from Redshift
delete templates.functions.DATEDIFF;
templates.functions.DATEDIFF = 'DATEDIFF({{ date_part }}, DATE_TRUNC(\'{{ date_part }}\', {{ args[1] }}), DATE_TRUNC(\'{{ date_part }}\', {{ args[2] }}))';
return templates;
}
}
3 changes: 2 additions & 1 deletion packages/cubejs-schema-compiler/src/adapter/PostgresQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ export class PostgresQuery extends BaseQuery {
templates.functions.NOW = 'NOW({{ args_concat }})';
// DATEADD is being rewritten to DATE_ADD
// templates.functions.DATEADD = '({{ args[2] }} + \'{{ interval }} {{ date_part }}\'::interval)';
delete templates.functions.DATEDIFF;
// TODO: is DATEDIFF expr worth documenting?
templates.functions.DATEDIFF = 'CASE WHEN LOWER(\'{{ date_part }}\') IN (\'year\', \'quarter\', \'month\') THEN (EXTRACT(YEAR FROM AGE(DATE_TRUNC(\'{{ date_part }}\', {{ args[2] }}), DATE_TRUNC(\'{{ date_part }}\', {{ args[1] }}))) * 12 + EXTRACT(MONTH FROM AGE(DATE_TRUNC(\'{{ date_part }}\', {{ args[2] }}), DATE_TRUNC(\'{{ date_part }}\', {{ args[1] }})))) / CASE LOWER(\'{{ date_part }}\') WHEN \'year\' THEN 12 WHEN \'quarter\' THEN 3 WHEN \'month\' THEN 1 END ELSE EXTRACT(EPOCH FROM DATE_TRUNC(\'{{ date_part }}\', {{ args[2] }}) - DATE_TRUNC(\'{{ date_part }}\', {{ args[1] }})) / EXTRACT(EPOCH FROM \'1 {{ date_part }}\'::interval) END::bigint';
templates.expressions.interval = 'INTERVAL \'{{ interval }}\'';
templates.expressions.extract = 'EXTRACT({{ date_part }} FROM {{ expr }})';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export class RedshiftQuery extends PostgresQuery {
public sqlTemplates() {
const templates = super.sqlTemplates();
templates.functions.DLOG10 = 'LOG(10, {{ args_concat }})';
templates.functions.DATEDIFF = 'DATEDIFF({{ date_part }}, {{ args[1] }}, {{ args[2] }})';
delete templates.functions.COVAR_POP;
delete templates.functions.COVAR_SAMP;
return templates;
Expand Down
63 changes: 63 additions & 0 deletions rust/cubesql/cubesql/src/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20803,6 +20803,69 @@ limit
.sql;
assert!(sql.contains("DATETIME_DIFF(CAST("));
assert!(sql.contains("day)"));

// Databricks
let query_plan = convert_select_to_query_plan_customized(
"
SELECT DATEDIFF(DAY, order_date, last_mod) AS d
FROM KibanaSampleDataEcommerce AS k
GROUP BY 1
ORDER BY 1 DESC
"
.to_string(),
DatabaseProtocol::PostgreSQL,
vec![
("functions/DATEDIFF".to_string(), "DATEDIFF({{ date_part }}, DATE_TRUNC(\'{{ date_part }}\', {{ args[1] }}), DATE_TRUNC(\'{{ date_part }}\', {{ args[2] }}))".to_string()),
]
)
.await;

let physical_plan = query_plan.as_physical_plan().await.unwrap();
println!(
"Physical plan: {}",
displayable(physical_plan.as_ref()).indent()
);

let logical_plan = query_plan.as_logical_plan();
let sql = logical_plan
.find_cube_scan_wrapper()
.wrapped_sql
.unwrap()
.sql;
assert!(sql.contains("DATEDIFF(day,"));
assert!(sql.contains("DATE_TRUNC('day',"));

// PostgreSQL
let query_plan = convert_select_to_query_plan_customized(
"
SELECT DATEDIFF(DAY, order_date, last_mod) AS d
FROM KibanaSampleDataEcommerce AS k
GROUP BY 1
ORDER BY 1 DESC
"
.to_string(),
DatabaseProtocol::PostgreSQL,
vec![
("functions/DATEDIFF".to_string(), "CASE WHEN LOWER(\'{{ date_part }}\') IN (\'year\', \'quarter\', \'month\') THEN (EXTRACT(YEAR FROM AGE(DATE_TRUNC(\'{{ date_part }}\', {{ args[2] }}), DATE_TRUNC(\'{{ date_part }}\', {{ args[1] }}))) * 12 + EXTRACT(MONTH FROM AGE(DATE_TRUNC(\'{{ date_part }}\', {{ args[2] }}), DATE_TRUNC(\'{{ date_part }}\', {{ args[1] }})))) / CASE LOWER(\'{{ date_part }}\') WHEN \'year\' THEN 12 WHEN \'quarter\' THEN 3 WHEN \'month\' THEN 1 END ELSE EXTRACT(EPOCH FROM DATE_TRUNC(\'{{ date_part }}\', {{ args[2] }}) - DATE_TRUNC(\'{{ date_part }}\', {{ args[1] }})) / EXTRACT(EPOCH FROM \'1 {{ date_part }}\'::interval) END::bigint".to_string()),
]
)
.await;

let physical_plan = query_plan.as_physical_plan().await.unwrap();
println!(
"Physical plan: {}",
displayable(physical_plan.as_ref()).indent()
);

let logical_plan = query_plan.as_logical_plan();
let sql = logical_plan
.find_cube_scan_wrapper()
.wrapped_sql
.unwrap()
.sql;
assert!(sql.contains("CASE WHEN LOWER('day')"));
assert!(sql.contains("WHEN 'year' THEN 12 WHEN 'quarter' THEN 3 WHEN 'month' THEN 1 END"));
assert!(sql.contains("EXTRACT(EPOCH FROM"));
}

// redshift-dateadd-[literal-date32-]to-interval rewrites DATEADD to DATE_ADD
Expand Down

0 comments on commit ecaaf1c

Please sign in to comment.