@@ -23,10 +23,14 @@ use crate::iter_ext::Itertools;
2323use crate :: planner:: operator:: update:: UpdateOperator ;
2424use crate :: planner:: LogicalPlan ;
2525use crate :: storage:: Transaction ;
26- use crate :: types:: index:: Index ;
26+ use crate :: types:: index:: { Index , IndexMeta , IndexType } ;
2727use crate :: types:: tuple:: { Schema , Tuple } ;
2828use crate :: types:: tuple_builder:: TupleBuilder ;
29- use std:: { collections:: HashMap , mem} ;
29+ use crate :: types:: ColumnId ;
30+ use std:: {
31+ collections:: { HashMap , HashSet } ,
32+ mem,
33+ } ;
3034
3135pub struct Update {
3236 table_name : TableName ,
@@ -79,6 +83,24 @@ impl<'a, T: Transaction + 'a> WriteExecutor<'a, T> for Update {
7983 }
8084}
8185
86+ impl Update {
87+ fn index_needs_update (
88+ index_meta : & IndexMeta ,
89+ updated_column_ids : & HashSet < ColumnId > ,
90+ updates_primary_key : bool ,
91+ ) -> bool {
92+ if matches ! ( index_meta. ty, IndexType :: PrimaryKey { .. } ) {
93+ return false ;
94+ }
95+
96+ updates_primary_key
97+ || index_meta
98+ . column_ids
99+ . iter ( )
100+ . any ( |column_id| updated_column_ids. contains ( column_id) )
101+ }
102+ }
103+
82104impl < ' a , T : Transaction + ' a > ExecutorNode < ' a , T > for Update {
83105 fn next_tuple (
84106 & mut self ,
@@ -91,8 +113,14 @@ impl<'a, T: Transaction + 'a> ExecutorNode<'a, T> for Update {
91113 } ;
92114
93115 let mut exprs_map = HashMap :: with_capacity ( self . value_exprs . len ( ) ) ;
116+ let mut updated_column_ids = HashSet :: with_capacity ( self . value_exprs . len ( ) ) ;
94117 for ( column, expr) in self . value_exprs . drain ( ..) {
95- exprs_map. insert ( plan_arena. column ( column) . id ( ) , expr) ;
118+ let column = plan_arena. column ( column) ;
119+ let column_id = column
120+ . id ( )
121+ . ok_or_else ( || DatabaseError :: column_not_found ( column. name ( ) . to_string ( ) ) ) ?;
122+ updated_column_ids. insert ( column_id) ;
123+ exprs_map. insert ( column_id, expr) ;
96124 }
97125
98126 let table_cache = arena. context ( ) . table_cache ( ) ;
@@ -104,6 +132,13 @@ impl<'a, T: Transaction + 'a> ExecutorNode<'a, T> for Update {
104132 . transpose ( ) ?
105133 } ;
106134 if let Some ( table_snapshot) = table_snapshot {
135+ let updates_primary_key = table_snapshot. primary_key_indices . iter ( ) . any ( |index| {
136+ table_snapshot
137+ . columns
138+ . get ( * index)
139+ . and_then ( |column| plan_arena. column ( * column) . id ( ) )
140+ . is_some_and ( |column_id| updated_column_ids. contains ( & column_id) )
141+ } ) ;
107142 let serializers = self
108143 . input_schema
109144 . iter ( )
@@ -118,17 +153,30 @@ impl<'a, T: Transaction + 'a> ExecutorNode<'a, T> for Update {
118153 let Some ( old_pk) = arena. result_tuple ( ) . pk . clone ( ) else {
119154 continue ;
120155 } ;
121- for ( index_meta, exprs) in table_snapshot. index_metas . iter ( ) {
156+
157+ let mut old_index_values = Vec :: new ( ) ;
158+ for ( index_offset, ( index_meta, exprs) ) in
159+ table_snapshot. index_metas . iter ( ) . enumerate ( )
160+ {
122161 let index_meta = plan_arena. index ( * index_meta) ;
123- with_projection_tmp_value ( arena, None , exprs, |arena, value| {
124- let mut state = arena. local_state ( plan_arena) ;
125- let ( transaction, table_codec) = state. transaction_codec_mut ( ) ;
126- let index = Index :: new ( index_meta. id , & value, index_meta. ty ) ;
127- transaction. del_index ( table_codec, & self . table_name , & index, & old_pk)
162+ if !Self :: index_needs_update (
163+ index_meta,
164+ & updated_column_ids,
165+ updates_primary_key,
166+ ) {
167+ continue ;
168+ }
169+
170+ with_projection_tmp_value ( arena, None , exprs, |_, value| {
171+ old_index_values. push ( ( index_offset, value) ) ;
172+ Ok ( ( ) )
128173 } ) ?;
129174 }
130175 for ( i, column) in self . input_schema . iter ( ) . enumerate ( ) {
131- if let Some ( expr) = exprs_map. get ( & plan_arena. column ( * column) . id ( ) ) {
176+ let Some ( column_id) = plan_arena. column ( * column) . id ( ) else {
177+ continue ;
178+ } ;
179+ if let Some ( expr) = exprs_map. get ( & column_id) {
132180 let value = expr. eval ( Some ( arena. result_tuple ( ) ) ) ?;
133181 arena. result_tuple_mut ( ) . values [ i] = value;
134182 }
@@ -140,19 +188,35 @@ impl<'a, T: Transaction + 'a> ExecutorNode<'a, T> for Update {
140188 ) ;
141189 arena. result_tuple_mut ( ) . pk = Some ( new_pk. clone ( ) ) ;
142190
143- if new_pk != old_pk {
191+ let primary_key_changed = new_pk != old_pk;
192+ if primary_key_changed {
144193 let mut state = arena. local_state ( plan_arena) ;
145194 let ( transaction, table_codec) = state. transaction_codec_mut ( ) ;
146195 transaction. remove_tuple ( table_codec, & self . table_name , & old_pk) ?;
147196 is_overwrite = false ;
148197 }
149- for ( index_meta, exprs) in table_snapshot. index_metas . iter ( ) {
198+
199+ for ( index_offset, old_value) in old_index_values {
200+ let ( index_meta, exprs) = & table_snapshot. index_metas [ index_offset] ;
150201 let index_meta = plan_arena. index ( * index_meta) ;
202+ let index_id = index_meta. id ;
203+ let index_ty = index_meta. ty ;
151204 with_projection_tmp_value ( arena, None , exprs, |arena, value| {
205+ if !primary_key_changed && old_value == value {
206+ return Ok ( ( ) ) ;
207+ }
208+
152209 let mut state = arena. local_state ( plan_arena) ;
153210 let ( transaction, table_codec) = state. transaction_codec_mut ( ) ;
154- let index = Index :: new ( index_meta. id , & value, index_meta. ty ) ;
155- transaction. add_index ( table_codec, & self . table_name , index, & new_pk)
211+ let old_index = Index :: new ( index_id, & old_value, index_ty) ;
212+ transaction. del_index (
213+ table_codec,
214+ & self . table_name ,
215+ & old_index,
216+ & old_pk,
217+ ) ?;
218+ let new_index = Index :: new ( index_id, & value, index_ty) ;
219+ transaction. add_index ( table_codec, & self . table_name , new_index, & new_pk)
156220 } ) ?;
157221 }
158222
0 commit comments