1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2017, 2018, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /**************************************************//** |
21 | @file include/row0upd.h |
22 | Update of a row |
23 | |
24 | Created 12/27/1996 Heikki Tuuri |
25 | *******************************************************/ |
26 | |
27 | #ifndef row0upd_h |
28 | #define row0upd_h |
29 | |
30 | #include "data0data.h" |
31 | #include "row0types.h" |
32 | #include "btr0types.h" |
33 | #include "dict0types.h" |
34 | #include "trx0types.h" |
35 | #include "btr0pcur.h" |
36 | #include "que0types.h" |
37 | #include "pars0types.h" |
38 | |
39 | /*********************************************************************//** |
40 | Creates an update vector object. |
41 | @return own: update vector object */ |
42 | UNIV_INLINE |
43 | upd_t* |
44 | upd_create( |
45 | /*=======*/ |
46 | ulint n, /*!< in: number of fields */ |
47 | mem_heap_t* heap); /*!< in: heap from which memory allocated */ |
48 | /*********************************************************************//** |
49 | Returns the number of fields in the update vector == number of columns |
50 | to be updated by an update vector. |
51 | @return number of fields */ |
52 | UNIV_INLINE |
53 | ulint |
54 | upd_get_n_fields( |
55 | /*=============*/ |
56 | const upd_t* update); /*!< in: update vector */ |
57 | #ifdef UNIV_DEBUG |
58 | /*********************************************************************//** |
59 | Returns the nth field of an update vector. |
60 | @return update vector field */ |
61 | UNIV_INLINE |
62 | upd_field_t* |
63 | upd_get_nth_field( |
64 | /*==============*/ |
65 | const upd_t* update, /*!< in: update vector */ |
66 | ulint n); /*!< in: field position in update vector */ |
67 | #else |
68 | # define upd_get_nth_field(update, n) ((update)->fields + (n)) |
69 | #endif |
70 | |
71 | /*********************************************************************//** |
72 | Sets an index field number to be updated by an update vector field. */ |
73 | UNIV_INLINE |
74 | void |
75 | upd_field_set_field_no( |
76 | /*===================*/ |
77 | upd_field_t* upd_field, /*!< in: update vector field */ |
78 | ulint field_no, /*!< in: field number in a clustered |
79 | index */ |
80 | dict_index_t* index); |
81 | |
82 | /** set field number to a update vector field, marks this field is updated |
83 | @param[in,out] upd_field update vector field |
84 | @param[in] field_no virtual column sequence num |
85 | @param[in] index index */ |
86 | UNIV_INLINE |
87 | void |
88 | upd_field_set_v_field_no( |
89 | upd_field_t* upd_field, |
90 | ulint field_no, |
91 | dict_index_t* index); |
92 | /*********************************************************************//** |
93 | Returns a field of an update vector by field_no. |
94 | @return update vector field, or NULL */ |
95 | UNIV_INLINE |
96 | const upd_field_t* |
97 | upd_get_field_by_field_no( |
98 | /*======================*/ |
99 | const upd_t* update, /*!< in: update vector */ |
100 | ulint no, /*!< in: field_no */ |
101 | bool is_virtual) /*!< in: if it is a virtual column */ |
102 | MY_ATTRIBUTE((warn_unused_result)); |
103 | /*********************************************************************//** |
104 | Writes into the redo log the values of trx id and roll ptr and enough info |
105 | to determine their positions within a clustered index record. |
106 | @return new pointer to mlog */ |
107 | byte* |
108 | row_upd_write_sys_vals_to_log( |
109 | /*==========================*/ |
110 | dict_index_t* index, /*!< in: clustered index */ |
111 | trx_id_t trx_id, /*!< in: transaction id */ |
112 | roll_ptr_t roll_ptr,/*!< in: roll ptr of the undo log record */ |
113 | byte* log_ptr,/*!< pointer to a buffer of size > 20 opened |
114 | in mlog */ |
115 | mtr_t* mtr); /*!< in: mtr */ |
116 | /*********************************************************************//** |
117 | Updates the trx id and roll ptr field in a clustered index record when |
118 | a row is updated or marked deleted. */ |
119 | UNIV_INLINE |
120 | void |
121 | row_upd_rec_sys_fields( |
122 | /*===================*/ |
123 | rec_t* rec, /*!< in/out: record */ |
124 | page_zip_des_t* page_zip,/*!< in/out: compressed page whose |
125 | uncompressed part will be updated, or NULL */ |
126 | dict_index_t* index, /*!< in: clustered index */ |
127 | const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ |
128 | const trx_t* trx, /*!< in: transaction */ |
129 | roll_ptr_t roll_ptr);/*!< in: DB_ROLL_PTR to the undo log */ |
130 | /*********************************************************************//** |
131 | Sets the trx id or roll ptr field of a clustered index entry. */ |
132 | void |
133 | row_upd_index_entry_sys_field( |
134 | /*==========================*/ |
135 | dtuple_t* entry, /*!< in/out: index entry, where the memory |
136 | buffers for sys fields are already allocated: |
137 | the function just copies the new values to |
138 | them */ |
139 | dict_index_t* index, /*!< in: clustered index */ |
140 | ulint type, /*!< in: DATA_TRX_ID or DATA_ROLL_PTR */ |
141 | ib_uint64_t val); /*!< in: value to write */ |
142 | /*********************************************************************//** |
143 | Creates an update node for a query graph. |
144 | @return own: update node */ |
145 | upd_node_t* |
146 | upd_node_create( |
147 | /*============*/ |
148 | mem_heap_t* heap); /*!< in: mem heap where created */ |
149 | /***********************************************************//** |
150 | Writes to the redo log the new values of the fields occurring in the index. */ |
151 | void |
152 | row_upd_index_write_log( |
153 | /*====================*/ |
154 | const upd_t* update, /*!< in: update vector */ |
155 | byte* log_ptr,/*!< in: pointer to mlog buffer: must |
156 | contain at least MLOG_BUF_MARGIN bytes |
157 | of free space; the buffer is closed |
158 | within this function */ |
159 | mtr_t* mtr); /*!< in: mtr into whose log to write */ |
160 | /***********************************************************//** |
161 | Returns TRUE if row update changes size of some field in index or if some |
162 | field to be updated is stored externally in rec or update. |
163 | @return TRUE if the update changes the size of some field in index or |
164 | the field is external in rec or update */ |
165 | ibool |
166 | row_upd_changes_field_size_or_external( |
167 | /*===================================*/ |
168 | dict_index_t* index, /*!< in: index */ |
169 | const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ |
170 | const upd_t* update);/*!< in: update vector */ |
171 | /***********************************************************//** |
172 | Returns true if row update contains disowned external fields. |
173 | @return true if the update contains disowned external fields. */ |
174 | bool |
175 | row_upd_changes_disowned_external( |
176 | /*==============================*/ |
177 | const upd_t* update) /*!< in: update vector */ |
178 | MY_ATTRIBUTE((nonnull, warn_unused_result)); |
179 | /***********************************************************//** |
180 | Replaces the new column values stored in the update vector to the |
181 | record given. No field size changes are allowed. This function is |
182 | usually invoked on a clustered index. The only use case for a |
183 | secondary index is row_ins_sec_index_entry_by_modify() or its |
184 | counterpart in ibuf_insert_to_index_page(). */ |
185 | void |
186 | row_upd_rec_in_place( |
187 | /*=================*/ |
188 | rec_t* rec, /*!< in/out: record where replaced */ |
189 | dict_index_t* index, /*!< in: the index the record belongs to */ |
190 | const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ |
191 | const upd_t* update, /*!< in: update vector */ |
192 | page_zip_des_t* page_zip);/*!< in: compressed page with enough space |
193 | available, or NULL */ |
194 | |
195 | /***************************************************************//** |
196 | Builds an update vector from those fields which in a secondary index entry |
197 | differ from a record that has the equal ordering fields. NOTE: we compare |
198 | the fields as binary strings! |
199 | @return own: update vector of differing fields */ |
200 | upd_t* |
201 | row_upd_build_sec_rec_difference_binary( |
202 | /*====================================*/ |
203 | const rec_t* rec, /*!< in: secondary index record */ |
204 | dict_index_t* index, /*!< in: index */ |
205 | const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ |
206 | const dtuple_t* entry, /*!< in: entry to insert */ |
207 | mem_heap_t* heap) /*!< in: memory heap from which allocated */ |
208 | MY_ATTRIBUTE((warn_unused_result, nonnull)); |
209 | /** Builds an update vector from those fields, excluding the roll ptr and |
210 | trx id fields, which in an index entry differ from a record that has |
211 | the equal ordering fields. NOTE: we compare the fields as binary strings! |
212 | @param[in] index clustered index |
213 | @param[in] entry clustered index entry to insert |
214 | @param[in] rec clustered index record |
215 | @param[in] offsets rec_get_offsets(rec,index), or NULL |
216 | @param[in] no_sys skip the system columns |
217 | DB_TRX_ID and DB_ROLL_PTR |
218 | @param[in] trx transaction (for diagnostics), |
219 | or NULL |
220 | @param[in] heap memory heap from which allocated |
221 | @param[in,out] mysql_table NULL, or mysql table object when |
222 | user thread invokes dml |
223 | @return own: update vector of differing fields, excluding roll ptr and |
224 | trx id */ |
225 | upd_t* |
226 | row_upd_build_difference_binary( |
227 | dict_index_t* index, |
228 | const dtuple_t* entry, |
229 | const rec_t* rec, |
230 | const ulint* offsets, |
231 | bool no_sys, |
232 | trx_t* trx, |
233 | mem_heap_t* heap, |
234 | TABLE* mysql_table) |
235 | MY_ATTRIBUTE((nonnull(1,2,3,7), warn_unused_result)); |
236 | /** Apply an update vector to an index entry. |
237 | @param[in,out] entry index entry to be updated; the clustered index record |
238 | must be covered by a lock or a page latch to prevent |
239 | deletion (rollback or purge) |
240 | @param[in] index index of the entry |
241 | @param[in] update update vector built for the entry |
242 | @param[in,out] heap memory heap for copying off-page columns */ |
243 | void |
244 | row_upd_index_replace_new_col_vals_index_pos( |
245 | dtuple_t* entry, |
246 | const dict_index_t* index, |
247 | const upd_t* update, |
248 | mem_heap_t* heap) |
249 | MY_ATTRIBUTE((nonnull)); |
250 | /***********************************************************//** |
251 | Replaces the new column values stored in the update vector to the index entry |
252 | given. */ |
253 | void |
254 | row_upd_index_replace_new_col_vals( |
255 | /*===============================*/ |
256 | dtuple_t* entry, /*!< in/out: index entry where replaced; |
257 | the clustered index record must be |
258 | covered by a lock or a page latch to |
259 | prevent deletion (rollback or purge) */ |
260 | dict_index_t* index, /*!< in: index; NOTE that this may also be a |
261 | non-clustered index */ |
262 | const upd_t* update, /*!< in: an update vector built for the |
263 | CLUSTERED index so that the field number in |
264 | an upd_field is the clustered index position */ |
265 | mem_heap_t* heap) /*!< in: memory heap for allocating and |
266 | copying the new values */ |
267 | MY_ATTRIBUTE((nonnull)); |
268 | /***********************************************************//** |
269 | Replaces the new column values stored in the update vector. */ |
270 | void |
271 | row_upd_replace( |
272 | /*============*/ |
273 | dtuple_t* row, /*!< in/out: row where replaced, |
274 | indexed by col_no; |
275 | the clustered index record must be |
276 | covered by a lock or a page latch to |
277 | prevent deletion (rollback or purge) */ |
278 | row_ext_t** ext, /*!< out, own: NULL, or externally |
279 | stored column prefixes */ |
280 | const dict_index_t* index, /*!< in: clustered index */ |
281 | const upd_t* update, /*!< in: an update vector built for the |
282 | clustered index */ |
283 | mem_heap_t* heap); /*!< in: memory heap */ |
284 | /** Replaces the virtual column values stored in a dtuple with that of |
285 | a update vector. |
286 | @param[in,out] row dtuple whose column to be updated |
287 | @param[in] table table |
288 | @param[in] update an update vector built for the clustered index |
289 | @param[in] upd_new update to new or old value |
290 | @param[in,out] undo_row undo row (if needs to be updated) |
291 | @param[in] ptr remaining part in update undo log */ |
292 | void |
293 | row_upd_replace_vcol( |
294 | dtuple_t* row, |
295 | const dict_table_t* table, |
296 | const upd_t* update, |
297 | bool upd_new, |
298 | dtuple_t* undo_row, |
299 | const byte* ptr); |
300 | |
301 | /***********************************************************//** |
302 | Checks if an update vector changes an ordering field of an index record. |
303 | |
304 | This function is fast if the update vector is short or the number of ordering |
305 | fields in the index is small. Otherwise, this can be quadratic. |
306 | NOTE: we compare the fields as binary strings! |
307 | @return TRUE if update vector changes an ordering field in the index record */ |
308 | ibool |
309 | row_upd_changes_ord_field_binary_func( |
310 | /*==================================*/ |
311 | dict_index_t* index, /*!< in: index of the record */ |
312 | const upd_t* update, /*!< in: update vector for the row; NOTE: the |
313 | field numbers in this MUST be clustered index |
314 | positions! */ |
315 | #ifdef UNIV_DEBUG |
316 | const que_thr_t*thr, /*!< in: query thread */ |
317 | #endif /* UNIV_DEBUG */ |
318 | const dtuple_t* row, /*!< in: old value of row, or NULL if the |
319 | row and the data values in update are not |
320 | known when this function is called, e.g., at |
321 | compile time */ |
322 | const row_ext_t*ext, /*!< NULL, or prefixes of the externally |
323 | stored columns in the old row */ |
324 | ulint flag) /*!< in: ROW_BUILD_NORMAL, |
325 | ROW_BUILD_FOR_PURGE or ROW_BUILD_FOR_UNDO */ |
326 | MY_ATTRIBUTE((nonnull(1,2), warn_unused_result)); |
327 | #ifdef UNIV_DEBUG |
328 | # define row_upd_changes_ord_field_binary(index,update,thr,row,ext) \ |
329 | row_upd_changes_ord_field_binary_func(index,update,thr,row,ext,0) |
330 | #else /* UNIV_DEBUG */ |
331 | # define row_upd_changes_ord_field_binary(index,update,thr,row,ext) \ |
332 | row_upd_changes_ord_field_binary_func(index,update,row,ext,0) |
333 | #endif /* UNIV_DEBUG */ |
334 | /***********************************************************//** |
335 | Checks if an FTS indexed column is affected by an UPDATE. |
336 | @return offset within fts_t::indexes if FTS indexed column updated else |
337 | ULINT_UNDEFINED */ |
338 | ulint |
339 | row_upd_changes_fts_column( |
340 | /*=======================*/ |
341 | dict_table_t* table, /*!< in: table */ |
342 | upd_field_t* upd_field); /*!< in: field to check */ |
343 | /***********************************************************//** |
344 | Checks if an FTS Doc ID column is affected by an UPDATE. |
345 | @return whether Doc ID column is affected */ |
346 | bool |
347 | row_upd_changes_doc_id( |
348 | /*===================*/ |
349 | dict_table_t* table, /*!< in: table */ |
350 | upd_field_t* upd_field) /*!< in: field to check */ |
351 | MY_ATTRIBUTE((nonnull, warn_unused_result)); |
352 | /***********************************************************//** |
353 | Checks if an update vector changes an ordering field of an index record. |
354 | This function is fast if the update vector is short or the number of ordering |
355 | fields in the index is small. Otherwise, this can be quadratic. |
356 | NOTE: we compare the fields as binary strings! |
357 | @return TRUE if update vector may change an ordering field in an index |
358 | record */ |
359 | ibool |
360 | row_upd_changes_some_index_ord_field_binary( |
361 | /*========================================*/ |
362 | const dict_table_t* table, /*!< in: table */ |
363 | const upd_t* update);/*!< in: update vector for the row */ |
364 | /** Stores to the heap the row on which the node->pcur is positioned. |
365 | @param[in] node row update node |
366 | @param[in] thd mysql thread handle |
367 | @param[in,out] mysql_table NULL, or mysql table object when |
368 | user thread invokes dml */ |
369 | void |
370 | row_upd_store_row( |
371 | upd_node_t* node, |
372 | THD* thd, |
373 | TABLE* mysql_table); |
374 | /***********************************************************//** |
375 | Updates a row in a table. This is a high-level function used |
376 | in SQL execution graphs. |
377 | @return query thread to run next or NULL */ |
378 | que_thr_t* |
379 | row_upd_step( |
380 | /*=========*/ |
381 | que_thr_t* thr); /*!< in: query thread */ |
382 | /*********************************************************************//** |
383 | Parses the log data of system field values. |
384 | @return log data end or NULL */ |
385 | byte* |
386 | row_upd_parse_sys_vals( |
387 | /*===================*/ |
388 | const byte* ptr, /*!< in: buffer */ |
389 | const byte* end_ptr,/*!< in: buffer end */ |
390 | ulint* pos, /*!< out: TRX_ID position in record */ |
391 | trx_id_t* trx_id, /*!< out: trx id */ |
392 | roll_ptr_t* roll_ptr);/*!< out: roll ptr */ |
393 | /*********************************************************************//** |
394 | Updates the trx id and roll ptr field in a clustered index record in database |
395 | recovery. */ |
396 | void |
397 | row_upd_rec_sys_fields_in_recovery( |
398 | /*===============================*/ |
399 | rec_t* rec, /*!< in/out: record */ |
400 | page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ |
401 | const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ |
402 | ulint pos, /*!< in: TRX_ID position in rec */ |
403 | trx_id_t trx_id, /*!< in: transaction id */ |
404 | roll_ptr_t roll_ptr);/*!< in: roll ptr of the undo log record */ |
405 | /*********************************************************************//** |
406 | Parses the log data written by row_upd_index_write_log. |
407 | @return log data end or NULL */ |
408 | byte* |
409 | row_upd_index_parse( |
410 | /*================*/ |
411 | const byte* ptr, /*!< in: buffer */ |
412 | const byte* end_ptr,/*!< in: buffer end */ |
413 | mem_heap_t* heap, /*!< in: memory heap where update vector is |
414 | built */ |
415 | upd_t** update_out);/*!< out: update vector */ |
416 | |
417 | |
418 | /* Update vector field */ |
419 | struct upd_field_t{ |
420 | unsigned field_no:16; /*!< field number in an index, usually |
421 | the clustered index, but in updating |
422 | a secondary index record in btr0cur.cc |
423 | this is the position in the secondary |
424 | index. If this field is a virtual |
425 | column, then field_no represents |
426 | the nth virtual column in the table */ |
427 | unsigned orig_len:16; /*!< original length of the locally |
428 | stored part of an externally stored |
429 | column, or 0 */ |
430 | que_node_t* exp; /*!< expression for calculating a new |
431 | value: it refers to column values and |
432 | constants in the symbol table of the |
433 | query graph */ |
434 | dfield_t new_val; /*!< new value for the column */ |
435 | dfield_t* old_v_val; /*!< old value for the virtual column */ |
436 | }; |
437 | |
438 | |
439 | /* check whether an update field is on virtual column */ |
440 | #define upd_fld_is_virtual_col(upd_fld) \ |
441 | (((upd_fld)->new_val.type.prtype & DATA_VIRTUAL) == DATA_VIRTUAL) |
442 | |
443 | /* set DATA_VIRTUAL bit on update field to show it is a virtual column */ |
444 | #define upd_fld_set_virtual_col(upd_fld) \ |
445 | ((upd_fld)->new_val.type.prtype |= DATA_VIRTUAL) |
446 | |
447 | /* Update vector structure */ |
448 | struct upd_t{ |
449 | mem_heap_t* heap; /*!< heap from which memory allocated */ |
450 | ulint info_bits; /*!< new value of info bits to record; |
451 | default is 0 */ |
452 | dtuple_t* old_vrow; /*!< pointer to old row, used for |
453 | virtual column update now */ |
454 | ulint n_fields; /*!< number of update fields */ |
455 | upd_field_t* fields; /*!< array of update fields */ |
456 | byte vers_sys_value[8]; /*!< buffer for updating system fields */ |
457 | |
458 | /** Append an update field to the end of array |
459 | @param[in] field an update field */ |
460 | void append(const upd_field_t& field) |
461 | { |
462 | fields[n_fields++] = field; |
463 | } |
464 | |
465 | /** Determine if the given field_no is modified. |
466 | @return true if modified, false otherwise. */ |
467 | bool is_modified(const ulint field_no) const |
468 | { |
469 | for (ulint i = 0; i < n_fields; ++i) { |
470 | if (field_no == fields[i].field_no) { |
471 | return(true); |
472 | } |
473 | } |
474 | return(false); |
475 | } |
476 | |
477 | /** Determine if the update affects a system versioned column or row_end. */ |
478 | bool affects_versioned() const |
479 | { |
480 | for (ulint i = 0; i < n_fields; i++) { |
481 | dtype_t type = fields[i].new_val.type; |
482 | if (type.is_versioned()) { |
483 | return true; |
484 | } |
485 | // versioned DELETE is UPDATE SET row_end=NOW |
486 | if (type.vers_sys_end()) { |
487 | return true; |
488 | } |
489 | } |
490 | return false; |
491 | } |
492 | |
493 | #ifdef UNIV_DEBUG |
494 | bool validate() const |
495 | { |
496 | for (ulint i = 0; i < n_fields; ++i) { |
497 | dfield_t* field = &fields[i].new_val; |
498 | if (dfield_is_ext(field)) { |
499 | ut_ad(dfield_get_len(field) |
500 | >= BTR_EXTERN_FIELD_REF_SIZE); |
501 | } |
502 | } |
503 | return(true); |
504 | } |
505 | #endif // UNIV_DEBUG |
506 | |
507 | }; |
508 | |
509 | /** Kinds of update operation */ |
510 | enum delete_mode_t { |
511 | NO_DELETE = 0, /*!< this operation does not delete */ |
512 | PLAIN_DELETE, /*!< ordinary delete */ |
513 | VERSIONED_DELETE /*!< update old and insert a new row */ |
514 | }; |
515 | |
516 | /* Update node structure which also implements the delete operation |
517 | of a row */ |
518 | |
519 | struct upd_node_t{ |
520 | que_common_t common; /*!< node type: QUE_NODE_UPDATE */ |
521 | delete_mode_t is_delete; /*!< kind of DELETE */ |
522 | ibool searched_update; |
523 | /* TRUE if searched update, FALSE if |
524 | positioned */ |
525 | bool in_mysql_interface; |
526 | /* whether the update node was created |
527 | for the MySQL interface */ |
528 | dict_foreign_t* foreign;/* NULL or pointer to a foreign key |
529 | constraint if this update node is used in |
530 | doing an ON DELETE or ON UPDATE operation */ |
531 | upd_node_t* cascade_node;/* NULL or an update node template which |
532 | is used to implement ON DELETE/UPDATE CASCADE |
533 | or ... SET NULL for foreign keys */ |
534 | mem_heap_t* cascade_heap; |
535 | /*!< NULL or a mem heap where cascade |
536 | node is created.*/ |
537 | sel_node_t* select; /*!< query graph subtree implementing a base |
538 | table cursor: the rows returned will be |
539 | updated */ |
540 | btr_pcur_t* pcur; /*!< persistent cursor placed on the clustered |
541 | index record which should be updated or |
542 | deleted; the cursor is stored in the graph |
543 | of 'select' field above, except in the case |
544 | of the MySQL interface */ |
545 | dict_table_t* table; /*!< table where updated */ |
546 | upd_t* update; /*!< update vector for the row */ |
547 | ulint update_n_fields; |
548 | /* when this struct is used to implement |
549 | a cascade operation for foreign keys, we store |
550 | here the size of the buffer allocated for use |
551 | as the update vector */ |
552 | sym_node_list_t columns;/* symbol table nodes for the columns |
553 | to retrieve from the table */ |
554 | ibool has_clust_rec_x_lock; |
555 | /* TRUE if the select which retrieves the |
556 | records to update already sets an x-lock on |
557 | the clustered record; note that it must always |
558 | set at least an s-lock */ |
559 | ulint cmpl_info;/* information extracted during query |
560 | compilation; speeds up execution: |
561 | UPD_NODE_NO_ORD_CHANGE and |
562 | UPD_NODE_NO_SIZE_CHANGE, ORed */ |
563 | /*----------------------*/ |
564 | /* Local storage for this graph node */ |
565 | ulint state; /*!< node execution state */ |
566 | dict_index_t* index; /*!< NULL, or the next index whose record should |
567 | be updated */ |
568 | dtuple_t* row; /*!< NULL, or a copy (also fields copied to |
569 | heap) of the row to update; this must be reset |
570 | to NULL after a successful update */ |
571 | dtuple_t* historical_row; /*!< historical row used in |
572 | CASCADE UPDATE/SET NULL; |
573 | allocated from historical_heap */ |
574 | mem_heap_t* historical_heap; /*!< heap for historical row insertion; |
575 | created when row to update is located; |
576 | freed right before row update */ |
577 | row_ext_t* ext; /*!< NULL, or prefixes of the externally |
578 | stored columns in the old row */ |
579 | dtuple_t* upd_row;/* NULL, or a copy of the updated row */ |
580 | row_ext_t* upd_ext;/* NULL, or prefixes of the externally |
581 | stored columns in upd_row */ |
582 | mem_heap_t* heap; /*!< memory heap used as auxiliary storage; |
583 | this must be emptied after a successful |
584 | update */ |
585 | /*----------------------*/ |
586 | sym_node_t* table_sym;/* table node in symbol table */ |
587 | que_node_t* col_assign_list; |
588 | /* column assignment list */ |
589 | ulint magic_n; |
590 | |
591 | /** Also set row_start = CURRENT_TIMESTAMP/trx->id |
592 | @param[in] trx transaction */ |
593 | void make_versioned_update(const trx_t* trx); |
594 | /** Only set row_end = CURRENT_TIMESTAMP/trx->id. |
595 | Do not touch other fields at all. |
596 | @param[in] trx transaction */ |
597 | void make_versioned_delete(const trx_t* trx); |
598 | |
599 | private: |
600 | /** Appends row_start or row_end field to update vector and sets a |
601 | CURRENT_TIMESTAMP/trx->id value to it. |
602 | Supposed to be called only by make_versioned_update() and |
603 | make_versioned_delete(). |
604 | @param[in] trx transaction |
605 | @param[in] vers_sys_idx table->row_start or table->row_end */ |
606 | void make_versioned_helper(const trx_t* trx, ulint idx); |
607 | }; |
608 | |
609 | #define UPD_NODE_MAGIC_N 1579975 |
610 | |
611 | /* Node execution states */ |
612 | #define UPD_NODE_SET_IX_LOCK 1 /* execution came to the node from |
613 | a node above and if the field |
614 | has_clust_rec_x_lock is FALSE, we |
615 | should set an intention x-lock on |
616 | the table */ |
617 | #define UPD_NODE_UPDATE_CLUSTERED 2 /* clustered index record should be |
618 | updated */ |
619 | #define UPD_NODE_INSERT_CLUSTERED 3 /* clustered index record should be |
620 | inserted, old record is already delete |
621 | marked */ |
622 | #define UPD_NODE_UPDATE_ALL_SEC 5 /* an ordering field of the clustered |
623 | index record was changed, or this is |
624 | a delete operation: should update |
625 | all the secondary index records */ |
626 | #define UPD_NODE_UPDATE_SOME_SEC 6 /* secondary index entries should be |
627 | looked at and updated if an ordering |
628 | field changed */ |
629 | |
630 | /* Compilation info flags: these must fit within 3 bits; see trx0rec.h */ |
631 | #define UPD_NODE_NO_ORD_CHANGE 1 /* no secondary index record will be |
632 | changed in the update and no ordering |
633 | field of the clustered index */ |
634 | #define UPD_NODE_NO_SIZE_CHANGE 2 /* no record field size will be |
635 | changed in the update */ |
636 | |
637 | |
638 | #include "row0upd.ic" |
639 | |
640 | #endif |
641 | |