1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2020, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License, version 2.0, as published by the
7 Free Software Foundation.
8 
9 This program is also distributed with certain software (including but not
10 limited to OpenSSL) that is licensed under separate terms, as designated in a
11 particular file or component or in included license documentation. The authors
12 of MySQL hereby grant you an additional permission to link the program and
13 your derivative works with the separately licensed software that they have
14 included with MySQL.
15 
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19 for more details.
20 
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
24 
25 *****************************************************************************/
26 
27 /** @file include/row0upd.h
28  Update of a row
29 
30  Created 12/27/1996 Heikki Tuuri
31  *******************************************************/
32 
33 #ifndef row0upd_h
34 #define row0upd_h
35 
36 #include <stack>
37 #include "btr0types.h"
38 #include "data0data.h"
39 #include "dict0types.h"
40 #include "lob0lob.h"
41 #include "row0types.h"
42 #include "table.h"
43 #include "trx0types.h"
44 #include "univ.i"
45 
46 #include "btr0pcur.h"
47 #ifndef UNIV_HOTBACKUP
48 #include "pars0types.h"
49 #include "que0types.h"
50 #endif /* !UNIV_HOTBACKUP */
51 
52 /** Creates an update vector object.
53 @param[in]	n	number of fields
54 @param[in]	heap	heap from which memory allocated
55 @return own: update vector object */
56 UNIV_INLINE
57 upd_t *upd_create(ulint n, mem_heap_t *heap);
58 
59 /** Returns the number of fields in the update vector == number of columns
60  to be updated by an update vector.
61  @return number of fields */
62 UNIV_INLINE
63 ulint upd_get_n_fields(const upd_t *update); /*!< in: update vector */
64 
65 #ifdef UNIV_DEBUG
66 /** Returns the nth field of an update vector.
67 @param[in]	update	update vector
68 @param[in]	n	field position in update vector
69 @return update vector field */
70 UNIV_INLINE
71 upd_field_t *upd_get_nth_field(const upd_t *update, ulint n);
72 #else
73 #define upd_get_nth_field(update, n) ((update)->fields + (n))
74 #endif
75 /** Sets an index field number to be updated by an update vector field.
76 @param[in]	upd_field	update vector field
77 @param[in]	field_no	field number in a clustered index
78 @param[in]	index		index
79 @param[in]	trx		transaction */
80 UNIV_INLINE
81 void upd_field_set_field_no(upd_field_t *upd_field, ulint field_no,
82                             const dict_index_t *index, trx_t *trx);
83 
84 /** set field number to a update vector field, marks this field is updated
85 @param[in,out]	upd_field	update vector field
86 @param[in]	field_no	virtual column sequence num
87 @param[in]	index		index */
88 UNIV_INLINE
89 void upd_field_set_v_field_no(upd_field_t *upd_field, ulint field_no,
90                               const dict_index_t *index);
91 /** Returns a field of an update vector by field_no.
92  @return update vector field, or NULL */
93 UNIV_INLINE
94 const upd_field_t *upd_get_field_by_field_no(
95     const upd_t *update, /*!< in: update vector */
96     ulint no,            /*!< in: field_no */
97     bool is_virtual)     /*!< in: if it is a virtual column */
98     MY_ATTRIBUTE((warn_unused_result));
99 /** Writes into the redo log the values of trx id and roll ptr and enough info
100  to determine their positions within a clustered index record.
101  @return new pointer to mlog */
102 byte *row_upd_write_sys_vals_to_log(
103     dict_index_t *index, /*!< in: clustered index */
104     trx_id_t trx_id,     /*!< in: transaction id */
105     roll_ptr_t roll_ptr, /*!< in: roll ptr of the undo log record */
106     byte *log_ptr,       /*!< pointer to a buffer of size > 20 opened
107                          in mlog */
108     mtr_t *mtr);         /*!< in: mtr */
109 
110 /** Updates the trx id and roll ptr field in a clustered index record when a
111 row is updated or marked deleted.
112 @param[in,out]	rec		record
113 @param[in,out]	page_zip	compressed page whose uncompressed part will
114                                 be updated, or NULL
115 @param[in]	index		clustered index
116 @param[in]	offsets		rec_get_offsets(rec, index)
117 @param[in]	trx		transaction
118 @param[in]	roll_ptr	roll ptr of the undo log record, can be 0
119                                 during IMPORT */
120 UNIV_INLINE
121 void row_upd_rec_sys_fields(rec_t *rec, page_zip_des_t *page_zip,
122                             const dict_index_t *index, const ulint *offsets,
123                             const trx_t *trx, roll_ptr_t roll_ptr);
124 
125 /** Sets the trx id or roll ptr field of a clustered index entry. */
126 void row_upd_index_entry_sys_field(
127     dtuple_t *entry,     /*!< in/out: index entry, where the memory
128                          buffers for sys fields are already allocated:
129                          the function just copies the new values to
130                          them */
131     dict_index_t *index, /*!< in: clustered index */
132     ulint type,          /*!< in: DATA_TRX_ID or DATA_ROLL_PTR */
133     ib_uint64_t val);    /*!< in: value to write */
134 /** Creates an update node for a query graph.
135  @return own: update node */
136 upd_node_t *upd_node_create(
137     mem_heap_t *heap); /*!< in: mem heap where created */
138 
139 /** Writes to the redo log the new values of the fields occurring in the index.
140 @param[in]	index	index which to be updated
141 @param[in]	update	update vector
142 @param[in]	log_ptr	pointer to mlog buffer: must contain at least
143                         MLOG_BUF_MARGIN bytes of free space; the buffer
144                         is closed within this function
145 @param[in]	mtr	mtr into whose log to write */
146 void row_upd_index_write_log(dict_index_t *index, const upd_t *update,
147                              byte *log_ptr, mtr_t *mtr);
148 
149 /** Returns TRUE if row update changes size of some field in index or if some
150  field to be updated is stored externally in rec or update.
151  @return true if the update changes the size of some field in index or
152  the field is external in rec or update */
153 ibool row_upd_changes_field_size_or_external(
154     const dict_index_t *index, /*!< in: index */
155     const ulint *offsets,      /*!< in: rec_get_offsets(rec, index) */
156     const upd_t *update);      /*!< in: update vector */
157 /** Returns true if row update contains disowned external fields.
158  @return true if the update contains disowned external fields. */
159 bool row_upd_changes_disowned_external(
160     const upd_t *update) /*!< in: update vector */
161     MY_ATTRIBUTE((warn_unused_result));
162 /** Replaces the new column values stored in the update vector to the
163  record given. No field size changes are allowed. This function is
164  usually invoked on a clustered index. The only use case for a
165  secondary index is row_ins_sec_index_entry_by_modify() or its
166  counterpart in ibuf_insert_to_index_page(). */
167 void row_upd_rec_in_place(
168     rec_t *rec,                /*!< in/out: record where replaced */
169     const dict_index_t *index, /*!< in: the index the record belongs to */
170     const ulint *offsets,      /*!< in: array returned by rec_get_offsets() */
171     const upd_t *update,       /*!< in: update vector */
172     page_zip_des_t *page_zip); /*!< in: compressed page with enough space
173                              available, or NULL */
174 /** Builds an update vector from those fields which in a secondary index entry
175  differ from a record that has the equal ordering fields. NOTE: we compare
176  the fields as binary strings!
177  @return own: update vector of differing fields */
178 upd_t *row_upd_build_sec_rec_difference_binary(
179     const rec_t *rec,      /*!< in: secondary index record */
180     dict_index_t *index,   /*!< in: index */
181     const ulint *offsets,  /*!< in: rec_get_offsets(rec, index) */
182     const dtuple_t *entry, /*!< in: entry to insert */
183     mem_heap_t *heap)      /*!< in: memory heap from which allocated */
184     MY_ATTRIBUTE((warn_unused_result));
185 /** Builds an update vector from those fields, excluding the roll ptr and
186 trx id fields, which in an index entry differ from a record that has
187 the equal ordering fields. NOTE: we compare the fields as binary strings!
188 @param[in]	index		clustered index
189 @param[in]	entry		clustered index entry to insert
190 @param[in]	rec		clustered index record
191 @param[in]	offsets		rec_get_offsets(rec,index), or NULL
192 @param[in]	no_sys		skip the system columns
193                                 DB_TRX_ID and DB_ROLL_PTR
194 @param[in]	trx		transaction (for diagnostics),
195                                 or NULL
196 @param[in]	heap		memory heap from which allocated
197 @param[in]	mysql_table	NULL, or mysql table object when
198                                 user thread invokes dml
199 @param[out]	error		error number in case of failure
200 @return own: update vector of differing fields, excluding roll ptr and
201 trx id */
202 upd_t *row_upd_build_difference_binary(dict_index_t *index,
203                                        const dtuple_t *entry, const rec_t *rec,
204                                        const ulint *offsets, bool no_sys,
205                                        trx_t *trx, mem_heap_t *heap,
206                                        TABLE *mysql_table, dberr_t *error)
207     MY_ATTRIBUTE((warn_unused_result));
208 /** Replaces the new column values stored in the update vector to the index
209  entry given. */
210 void row_upd_index_replace_new_col_vals_index_pos(
211     dtuple_t *entry,           /*!< in/out: index entry where replaced;
212                                the clustered index record must be
213                                covered by a lock or a page latch to
214                                prevent deletion (rollback or purge) */
215     const dict_index_t *index, /*!< in: index; NOTE that this may also be a
216                          non-clustered index */
217     const upd_t *update,       /*!< in: an update vector built for the index so
218                                that the field number in an upd_field is the
219                                index position */
220     ibool order_only,
221     /*!< in: if TRUE, limit the replacement to
222     ordering fields of index; note that this
223     does not work for non-clustered indexes. */
224     mem_heap_t *heap); /*!< in: memory heap for allocating and
225                        copying the new values */
226 /** Replaces the new column values stored in the update vector to the index
227  entry given. */
228 void row_upd_index_replace_new_col_vals(
229     dtuple_t *entry,           /*!< in/out: index entry where replaced;
230                                the clustered index record must be
231                                covered by a lock or a page latch to
232                                prevent deletion (rollback or purge) */
233     const dict_index_t *index, /*!< in: index; NOTE that this may also be a
234                          non-clustered index */
235     const upd_t *update,       /*!< in: an update vector built for the
236                                CLUSTERED index so that the field number in
237                                an upd_field is the clustered index position */
238     mem_heap_t *heap);         /*!< in: memory heap for allocating and
239                                copying the new values */
240 /** Replaces the new column values stored in the update vector. */
241 void row_upd_replace(trx_t *trx,      /*!< in: current transaction. */
242                      dtuple_t *row,   /*!< in/out: row where replaced,
243                                       indexed by col_no;
244                                       the clustered index record must be
245                                       covered by a lock or a page latch to
246                                       prevent deletion (rollback or purge) */
247                      row_ext_t **ext, /*!< out, own: NULL, or externally
248                                       stored column prefixes */
249                      const dict_index_t *index, /*!< in: clustered index */
250                      const upd_t *update, /*!< in: an update vector built for
251                                           the clustered index */
252                      mem_heap_t *heap);   /*!< in: memory heap */
253 /** Replaces the virtual column values stored in a dtuple with that of
254 a update vector.
255 @param[in,out]	row	dtuple whose column to be updated
256 @param[in]	table	table
257 @param[in]	update	an update vector built for the clustered index
258 @param[in]	upd_new	update to new or old value
259 @param[in,out]	undo_row undo row (if needs to be updated)
260 @param[in]	ptr	remaining part in update undo log */
261 void row_upd_replace_vcol(dtuple_t *row, const dict_table_t *table,
262                           const upd_t *update, bool upd_new, dtuple_t *undo_row,
263                           const byte *ptr);
264 
265 /** Checks if an update vector changes an ordering field of an index record.
266 It will also help check if any non-multi-value field on the multi-value index
267 gets updated or not.
268 
269 This function is fast if the update vector is short or the number of ordering
270 fields in the index is small. Otherwise, this can be quadratic.
271 NOTE: we compare the fields as binary strings!
272 @param[in]	index		index of the record
273 @param[in]	update		update vector for the row; NOTE: the
274                                 field numbers in this MUST be clustered index
275                                 positions! */
276 #ifdef UNIV_DEBUG
277 /**
278 @param[in]	thr		query thread, or NULL */
279 #endif /* UNIV_DEBUG */
280 /**
281 @param[in]	row		old value of row, or NULL if the
282                                 row and the data values in update are not
283                                 known when this function is called, e.g., at
284                                 compile time
285 @param[in]	ext		NULL, or prefixes of the externally
286                                 stored columns in the old row
287 @param[in,out]	non_mv_upd	NULL, or not NULL pointer to get the
288                                 information about whether any non-multi-value
289                                 field on the multi-value index gets updated
290 @param[in]	flag		ROW_BUILD_NORMAL, ROW_BUILD_FOR_PURGE or
291                                 ROW_BUILD_FOR_UNDO
292 @return true if update vector changes an ordering field in the index record */
293 bool row_upd_changes_ord_field_binary_func(dict_index_t *index,
294                                            const upd_t *update,
295 #ifdef UNIV_DEBUG
296                                            const que_thr_t *thr,
297 #endif /* UNIV_DEBUG */
298                                            const dtuple_t *row,
299                                            const row_ext_t *ext,
300                                            bool *non_mv_upd, ulint flag)
301     MY_ATTRIBUTE((warn_unused_result));
302 
303 #ifdef UNIV_DEBUG
304 #define row_upd_changes_ord_field_binary(index, update, thr, row, ext, \
305                                          non_mv_upd)                   \
306   row_upd_changes_ord_field_binary_func(index, update, thr, row, ext,  \
307                                         non_mv_upd, 0)
308 #else /* UNIV_DEBUG */
309 #define row_upd_changes_ord_field_binary(index, update, thr, row, ext, \
310                                          non_mv_upd)                   \
311   row_upd_changes_ord_field_binary_func(index, update, row, ext, non_mv_upd, 0)
312 #endif /* UNIV_DEBUG */
313 
314 /** Checks if an FTS indexed column is affected by an UPDATE.
315  @return offset within fts_t::indexes if FTS indexed column updated else
316  ULINT_UNDEFINED */
317 ulint row_upd_changes_fts_column(
318     dict_table_t *table,     /*!< in: table */
319     upd_field_t *upd_field); /*!< in: field to check */
320 /** Checks if an FTS Doc ID column is affected by an UPDATE.
321  @return whether Doc ID column is affected */
322 bool row_upd_changes_doc_id(dict_table_t *table,    /*!< in: table */
323                             upd_field_t *upd_field) /*!< in: field to check */
324     MY_ATTRIBUTE((warn_unused_result));
325 /** Checks if an update vector changes an ordering field of an index record.
326  This function is fast if the update vector is short or the number of ordering
327  fields in the index is small. Otherwise, this can be quadratic.
328  NOTE: we compare the fields as binary strings!
329  @return true if update vector may change an ordering field in an index
330  record */
331 ibool row_upd_changes_some_index_ord_field_binary(
332     const dict_table_t *table, /*!< in: table */
333     const upd_t *update);      /*!< in: update vector for the row */
334 /** Stores to the heap the row on which the node->pcur is positioned.
335 @param[in]	node		row update node
336 @param[in]	thd		mysql thread handle
337 @param[in,out]	mysql_table	NULL, or mysql table object when
338                                 user thread invokes dml */
339 void row_upd_store_row(trx_t *trx, upd_node_t *node, THD *thd,
340                        TABLE *mysql_table);
341 /** Updates a row in a table. This is a high-level function used
342  in SQL execution graphs.
343  @return query thread to run next or NULL */
344 que_thr_t *row_upd_step(que_thr_t *thr); /*!< in: query thread */
345 /** Parses the log data of system field values.
346  @return log data end or NULL */
347 byte *row_upd_parse_sys_vals(const byte *ptr,     /*!< in: buffer */
348                              const byte *end_ptr, /*!< in: buffer end */
349                              ulint *pos, /*!< out: TRX_ID position in record */
350                              trx_id_t *trx_id,      /*!< out: trx id */
351                              roll_ptr_t *roll_ptr); /*!< out: roll ptr */
352 /** Updates the trx id and roll ptr field in a clustered index record in
353  database recovery. */
354 void row_upd_rec_sys_fields_in_recovery(
355     rec_t *rec,               /*!< in/out: record */
356     page_zip_des_t *page_zip, /*!< in/out: compressed page, or NULL */
357     const ulint *offsets,     /*!< in: array returned by rec_get_offsets() */
358     ulint pos,                /*!< in: TRX_ID position in rec */
359     trx_id_t trx_id,          /*!< in: transaction id */
360     roll_ptr_t roll_ptr);     /*!< in: roll ptr of the undo log record */
361 /** Parses the log data written by row_upd_index_write_log.
362  @return log data end or NULL */
363 byte *row_upd_index_parse(const byte *ptr,     /*!< in: buffer */
364                           const byte *end_ptr, /*!< in: buffer end */
365                           mem_heap_t *heap,    /*!< in: memory heap where update
366                                                vector is    built */
367                           upd_t **update_out); /*!< out: update vector */
368 
369 /** Get the new autoinc counter from the update vector when there is
370 an autoinc field defined in this table.
371 @param[in]	update			update vector for the clustered index
372 @param[in]	autoinc_field_no	autoinc field's order in clustered index
373 @return the new counter if we find it in the update vector, otherwise 0 */
374 ib_uint64_t row_upd_get_new_autoinc_counter(const upd_t *update,
375                                             ulint autoinc_field_no);
376 
377 /** This structure is used for undo logging of LOB index changes. */
378 struct lob_index_diff_t {
379   trx_id_t m_modifier_trxid;
380   undo_no_t m_modifier_undo_no;
381 
382   /** Print the current object into the given output stream.
383   @param[in,out]	out	the output stream.
384   @return the output stream. */
printlob_index_diff_t385   std::ostream &print(std::ostream &out) const {
386     out << "[lob_index_diff_t: m_modifier_trxid=" << m_modifier_trxid
387         << ", m_modifier_undo_no=" << m_modifier_undo_no << "]";
388     return (out);
389   }
390 };
391 
392 using Lob_index_diff_vec =
393     std::vector<lob_index_diff_t, mem_heap_allocator<lob_index_diff_t>>;
394 
395 /** Overloading the global output operator to print lob_index_diff_t object.
396 @param[in,out]	out	the output stream.
397 @param[in]	obj	the object to be printed.
398 @return the output stream.*/
399 inline std::ostream &operator<<(std::ostream &out,
400                                 const lob_index_diff_t &obj) {
401   return (obj.print(out));
402 }
403 
404 /** The modification done to the LOB. */
405 struct Lob_diff {
406   /** Constructor.
407   @param[in]  mem_heap  the memory heap in which this object
408                         has been created. */
Lob_diffLob_diff409   Lob_diff(mem_heap_t *mem_heap) : heap(mem_heap) {
410     m_idx_diffs = static_cast<Lob_index_diff_vec *>(
411         mem_heap_alloc(heap, sizeof(Lob_index_diff_vec)));
412     new (m_idx_diffs)
413         Lob_index_diff_vec(mem_heap_allocator<lob_index_diff_t>(heap));
414   }
415 
416   /** Read the offset from the undo record.
417   @param[in]   undo_ptr   pointer into the undo log record.
418   @return pointer into the undo log record after offset. */
read_offsetLob_diff419   const byte *read_offset(const byte *undo_ptr) {
420     /* Read the offset. */
421     m_offset = mach_read_next_compressed(&undo_ptr);
422     return (undo_ptr);
423   }
424 
425   /** Read the length from the undo record.
426   @param[in]   undo_ptr   pointer into the undo log record.
427   @return pointer into the undo log record after length information. */
read_lengthLob_diff428   const byte *read_length(const byte *undo_ptr) {
429     /* Read the length. */
430     m_length = mach_read_next_compressed(&undo_ptr);
431     ut_ad(m_length <= lob::ref_t::LOB_SMALL_CHANGE_THRESHOLD);
432 
433     return (undo_ptr);
434   }
435 
set_old_dataLob_diff436   void set_old_data(const byte *undo_ptr) { m_old_data = undo_ptr; }
437 
printLob_diff438   std::ostream &print(std::ostream &out) const {
439     out << "[Lob_diff: offset=" << m_offset << ", length=" << m_length;
440     if (m_old_data == nullptr) {
441       out << ", m_old_data=nullptr";
442     } else {
443       out << ", m_old_data=" << PrintBuffer(m_old_data, m_length);
444     }
445 
446     if (m_idx_diffs != nullptr) {
447       for (auto iter = m_idx_diffs->begin(); iter != m_idx_diffs->end();
448            ++iter) {
449         out << *iter;
450       }
451     }
452 
453     out << "]";
454     return (out);
455   }
456 
457   /** The offset within LOB where partial update happened. */
458   ulint m_offset = 0;
459 
460   /** The length of the modification. */
461   ulint m_length = 0;
462 
463   /** Changes to the LOB data. */
464   const byte *m_old_data = nullptr;
465 
466   /** Changes to the LOB index. */
467   Lob_index_diff_vec *m_idx_diffs;
468 
469   /** Memory heap in which this object is allocated. */
470   mem_heap_t *heap;
471 };
472 
473 using Lob_diff_vector = std::vector<Lob_diff, mem_heap_allocator<Lob_diff>>;
474 
475 inline std::ostream &operator<<(std::ostream &out, const Lob_diff &obj) {
476   return (obj.print(out));
477 }
478 
479 /* Update vector field */
480 struct upd_field_t {
upd_field_tupd_field_t481   upd_field_t()
482       : field_no(0),
483         orig_len(0),
484         exp(nullptr),
485         old_v_val(nullptr),
486         mysql_field(nullptr),
487         ext_in_old(false),
488         lob_diffs(nullptr),
489         lob_first_page_no(FIL_NULL),
490         lob_version(0),
491         last_trx_id(0),
492         last_undo_no(0),
493         heap(nullptr) {}
494 
is_virtualupd_field_t495   bool is_virtual() const { return (new_val.is_virtual()); }
496 
497   unsigned field_no : 16; /*!< field number in an index, usually
498                           the clustered index, but in updating
499                           a secondary index record in btr0cur.cc
500                           this is the position in the secondary
501                           index, also it could be the position
502                           in virtual index for virtual column */
503   unsigned orig_len : 16; /*!< original length of the locally
504                           stored part of an externally stored
505                           column, or 0 */
506   que_node_t *exp;        /*!< expression for calculating a new
507                           value: it refers to column values and
508                           constants in the symbol table of the
509                           query graph */
510   dfield_t old_val;       /*!< old value for the column */
511   dfield_t new_val;       /*!< new value for the column */
512   dfield_t *old_v_val;    /*!< old value for the virtual column */
513 
514   Field *mysql_field; /*!< the mysql field object. */
515 
516   /** If true, the field was stored externally in the old row. */
517   bool ext_in_old;
518 
push_lob_diffupd_field_t519   void push_lob_diff(const Lob_diff &lob_diff) {
520     if (lob_diffs == nullptr) {
521       lob_diffs = static_cast<Lob_diff_vector *>(
522           mem_heap_alloc(heap, sizeof(Lob_diff_vector)));
523       new (lob_diffs) Lob_diff_vector(mem_heap_allocator<Lob_diff>(heap));
524     }
525     lob_diffs->push_back(lob_diff);
526   }
527 
528   /** List of changes done to this updated field.  This is usually
529   populated from the undo log. */
530   Lob_diff_vector *lob_diffs;
531 
532   /** The LOB first page number.  This information is read from
533   the undo log. */
534   page_no_t lob_first_page_no;
535 
536   ulint lob_version;
537 
538   /** The last trx that modified the LOB. */
539   trx_id_t last_trx_id;
540 
541   /** The last stmt within trx that modified the LOB. */
542   undo_no_t last_undo_no;
543 
544   std::ostream &print(std::ostream &out) const;
545 
546   /** Empty the information collected on LOB diffs. */
resetupd_field_t547   void reset() {
548     if (lob_diffs != nullptr) {
549       lob_diffs->clear();
550     }
551   }
552 
553   /** Memory heap in which this object is allocated. */
554   mem_heap_t *heap;
555 };
556 
557 inline std::ostream &operator<<(std::ostream &out, const upd_field_t &obj) {
558   return (obj.print(out));
559 }
560 
561 /* check whether an update field is on virtual column */
562 #define upd_fld_is_virtual_col(upd_fld) \
563   (((upd_fld)->new_val.type.prtype & DATA_VIRTUAL) == DATA_VIRTUAL)
564 
565 /* check whether an update field is on multi-value virtual column */
566 #define upd_fld_is_multi_value_col(upd_fld) \
567   (dfield_is_multi_value(&((upd_fld)->new_val)))
568 
569 /* set DATA_VIRTUAL bit on update field to show it is a virtual column */
570 #define upd_fld_set_virtual_col(upd_fld) \
571   ((upd_fld)->new_val.type.prtype |= DATA_VIRTUAL)
572 
573 /* Update vector structure */
574 struct upd_t {
575   mem_heap_t *heap;    /*!< heap from which memory allocated */
576   ulint info_bits;     /*!< new value of info bits to record;
577                        default is 0 */
578   dtuple_t *old_vrow;  /*!< pointer to old row, used for
579                        virtual column update now */
580   dict_table_t *table; /*!< the table object */
581   TABLE *mysql_table;  /*!< the mysql table object */
582 
583   ulint n_fields;      /*!< number of update fields */
584   upd_field_t *fields; /*!< array of update fields */
585 
586   /** Append an update field to the end of array
587   @param[in]	field	an update field */
appendupd_t588   void append(const upd_field_t &field) { fields[n_fields++] = field; }
589 
590   /** Determine if the given field_no is modified.
591   @return true if modified, false otherwise.  */
is_modifiedupd_t592   bool is_modified(const ulint field_no) const {
593     return (get_field_by_field_no(field_no, table->first_index()) != nullptr);
594   }
595 
596   /** Reset the update fields. */
resetupd_t597   void reset() {
598     for (ulint i = 0; i < n_fields; ++i) {
599       fields[i].reset();
600     }
601   }
602 
603 #ifdef UNIV_DEBUG
validateupd_t604   bool validate() const {
605     for (ulint i = 0; i < n_fields; ++i) {
606       dfield_t *field = &fields[i].new_val;
607       if (dfield_is_ext(field)) {
608         ut_ad(dfield_get_len(field) >= BTR_EXTERN_FIELD_REF_SIZE);
609       }
610     }
611     return (true);
612   }
613 #endif  // UNIV_DEBUG
614 
615   /** Check if the given field number is partially updated.
616   @param[in]	field_no	the field number.
617   @return true if partially updated, false otherwise. */
618   bool is_partially_updated(ulint field_no) const;
619 
620   upd_field_t *get_field_by_field_no(ulint field_no, dict_index_t *index) const;
621 
622   const Binary_diff_vector *get_binary_diff_by_field_no(ulint field_no) const;
623 
624   /** Calculate the total number of bytes modified in one BLOB.
625   @param[in]	bdv	the binary diff vector containing all the
626                           modifications to one BLOB.
627   @return the total modified bytes. */
get_total_modified_bytesupd_t628   static size_t get_total_modified_bytes(const Binary_diff_vector &bdv) {
629     size_t total = 0;
630     for (const Binary_diff &bdiff : bdv) {
631       total += bdiff.length();
632     }
633     return (total);
634   }
635 
636   std::ostream &print(std::ostream &out) const;
637 
638   /** Print the partial update vector (puvect) of the given update
639   field.
640   @param[in,out]	out	the output stream
641   @param[in]	uf	the updated field.
642   @return the output stream. */
643   std::ostream &print_puvect(std::ostream &out, upd_field_t *uf) const;
644 };
645 
646 #ifdef UNIV_DEBUG
647 /** Print the given binary diff into the given output stream.
648 @param[in]	out	the output stream
649 @param[in]	bdiff	binary diff to be printed.
650 @param[in]	table	the table dictionary object.
651 @param[in]	field	mysql field object.
652 @return the output stream */
653 std::ostream &print_binary_diff(std::ostream &out, const Binary_diff *bdiff,
654                                 const dict_table_t *table, const Field *field);
655 
656 std::ostream &print_binary_diff(std::ostream &out, const Binary_diff *bdiff);
657 
658 inline std::ostream &operator<<(std::ostream &out, const upd_t &obj) {
659   return (obj.print(out));
660 }
661 
662 inline std::ostream &operator<<(std::ostream &out,
663                                 const Binary_diff_vector &obj) {
664   return (out);
665 }
666 #endif /* UNIV_DEBUG */
667 
668 #ifndef UNIV_HOTBACKUP
669 /* Update node structure which also implements the delete operation
670 of a row */
671 
672 struct upd_node_t {
673   que_common_t common; /*!< node type: QUE_NODE_UPDATE */
674   ibool is_delete;     /* TRUE if delete, FALSE if update */
675   ibool searched_update;
676   /* TRUE if searched update, FALSE if
677   positioned */
678   ibool in_mysql_interface;
679   /* TRUE if the update node was created
680   for the MySQL interface */
681   dict_foreign_t *foreign;  /* NULL or pointer to a foreign key
682                             constraint if this update node is used in
683                             doing an ON DELETE or ON UPDATE operation */
684   upd_node_t *cascade_node; /* NULL or an update node template which
685                        is used to implement ON DELETE/UPDATE CASCADE
686                        or ... SET NULL for foreign keys */
687   mem_heap_t *cascade_heap;
688   /*!< NULL or a mem heap where cascade_upd_nodes
689   are created.*/
690   sel_node_t *select;  /*!< query graph subtree implementing a base
691                        table cursor: the rows returned will be
692                        updated */
693   btr_pcur_t *pcur;    /*!< persistent cursor placed on the clustered
694                        index record which should be updated or
695                        deleted; the cursor is stored in the graph
696                        of 'select' field above, except in the case
697                        of the MySQL interface */
698   dict_table_t *table; /*!< table where updated */
699   upd_t *update;       /*!< update vector for the row */
700   ulint update_n_fields;
701   /* when this struct is used to implement
702   a cascade operation for foreign keys, we store
703   here the size of the buffer allocated for use
704   as the update vector */
705   sym_node_list_t columns; /* symbol table nodes for the columns
706                            to retrieve from the table */
707   ibool has_clust_rec_x_lock;
708   /* TRUE if the select which retrieves the
709   records to update already sets an x-lock on
710   the clustered record; note that it must always
711   set at least an s-lock */
712   ulint cmpl_info; /* information extracted during query
713                  compilation; speeds up execution:
714                  UPD_NODE_NO_ORD_CHANGE and
715                  UPD_NODE_NO_SIZE_CHANGE, ORed */
716   /*----------------------*/
717   /* Local storage for this graph node */
718   ulint state;         /*!< node execution state */
719   dict_index_t *index; /*!< NULL, or the next index whose record should
720                        be updated */
721   dtuple_t *row;       /*!< NULL, or a copy (also fields copied to
722                        heap) of the row to update; this must be reset
723                        to NULL after a successful update */
724   row_ext_t *ext;      /*!< NULL, or prefixes of the externally
725                        stored columns in the old row */
726   dtuple_t *upd_row;   /* NULL, or a copy of the updated row */
727   row_ext_t *upd_ext;  /* NULL, or prefixes of the externally
728                        stored columns in upd_row */
729   mem_heap_t *heap;    /*!< memory heap used as auxiliary storage;
730                        this must be emptied after a successful
731                        update */
732   /*----------------------*/
733   sym_node_t *table_sym; /* table node in symbol table */
734   que_node_t *col_assign_list;
735   /* column assignment list */
736 
737   /** When there is a lock wait error, this remembers current position of
738   the multi-value field, before which the values have been deleted.
739   This will be used for both DELETE and the delete phase of UPDATE. */
740   uint32_t del_multi_val_pos;
741 
742   /** When there is a lock wait error, this remembers current position of
743   the multi-value field, before which the values have been updated. */
744   uint32_t upd_multi_val_pos;
745 
746   ulint magic_n;
747 };
748 
749 #define UPD_NODE_MAGIC_N 1579975
750 
751 /* Node execution states */
752 #define UPD_NODE_SET_IX_LOCK           \
753   1 /* execution came to the node from \
754     a node above and if the field      \
755     has_clust_rec_x_lock is FALSE, we  \
756     should set an intention x-lock on  \
757     the table */
758 #define UPD_NODE_UPDATE_CLUSTERED       \
759   2 /* clustered index record should be \
760     updated */
761 #define UPD_NODE_INSERT_CLUSTERED          \
762   3 /* clustered index record should be    \
763     inserted, old record is already delete \
764     marked */
765 #define UPD_NODE_UPDATE_ALL_SEC           \
766   5 /* an ordering field of the clustered \
767     index record was changed, or this is  \
768     a delete operation: should update     \
769     all the secondary index records */
770 #define UPD_NODE_UPDATE_SOME_SEC         \
771   6 /* secondary index entries should be \
772     looked at and updated if an ordering \
773     field changed */
774 
775 /* Compilation info flags: these must fit within 2 bits; see trx0rec.h */
776 #define UPD_NODE_NO_ORD_CHANGE            \
777   1 /* no secondary index record will be  \
778     changed in the update and no ordering \
779     field of the clustered index */
780 #define UPD_NODE_NO_SIZE_CHANGE        \
781   2    /* no record field size will be \
782        changed in the update */
783 #endif /* !UNIV_HOTBACKUP */
784 
785 #include "row0upd.ic"
786 
787 #endif
788