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 	uint16_t	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 	uint16_t	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 	uint16_t	no,	/*!< in: field_no */
101 	bool		is_virtual) /*!< in: if it is a virtual column */
102 	MY_ATTRIBUTE((warn_unused_result));
103 /*********************************************************************//**
104 Creates an update node for a query graph.
105 @return own: update node */
106 upd_node_t*
107 upd_node_create(
108 /*============*/
109 	mem_heap_t*	heap);	/*!< in: mem heap where created */
110 /***********************************************************//**
111 Returns TRUE if row update changes size of some field in index or if some
112 field to be updated is stored externally in rec or update.
113 @return TRUE if the update changes the size of some field in index or
114 the field is external in rec or update */
115 ibool
116 row_upd_changes_field_size_or_external(
117 /*===================================*/
118 	dict_index_t*	index,	/*!< in: index */
119 	const rec_offs*	offsets,/*!< in: rec_get_offsets(rec, index) */
120 	const upd_t*	update);/*!< in: update vector */
121 /***********************************************************//**
122 Returns true if row update contains disowned external fields.
123 @return true if the update contains disowned external fields. */
124 bool
125 row_upd_changes_disowned_external(
126 /*==============================*/
127 	const upd_t*	update)	/*!< in: update vector */
128 	MY_ATTRIBUTE((nonnull, warn_unused_result));
129 
130 /***************************************************************//**
131 Builds an update vector from those fields which in a secondary index entry
132 differ from a record that has the equal ordering fields. NOTE: we compare
133 the fields as binary strings!
134 @return own: update vector of differing fields */
135 upd_t*
136 row_upd_build_sec_rec_difference_binary(
137 /*====================================*/
138 	const rec_t*	rec,	/*!< in: secondary index record */
139 	dict_index_t*	index,	/*!< in: index */
140 	const rec_offs*	offsets,/*!< in: rec_get_offsets(rec, index) */
141 	const dtuple_t*	entry,	/*!< in: entry to insert */
142 	mem_heap_t*	heap)	/*!< in: memory heap from which allocated */
143 	MY_ATTRIBUTE((warn_unused_result, nonnull));
144 /** Builds an update vector from those fields, excluding the roll ptr and
145 trx id fields, which in an index entry differ from a record that has
146 the equal ordering fields. NOTE: we compare the fields as binary strings!
147 @param[in]	index		clustered index
148 @param[in]	entry		clustered index entry to insert
149 @param[in]	rec		clustered index record
150 @param[in]	offsets		rec_get_offsets(rec,index), or NULL
151 @param[in]	no_sys		skip the system columns
152 				DB_TRX_ID and DB_ROLL_PTR
153 @param[in]	trx		transaction (for diagnostics),
154 				or NULL
155 @param[in]	heap		memory heap from which allocated
156 @param[in,out]	mysql_table	NULL, or mysql table object when
157 				user thread invokes dml
158 @param[out]	error		error number in case of failure
159 @return own: update vector of differing fields, excluding roll ptr and
160 trx id */
161 upd_t*
162 row_upd_build_difference_binary(
163 	dict_index_t*	index,
164 	const dtuple_t*	entry,
165 	const rec_t*	rec,
166 	const rec_offs*	offsets,
167 	bool		no_sys,
168 	trx_t*		trx,
169 	mem_heap_t*	heap,
170 	TABLE*		mysql_table,
171 	dberr_t*	error)
172 	MY_ATTRIBUTE((nonnull(1,2,3,7,9), warn_unused_result));
173 /** Apply an update vector to an index entry.
174 @param[in,out]	entry	index entry to be updated; the clustered index record
175 			must be covered by a lock or a page latch to prevent
176 			deletion (rollback or purge)
177 @param[in]	index	index of the entry
178 @param[in]	update	update vector built for the entry
179 @param[in,out]	heap	memory heap for copying off-page columns */
180 void
181 row_upd_index_replace_new_col_vals_index_pos(
182 	dtuple_t*		entry,
183 	const dict_index_t*	index,
184 	const upd_t*		update,
185 	mem_heap_t*		heap)
186 	MY_ATTRIBUTE((nonnull));
187 /** Replace the new column values stored in the update vector,
188 during trx_undo_prev_version_build().
189 @param entry   clustered index tuple where the values are replaced
190                (the clustered index leaf page latch must be held)
191 @param index   clustered index
192 @param update  update vector for the clustered index
193 @param heap    memory heap for allocating and copying values
194 @return whether the previous version was built successfully */
195 bool
196 row_upd_index_replace_new_col_vals(dtuple_t *entry, const dict_index_t &index,
197                                    const upd_t *update, mem_heap_t *heap)
198   MY_ATTRIBUTE((nonnull, warn_unused_result));
199 /***********************************************************//**
200 Replaces the new column values stored in the update vector. */
201 void
202 row_upd_replace(
203 /*============*/
204 	dtuple_t*		row,	/*!< in/out: row where replaced,
205 					indexed by col_no;
206 					the clustered index record must be
207 					covered by a lock or a page latch to
208 					prevent deletion (rollback or purge) */
209 	row_ext_t**		ext,	/*!< out, own: NULL, or externally
210 					stored column prefixes */
211 	const dict_index_t*	index,	/*!< in: clustered index */
212 	const upd_t*		update,	/*!< in: an update vector built for the
213 					clustered index */
214 	mem_heap_t*		heap);	/*!< in: memory heap */
215 /** Replaces the virtual column values stored in a dtuple with that of
216 a update vector.
217 @param[in,out]	row	dtuple whose column to be updated
218 @param[in]	table	table
219 @param[in]	update	an update vector built for the clustered index
220 @param[in]	upd_new	update to new or old value
221 @param[in,out]	undo_row undo row (if needs to be updated)
222 @param[in]	ptr	remaining part in update undo log */
223 void
224 row_upd_replace_vcol(
225 	dtuple_t*		row,
226 	const dict_table_t*	table,
227 	const upd_t*		update,
228 	bool			upd_new,
229 	dtuple_t*		undo_row,
230 	const byte*		ptr);
231 
232 /***********************************************************//**
233 Checks if an update vector changes an ordering field of an index record.
234 
235 This function is fast if the update vector is short or the number of ordering
236 fields in the index is small. Otherwise, this can be quadratic.
237 NOTE: we compare the fields as binary strings!
238 @return TRUE if update vector changes an ordering field in the index record */
239 ibool
240 row_upd_changes_ord_field_binary_func(
241 /*==================================*/
242 	dict_index_t*	index,	/*!< in: index of the record */
243 	const upd_t*	update,	/*!< in: update vector for the row; NOTE: the
244 				field numbers in this MUST be clustered index
245 				positions! */
246 #ifdef UNIV_DEBUG
247 	const que_thr_t*thr,	/*!< in: query thread */
248 #endif /* UNIV_DEBUG */
249 	const dtuple_t*	row,	/*!< in: old value of row, or NULL if the
250 				row and the data values in update are not
251 				known when this function is called, e.g., at
252 				compile time */
253 	const row_ext_t*ext,	/*!< NULL, or prefixes of the externally
254 				stored columns in the old row */
255 	ulint		flag)	/*!< in: ROW_BUILD_NORMAL,
256 				ROW_BUILD_FOR_PURGE or ROW_BUILD_FOR_UNDO */
257 	MY_ATTRIBUTE((nonnull(1,2), warn_unused_result));
258 #ifdef UNIV_DEBUG
259 # define row_upd_changes_ord_field_binary(index,update,thr,row,ext)	\
260 	row_upd_changes_ord_field_binary_func(index,update,thr,row,ext,0)
261 #else /* UNIV_DEBUG */
262 # define row_upd_changes_ord_field_binary(index,update,thr,row,ext)	\
263 	row_upd_changes_ord_field_binary_func(index,update,row,ext,0)
264 #endif /* UNIV_DEBUG */
265 /***********************************************************//**
266 Checks if an FTS indexed column is affected by an UPDATE.
267 @return offset within fts_t::indexes if FTS indexed column updated else
268 ULINT_UNDEFINED */
269 ulint
270 row_upd_changes_fts_column(
271 /*=======================*/
272 	dict_table_t*	table,		/*!< in: table */
273 	upd_field_t*	upd_field);	/*!< in: field to check */
274 /***********************************************************//**
275 Checks if an FTS Doc ID column is affected by an UPDATE.
276 @return whether Doc ID column is affected */
277 bool
278 row_upd_changes_doc_id(
279 /*===================*/
280 	dict_table_t*	table,		/*!< in: table */
281 	upd_field_t*	upd_field)	/*!< in: field to check */
282 	MY_ATTRIBUTE((nonnull, warn_unused_result));
283 /***********************************************************//**
284 Checks if an update vector changes an ordering field of an index record.
285 This function is fast if the update vector is short or the number of ordering
286 fields in the index is small. Otherwise, this can be quadratic.
287 NOTE: we compare the fields as binary strings!
288 @return TRUE if update vector may change an ordering field in an index
289 record */
290 ibool
291 row_upd_changes_some_index_ord_field_binary(
292 /*========================================*/
293 	const dict_table_t*	table,	/*!< in: table */
294 	const upd_t*		update);/*!< in: update vector for the row */
295 /***********************************************************//**
296 Updates a row in a table. This is a high-level function used
297 in SQL execution graphs.
298 @return query thread to run next or NULL */
299 que_thr_t*
300 row_upd_step(
301 /*=========*/
302 	que_thr_t*	thr);	/*!< in: query thread */
303 
304 /* Update vector field */
305 struct upd_field_t{
306 	uint16_t	field_no;	/*!< field number in an index, usually
307 					the clustered index, but in updating
308 					a secondary index record in btr0cur.cc
309 					this is the position in the secondary
310 					index. If this field is a virtual
311 					column, then field_no represents
312 					the nth virtual	column in the table */
313 	uint16_t	orig_len;	/*!< original length of the locally
314 					stored part of an externally stored
315 					column, or 0 */
316 	que_node_t*	exp;		/*!< expression for calculating a new
317 					value: it refers to column values and
318 					constants in the symbol table of the
319 					query graph */
320 	dfield_t	new_val;	/*!< new value for the column */
321 	dfield_t*	old_v_val;	/*!< old value for the virtual column */
322 };
323 
324 
325 /* check whether an update field is on virtual column */
326 #define upd_fld_is_virtual_col(upd_fld)			\
327 	(((upd_fld)->new_val.type.prtype & DATA_VIRTUAL) == DATA_VIRTUAL)
328 
329 /* set DATA_VIRTUAL bit on update field to show it is a virtual column */
330 #define upd_fld_set_virtual_col(upd_fld)			\
331 	((upd_fld)->new_val.type.prtype |= DATA_VIRTUAL)
332 
333 /* Update vector structure */
334 struct upd_t{
335 	mem_heap_t*	heap;		/*!< heap from which memory allocated */
336 	byte		info_bits;	/*!< new value of info bits to record;
337 					default is 0 */
338 	dtuple_t*	old_vrow;	/*!< pointer to old row, used for
339 					virtual column update now */
340 	ulint		n_fields;	/*!< number of update fields */
341 	upd_field_t*	fields;		/*!< array of update fields */
342 	byte		vers_sys_value[8]; /*!< buffer for updating system fields */
343 
344 	/** Append an update field to the end of array
345 	@param[in]	field	an update field */
appendupd_t346 	void append(const upd_field_t& field)
347 	{
348 		fields[n_fields++] = field;
349 	}
350 
remove_elementupd_t351         void remove_element(ulint i)
352         {
353           ut_ad(n_fields > 0);
354           ut_ad(i < n_fields);
355           while (i < n_fields - 1)
356           {
357             fields[i]= fields[i + 1];
358             i++;
359           }
360           n_fields--;
361         }
362 
removeupd_t363         bool remove(const ulint field_no)
364         {
365           for (ulint i= 0; i < n_fields; ++i)
366           {
367             if (field_no == fields[i].field_no)
368             {
369               remove_element(i);
370               return true;
371             }
372           }
373           return false;
374         }
375 
376         /** Determine if the given field_no is modified.
377 	@return true if modified, false otherwise.  */
is_modifiedupd_t378 	bool is_modified(uint16_t field_no) const
379 	{
380 		for (ulint i = 0; i < n_fields; ++i) {
381 			if (field_no == fields[i].field_no) {
382 				return(true);
383 			}
384 		}
385 		return(false);
386 	}
387 
388 	/** Determine if the update affects a system versioned column or row_end. */
affects_versionedupd_t389 	bool affects_versioned() const
390 	{
391 		for (ulint i = 0; i < n_fields; i++) {
392 			dtype_t type = fields[i].new_val.type;
393 			if (type.is_versioned()) {
394 				return true;
395 			}
396 			// versioned DELETE is UPDATE SET row_end=NOW
397 			if (type.vers_sys_end()) {
398 				return true;
399 			}
400 		}
401 		return false;
402 	}
403 
404 	/** @return whether this is for a hidden metadata record
405 	for instant ALTER TABLE */
is_metadataupd_t406 	bool is_metadata() const { return dtuple_t::is_metadata(info_bits); }
407 	/** @return whether this is for a hidden metadata record
408 	for instant ALTER TABLE (not only ADD COLUMN) */
is_alter_metadataupd_t409 	bool is_alter_metadata() const
410 	{ return dtuple_t::is_alter_metadata(info_bits); }
411 
412 #ifdef UNIV_DEBUG
validateupd_t413         bool validate() const
414         {
415                 for (ulint i = 0; i < n_fields; ++i) {
416                         dfield_t* field = &fields[i].new_val;
417                         if (dfield_is_ext(field)) {
418 				ut_ad(dfield_get_len(field)
419 				      >= BTR_EXTERN_FIELD_REF_SIZE);
420                         }
421                 }
422                 return(true);
423         }
424 #endif // UNIV_DEBUG
425 };
426 
427 /** Kinds of update operation */
428 enum delete_mode_t {
429 	NO_DELETE = 0,		/*!< this operation does not delete */
430 	PLAIN_DELETE,		/*!< ordinary delete */
431 	VERSIONED_DELETE	/*!< update old and insert a new row */
432 };
433 
434 /* Update node structure which also implements the delete operation
435 of a row */
436 
437 struct upd_node_t{
438 	que_common_t	common;	/*!< node type: QUE_NODE_UPDATE */
439 	delete_mode_t	is_delete;	/*!< kind of DELETE */
440 	ibool		searched_update;
441 				/* TRUE if searched update, FALSE if
442 				positioned */
443 	bool		in_mysql_interface;
444 				/* whether the update node was created
445 				for the MySQL interface */
446 	dict_foreign_t*	foreign;/* NULL or pointer to a foreign key
447 				constraint if this update node is used in
448 				doing an ON DELETE or ON UPDATE operation */
449 	upd_node_t*	cascade_node;/* NULL or an update node template which
450 				is used to implement ON DELETE/UPDATE CASCADE
451 				or ... SET NULL for foreign keys */
452 	mem_heap_t*	cascade_heap;
453 				/*!< NULL or a mem heap where cascade
454 				node is created.*/
455 	sel_node_t*	select;	/*!< query graph subtree implementing a base
456 				table cursor: the rows returned will be
457 				updated */
458 	btr_pcur_t*	pcur;	/*!< persistent cursor placed on the clustered
459 				index record which should be updated or
460 				deleted; the cursor is stored in the graph
461 				of 'select' field above, except in the case
462 				of the MySQL interface */
463 	dict_table_t*	table;	/*!< table where updated */
464 	upd_t*		update;	/*!< update vector for the row */
465 	ulint		update_n_fields;
466 				/* when this struct is used to implement
467 				a cascade operation for foreign keys, we store
468 				here the size of the buffer allocated for use
469 				as the update vector */
470 	sym_node_list_t	columns;/* symbol table nodes for the columns
471 				to retrieve from the table */
472 	ibool		has_clust_rec_x_lock;
473 				/* TRUE if the select which retrieves the
474 				records to update already sets an x-lock on
475 				the clustered record; note that it must always
476 				set at least an s-lock */
477 	ulint		cmpl_info;/* information extracted during query
478 				compilation; speeds up execution:
479 				UPD_NODE_NO_ORD_CHANGE and
480 				UPD_NODE_NO_SIZE_CHANGE, ORed */
481 	/*----------------------*/
482 	/* Local storage for this graph node */
483 	ulint		state;	/*!< node execution state */
484 	dict_index_t*	index;	/*!< NULL, or the next index whose record should
485 				be updated */
486 	dtuple_t*	row;	/*!< NULL, or a copy (also fields copied to
487 				heap) of the row to update; this must be reset
488 				to NULL after a successful update */
489 	dtuple_t*	historical_row;	/*!< historical row used in
490 				CASCADE UPDATE/SET NULL;
491 				allocated from historical_heap  */
492 	mem_heap_t*	historical_heap; /*!< heap for historical row insertion;
493 				created when row to update is located;
494 				freed right before row update */
495 	row_ext_t*	ext;	/*!< NULL, or prefixes of the externally
496 				stored columns in the old row */
497 	dtuple_t*	upd_row;/* NULL, or a copy of the updated row */
498 	row_ext_t*	upd_ext;/* NULL, or prefixes of the externally
499 				stored columns in upd_row */
500 	mem_heap_t*	heap;	/*!< memory heap used as auxiliary storage;
501 				this must be emptied after a successful
502 				update */
503 	/*----------------------*/
504 	sym_node_t*	table_sym;/* table node in symbol table */
505 	que_node_t*	col_assign_list;
506 				/* column assignment list */
507 	ulint		magic_n;
508 
509 private:
510 	/** Appends row_start or row_end field to update vector and sets a
511 	CURRENT_TIMESTAMP/trx->id value to it.
512 	Supposed to be called only by make_versioned_update() and
513 	make_versioned_delete().
514 	@param[in]	trx	transaction
515 	@param[in]	vers_sys_idx	table->row_start or table->row_end */
516   void vers_update_fields(const trx_t *trx, ulint idx);
517 
518 public:
519 	/** Also set row_start = CURRENT_TIMESTAMP/trx->id
520 	@param[in]	trx	transaction */
vers_make_updateupd_node_t521   void vers_make_update(const trx_t *trx)
522   {
523     vers_update_fields(trx, table->vers_start);
524         }
525 
526 	/** Only set row_end = CURRENT_TIMESTAMP/trx->id.
527 	Do not touch other fields at all.
528 	@param[in]	trx	transaction */
vers_make_deleteupd_node_t529         void vers_make_delete(const trx_t *trx)
530         {
531 		update->n_fields = 0;
532 		is_delete = VERSIONED_DELETE;
533                 vers_update_fields(trx, table->vers_end);
534         }
535 };
536 
537 #define	UPD_NODE_MAGIC_N	1579975
538 
539 /* Node execution states */
540 #define UPD_NODE_SET_IX_LOCK	   1	/* execution came to the node from
541 					a node above and if the field
542 					has_clust_rec_x_lock is FALSE, we
543 					should set an intention x-lock on
544 					the table */
545 #define UPD_NODE_UPDATE_CLUSTERED  2	/* clustered index record should be
546 					updated */
547 #define UPD_NODE_INSERT_CLUSTERED  3	/* clustered index record should be
548 					inserted, old record is already delete
549 					marked */
550 #define UPD_NODE_UPDATE_ALL_SEC	   5	/* an ordering field of the clustered
551 					index record was changed, or this is
552 					a delete operation: should update
553 					all the secondary index records */
554 #define UPD_NODE_UPDATE_SOME_SEC   6	/* secondary index entries should be
555 					looked at and updated if an ordering
556 					field changed */
557 
558 /* Compilation info flags: these must fit within 3 bits; see trx0rec.h */
559 #define UPD_NODE_NO_ORD_CHANGE	1	/* no secondary index record will be
560 					changed in the update and no ordering
561 					field of the clustered index */
562 #define UPD_NODE_NO_SIZE_CHANGE	2	/* no record field size will be
563 					changed in the update */
564 
565 
566 #include "row0upd.inl"
567 
568 #endif
569