1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2017, 2020, 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, Fifth Floor, 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 "rem0types.h"
32 #include "row0types.h"
33 #include "btr0types.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 rec_offs*	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 rec_offs*	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 rec_offs*	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 rec_offs*	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 @param[out]	error		error number in case of failure
224 @return own: update vector of differing fields, excluding roll ptr and
225 trx id */
226 upd_t*
227 row_upd_build_difference_binary(
228 	dict_index_t*	index,
229 	const dtuple_t*	entry,
230 	const rec_t*	rec,
231 	const rec_offs*	offsets,
232 	bool		no_sys,
233 	trx_t*		trx,
234 	mem_heap_t*	heap,
235 	TABLE*		mysql_table,
236 	dberr_t*	error)
237 	MY_ATTRIBUTE((nonnull(1,2,3,7,9), warn_unused_result));
238 /** Apply an update vector to an index entry.
239 @param[in,out]	entry	index entry to be updated; the clustered index record
240 			must be covered by a lock or a page latch to prevent
241 			deletion (rollback or purge)
242 @param[in]	index	index of the entry
243 @param[in]	update	update vector built for the entry
244 @param[in,out]	heap	memory heap for copying off-page columns */
245 void
246 row_upd_index_replace_new_col_vals_index_pos(
247 	dtuple_t*		entry,
248 	const dict_index_t*	index,
249 	const upd_t*		update,
250 	mem_heap_t*		heap)
251 	MY_ATTRIBUTE((nonnull));
252 /** Replace the new column values stored in the update vector,
253 during trx_undo_prev_version_build().
254 @param entry   clustered index tuple where the values are replaced
255                (the clustered index leaf page latch must be held)
256 @param index   clustered index
257 @param update  update vector for the clustered index
258 @param heap    memory heap for allocating and copying values
259 @return whether the previous version was built successfully */
260 bool
261 row_upd_index_replace_new_col_vals(dtuple_t *entry, const dict_index_t &index,
262                                    const upd_t *update, mem_heap_t *heap)
263   MY_ATTRIBUTE((nonnull, warn_unused_result));
264 /***********************************************************//**
265 Replaces the new column values stored in the update vector. */
266 void
267 row_upd_replace(
268 /*============*/
269 	dtuple_t*		row,	/*!< in/out: row where replaced,
270 					indexed by col_no;
271 					the clustered index record must be
272 					covered by a lock or a page latch to
273 					prevent deletion (rollback or purge) */
274 	row_ext_t**		ext,	/*!< out, own: NULL, or externally
275 					stored column prefixes */
276 	const dict_index_t*	index,	/*!< in: clustered index */
277 	const upd_t*		update,	/*!< in: an update vector built for the
278 					clustered index */
279 	mem_heap_t*		heap);	/*!< in: memory heap */
280 /** Replaces the virtual column values stored in a dtuple with that of
281 a update vector.
282 @param[in,out]	row	dtuple whose column to be updated
283 @param[in]	table	table
284 @param[in]	update	an update vector built for the clustered index
285 @param[in]	upd_new	update to new or old value
286 @param[in,out]	undo_row undo row (if needs to be updated)
287 @param[in]	ptr	remaining part in update undo log */
288 void
289 row_upd_replace_vcol(
290 	dtuple_t*		row,
291 	const dict_table_t*	table,
292 	const upd_t*		update,
293 	bool			upd_new,
294 	dtuple_t*		undo_row,
295 	const byte*		ptr);
296 
297 /***********************************************************//**
298 Checks if an update vector changes an ordering field of an index record.
299 
300 This function is fast if the update vector is short or the number of ordering
301 fields in the index is small. Otherwise, this can be quadratic.
302 NOTE: we compare the fields as binary strings!
303 @return TRUE if update vector changes an ordering field in the index record */
304 ibool
305 row_upd_changes_ord_field_binary_func(
306 /*==================================*/
307 	dict_index_t*	index,	/*!< in: index of the record */
308 	const upd_t*	update,	/*!< in: update vector for the row; NOTE: the
309 				field numbers in this MUST be clustered index
310 				positions! */
311 #ifdef UNIV_DEBUG
312 	const que_thr_t*thr,	/*!< in: query thread */
313 #endif /* UNIV_DEBUG */
314 	const dtuple_t*	row,	/*!< in: old value of row, or NULL if the
315 				row and the data values in update are not
316 				known when this function is called, e.g., at
317 				compile time */
318 	const row_ext_t*ext,	/*!< NULL, or prefixes of the externally
319 				stored columns in the old row */
320 	ulint		flag)	/*!< in: ROW_BUILD_NORMAL,
321 				ROW_BUILD_FOR_PURGE or ROW_BUILD_FOR_UNDO */
322 	MY_ATTRIBUTE((nonnull(1,2), warn_unused_result));
323 #ifdef UNIV_DEBUG
324 # define row_upd_changes_ord_field_binary(index,update,thr,row,ext)	\
325 	row_upd_changes_ord_field_binary_func(index,update,thr,row,ext,0)
326 #else /* UNIV_DEBUG */
327 # define row_upd_changes_ord_field_binary(index,update,thr,row,ext)	\
328 	row_upd_changes_ord_field_binary_func(index,update,row,ext,0)
329 #endif /* UNIV_DEBUG */
330 /***********************************************************//**
331 Checks if an FTS indexed column is affected by an UPDATE.
332 @return offset within fts_t::indexes if FTS indexed column updated else
333 ULINT_UNDEFINED */
334 ulint
335 row_upd_changes_fts_column(
336 /*=======================*/
337 	dict_table_t*	table,		/*!< in: table */
338 	upd_field_t*	upd_field);	/*!< in: field to check */
339 /***********************************************************//**
340 Checks if an FTS Doc ID column is affected by an UPDATE.
341 @return whether Doc ID column is affected */
342 bool
343 row_upd_changes_doc_id(
344 /*===================*/
345 	dict_table_t*	table,		/*!< in: table */
346 	upd_field_t*	upd_field)	/*!< in: field to check */
347 	MY_ATTRIBUTE((nonnull, warn_unused_result));
348 /***********************************************************//**
349 Checks if an update vector changes an ordering field of an index record.
350 This function is fast if the update vector is short or the number of ordering
351 fields in the index is small. Otherwise, this can be quadratic.
352 NOTE: we compare the fields as binary strings!
353 @return TRUE if update vector may change an ordering field in an index
354 record */
355 ibool
356 row_upd_changes_some_index_ord_field_binary(
357 /*========================================*/
358 	const dict_table_t*	table,	/*!< in: table */
359 	const upd_t*		update);/*!< in: update vector for the row */
360 /***********************************************************//**
361 Updates a row in a table. This is a high-level function used
362 in SQL execution graphs.
363 @return query thread to run next or NULL */
364 que_thr_t*
365 row_upd_step(
366 /*=========*/
367 	que_thr_t*	thr);	/*!< in: query thread */
368 /*********************************************************************//**
369 Parses the log data of system field values.
370 @return log data end or NULL */
371 byte*
372 row_upd_parse_sys_vals(
373 /*===================*/
374 	const byte*	ptr,	/*!< in: buffer */
375 	const byte*	end_ptr,/*!< in: buffer end */
376 	ulint*		pos,	/*!< out: TRX_ID position in record */
377 	trx_id_t*	trx_id,	/*!< out: trx id */
378 	roll_ptr_t*	roll_ptr);/*!< out: roll ptr */
379 /*********************************************************************//**
380 Updates the trx id and roll ptr field in a clustered index record in database
381 recovery. */
382 void
383 row_upd_rec_sys_fields_in_recovery(
384 /*===============================*/
385 	rec_t*		rec,	/*!< in/out: record */
386 	page_zip_des_t*	page_zip,/*!< in/out: compressed page, or NULL */
387 	const rec_offs*	offsets,/*!< in: array returned by rec_get_offsets() */
388 	ulint		pos,	/*!< in: TRX_ID position in rec */
389 	trx_id_t	trx_id,	/*!< in: transaction id */
390 	roll_ptr_t	roll_ptr);/*!< in: roll ptr of the undo log record */
391 /*********************************************************************//**
392 Parses the log data written by row_upd_index_write_log.
393 @return log data end or NULL */
394 byte*
395 row_upd_index_parse(
396 /*================*/
397 	const byte*	ptr,	/*!< in: buffer */
398 	const byte*	end_ptr,/*!< in: buffer end */
399 	mem_heap_t*	heap,	/*!< in: memory heap where update vector is
400 				built */
401 	upd_t**		update_out);/*!< out: update vector */
402 
403 
404 /* Update vector field */
405 struct upd_field_t{
406 	unsigned	field_no:16;	/*!< field number in an index, usually
407 					the clustered index, but in updating
408 					a secondary index record in btr0cur.cc
409 					this is the position in the secondary
410 					index. If this field is a virtual
411 					column, then field_no represents
412 					the nth virtual	column in the table */
413 	unsigned	orig_len:16;	/*!< original length of the locally
414 					stored part of an externally stored
415 					column, or 0 */
416 	que_node_t*	exp;		/*!< expression for calculating a new
417 					value: it refers to column values and
418 					constants in the symbol table of the
419 					query graph */
420 	dfield_t	new_val;	/*!< new value for the column */
421 	dfield_t*	old_v_val;	/*!< old value for the virtual column */
422 };
423 
424 
425 /* check whether an update field is on virtual column */
426 #define upd_fld_is_virtual_col(upd_fld)			\
427 	(((upd_fld)->new_val.type.prtype & DATA_VIRTUAL) == DATA_VIRTUAL)
428 
429 /* set DATA_VIRTUAL bit on update field to show it is a virtual column */
430 #define upd_fld_set_virtual_col(upd_fld)			\
431 	((upd_fld)->new_val.type.prtype |= DATA_VIRTUAL)
432 
433 /* Update vector structure */
434 struct upd_t{
435 	mem_heap_t*	heap;		/*!< heap from which memory allocated */
436 	ulint		info_bits;	/*!< new value of info bits to record;
437 					default is 0 */
438 	dtuple_t*	old_vrow;	/*!< pointer to old row, used for
439 					virtual column update now */
440 	ulint		n_fields;	/*!< number of update fields */
441 	upd_field_t*	fields;		/*!< array of update fields */
442 	byte		vers_sys_value[8]; /*!< buffer for updating system fields */
443 
444 	/** Append an update field to the end of array
445 	@param[in]	field	an update field */
appendupd_t446 	void append(const upd_field_t& field)
447 	{
448 		fields[n_fields++] = field;
449 	}
450 
remove_elementupd_t451         void remove_element(ulint i)
452         {
453           ut_ad(n_fields > 0);
454           ut_ad(i < n_fields);
455           while (i < n_fields - 1)
456           {
457             fields[i]= fields[i + 1];
458             i++;
459           }
460           n_fields--;
461         }
462 
removeupd_t463         bool remove(const ulint field_no)
464         {
465           for (ulint i= 0; i < n_fields; ++i)
466           {
467             if (field_no == fields[i].field_no)
468             {
469               remove_element(i);
470               return true;
471             }
472           }
473           return false;
474         }
475 
476         /** Determine if the given field_no is modified.
477 	@return true if modified, false otherwise.  */
is_modifiedupd_t478 	bool is_modified(const ulint field_no) const
479 	{
480 		for (ulint i = 0; i < n_fields; ++i) {
481 			if (field_no == fields[i].field_no) {
482 				return(true);
483 			}
484 		}
485 		return(false);
486 	}
487 
488 	/** Determine if the update affects a system versioned column or row_end. */
affects_versionedupd_t489 	bool affects_versioned() const
490 	{
491 		for (ulint i = 0; i < n_fields; i++) {
492 			dtype_t type = fields[i].new_val.type;
493 			if (type.is_versioned()) {
494 				return true;
495 			}
496 			// versioned DELETE is UPDATE SET row_end=NOW
497 			if (type.vers_sys_end()) {
498 				return true;
499 			}
500 		}
501 		return false;
502 	}
503 
504 #ifdef UNIV_DEBUG
validateupd_t505         bool validate() const
506         {
507                 for (ulint i = 0; i < n_fields; ++i) {
508                         dfield_t* field = &fields[i].new_val;
509                         if (dfield_is_ext(field)) {
510 				ut_ad(dfield_get_len(field)
511 				      >= BTR_EXTERN_FIELD_REF_SIZE);
512                         }
513                 }
514                 return(true);
515         }
516 #endif // UNIV_DEBUG
517 
518 };
519 
520 /** Kinds of update operation */
521 enum delete_mode_t {
522 	NO_DELETE = 0,		/*!< this operation does not delete */
523 	PLAIN_DELETE,		/*!< ordinary delete */
524 	VERSIONED_DELETE	/*!< update old and insert a new row */
525 };
526 
527 /* Update node structure which also implements the delete operation
528 of a row */
529 
530 struct upd_node_t{
531 	que_common_t	common;	/*!< node type: QUE_NODE_UPDATE */
532 	delete_mode_t	is_delete;	/*!< kind of DELETE */
533 	ibool		searched_update;
534 				/* TRUE if searched update, FALSE if
535 				positioned */
536 	bool		in_mysql_interface;
537 				/* whether the update node was created
538 				for the MySQL interface */
539 	dict_foreign_t*	foreign;/* NULL or pointer to a foreign key
540 				constraint if this update node is used in
541 				doing an ON DELETE or ON UPDATE operation */
542 	upd_node_t*	cascade_node;/* NULL or an update node template which
543 				is used to implement ON DELETE/UPDATE CASCADE
544 				or ... SET NULL for foreign keys */
545 	mem_heap_t*	cascade_heap;
546 				/*!< NULL or a mem heap where cascade
547 				node is created.*/
548 	sel_node_t*	select;	/*!< query graph subtree implementing a base
549 				table cursor: the rows returned will be
550 				updated */
551 	btr_pcur_t*	pcur;	/*!< persistent cursor placed on the clustered
552 				index record which should be updated or
553 				deleted; the cursor is stored in the graph
554 				of 'select' field above, except in the case
555 				of the MySQL interface */
556 	dict_table_t*	table;	/*!< table where updated */
557 	upd_t*		update;	/*!< update vector for the row */
558 	ulint		update_n_fields;
559 				/* when this struct is used to implement
560 				a cascade operation for foreign keys, we store
561 				here the size of the buffer allocated for use
562 				as the update vector */
563 	sym_node_list_t	columns;/* symbol table nodes for the columns
564 				to retrieve from the table */
565 	ibool		has_clust_rec_x_lock;
566 				/* TRUE if the select which retrieves the
567 				records to update already sets an x-lock on
568 				the clustered record; note that it must always
569 				set at least an s-lock */
570 	ulint		cmpl_info;/* information extracted during query
571 				compilation; speeds up execution:
572 				UPD_NODE_NO_ORD_CHANGE and
573 				UPD_NODE_NO_SIZE_CHANGE, ORed */
574 	/*----------------------*/
575 	/* Local storage for this graph node */
576 	ulint		state;	/*!< node execution state */
577 	dict_index_t*	index;	/*!< NULL, or the next index whose record should
578 				be updated */
579 	dtuple_t*	row;	/*!< NULL, or a copy (also fields copied to
580 				heap) of the row to update; this must be reset
581 				to NULL after a successful update */
582 	dtuple_t*	historical_row;	/*!< historical row used in
583 				CASCADE UPDATE/SET NULL;
584 				allocated from historical_heap  */
585 	mem_heap_t*	historical_heap; /*!< heap for historical row insertion;
586 				created when row to update is located;
587 				freed right before row update */
588 	row_ext_t*	ext;	/*!< NULL, or prefixes of the externally
589 				stored columns in the old row */
590 	dtuple_t*	upd_row;/* NULL, or a copy of the updated row */
591 	row_ext_t*	upd_ext;/* NULL, or prefixes of the externally
592 				stored columns in upd_row */
593 	mem_heap_t*	heap;	/*!< memory heap used as auxiliary storage;
594 				this must be emptied after a successful
595 				update */
596 	/*----------------------*/
597 	sym_node_t*	table_sym;/* table node in symbol table */
598 	que_node_t*	col_assign_list;
599 				/* column assignment list */
600 	ulint		magic_n;
601 
602 private:
603 	/** Appends row_start or row_end field to update vector and sets a
604 	CURRENT_TIMESTAMP/trx->id value to it.
605 	Supposed to be called only by make_versioned_update() and
606 	make_versioned_delete().
607 	@param[in]	trx	transaction
608 	@param[in]	vers_sys_idx	table->row_start or table->row_end */
609   void vers_update_fields(const trx_t *trx, ulint idx);
610 
611 public:
612 	/** Also set row_start = CURRENT_TIMESTAMP/trx->id
613 	@param[in]	trx	transaction */
vers_make_updateupd_node_t614   void vers_make_update(const trx_t *trx)
615   {
616     vers_update_fields(trx, table->vers_start);
617         }
618 
619 	/** Only set row_end = CURRENT_TIMESTAMP/trx->id.
620 	Do not touch other fields at all.
621 	@param[in]	trx	transaction */
vers_make_deleteupd_node_t622         void vers_make_delete(const trx_t *trx)
623         {
624 		update->n_fields = 0;
625 		is_delete = VERSIONED_DELETE;
626                 vers_update_fields(trx, table->vers_end);
627         }
628 };
629 
630 #define	UPD_NODE_MAGIC_N	1579975
631 
632 /* Node execution states */
633 #define UPD_NODE_SET_IX_LOCK	   1	/* execution came to the node from
634 					a node above and if the field
635 					has_clust_rec_x_lock is FALSE, we
636 					should set an intention x-lock on
637 					the table */
638 #define UPD_NODE_UPDATE_CLUSTERED  2	/* clustered index record should be
639 					updated */
640 #define UPD_NODE_INSERT_CLUSTERED  3	/* clustered index record should be
641 					inserted, old record is already delete
642 					marked */
643 #define UPD_NODE_UPDATE_ALL_SEC	   5	/* an ordering field of the clustered
644 					index record was changed, or this is
645 					a delete operation: should update
646 					all the secondary index records */
647 #define UPD_NODE_UPDATE_SOME_SEC   6	/* secondary index entries should be
648 					looked at and updated if an ordering
649 					field changed */
650 
651 /* Compilation info flags: these must fit within 3 bits; see trx0rec.h */
652 #define UPD_NODE_NO_ORD_CHANGE	1	/* no secondary index record will be
653 					changed in the update and no ordering
654 					field of the clustered index */
655 #define UPD_NODE_NO_SIZE_CHANGE	2	/* no record field size will be
656 					changed in the update */
657 
658 
659 #include "row0upd.inl"
660 
661 #endif
662