risingwavelabs/risingwave · error
join plan cannot be generated, tables not connected.
Error message
join plan cannot be generated, tables not connected.
What it means
find_lookup_path builds a join order for a delta join by repeatedly finding a lookup-joinable connection between indexed tables. If, after a step, not all tables have been placed in the path yet but no more joins can be added, the tables are disconnected and no lookup join plan exists.
Solutions
- Create indexes on the join columns of the disconnected tables so lookup joins become possible.
- Rewrite the query so tables are connected through indexed equality join predicates.
- Remove the intermediate table if it is not needed, or include the connecting table in the query.
- Fall back to a standard (non-delta-join) MV plan by not relying on index lookup joins.
Defensive patterns
Strategy: validation
Validate before calling
-- ensure all joined tables have indexes on equality join keys before creating the MV SELECT name FROM rw_catalog.rw_indexes WHERE ... ;
Try / catch
match create_mv_result {
Err(e) if e.to_string().contains("tables not connected") => {
eprintln!("Delta join requires index-connected tables; add missing indexes or rewrite joins");
}
other => other?,
} Prevention
- Create an index on every table's equality join keys used in the delta-join query.
- Avoid cross joins and non-equality joins in index-backed MVs.
- Verify the join graph is connected across all base tables before enabling delta joins.
When it happens
Trigger: Creating a materialized view over base tables where some index-connected tables share no join predicates that allow lookup joins, so the delta join solver cannot connect every table in one path (solve -> find_lookup_path).
Common situations: Delta join (index-based MVs) where the query joins tables that are only connected via non-indexed columns or via a third table not included; cross joins or predicates the delta join solver does not recognize.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- only inner join without non-equal condition is supported…
- children expression must not be empty for constant lookup…
- does not support struct, array, map, vector, jsonb for…
- `DynamicFilterExecutor` only supports comparators…
- GenerateSeriesExecutor should not have child!
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/d4057d7eae1d9795.
Report an issue: GitHub.
Appendix: source
Thrown at src/frontend/src/optimizer/delta_join_solver.rs:391
// step 4: place arrangements according to the arrange strategy, update current
// distribution and current table set.
for table in &solver_env.arrange_placement_order {
if let Some(edge) = reachable_tables.get(table) {
current_table_set.insert(edge.right);
path.push(edge.right);
current_distribution.clear();
current_distribution.push((edge.right, edge.right_join_key.clone()));
continue 'next_table;
}
}
// step 5: no tables can be joined any more, what happened?
if self.join_order.len() - 1 == path.len() {
break;
} else {
// no table can be joined, while path is still incomplete
return Err(anyhow!(
"join plan cannot be generated, tables not connected."
));
}
}
Ok(LookupPath(input_stream, path))
}
pub fn solve(&self) -> Result<Vec<LookupPath>> {
let solver_env = SolverEnv::build_from(self);
solver_env
.stream_placement_order
.iter()
.map(|x| self.find_lookup_path(&solver_env, *x))
.collect()
}
View on GitHub (pinned to 6469eb736d)