diff --git a/packages/cubejs-schema-compiler/test/integration/postgres/sql-generation.test.ts b/packages/cubejs-schema-compiler/test/integration/postgres/sql-generation.test.ts index e11b7f01b3af3..64e09f25894ad 100644 --- a/packages/cubejs-schema-compiler/test/integration/postgres/sql-generation.test.ts +++ b/packages/cubejs-schema-compiler/test/integration/postgres/sql-generation.test.ts @@ -714,8 +714,6 @@ SELECT 1 AS revenue, cast('2024-01-01' AS timestamp) as time UNION ALL await compiler.compile(); const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, q); - // console.log(query.buildSqlAndParams()); - const res = await dbRunner.testQuery(query.buildSqlAndParams()); console.log(JSON.stringify(res)); @@ -3379,6 +3377,45 @@ SELECT 1 AS revenue, cast('2024-01-01' AS timestamp) as time UNION ALL }); }); + it('don\'t use COALESCE with single argument', async () => { + if (!getEnv('nativeSqlPlanner')) { + return; + } + await compiler.compile(); + + const query = new PostgresQuery({ joinGraph, cubeEvaluator, compiler }, { + measures: [ + 'visitors.visitor_revenue' + ], + dimensions: [ + 'visitors.source' + ], + timeDimensions: [], + timezone: 'America/Los_Angeles', + filters: [{ + dimension: 'visitor_checkins.source', + operator: 'equals', + values: ['google'] + }], + order: [{ + id: 'visitors.source' + }] + }); + const queryAndParams = query.buildSqlAndParams(); + console.log(queryAndParams); + expect(queryAndParams[0]).not.toContain('COALESCE'); + + await dbRunner.testQuery(queryAndParams).then(res => { + console.log(JSON.stringify(res)); + expect(res).toEqual( + [{ + visitors__source: 'some', + visitors__visitor_revenue: '100' + }] + ); + }); + }); + it('expression cube name cache', async () => { await runQueryTest( { diff --git a/rust/cubesqlplanner/cubesqlplanner/src/plan/builder/select.rs b/rust/cubesqlplanner/cubesqlplanner/src/plan/builder/select.rs index 4312aa48fd867..33b22bb41f35f 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/plan/builder/select.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/plan/builder/select.rs @@ -6,6 +6,7 @@ use crate::plan::{ use crate::plan::expression::FunctionExpression; use crate::planner::sql_evaluator::sql_nodes::SqlNodesFactory; use crate::planner::{BaseMember, VisitorContext}; +use cubenativeutils::CubeError; use std::collections::HashMap; use std::rc::Rc; @@ -79,21 +80,30 @@ impl SelectBuilder { member: &Rc, references: Vec, alias: Option, - ) { + ) -> Result<(), CubeError> { let alias = if let Some(alias) = alias { alias } else { member.alias_name() }; - let expr = Expr::Function(FunctionExpression { - function: "COALESCE".to_string(), - arguments: references - .into_iter() - // TODO unwrap - .map(|r| Expr::Reference(r)) - .collect(), - }); + let expr = if references.len() > 1 { + Expr::Function(FunctionExpression { + function: "COALESCE".to_string(), + arguments: references + .into_iter() + // TODO unwrap + .map(|r| Expr::Reference(r)) + .collect(), + }) + } else if references.len() == 1 { + Expr::Reference(references[0].clone()) + } else { + return Err(CubeError::internal( + "Cannot add coalesce projection without references".to_string(), + )); + }; + let aliased_expr = AliasedExpr { expr, alias: alias.clone(), @@ -102,6 +112,7 @@ impl SelectBuilder { self.projection_columns.push(aliased_expr); self.result_schema .add_column(SchemaColumn::new(alias.clone(), Some(member.full_name()))); + Ok(()) } pub fn set_filter(&mut self, filter: Option) { diff --git a/rust/cubesqlplanner/cubesqlplanner/src/planner/planners/full_key_query_aggregate_planner.rs b/rust/cubesqlplanner/cubesqlplanner/src/planner/planners/full_key_query_aggregate_planner.rs index a89db3fe234ea..837a75137b655 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/planner/planners/full_key_query_aggregate_planner.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/planner/planners/full_key_query_aggregate_planner.rs @@ -127,7 +127,7 @@ impl FullKeyAggregateQueryPlanner { .collect::, _>>()?; let alias = references_builder .resolve_alias_for_member(&member.full_name(), &dimensions_source); - select_builder.add_projection_coalesce_member(member, references, alias); + select_builder.add_projection_coalesce_member(member, references, alias)?; } for member in BaseMemberHelper::iter_as_base_member(&outer_measures) {