MySQL 9.4.0
Source Code Documentation
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
row0upd.h
Go to the documentation of this file.
1/*****************************************************************************
2
3Copyright (c) 1996, 2025, Oracle and/or its affiliates.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License, version 2.0, as published by the
7Free Software Foundation.
8
9This program is designed to work with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation. The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have either included with
15the program or referenced in the documentation.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
20for more details.
21
22You should have received a copy of the GNU General Public License along with
23this program; if not, write to the Free Software Foundation, Inc.,
2451 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
26*****************************************************************************/
27
28/** @file include/row0upd.h
29 Update of a row
30
31 Created 12/27/1996 Heikki Tuuri
32 *******************************************************/
33
34#ifndef row0upd_h
35#define row0upd_h
36
37#include <stack>
38#include "btr0types.h"
39#include "data0data.h"
40#include "dict0types.h"
41#include "lob0lob.h"
42#include "row0types.h"
43#include "table.h"
44#include "trx0types.h"
45#include "univ.i"
46
47#include "btr0pcur.h"
48#ifndef UNIV_HOTBACKUP
49#include "pars0types.h"
50#include "que0types.h"
51#endif /* !UNIV_HOTBACKUP */
52
53/** Creates an update vector object.
54@param[in] n number of fields
55@param[in] heap heap from which memory allocated
56@return own: update vector object */
57inline 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 @param[in] update update vector
62 @return number of fields */
63inline ulint upd_get_n_fields(const upd_t *update);
64
65/** Returns the nth field of an update vector.
66@param[in] update update vector
67@param[in] n field position in update vector
68@return update vector field */
70
71/** Returns the nth field of an update vector.
72@param[in] update update vector
73@param[in] n field position in update vector
74@return update vector field */
75inline const upd_field_t *upd_get_nth_field(const upd_t *update, ulint n);
76
77/** Set which index field is updated by an update vector field.
78@param[in] upd_field update vector field
79@param[in] field_no field position in index
80@param[in] index index */
81inline void upd_field_set_field_no(upd_field_t *upd_field, ulint field_no,
82 const dict_index_t *index);
83
84/** Set for which virtual column the value is updated by an update vector
85field.
86@param[in,out] upd_field update vector field
87@param[in] field_no virtual column number in table
88@param[in] index index */
89inline void upd_field_set_v_field_no(upd_field_t *upd_field, ulint field_no,
90 const dict_index_t *index);
91
92/** Returns a field of an update vector by field_no.
93@param[in] update Update vector.
94@param[in] no "Field number" as stored in the update vector:
95 when is_virtual is false the position of the field
96 in the updated index, otherwise the column number
97 of the virtual field in table. @see upd_field::field_no
98@param[in] is_virtual If it is a virtual column.
99@return update vector field, or nullptr. */
100[[nodiscard]] inline const upd_field_t *upd_get_field_by_field_no(
101 const upd_t *update, ulint no, bool is_virtual);
102
103/** Writes into the redo log the values of trx id and roll ptr and enough info
104to determine their positions within a clustered index record.
105@param[in] index Clustered index.
106@param[in] trx_id Transaction ID.
107@param[in] roll_ptr Roll ptr of the undo log record.
108@param[in] log_ptr Pointer to a buffer of size > 20 opened in mlog.
109@param[in] mtr Mini-transaction.
110@return new pointer to mlog */
112 roll_ptr_t roll_ptr, byte *log_ptr,
113 mtr_t *mtr);
114
115#ifndef UNIV_HOTBACKUP
116/** Updates the trx id and roll ptr field in a clustered index record when a
117row is updated or marked deleted.
118@param[in,out] rec record
119@param[in,out] page_zip compressed page whose uncompressed part will
120 be updated, or NULL
121@param[in] index clustered index
122@param[in] offsets rec_get_offsets(rec, index)
123@param[in] trx transaction
124@param[in] roll_ptr roll ptr of the undo log record, can be 0
125 during IMPORT */
126inline void row_upd_rec_sys_fields(rec_t *rec, page_zip_des_t *page_zip,
127 const dict_index_t *index,
128 const ulint *offsets, const trx_t *trx,
129 roll_ptr_t roll_ptr);
130#endif /* !UNIV_HOTBACKUP */
131
132/** Sets the trx id or roll ptr field of a clustered index entry.
133@param[in,out] entry Index entry, where the memory buffers for sys fields are
134already allocated: the function just copies the new values to them
135@param[in] index Clustered index
136@param[in] type Data_trx_id or data_roll_ptr
137@param[in] val Value to write */
139 ulint type, uint64_t val);
140
141/** Creates an update node for a query graph.
142 @return own: update node */
144 mem_heap_t *heap); /*!< in: mem heap where created */
145
146/** Writes to the redo log the new values of the fields occurring in the index.
147@param[in] index index which to be updated
148@param[in] update update vector
149@param[in] log_ptr pointer to mlog buffer: must contain at least
150 MLOG_BUF_MARGIN bytes of free space; the buffer
151 is closed within this function
152@param[in] mtr mtr into whose log to write */
154 byte *log_ptr, mtr_t *mtr);
155
156/** Returns true if row update changes size of some field in index or if some
157 field to be updated is stored externally in rec or update.
158 @return true if the update changes the size of some field in index or
159 the field is external in rec or update */
161 const dict_index_t *index, /*!< in: index */
162 const ulint *offsets, /*!< in: rec_get_offsets(rec, index) */
163 const upd_t *update); /*!< in: update vector */
164/** Returns true if row update contains disowned external fields.
165 @return true if the update contains disowned external fields. */
166[[nodiscard]] bool row_upd_changes_disowned_external(
167 const upd_t *update); /*!< in: update vector */
168/** Replaces the new column values stored in the update vector to the
169 record given. No field size changes are allowed. This function is
170 usually invoked on a clustered index. The only use case for a
171 secondary index is row_ins_sec_index_entry_by_modify() or its
172 counterpart in ibuf_insert_to_index_page(). */
174 rec_t *rec, /*!< in/out: record where replaced */
175 const dict_index_t *index, /*!< in: the index the record belongs to */
176 const ulint *offsets, /*!< in: array returned by rec_get_offsets() */
177 const upd_t *update, /*!< in: update vector */
178 page_zip_des_t *page_zip); /*!< in: compressed page with enough space
179 available, or NULL */
180/** Builds an update vector from those fields which in a secondary index entry
181 differ from a record that has the equal ordering fields. NOTE: we compare
182 the fields as binary strings!
183 @return own: update vector of differing fields */
185 const rec_t *rec, /*!< in: secondary index record */
186 dict_index_t *index, /*!< in: index */
187 const ulint *offsets, /*!< in: rec_get_offsets(rec, index) */
188 const dtuple_t *entry, /*!< in: entry to insert */
189 mem_heap_t *heap); /*!< in: memory heap from which allocated */
190/** Builds an update vector from those fields, excluding the roll ptr and
191trx id fields, which in an index entry differ from a record that has
192the equal ordering fields. NOTE: we compare the fields as binary strings!
193@param[in] index clustered index
194@param[in] entry clustered index entry to insert
195@param[in] rec clustered index record
196@param[in] offsets rec_get_offsets(rec,index), or NULL
197@param[in] no_sys skip the system columns
198 DB_TRX_ID and DB_ROLL_PTR
199@param[in] trx transaction (for diagnostics),
200 or NULL
201@param[in] heap memory heap from which allocated
202@param[in] mysql_table NULL, or mysql table object when
203 user thread invokes dml
204@param[out] error error number in case of failure
205@return own: update vector of differing fields, excluding roll ptr and
206trx id */
208 dict_index_t *index, const dtuple_t *entry, const rec_t *rec,
209 const ulint *offsets, bool no_sys, trx_t *trx, mem_heap_t *heap,
210 TABLE *mysql_table, dberr_t *error);
211
212/** Replaces the new column values stored in the update vector to the index
213 entry given.
214@param[in,out] entry Index entry where replaced; the clustered index record must
215be covered by a lock or a page latch to prevent deletion [rollback or purge]
216@param[in] index Index; note that this may also be a non-clustered index
217@param[in] update An update vector built for the index so that the field number
218in an upd_field is the index position
219@param[in] order_only If true, limit the replacement to ordering fields of
220index; note that this does not work for non-clustered indexes.
221@param[in] heap Memory heap for allocating and copying the new values */
223 const dict_index_t *index,
224 const upd_t *update,
225 bool order_only,
226 mem_heap_t *heap);
227
228/** Replaces the new column values stored in the update vector to the index
229 entry given.
230@param[in,out] entry Index entry where replaced; the clustered index record must
231be covered by a lock or a page latch to prevent deletion (rollback or purge)
232@param[in] index Index; note that this may also be a non-clustered index
233@param[in] update An update vector built for the clustered index so that the
234field number in an upd_field is the clustered index position
235@param[in] heap Memory heap for allocating and copying the new values */
237 const dict_index_t *index,
238 const upd_t *update, mem_heap_t *heap);
239
240/** Replaces the new column values stored in the update vector.
241@param[in,out] row Row where replaced, indexed by col_no; the clustered index
242record must be covered by a lock or a page latch to prevent deletion (rollback
243or purge)
244@param[in,out] ext Null, or externally stored column prefixes
245@param[in] index Clustered index
246@param[in] update An update vector built for the clustered index
247@param[in] heap Memory heap */
249 const upd_t *update, mem_heap_t *heap);
250
251/** Replaces the virtual column values stored in a dtuple with that of
252a update vector.
253@param[in,out] row dtuple whose column to be updated
254@param[in] table table
255@param[in] update an update vector built for the clustered index
256@param[in] upd_new update to new or old value
257@param[in,out] undo_row undo row (if needs to be updated)
258@param[in] ptr remaining part in update undo log */
260 const upd_t *update, bool upd_new, dtuple_t *undo_row,
261 const byte *ptr);
262
263/** Checks if an update vector changes an ordering field of an index record.
264It will also help check if any non-multi-value field on the multi-value index
265gets updated or not.
266
267This function is fast if the update vector is short or the number of ordering
268fields in the index is small. Otherwise, this can be quadratic.
269NOTE: we compare the fields as binary strings!
270@param[in] index index of the record
271@param[in] update update vector for the row; NOTE: the
272 field numbers in this MUST be clustered index
273 positions!
274@param[in] thr query thread, or NULL
275@param[in] row old value of row, or NULL if the
276 row and the data values in update are not
277 known when this function is called, e.g., at
278 compile time
279@param[in] ext NULL, or prefixes of the externally
280 stored columns in the old row
281@param[in,out] non_mv_upd NULL, or not NULL pointer to get the
282 information about whether any non-multi-value
283 field on the multi-value index gets updated
284@param[in] flag ROW_BUILD_NORMAL, ROW_BUILD_FOR_PURGE or
285 ROW_BUILD_FOR_UNDO
286@return true if update vector changes an ordering field in the index record */
289 IF_DEBUG(const que_thr_t *thr, ) const dtuple_t *row, const row_ext_t *ext,
290 bool *non_mv_upd, ulint flag);
291
294 const que_thr_t *thr [[maybe_unused]], const dtuple_t *row,
295 const row_ext_t *ext, bool *non_mv_upd) {
297 index, update, IF_DEBUG(thr, ) row, ext, non_mv_upd, 0);
298}
299
300/** Checks if an FTS indexed column is affected by an UPDATE.
301 @return offset within fts_t::indexes if FTS indexed column updated else
302 ULINT_UNDEFINED */
304 dict_table_t *table, /*!< in: table */
305 upd_field_t *upd_field); /*!< in: field to check */
306/** Checks if an FTS Doc ID column is affected by an UPDATE.
307 @return whether Doc ID column is affected */
308[[nodiscard]] bool row_upd_changes_doc_id(
309 dict_table_t *table, /*!< in: table */
310 upd_field_t *upd_field); /*!< in: field to check */
311/** Checks if an update vector changes an ordering field of an index record.
312 This function is fast if the update vector is short or the number of ordering
313 fields in the index is small. Otherwise, this can be quadratic.
314 NOTE: we compare the fields as binary strings!
315 @return true if update vector may change an ordering field in an index
316 record */
318 const dict_table_t *table, /*!< in: table */
319 const upd_t *update); /*!< in: update vector for the row */
320
321/** Stores to the heap the row on which the node->pcur is positioned.
322@param[in] node row update node
323@param[in] thd mysql thread handle
324@param[in,out] mysql_table NULL, or mysql table object when
325 user thread invokes dml */
326void row_upd_store_row(upd_node_t *node, THD *thd, TABLE *mysql_table);
327
328/** Updates a row in a table. This is a high-level function used
329 in SQL execution graphs.
330 @return query thread to run next or NULL */
331que_thr_t *row_upd_step(que_thr_t *thr); /*!< in: query thread */
332/** Parses the log data of system field values.
333 @return log data end or NULL */
334byte *row_upd_parse_sys_vals(const byte *ptr, /*!< in: buffer */
335 const byte *end_ptr, /*!< in: buffer end */
336 ulint *pos, /*!< out: TRX_ID position in record */
337 trx_id_t *trx_id, /*!< out: trx id */
338 roll_ptr_t *roll_ptr); /*!< out: roll ptr */
339
340/** Updates the trx id and roll ptr field in a clustered index record in
341 database recovery.
342@param[in,out] rec Record
343@param[in,out] page_zip Compressed page, or null
344@param[in] offsets Array returned by rec_get_offsets()
345@param[in] pos Trx_id position in rec
346@param[in] trx_id Transaction id
347@param[in] roll_ptr Roll ptr of the undo log record */
349 const ulint *offsets, ulint pos,
350 trx_id_t trx_id, roll_ptr_t roll_ptr);
351
352/** Parses the log data written by row_upd_index_write_log.
353 @return log data end or NULL */
354byte *row_upd_index_parse(const byte *ptr, /*!< in: buffer */
355 const byte *end_ptr, /*!< in: buffer end */
356 mem_heap_t *heap, /*!< in: memory heap where update
357 vector is built */
358 upd_t **update_out); /*!< out: update vector */
359
360/** Get the new autoinc counter from the update vector when there is
361an autoinc field defined in this table.
362@param[in] update update vector for the clustered index
363@param[in] autoinc_field_no autoinc field's order in clustered index
364@return the new counter if we find it in the update vector, otherwise 0.
365We don't mind that the new counter happens to be 0, we just care about
366non-zero counters. */
368 ulint autoinc_field_no);
369
370/** This structure is used for undo logging of LOB index changes. */
374
375 /** Print the current object into the given output stream.
376 @param[in,out] out the output stream.
377 @return the output stream. */
378 std::ostream &print(std::ostream &out) const {
379 out << "[lob_index_diff_t: m_modifier_trxid=" << m_modifier_trxid
380 << ", m_modifier_undo_no=" << m_modifier_undo_no << "]";
381 return (out);
382 }
383};
384
386 std::vector<lob_index_diff_t, mem_heap_allocator<lob_index_diff_t>>;
387
388/** Overloading the global output operator to print lob_index_diff_t object.
389@param[in,out] out the output stream.
390@param[in] obj the object to be printed.
391@return the output stream.*/
392inline std::ostream &operator<<(std::ostream &out,
393 const lob_index_diff_t &obj) {
394 return (obj.print(out));
395}
396
397/** The modification done to the LOB. */
398struct Lob_diff {
399 /** Constructor.
400 @param[in] mem_heap the memory heap in which this object
401 has been created. */
402 Lob_diff(mem_heap_t *mem_heap) : heap(mem_heap) {
403 m_idx_diffs = static_cast<Lob_index_diff_vec *>(
405 new (m_idx_diffs)
407 }
408
409 /** Read the offset from the undo record.
410 @param[in] undo_ptr pointer into the undo log record.
411 @return pointer into the undo log record after offset. */
412 const byte *read_offset(const byte *undo_ptr) {
413 /* Read the offset. */
415 return (undo_ptr);
416 }
417
418 /** Read the length from the undo record.
419 @param[in] undo_ptr pointer into the undo log record.
420 @return pointer into the undo log record after length information. */
421 const byte *read_length(const byte *undo_ptr) {
422 /* Read the length. */
425
426 return (undo_ptr);
427 }
428
429 void set_old_data(const byte *undo_ptr) { m_old_data = undo_ptr; }
430
431 std::ostream &print(std::ostream &out) const {
432 out << "[Lob_diff: offset=" << m_offset << ", length=" << m_length;
433 if (m_old_data == nullptr) {
434 out << ", m_old_data=nullptr";
435 } else {
436 out << ", m_old_data=" << PrintBuffer(m_old_data, m_length);
437 }
438
439 if (m_idx_diffs != nullptr) {
440 for (auto iter = m_idx_diffs->begin(); iter != m_idx_diffs->end();
441 ++iter) {
442 out << *iter;
443 }
444 }
445
446 out << "]";
447 return (out);
448 }
449
450 /** The offset within LOB where partial update happened. */
452
453 /** The length of the modification. */
455
456 /** Changes to the LOB data. */
457 const byte *m_old_data = nullptr;
458
459 /** Changes to the LOB index. */
461
462 /** Memory heap in which this object is allocated. */
464};
465
466using Lob_diff_vector = std::vector<Lob_diff, mem_heap_allocator<Lob_diff>>;
467
468inline std::ostream &operator<<(std::ostream &out, const Lob_diff &obj) {
469 return (obj.print(out));
470}
471
472/* Update vector field */
475 : field_no(0),
476 orig_len(0),
477 exp(nullptr),
480 ext_in_old(false),
483 lob_version(0),
484 last_trx_id(0),
485 last_undo_no(0),
486 heap(nullptr) {}
487
488 bool is_virtual() const { return (new_val.is_virtual()); }
489
490 unsigned field_no : 16; /*!< for non-virtual fields, the field
491 position in an index, usually
492 the clustered index, but in updating
493 a secondary index record in btr0cur.cc
494 this is the position in the secondary
495 index; for virtual fields the number
496 of correcponding virtual column in
497 table metadata */
499 unsigned orig_len : 16; /*!< original length of the locally
500 stored part of an externally stored
501 column, or 0 */
502 que_node_t *exp; /*!< expression for calculating a new
503 value: it refers to column values and
504 constants in the symbol table of the
505 query graph */
506 dfield_t old_val; /*!< old value for the column */
507 dfield_t new_val; /*!< new value for the column */
508 dfield_t *old_v_val; /*!< old value for the virtual column */
509
510 Field *mysql_field; /*!< the mysql field object. */
511
512 /** If true, the field was stored externally in the old row. */
514
515 void push_lob_diff(const Lob_diff &lob_diff) {
516 if (lob_diffs == nullptr) {
517 lob_diffs = static_cast<Lob_diff_vector *>(
520 }
521 lob_diffs->push_back(lob_diff);
522 }
523
524 /** List of changes done to this updated field. This is usually
525 populated from the undo log. */
527
528 /** The LOB first page number. This information is read from
529 the undo log. */
531
533
534 /** The last trx that modified the LOB. */
536
537 /** The last stmt within trx that modified the LOB. */
539
540 std::ostream &print(std::ostream &out) const;
541
542 /** Empty the information collected on LOB diffs. */
543 void reset() {
544 if (lob_diffs != nullptr) {
545 lob_diffs->clear();
546 }
547 }
548
549 /** Memory heap in which this object is allocated. */
551};
552
553inline std::ostream &operator<<(std::ostream &out, const upd_field_t &obj) {
554 return (obj.print(out));
555}
556
557/* check whether an update field is on virtual column */
558inline bool upd_fld_is_virtual_col(const upd_field_t *upd_fld) {
559 return upd_fld->is_virtual();
560}
561
562/* check whether an update field is on multi-value virtual column */
563inline bool upd_fld_is_multi_value_col(const upd_field_t *upd_fld) {
564 return dfield_is_multi_value(&upd_fld->new_val);
565}
566
567/* set DATA_VIRTUAL bit on update field to show it is a virtual column */
569 upd_fld->new_val.type.prtype |= DATA_VIRTUAL;
570}
571
572/* Update vector structure */
573struct upd_t {
574 /** Heap from which memory allocated. This is not a new heap, rather
575 will point to other heap. Therefore memory allocated from this heap
576 is released when the pointed heap is freed or emptied. */
578
579 /** Heap from which memory is allocated if required only for current
580 statement. This heap is emtied at the end of statement from inside
581 ha_innobase::end_stmt(). */
583
584 /** New value of info bits to record; default is 0. */
586
587 /** Pointer to old row, used for virtual column update now. */
589
590 /** The table object. */
592
593 /** The mysql table object. */
595
596 /** Number of update fields. */
598
599 /** Array of update fields. */
601
602 /** Capacity of the fields array */
604
605 /** Append an update field to the end of array. If fields array is full, more
606 space is allocated on the heap.
607 @param[in] field an update field */
608 void append(const upd_field_t &field);
609
610 /** Determine if the given field_no is modified.
611 @return true if modified, false otherwise. */
612 bool is_modified(const ulint field_no) const {
613 if (table == nullptr) {
614 ut_d(ut_error);
615 ut_o(return false);
616 }
617
618 return (get_field_by_field_no(field_no, table->first_index()) != nullptr);
619 }
620
621 /** Reset the update fields. */
622 void reset() {
623 for (ulint i = 0; i < n_fields; ++i) {
624 fields[i].reset();
625 }
626 }
627
628#ifdef UNIV_DEBUG
629 bool validate() const {
630 for (ulint i = 0; i < n_fields; ++i) {
631 dfield_t *field = &fields[i].new_val;
632 if (dfield_is_ext(field)) {
634 }
635 }
636 return (true);
637 }
638#endif // UNIV_DEBUG
639
640 /** Check if the given field number is partially updated.
641 @param[in] field_no the field number.
642 @return true if partially updated, false otherwise. */
643 bool is_partially_updated(ulint field_no) const;
644
646 const dict_index_t *index) const;
647
649
650 /** Calculate the total number of bytes modified in one BLOB.
651 @param[in] bdv the binary diff vector containing all the
652 modifications to one BLOB.
653 @return the total modified bytes. */
655 size_t total = 0;
656 for (const Binary_diff &bdiff : bdv) {
657 total += bdiff.length();
658 }
659 return (total);
660 }
661
662 /** Empty the per_stmt_heap. */
664 if (per_stmt_heap != nullptr) {
666 }
667 }
668
669 /** Free the per_stmt_heap. */
671 if (per_stmt_heap != nullptr) {
673 per_stmt_heap = nullptr;
674 }
675 }
676
677 std::ostream &print(std::ostream &out) const;
678
679 /** Print the partial update vector (puvect) of the given update
680 field.
681 @param[in,out] out the output stream
682 @param[in] uf the updated field.
683 @return the output stream. */
684 std::ostream &print_puvect(std::ostream &out, upd_field_t *uf) const;
685};
686
687#ifdef UNIV_DEBUG
688/** Print the given binary diff into the given output stream.
689@param[in] out the output stream
690@param[in] bdiff binary diff to be printed.
691@param[in] table the table dictionary object.
692@param[in] field mysql field object.
693@param[in] print_old prints old data of the updated field
694@return the output stream */
695std::ostream &print_binary_diff(std::ostream &out, const Binary_diff *bdiff,
696 const dict_table_t *table, const Field *field,
697 bool print_old);
698
699std::ostream &print_binary_diff(std::ostream &out, const Binary_diff *bdiff);
700
701inline std::ostream &operator<<(std::ostream &out, const upd_t &obj) {
702 return (obj.print(out));
703}
704
705inline std::ostream &operator<<(std::ostream &out, const Binary_diff_vector &) {
706 return (out);
707}
708#endif /* UNIV_DEBUG */
709
710#ifndef UNIV_HOTBACKUP
711/* Update node structure which also implements the delete operation
712of a row */
713
715 que_common_t common; /*!< node type: QUE_NODE_UPDATE */
716 bool is_delete; /* true if delete, false if update */
718 /* true if searched update, false if
719 positioned */
721 /* true if the update node was created
722 for the MySQL interface */
723 dict_foreign_t *foreign; /* NULL or pointer to a foreign key
724 constraint if this update node is used in
725 doing an ON DELETE or ON UPDATE operation */
726 upd_node_t *cascade_node; /* NULL or an update node template which
727 is used to implement ON DELETE/UPDATE CASCADE
728 or ... SET NULL for foreign keys. If present,
729 this node updates the child (referencing) table's
730 clustered index */
732 /*!< NULL or a mem heap where cascade_upd_nodes
733 are created.*/
734 sel_node_t *select; /*!< query graph subtree implementing a base
735 table cursor: the rows returned will be
736 updated */
737 btr_pcur_t *pcur; /*!< persistent cursor placed on the clustered
738 index record which should be updated or
739 deleted; the cursor is stored in the graph
740 of 'select' field above, except in the case
741 of the MySQL interface */
742 dict_table_t *table; /*!< table where updated */
743 upd_t *update; /*!< update vector for the row */
745 /* when this struct is used to implement
746 a cascade operation for foreign keys, we store
747 here the size of the buffer allocated for use
748 as the update vector */
749 sym_node_list_t columns; /* symbol table nodes for the columns
750 to retrieve from the table */
752 /* true if the select which retrieves the
753 records to update already sets an x-lock on
754 the clustered record; note that it must always
755 set at least an s-lock */
756 ulint cmpl_info; /* information extracted during query
757 compilation; speeds up execution:
758 UPD_NODE_NO_ORD_CHANGE and
759 UPD_NODE_NO_SIZE_CHANGE, ORed */
760 /*----------------------*/
761 /* Local storage for this graph node */
762 ulint state; /*!< node execution state */
763 dict_index_t *index; /*!< NULL, or the next index whose record should
764 be updated */
765 dtuple_t *row; /*!< NULL, or a copy (also fields copied to
766 heap) of the row to update; this must be reset
767 to NULL after a successful update */
768 row_ext_t *ext; /*!< NULL, or prefixes of the externally
769 stored columns in the old row */
770 dtuple_t *upd_row; /* NULL, or a copy of the updated row */
771 row_ext_t *upd_ext; /* NULL, or prefixes of the externally
772 stored columns in upd_row */
773 mem_heap_t *heap; /*!< memory heap used as auxiliary storage;
774 this must be emptied after a successful
775 update */
776 /*----------------------*/
777 sym_node_t *table_sym; /* table node in symbol table */
779 /* column assignment list */
780
781 /** When there is a lock wait error, this remembers current position of
782 the multi-value field, before which the values have been deleted.
783 This will be used for both DELETE and the delete phase of UPDATE. */
785
786 /** When there is a lock wait error, this remembers current position of
787 the multi-value field, before which the values have been updated. */
789
791};
792
793constexpr uint32_t UPD_NODE_MAGIC_N = 1579975;
794
795/* Node execution states */
796/** execution came to the node from a node above and if the field
797has_clust_rec_x_lock is false, we should set an intention x-lock on the table
798 */
799constexpr uint32_t UPD_NODE_SET_IX_LOCK = 1;
800/** clustered index record should be updated */
801constexpr uint32_t UPD_NODE_UPDATE_CLUSTERED = 2;
802/* clustered index record should be inserted, old record is already delete
803 marked */
804constexpr uint32_t UPD_NODE_INSERT_CLUSTERED = 3;
805/** an ordering field of the clustered index record was changed, or this is a
806 delete operation: should update all the secondary index records */
807constexpr uint32_t UPD_NODE_UPDATE_ALL_SEC = 5;
808/** secondary index entries should be looked at and updated if an ordering field
809 changed */
810constexpr uint32_t UPD_NODE_UPDATE_SOME_SEC = 6;
811
812/* Compilation info flags: these must fit within 2 bits; see trx0rec.h */
813/** no secondary index record will be changed in the update and no ordering
814 field of the clustered index */
815constexpr uint32_t UPD_NODE_NO_ORD_CHANGE = 1;
816/** no record field size will be changed in the update */
817constexpr uint32_t UPD_NODE_NO_SIZE_CHANGE = 2;
818#endif /* !UNIV_HOTBACKUP */
819
820#include "row0upd.ic"
821
822#endif
uint32_t page_no_t
Page number.
Definition: api0api.h:46
Kerberos Client Authentication nullptr
Definition: auth_kerberos_client_plugin.cc:247
The index tree persistent cursor.
The index tree general types.
constexpr uint32_t BTR_EXTERN_FIELD_REF_SIZE
The size of a reference to data stored on a different page.
Definition: btr0types.h:66
Class that represents a single change to a column value in partial update of a JSON column.
Definition: table.h:1350
Definition: field.h:569
A typesafe replacement for DYNAMIC_ARRAY.
Definition: mem_root_array.h:432
For each client connection we create a separate thread with THD serving as a thread/connection descri...
Definition: sql_lexer_thd.h:36
A C++ wrapper class to the mem_heap_t routines, so that it can be used as an STL allocator.
Definition: mem0mem.h:356
SQL data field and tuple.
static uint32_t dfield_get_len(const dfield_t *field)
Gets length of field data.
static bool dfield_is_ext(const dfield_t *field)
Determines if a field is externally stored.
static bool dfield_is_multi_value(const dfield_t *field)
Determine if a field is of multi-value type.
constexpr uint32_t DATA_VIRTUAL
Virtual column.
Definition: data0type.h:223
dberr_t
Definition: db0err.h:39
Data dictionary global types.
constexpr page_no_t FIL_NULL
'null' (undefined) page offset in the context of file spaces
Definition: fil0fil.h:1161
static int flag
Definition: hp_test1.cc:40
#define UINT16_MAX
Definition: lexyy.cc:83
Implements the large objects (LOB) module.
static uint32_t mach_read_next_compressed(const byte **b)
Read a 32-bit integer in a compressed form.
static void * mem_heap_alloc(mem_heap_t *heap, ulint n)
Allocates n bytes of memory from a memory heap.
static void mem_heap_free(mem_heap_t *heap)
Frees the space occupied by a memory heap.
static void mem_heap_empty(mem_heap_t *heap)
Empties a memory heap.
static uint update
Definition: myisamlog.cc:94
void error(const char *format,...)
Type total(const Shards< COUNT > &shards) noexcept
Get the total value of all shards.
Definition: ut0counter.h:333
static PFS_engine_table_share_proxy table
Definition: pfs.cc:61
bool index(const std::string &value, const String &search_for, uint32_t *idx)
Definition: contains.h:76
Json_data_extension ext
Definition: backend.cc:50
SQL parser global types.
Query graph global types.
void que_node_t
Definition: que0types.h:41
byte rec_t
Definition: rem0types.h:41
required string type
Definition: replication_group_member_actions.proto:34
Row operation global types.
upd_t * row_upd_build_difference_binary(dict_index_t *index, const dtuple_t *entry, const rec_t *rec, const ulint *offsets, bool no_sys, trx_t *trx, mem_heap_t *heap, TABLE *mysql_table, dberr_t *error)
Builds an update vector from those fields, excluding the roll ptr and trx id fields,...
Definition: row0upd.cc:827
void upd_field_set_v_field_no(upd_field_t *upd_field, ulint field_no, const dict_index_t *index)
Set for which virtual column the value is updated by an update vector field.
Definition: row0upd.ic:100
constexpr uint32_t UPD_NODE_UPDATE_SOME_SEC
secondary index entries should be looked at and updated if an ordering field changed
Definition: row0upd.h:810
byte * row_upd_index_parse(const byte *ptr, const byte *end_ptr, mem_heap_t *heap, upd_t **update_out)
Parses the log data written by row_upd_index_write_log.
Definition: row0upd.cc:675
bool row_upd_changes_some_index_ord_field_binary(const dict_table_t *table, const upd_t *update)
Checks if an update vector changes an ordering field of an index record.
Definition: row0upd.cc:1652
bool row_upd_changes_field_size_or_external(const dict_index_t *index, const ulint *offsets, const upd_t *update)
Returns true if row update changes size of some field in index or if some field to be updated is stor...
Definition: row0upd.cc:353
void row_upd_index_write_log(dict_index_t *index, const upd_t *update, byte *log_ptr, mtr_t *mtr)
Writes to the redo log the new values of the fields occurring in the index.
Definition: row0upd.cc:590
std::vector< lob_index_diff_t, mem_heap_allocator< lob_index_diff_t > > Lob_index_diff_vec
Definition: row0upd.h:386
constexpr uint32_t UPD_NODE_MAGIC_N
Definition: row0upd.h:793
std::vector< Lob_diff, mem_heap_allocator< Lob_diff > > Lob_diff_vector
Definition: row0upd.h:466
void upd_fld_set_virtual_col(upd_field_t *upd_fld)
Definition: row0upd.h:568
constexpr uint32_t UPD_NODE_NO_ORD_CHANGE
no secondary index record will be changed in the update and no ordering field of the clustered index
Definition: row0upd.h:815
void row_upd_replace(dtuple_t *row, row_ext_t **ext, const dict_index_t *index, const upd_t *update, mem_heap_t *heap)
Replaces the new column values stored in the update vector.
Definition: row0upd.cc:1353
static bool row_upd_changes_ord_field_binary(dict_index_t *index, const upd_t *update, const que_thr_t *thr, const dtuple_t *row, const row_ext_t *ext, bool *non_mv_upd)
Definition: row0upd.h:292
upd_t * upd_create(ulint n, mem_heap_t *heap)
Creates an update vector object.
Definition: row0upd.ic:43
void row_upd_index_entry_sys_field(dtuple_t *entry, dict_index_t *index, ulint type, uint64_t val)
Sets the trx id or roll ptr field of a clustered index entry.
Definition: row0upd.cc:327
void row_upd_rec_sys_fields(rec_t *rec, page_zip_des_t *page_zip, const dict_index_t *index, const ulint *offsets, const trx_t *trx, roll_ptr_t roll_ptr)
Updates the trx id and roll ptr field in a clustered index record when a row is updated or marked del...
Definition: row0upd.ic:138
constexpr uint32_t UPD_NODE_UPDATE_CLUSTERED
clustered index record should be updated
Definition: row0upd.h:801
upd_node_t * upd_node_create(mem_heap_t *heap)
Creates an update node for a query graph.
Definition: row0upd.cc:278
bool upd_fld_is_virtual_col(const upd_field_t *upd_fld)
Definition: row0upd.h:558
bool upd_fld_is_multi_value_col(const upd_field_t *upd_fld)
Definition: row0upd.h:563
void row_upd_store_row(upd_node_t *node, THD *thd, TABLE *mysql_table)
Stores to the heap the row on which the node->pcur is positioned.
Definition: row0upd.cc:1914
bool row_upd_changes_disowned_external(const upd_t *update)
Returns true if row update contains disowned external fields.
Definition: row0upd.cc:433
constexpr uint32_t UPD_NODE_INSERT_CLUSTERED
Definition: row0upd.h:804
upd_field_t * upd_get_nth_field(upd_t *update, ulint n)
Returns the nth field of an update vector.
Definition: row0upd.ic:76
byte * row_upd_parse_sys_vals(const byte *ptr, const byte *end_ptr, ulint *pos, trx_id_t *trx_id, roll_ptr_t *roll_ptr)
Parses the log data of system field values.
Definition: row0upd.cc:565
que_thr_t * row_upd_step(que_thr_t *thr)
Updates a row in a table.
Definition: row0upd.cc:3273
void row_upd_index_replace_new_col_vals(dtuple_t *entry, const dict_index_t *index, const upd_t *update, mem_heap_t *heap)
Replaces the new column values stored in the update vector to the index entry given.
Definition: row0upd.cc:1165
byte * row_upd_write_sys_vals_to_log(dict_index_t *index, trx_id_t trx_id, roll_ptr_t roll_ptr, byte *log_ptr, mtr_t *mtr)
Writes into the redo log the values of trx id and roll ptr and enough info to determine their positio...
Definition: row0upd.cc:545
constexpr uint32_t UPD_NODE_UPDATE_ALL_SEC
an ordering field of the clustered index record was changed, or this is a delete operation: should up...
Definition: row0upd.h:807
std::ostream & print_binary_diff(std::ostream &out, const Binary_diff *bdiff, const dict_table_t *table, const Field *field, bool print_old)
Print the given binary diff into the given output stream.
Definition: row0upd.cc:3400
ulint row_upd_changes_fts_column(dict_table_t *table, upd_field_t *upd_field)
Checks if an FTS indexed column is affected by an UPDATE.
Definition: row0upd.cc:1702
constexpr uint32_t UPD_NODE_SET_IX_LOCK
execution came to the node from a node above and if the field has_clust_rec_x_lock is false,...
Definition: row0upd.h:799
std::ostream & operator<<(std::ostream &out, const lob_index_diff_t &obj)
Overloading the global output operator to print lob_index_diff_t object.
Definition: row0upd.h:392
void row_upd_rec_sys_fields_in_recovery(rec_t *rec, page_zip_des_t *page_zip, const ulint *offsets, ulint pos, trx_id_t trx_id, roll_ptr_t roll_ptr)
Updates the trx id and roll ptr field in a clustered index record in database recovery.
Definition: row0upd.cc:301
const upd_field_t * upd_get_field_by_field_no(const upd_t *update, ulint no, bool is_virtual)
Returns a field of an update vector by field_no.
Definition: row0upd.ic:117
constexpr uint32_t UPD_NODE_NO_SIZE_CHANGE
no record field size will be changed in the update
Definition: row0upd.h:817
ulint upd_get_n_fields(const upd_t *update)
Returns the number of fields in the update vector == number of columns to be updated by an update vec...
Definition: row0upd.ic:63
upd_t * row_upd_build_sec_rec_difference_binary(const rec_t *rec, dict_index_t *index, const ulint *offsets, const dtuple_t *entry, mem_heap_t *heap)
Builds an update vector from those fields which in a secondary index entry differ from a record that ...
Definition: row0upd.cc:752
void row_upd_rec_in_place(rec_t *rec, const dict_index_t *index, const ulint *offsets, const upd_t *update, page_zip_des_t *page_zip)
Replaces the new column values stored in the update vector to the record given.
Definition: row0upd.cc:469
void row_upd_replace_vcol(dtuple_t *row, const dict_table_t *table, const upd_t *update, bool upd_new, dtuple_t *undo_row, const byte *ptr)
Replaces the virtual column values stored in a dtuple with that of a update vector.
Definition: row0upd.cc:1224
uint64_t row_upd_get_new_autoinc_counter(const upd_t *update, ulint autoinc_field_no)
Get the new autoinc counter from the update vector when there is an autoinc field defined in this tab...
Definition: row0upd.cc:2694
void row_upd_index_replace_new_col_vals_index_pos(dtuple_t *entry, const dict_index_t *index, const upd_t *update, bool order_only, mem_heap_t *heap)
Replaces the new column values stored in the update vector to the index entry given.
Definition: row0upd.cc:1110
bool row_upd_changes_doc_id(dict_table_t *table, upd_field_t *upd_field)
Checks if an FTS Doc ID column is affected by an UPDATE.
Definition: row0upd.cc:1682
void upd_field_set_field_no(upd_field_t *upd_field, ulint field_no, const dict_index_t *index)
Set which index field is updated by an update vector field.
Definition: row0upd.ic:84
bool row_upd_changes_ord_field_binary_func(dict_index_t *index, const upd_t *update, const que_thr_t *thr, const dtuple_t *row, const row_ext_t *ext, bool *non_mv_upd, ulint flag)
Checks if an update vector changes an ordering field of an index record.
Definition: row0upd.cc:1420
Update of a row.
TempTable Table declarations.
The modification done to the LOB.
Definition: row0upd.h:398
std::ostream & print(std::ostream &out) const
Definition: row0upd.h:431
const byte * read_offset(const byte *undo_ptr)
Read the offset from the undo record.
Definition: row0upd.h:412
Lob_diff(mem_heap_t *mem_heap)
Constructor.
Definition: row0upd.h:402
const byte * m_old_data
Changes to the LOB data.
Definition: row0upd.h:457
mem_heap_t * heap
Memory heap in which this object is allocated.
Definition: row0upd.h:463
Lob_index_diff_vec * m_idx_diffs
Changes to the LOB index.
Definition: row0upd.h:460
const byte * read_length(const byte *undo_ptr)
Read the length from the undo record.
Definition: row0upd.h:421
ulint m_length
The length of the modification.
Definition: row0upd.h:454
void set_old_data(const byte *undo_ptr)
Definition: row0upd.h:429
ulint m_offset
The offset within LOB where partial update happened.
Definition: row0upd.h:451
Definition: ut.h:72
Definition: table.h:1433
Definition: completion_hash.h:35
Definition: btr0pcur.h:99
Structure for an SQL data field.
Definition: data0data.h:617
dtype_t type
type of data
Definition: data0data.h:624
bool is_virtual() const
Definition: data0data.h:628
Data structure for a foreign key constraint; an example: FOREIGN KEY (A, B) REFERENCES TABLE2 (C,...
Definition: dict0mem.h:1661
Data structure for an index.
Definition: dict0mem.h:1041
Data structure for a database table.
Definition: dict0mem.h:1913
const dict_index_t * first_index() const
Definition: dict0mem.h:2471
Structure for an SQL data tuple of fields (logical record)
Definition: data0data.h:696
unsigned prtype
precise type; MySQL data type, charset code, flags to indicate nullability, signedness,...
Definition: data0type.h:499
static const ulint LOB_SMALL_CHANGE_THRESHOLD
If the total number of bytes modified in an LOB, in an update operation, is less than or equal to thi...
Definition: lob0lob.h:210
This structure is used for undo logging of LOB index changes.
Definition: row0upd.h:371
undo_no_t m_modifier_undo_no
Definition: row0upd.h:373
trx_id_t m_modifier_trxid
Definition: row0upd.h:372
std::ostream & print(std::ostream &out) const
Print the current object into the given output stream.
Definition: row0upd.h:378
The info structure stored at the beginning of a heap block.
Definition: mem0mem.h:302
Mini-transaction handle and buffer.
Definition: mtr0mtr.h:177
Compressed page descriptor.
Definition: page0types.h:201
Definition: que0types.h:51
Definition: que0que.h:242
Prefixes of externally stored columns.
Definition: row0ext.h:95
Select statement node.
Definition: row0sel.h:329
Symbol table node.
Definition: pars0sym.h:113
Definition: trx0trx.h:675
Definition: row0upd.h:473
unsigned orig_len
original length of the locally stored part of an externally stored column, or 0
Definition: row0upd.h:499
dfield_t new_val
new value for the column
Definition: row0upd.h:507
undo_no_t last_undo_no
The last stmt within trx that modified the LOB.
Definition: row0upd.h:538
bool ext_in_old
If true, the field was stored externally in the old row.
Definition: row0upd.h:513
unsigned field_no
for non-virtual fields, the field position in an index, usually the clustered index,...
Definition: row0upd.h:490
trx_id_t last_trx_id
The last trx that modified the LOB.
Definition: row0upd.h:535
void push_lob_diff(const Lob_diff &lob_diff)
Definition: row0upd.h:515
page_no_t lob_first_page_no
The LOB first page number.
Definition: row0upd.h:530
upd_field_t()
Definition: row0upd.h:474
dfield_t old_val
old value for the column
Definition: row0upd.h:506
std::ostream & print(std::ostream &out) const
Definition: row0upd.cc:3374
Field * mysql_field
the mysql field object.
Definition: row0upd.h:510
mem_heap_t * heap
Memory heap in which this object is allocated.
Definition: row0upd.h:550
que_node_t * exp
expression for calculating a new value: it refers to column values and constants in the symbol table ...
Definition: row0upd.h:502
Lob_diff_vector * lob_diffs
List of changes done to this updated field.
Definition: row0upd.h:526
uint16_t field_phy_pos
Definition: row0upd.h:498
bool is_virtual() const
Definition: row0upd.h:488
ulint lob_version
Definition: row0upd.h:532
dfield_t * old_v_val
old value for the virtual column
Definition: row0upd.h:508
void reset()
Empty the information collected on LOB diffs.
Definition: row0upd.h:543
Definition: row0upd.h:714
bool in_mysql_interface
Definition: row0upd.h:720
sym_node_list_t columns
Definition: row0upd.h:749
sym_node_t * table_sym
Definition: row0upd.h:777
dtuple_t * upd_row
Definition: row0upd.h:770
ulint update_n_fields
Definition: row0upd.h:744
dict_foreign_t * foreign
Definition: row0upd.h:723
dict_index_t * index
NULL, or the next index whose record should be updated.
Definition: row0upd.h:763
row_ext_t * ext
NULL, or prefixes of the externally stored columns in the old row.
Definition: row0upd.h:768
mem_heap_t * cascade_heap
NULL or a mem heap where cascade_upd_nodes are created.
Definition: row0upd.h:731
uint32_t del_multi_val_pos
When there is a lock wait error, this remembers current position of the multi-value field,...
Definition: row0upd.h:784
que_node_t * col_assign_list
Definition: row0upd.h:778
bool searched_update
Definition: row0upd.h:717
ulint state
node execution state
Definition: row0upd.h:762
upd_t * update
update vector for the row
Definition: row0upd.h:743
dict_table_t * table
table where updated
Definition: row0upd.h:742
sel_node_t * select
query graph subtree implementing a base table cursor: the rows returned will be updated
Definition: row0upd.h:734
btr_pcur_t * pcur
persistent cursor placed on the clustered index record which should be updated or deleted; the cursor...
Definition: row0upd.h:737
row_ext_t * upd_ext
Definition: row0upd.h:771
dtuple_t * row
NULL, or a copy (also fields copied to heap) of the row to update; this must be reset to NULL after a...
Definition: row0upd.h:765
que_common_t common
node type: QUE_NODE_UPDATE
Definition: row0upd.h:715
bool has_clust_rec_x_lock
Definition: row0upd.h:751
bool is_delete
Definition: row0upd.h:716
ulint magic_n
Definition: row0upd.h:790
uint32_t upd_multi_val_pos
When there is a lock wait error, this remembers current position of the multi-value field,...
Definition: row0upd.h:788
ulint cmpl_info
Definition: row0upd.h:756
mem_heap_t * heap
memory heap used as auxiliary storage; this must be emptied after a successful update
Definition: row0upd.h:773
upd_node_t * cascade_node
Definition: row0upd.h:726
Definition: row0upd.h:573
void append(const upd_field_t &field)
Append an update field to the end of array.
Definition: row0upd.cc:2770
static size_t get_total_modified_bytes(const Binary_diff_vector &bdv)
Calculate the total number of bytes modified in one BLOB.
Definition: row0upd.h:654
bool is_partially_updated(ulint field_no) const
Check if the given field number is partially updated.
Definition: row0upd.cc:3470
mem_heap_t * heap
Heap from which memory allocated.
Definition: row0upd.h:577
void free_per_stmt_heap()
Free the per_stmt_heap.
Definition: row0upd.h:670
bool validate() const
Definition: row0upd.h:629
void empty_per_stmt_heap()
Empty the per_stmt_heap.
Definition: row0upd.h:663
dtuple_t * old_vrow
Pointer to old row, used for virtual column update now.
Definition: row0upd.h:588
upd_field_t * fields
Array of update fields.
Definition: row0upd.h:600
const dict_table_t * table
The table object.
Definition: row0upd.h:591
ulint info_bits
New value of info bits to record; default is 0.
Definition: row0upd.h:585
mem_heap_t * per_stmt_heap
Heap from which memory is allocated if required only for current statement.
Definition: row0upd.h:582
const Binary_diff_vector * get_binary_diff_by_field_no(ulint field_no) const
Definition: row0upd.cc:3515
const upd_field_t * get_field_by_field_no(ulint field_no, const dict_index_t *index) const
Definition: row0upd.cc:3454
std::ostream & print(std::ostream &out) const
Definition: row0upd.cc:3390
TABLE * mysql_table
The mysql table object.
Definition: row0upd.h:594
bool is_modified(const ulint field_no) const
Determine if the given field_no is modified.
Definition: row0upd.h:612
size_t n_capacity
Capacity of the fields array.
Definition: row0upd.h:603
ulint n_fields
Number of update fields.
Definition: row0upd.h:597
void reset()
Reset the update fields.
Definition: row0upd.h:622
std::ostream & print_puvect(std::ostream &out, upd_field_t *uf) const
Print the partial update vector (puvect) of the given update field.
Definition: row0upd.cc:3436
Transaction system global type definitions.
ib_id_t undo_no_t
Undo number.
Definition: trx0types.h:142
ib_id_t trx_id_t
Transaction identifier (DB_TRX_ID, DATA_TRX_ID)
Definition: trx0types.h:138
ib_id_t roll_ptr_t
Rollback pointer (DB_ROLL_PTR, DATA_ROLL_PTR)
Definition: trx0types.h:140
Version control for database, common definitions, and include files.
#define IF_DEBUG(...)
Definition: univ.i:674
unsigned long int ulint
Definition: univ.i:406
#define ut_error
Abort execution.
Definition: ut0dbg.h:101
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:105
#define ut_o(EXPR)
Opposite of ut_d().
Definition: ut0dbg.h:109
#define ut_d(EXPR)
Debug statement.
Definition: ut0dbg.h:107
int n
Definition: xcom_base.cc:509