diff --git a/src/completion.rs b/src/completion.rs index 85bce63..c0b9117 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -1177,8 +1177,11 @@ mod tests { #[test] fn drop_column_from_offers_only_current_table_columns() { - // The drop-column path also writes_table → narrowed - // columns should appear here too. + // The DDL `TABLE_NAME_EXISTING` slot now sets + // `writes_table` (handoff-13 §2.2 fix), so the + // column-name slot after the table name narrows to that + // table's columns. `OrderTotal` belongs to no table in + // this cache's `table_columns`, so it must not leak. use crate::dsl::types::Type; let mut cache = schema_with_table( "Customers", @@ -1187,13 +1190,12 @@ mod tests { cache.columns.push("OrderTotal".to_string()); let cs = cands_with("drop column from Customers: ", 28, &cache); - // Note: drop column's table-name slot doesn't set - // writes_table today (DDL paths don't carry Phase D - // table-column resolution yet). Falls back to global - // cache.columns, which is the documented schemaless - // fallback. Either narrowed-or-flat is acceptable; the - // test just confirms valid columns appear. assert!(cs.contains(&"Email".to_string()), "got {cs:?}"); + assert!(cs.contains(&"id".to_string()), "got {cs:?}"); + assert!( + !cs.contains(&"OrderTotal".to_string()), + "OrderTotal (not a Customers column) must not leak: got {cs:?}", + ); } #[test] diff --git a/src/dsl/grammar/ddl.rs b/src/dsl/grammar/ddl.rs index 7d06373..8eaf699 100644 --- a/src/dsl/grammar/ddl.rs +++ b/src/dsl/grammar/ddl.rs @@ -34,12 +34,19 @@ const TABLE_NAME_NEW: Node = Node::Ident { writes_user_listed_column: false, }; +// `writes_table: true` so that the column-name slots that +// follow the table name in `drop column` / `rename column` / +// `change column` / `add column` can narrow their candidates to +// this table's columns (handoff-12 §2.2). The walker writes +// `current_table` / `current_table_columns` on match; the +// completion engine reads the snapshot. `drop table` has no +// downstream column slot, so the write is harmless there. const TABLE_NAME_EXISTING: Node = Node::Ident { source: IdentSource::Tables, role: "table_name", validator: None, highlight_override: None, - writes_table: false, + writes_table: true, writes_column: false, writes_user_listed_column: false, }; @@ -118,13 +125,19 @@ const DROP_COLUMN: Node = Node::Seq(DROP_COLUMN_NODES); // drop_relationship — `drop relationship (endpoints | name)` // ================================================================= +// `writes_table: true` on each endpoint's table ident so the +// `.