{"record":{"id":"8bc0de7f90f8c7e4","repo":"risingwavelabs/risingwave","slug":"auto-schema-change-with-drop-column-only-supports","errorCode":null,"errorMessage":"auto schema change with drop column only supports Project with InputRef","messagePattern":"auto schema change with drop column only supports Project with InputRef","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/meta/src/stream/stream_graph/fragment.rs","lineNumber":696,"sourceCode":"    project_node: &mut StreamNode,\n    scan_rewrite: &ScanRewriteResult,\n    newly_added_columns: &[ColumnCatalog],\n    removed_column_ids: &HashSet<ColumnId>,\n    upstream_table_name: &str,\n) -> MetaResult<()> {\n    let PbNodeBody::Project(project_node_body) = project_node.node_body.as_mut().unwrap() else {\n        return Err(anyhow!(\n            \"expect PbNodeBody::Project but got: {:?}\",\n            project_node.node_body\n        )\n        .into());\n    };\n    let has_non_input_ref = project_node_body\n        .select_list\n        .iter()\n        .any(|expr| !matches!(expr.rex_node, Some(expr_node::RexNode::InputRef(_))));\n    if has_non_input_ref && !removed_column_ids.is_empty() {\n        return Err(anyhow!(\n            \"auto schema change with drop column only supports Project with InputRef\"\n        )\n        .into());\n    }\n\n    let mut new_select_list = Vec::with_capacity(project_node_body.select_list.len());\n    let mut new_project_fields = Vec::with_capacity(project_node.fields.len());\n    for (index, expr) in project_node_body.select_list.iter().enumerate() {\n        let mut new_expr = expr.clone();\n        if let Some(expr_node::RexNode::InputRef(old_index)) = new_expr.rex_node {\n            let Some(&new_index) = scan_rewrite\n                .old_output_index_to_new_output_index\n                .get(&old_index)\n            else {\n                continue;\n            };\n            new_expr.rex_node = Some(expr_node::RexNode::InputRef(new_index));\n        } else if !removed_column_ids.is_empty() {","sourceCodeStart":678,"sourceCodeEnd":714,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/src/stream/stream_graph/fragment.rs#L678-L714","documentation":"During ALTER TABLE auto schema change, the meta service rewrites the sink fragment's Project node to remap InputRefs after columns are dropped. If the Project's select list contains any expression that is not a bare InputRef (e.g. a function call or literal) AND columns were removed, the rewrite cannot remap it safely, so `rewrite_project_node` fails fast. The library only supports pure column-pass-through Projects when dropping columns.","triggerScenarios":"Calling `rewrite_refresh_schema_sink_fragment` (via replace_job for ALTER TABLE DROP COLUMN) where the MV/sink pipeline between the StreamScan and the Sink is a Project containing computed expressions (functions, literals, casts) rather than only InputRefs, with a non-empty removed_column_ids set.","commonSituations":"User alters a materialized view to drop a column while the MV's select list computes derived expressions (e.g. `SELECT a + b AS c`), so the sink input is a Project with non-InputRef expressions.","solutions":["Rewrite the MV so the Project is a pure column pass-through before dropping columns, computing expressions elsewhere.","Drop the column without computed expressions in the pipeline: recreate the MV without the column instead of ALTER.","If you maintain RisingWave, extend rewrite_project_node to remap InputRef children inside non-InputRef expressions."],"exampleFix":"-- before\nCREATE MV mv AS SELECT a, a + b AS s FROM t;\nALTER TABLE t DROP COLUMN b; -- fails: Project contains a+b\n-- after\nCREATE MV mv AS SELECT a, s FROM (SELECT a, a + b AS s FROM t) sub; -- or recreate MV without b","handlingStrategy":"validation","validationCode":"// Before ALTER ... DROP COLUMN, ensure the MV select list is pure pass-through\n// e.g. check the MV definition contains only plain column references over the altered table.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep downstream MVs of columns you plan to alter as simple column projections.","Prefer recreating MVs when complex expressions are involved.","Review MV definitions with SHOW CREATE MATERIALIZED VIEW before ALTER TABLE."],"tags":["meta-service","schema-change","streaming-graph","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}