diff --git a/core/translate/alter.rs b/core/translate/alter.rs index 5875b201f..77a1949ea 100644 --- a/core/translate/alter.rs +++ b/core/translate/alter.rs @@ -119,13 +119,15 @@ pub fn translate_alter_table( for index in table_indexes.iter() { // Referenced in regular index - if index + let maybe_indexed_col = index .columns .iter() - .any(|col| col.pos_in_table == dropped_index) - { + .enumerate() + .find(|(_, col)| col.pos_in_table == dropped_index); + if let Some((pos_in_index, indexed_col)) = maybe_indexed_col { return Err(LimboError::ParseError(format!( - "cannot drop column \"{column_name}\": indexed" + "cannot drop column \"{column_name}\": it is referenced in the index {}; position in index is {pos_in_index}, position in table is {}", + index.name, indexed_col.pos_in_table ))); } // Referenced in partial index diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index af75bd83b..1a36b5f9d 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -7921,29 +7921,49 @@ pub fn op_drop_column( btree.columns.remove(*column_index) }); - let schema = conn.schema.read(); - if let Some(indexes) = schema.indexes.get(&normalized_table_name) { - for index in indexes { - if index - .columns - .iter() - .any(|column| column.pos_in_table == *column_index) - { - return Err(LimboError::ParseError(format!( - "cannot drop column \"{column_name}\": indexed" - ))); + { + let schema = conn.schema.read(); + if let Some(indexes) = schema.indexes.get(&normalized_table_name) { + for index in indexes { + if index + .columns + .iter() + .any(|column| column.pos_in_table == *column_index) + { + return Err(LimboError::ParseError(format!( + "cannot drop column \"{column_name}\": indexed" + ))); + } } } } - for (view_name, view) in schema.views.iter() { - let view_select_sql = format!("SELECT * FROM {view_name}"); - conn.prepare(view_select_sql.as_str()).map_err(|e| { - LimboError::ParseError(format!( - "cannot drop column \"{}\": referenced in VIEW {view_name}: {}", - column_name, view.sql, - )) - })?; + // Update index.pos_in_table for all indexes. + // For example, if the dropped column had index 2, then anything that was indexed on column 3 or higher should be decremented by 1. + conn.with_schema_mut(|schema| { + if let Some(indexes) = schema.indexes.get_mut(&normalized_table_name) { + for index in indexes { + let index = Arc::make_mut(index); + for index_column in index.columns.iter_mut() { + if index_column.pos_in_table > *column_index { + index_column.pos_in_table -= 1; + } + } + } + } + }); + + { + let schema = conn.schema.read(); + for (view_name, view) in schema.views.iter() { + let view_select_sql = format!("SELECT * FROM {view_name}"); + conn.prepare(view_select_sql.as_str()).map_err(|e| { + LimboError::ParseError(format!( + "cannot drop column \"{}\": referenced in VIEW {view_name}: {}", + column_name, view.sql, + )) + })?; + } } state.pc += 1;