From c76e71f937e17cbe7f8026aca620b2667275fedd Mon Sep 17 00:00:00 2001 From: Dmitriy Rusov Date: Thu, 2 Apr 2026 09:27:22 +0200 Subject: [PATCH 1/2] docs: Maintenance window and upgrade now button (#10609) --- .../workspace/maintenance-window.mdx | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/docs/content/product/administration/workspace/maintenance-window.mdx b/docs/content/product/administration/workspace/maintenance-window.mdx index 3649442621fa9..4ef1ce8729e85 100644 --- a/docs/content/product/administration/workspace/maintenance-window.mdx +++ b/docs/content/product/administration/workspace/maintenance-window.mdx @@ -98,21 +98,24 @@ revert to an older version, contact support. ## Upgrade now If a critical fix has been released and you don't want to wait for the -next scheduled maintenance window, you can apply the latest eligible -snapshot immediately. +next scheduled maintenance window, you can upgrade to the current +production versions immediately. When the maintenance window is enabled, an **Upgrade Now** section appears at the bottom of the settings page. Click **Upgrade Now** to -advance to the latest eligible snapshot right away. +create a snapshot from the service versions currently running in +production and switch your deployment to it right away. The button is disabled while the upgrade is in progress. Once complete, the new version will appear in the **Active Version** dropdown. -The same eligibility rules apply — only snapshots that are at least -24 hours old are considered. If you are already on the latest eligible -snapshot, the button will return an error. +Unlike the scheduled maintenance window, **Upgrade Now** does not +require a 24-hour eligibility buffer — it always uses the versions +running in production at the time you click the button. If your +deployment is already running those versions, the button will return +an error. @@ -145,8 +148,9 @@ above for details. ### Can I trigger an immediate upgrade without waiting for the window? -Yes. Use the **Upgrade Now** button on the settings page to apply the -latest eligible snapshot immediately. See [Upgrade now](#upgrade-now) -above for details. +Yes. Use the **Upgrade Now** button on the settings page to upgrade to +the current production versions immediately, without waiting for the +24-hour eligibility buffer. See [Upgrade now](#upgrade-now) above for +details. [ref-dedicated]: /product/deployment/cloud/deployment-types#production-cluster From 98e3c19e5d70cfdb1c705d58a87c88524e78d416 Mon Sep 17 00:00:00 2001 From: Josh Wilson Date: Thu, 2 Apr 2026 06:47:17 -0500 Subject: [PATCH 2/2] fix: skip annotation check for filter-only time dimensions, thanks @jwils (#10603) In #10590, `validate_query_members_in_annotation()` was added to check all requested members against the annotation map when query results are empty. However, time dimensions used purely for date-range filtering (no `granularity`) don't produce result columns and are not present in the annotation map. This causes false "You requested hidden member" errors for legitimate queries that return no rows. Only validate time dimensions that have a granularity set, since those are the ones that produce result columns and appear in the annotation. Fixes #10601 --------- Co-authored-by: Claude Opus 4.6 (1M context) Co-authored-by: Dmitry Patsura --- .../src/tests/testQueries.ts | 14 +++++ .../src/query_result_transform.rs | 55 ++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/packages/cubejs-testing-drivers/src/tests/testQueries.ts b/packages/cubejs-testing-drivers/src/tests/testQueries.ts index d5304e24a0a29..8a97514618b96 100644 --- a/packages/cubejs-testing-drivers/src/tests/testQueries.ts +++ b/packages/cubejs-testing-drivers/src/tests/testQueries.ts @@ -234,6 +234,20 @@ export function testQueries(type: string, { includeIncrementalSchemaSuite, exten }); }); + // https://github.com/cube-js/cube/issues/10601 + execute('querying ECommerce: dimensions + filter-only by TD to get empty results', async () => { + const response = await client.load({ + dimensions: [ + 'ECommerce.city', + ], + timeDimensions: [{ + dimension: 'ECommerce.orderDate', + dateRange: ['2099-01-01', '2099-12-31'], + }], + }); + expect(response.rawData()).toEqual([]); + }); + execute('querying Customers: dimensions', async () => { const response = await client.load({ dimensions: [ diff --git a/rust/cubeorchestrator/src/query_result_transform.rs b/rust/cubeorchestrator/src/query_result_transform.rs index 7404effa0df16..56ff3aed74cab 100644 --- a/rust/cubeorchestrator/src/query_result_transform.rs +++ b/rust/cubeorchestrator/src/query_result_transform.rs @@ -208,7 +208,15 @@ fn validate_query_members_in_annotation( ensure_member_in_annotation(m, annotation)?; } - for td in query.time_dimensions.iter().flat_map(|v| v.iter()) { + // Only validate time dimensions that have a granularity set. + // Time dimensions without granularity are used purely for date-range filtering + // and don't produce result columns, so they are not present in the annotation map. + for td in query + .time_dimensions + .iter() + .flat_map(|v| v.iter()) + .filter(|td| td.granularity.is_some()) + { ensure_member_in_annotation(td.dimension.as_str(), annotation)?; } @@ -2276,6 +2284,51 @@ mod tests { } } + #[test] + fn test_get_members_empty_dataset_with_filter_only_time_dimension() -> Result<()> { + let mut test_data = TEST_SUITE_DATA + .get(&"regular_profit_by_postal_code".to_string()) + .unwrap() + .clone(); + + // Add a filter-only time dimension (no granularity) to the query. + // This simulates a dateRange filter like: + // timeDimensions: [{ dimension: "Orders.created_at", dateRange: [...] }] + // These dimensions are NOT in the annotation because they don't produce + // result columns — they're only used for filtering. + test_data.request.query.time_dimensions = Some(vec![QueryTimeDimension { + dimension: "ECommerceRecordsUs2021.order_date".to_string(), + date_range: Some(vec!["2025-01-01".to_string(), "2025-12-31".to_string()]), + compare_date_range: None, + granularity: None, + }]); + + let alias_to_member_name_map = &test_data.request.alias_to_member_name_map; + let annotation = &test_data.request.annotation; + let query = &test_data.request.query; + let query_type = &test_data.request.query_type.clone().unwrap_or_default(); + + // Should succeed — filter-only time dimensions must not be checked + // against the annotation map. + let result = get_members( + query_type, + query, + &QueryResult { + columns: vec![], + rows: vec![], + columns_pos: IndexMap::new(), + }, + alias_to_member_name_map, + annotation, + ); + assert!( + result.is_ok(), + "Filter-only time dimension (no granularity) should not trigger hidden member error, got: {:?}", + result.err() + ); + Ok(()) + } + #[test] fn test_get_members_filled_dataset() -> Result<()> { let test_data = TEST_SUITE_DATA