risingwavelabs/risingwave · error
call predicate_pushdown of the PlanRef instead of calling di
Error message
call predicate_pushdown of the PlanRef instead of calling directly on LogicalShare
What it means
`LogicalShare::predicate_pushdown` is deliberately `unimplemented!()`. Predicate pushdown into a shared subplan must be routed through `PlanRef::predicate_pushdown`, which special-cases LogicalShare so predicates are duplicated/filtered above the share rather than pushed incorrectly into it. Calling the trait method directly breaks the API contract.
Source
Thrown at src/frontend/src/optimizer/plan_node/logical_share.rs:147
}
impl ColPrunable for LogicalShare {
fn prune_col(&self, _required_cols: &[usize], _ctx: &mut ColumnPruningContext) -> PlanRef {
unimplemented!("call prune_col of the PlanRef instead of calling directly on LogicalShare")
}
}
impl ExprRewritable<Logical> for LogicalShare {}
impl ExprVisitable for LogicalShare {}
impl PredicatePushdown for LogicalShare {
fn predicate_pushdown(
&self,
_predicate: Condition,
_ctx: &mut PredicatePushdownContext,
) -> PlanRef {
unimplemented!(
"call predicate_pushdown of the PlanRef instead of calling directly on LogicalShare"
)
}
}
impl ToBatch for LogicalShare {
fn to_batch(&self) -> Result<crate::optimizer::plan_node::BatchPlanRef> {
bail_not_implemented!("batch query doesn't support share operator for now");
}
}
impl ToStream for LogicalShare {
fn to_stream(
&self,
ctx: &mut ToStreamContext,
) -> Result<crate::optimizer::plan_node::StreamPlanRef> {
match ctx.get_to_stream_result(self.share_id()) {
None => {View on GitHub (pinned to 6469eb736d)
Solutions
- Call `PlanRef::from(share.clone()).predicate_pushdown(cond, ctx)` so the share-aware implementation runs.
- Keep predicate-pushdown code generic over `PlanRef` and avoid downcasting to LogicalShare before pushing predicates.
- If a built-in rule triggers this, file a RisingWave optimizer bug.
Example fix
// before let pushed = logical_share.predicate_pushdown(cond, ctx); // after let pushed = PlanRef::from(logical_share.clone()).predicate_pushdown(cond, ctx);
Defensive patterns
Strategy: type-guard
Validate before calling
if node.as_logical_share().is_some() {
let node = PlanRef::from(node.clone());
// call node.predicate_pushdown(cond, ctx)
} Type guard
fn pushable_ref(plan: PlanRef) -> PlanRef {
assert!(plan.as_logical_share().is_none(), "predicate_pushdown via PlanRef only");
plan
} Prevention
- Always push predicates through `PlanRef::predicate_pushdown`.
- Avoid `as_logical_share()` downcasts inside pushdown rules.
- Cover shared-subplan cases in rule tests.
- Follow the existing share-aware code path in predicate_pushdown for LogicalPlanRef.
When it happens
Trigger: Calling `predicate_pushdown(cond, ctx)` directly on a `LogicalShare` value instead of on a `PlanRef` wrapping it.
Common situations: Encountered by developers extending the predicate pushdown rules who downcast to LogicalShare and invoke the trait method, bypassing the share-aware dispatch.
Related errors
- call prune_col of the PlanRef instead of calling directly on
- shared node should be handled specially in PlanRef::clone_wi
- not implemented
- required column should be kept
- iceberg intermediate scan must have a source catalog
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/2dd8c1fd8b3237ba.
Report an issue: GitHub.