1
/******************************************************
2
Interface between Innobase row operations and MySQL.
3
Contains also create table and other data dictionary operations.
7
Created 9/17/2000 Heikki Tuuri
8
*******************************************************/
14
#include "data0data.h"
15
#include "que0types.h"
16
#include "dict0types.h"
17
#include "trx0types.h"
18
#include "row0types.h"
20
#include "trx0types.h"
22
extern ibool row_rollback_on_timeout;
24
typedef struct row_prebuilt_struct row_prebuilt_t;
26
/***********************************************************************
27
Frees the blob heap in prebuilt when no longer needed. */
30
row_mysql_prebuilt_free_blob_heap(
31
/*==============================*/
32
row_prebuilt_t* prebuilt); /* in: prebuilt struct of a
33
ha_innobase:: table handle */
34
/***********************************************************************
35
Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
39
row_mysql_store_true_var_len(
40
/*=========================*/
41
/* out: pointer to the data, we skip the 1 or 2 bytes
42
at the start that are used to store the len */
43
byte* dest, /* in: where to store */
44
ulint len, /* in: length, must fit in two bytes */
45
ulint lenlen);/* in: storage length of len: either 1 or 2 bytes */
46
/***********************************************************************
47
Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
48
returns a pointer to the data. */
51
row_mysql_read_true_varchar(
52
/*========================*/
53
/* out: pointer to the data, we skip the 1 or 2 bytes
54
at the start that are used to store the len */
55
ulint* len, /* out: variable-length field length */
56
byte* field, /* in: field in the MySQL format */
57
ulint lenlen);/* in: storage length of len: either 1 or 2 bytes */
58
/***********************************************************************
59
Stores a reference to a BLOB in the MySQL format. */
62
row_mysql_store_blob_ref(
63
/*=====================*/
64
byte* dest, /* in: where to store */
65
ulint col_len, /* in: dest buffer size: determines into
66
how many bytes the BLOB length is stored,
67
this may vary from 1 to 4 bytes */
68
byte* data, /* in: BLOB data */
69
ulint len); /* in: BLOB length */
70
/***********************************************************************
71
Reads a reference to a BLOB in the MySQL format. */
74
row_mysql_read_blob_ref(
75
/*====================*/
76
/* out: pointer to BLOB data */
77
ulint* len, /* out: BLOB length */
78
byte* ref, /* in: BLOB reference in the MySQL format */
79
ulint col_len); /* in: BLOB reference length (not BLOB
81
/******************************************************************
82
Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
83
The counterpart of this function is row_sel_field_store_in_mysql_format() in
87
row_mysql_store_col_in_innobase_format(
88
/*===================================*/
89
/* out: up to which byte we used
90
buf in the conversion */
91
dfield_t* dfield, /* in/out: dfield where dtype
92
information must be already set when
93
this function is called! */
94
byte* buf, /* in/out: buffer for a converted
95
integer value; this must be at least
97
ibool row_format_col, /* TRUE if the mysql_data is from
98
a MySQL row, FALSE if from a MySQL
100
in MySQL, a true VARCHAR storage
101
format differs in a row and in a
102
key value: in a key value the length
103
is always stored in 2 bytes! */
104
byte* mysql_data, /* in: MySQL column value, not
105
SQL NULL; NOTE that dfield may also
106
get a pointer to mysql_data,
107
therefore do not discard this as long
108
as dfield is used! */
109
ulint col_len, /* in: MySQL column length; NOTE that
110
this is the storage length of the
111
column in the MySQL format row, not
112
necessarily the length of the actual
113
payload data; if the column is a true
114
VARCHAR then this is irrelevant */
115
ulint comp); /* in: nonzero=compact format */
116
/********************************************************************
117
Handles user errors and lock waits detected by the database engine. */
120
row_mysql_handle_errors(
121
/*====================*/
122
/* out: TRUE if it was a lock wait and
123
we should continue running the query thread */
124
ulint* new_err,/* out: possible new error encountered in
125
rollback, or the old error which was
126
during the function entry */
127
trx_t* trx, /* in: transaction */
128
que_thr_t* thr, /* in: query thread */
129
trx_savept_t* savept);/* in: savepoint */
130
/************************************************************************
131
Create a prebuilt struct for a MySQL table handle. */
136
/* out, own: a prebuilt struct */
137
dict_table_t* table); /* in: Innobase table handle */
138
/************************************************************************
139
Free a prebuilt struct for a MySQL table handle. */
144
row_prebuilt_t* prebuilt); /* in, own: prebuilt struct */
145
/*************************************************************************
146
Updates the transaction pointers in query graphs stored in the prebuilt
150
row_update_prebuilt_trx(
151
/*====================*/
152
/* out: prebuilt dtuple */
153
row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL
155
trx_t* trx); /* in: transaction handle */
156
/*************************************************************************
157
Unlocks an AUTO_INC type lock possibly reserved by trx. */
160
row_unlock_table_autoinc_for_mysql(
161
/*===============================*/
162
trx_t* trx); /* in: transaction */
163
/*************************************************************************
164
Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
165
AUTO_INC lock gives exclusive access to the auto-inc counter of the
166
table. The lock is reserved only for the duration of an SQL statement.
167
It is not compatible with another AUTO_INC or exclusive lock on the
171
row_lock_table_autoinc_for_mysql(
172
/*=============================*/
173
/* out: error code or DB_SUCCESS */
174
row_prebuilt_t* prebuilt); /* in: prebuilt struct in the MySQL
176
/*************************************************************************
177
Sets a table lock on the table mentioned in prebuilt. */
180
row_lock_table_for_mysql(
181
/*=====================*/
182
/* out: error code or DB_SUCCESS */
183
row_prebuilt_t* prebuilt, /* in: prebuilt struct in the MySQL
185
dict_table_t* table, /* in: table to lock, or NULL
186
if prebuilt->table should be
188
prebuilt->select_lock_type */
189
ulint mode); /* in: lock mode of table
190
(ignored if table==NULL) */
192
/*************************************************************************
193
Does an insert for MySQL. */
196
row_insert_for_mysql(
197
/*=================*/
198
/* out: error code or DB_SUCCESS */
199
byte* mysql_rec, /* in: row in the MySQL format */
200
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
202
/*************************************************************************
203
Builds a dummy query graph used in selects. */
206
row_prebuild_sel_graph(
207
/*===================*/
208
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
210
/*************************************************************************
211
Gets pointer to a prebuilt update vector used in updates. If the update
212
graph has not yet been built in the prebuilt struct, then this function
216
row_get_prebuilt_update_vector(
217
/*===========================*/
218
/* out: prebuilt update vector */
219
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
221
/*************************************************************************
222
Checks if a table is such that we automatically created a clustered
223
index on it (on row id). */
226
row_table_got_default_clust_index(
227
/*==============================*/
228
dict_table_t* table);
229
/*************************************************************************
230
Calculates the key number used inside MySQL for an Innobase index. We have
231
to take into account if we generated a default clustered index for the table */
234
row_get_mysql_key_number_for_index(
235
/*===============================*/
236
dict_index_t* index);
237
/*************************************************************************
238
Does an update or delete of a row for MySQL. */
241
row_update_for_mysql(
242
/*=================*/
243
/* out: error code or DB_SUCCESS */
244
byte* mysql_rec, /* in: the row to be updated, in
246
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
248
/*************************************************************************
249
This can only be used when srv_locks_unsafe_for_binlog is TRUE or
250
session is using a READ COMMITTED isolation level. Before
251
calling this function we must use trx_reset_new_rec_lock_info() and
252
trx_register_new_rec_lock() to store the information which new record locks
253
really were set. This function removes a newly set lock under prebuilt->pcur,
254
and also under prebuilt->clust_pcur. Currently, this is only used and tested
255
in the case of an UPDATE or a DELETE statement, where the row lock is of the
257
Thus, this implements a 'mini-rollback' that releases the latest record
261
row_unlock_for_mysql(
262
/*=================*/
263
/* out: error code or DB_SUCCESS */
264
row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL
266
ibool has_latches_on_recs);/* TRUE if called so that we have
267
the latches on the records under pcur
268
and clust_pcur, and we do not need to
269
reposition the cursors. */
270
/*************************************************************************
271
Creates an query graph node of 'update' type to be used in the MySQL
275
row_create_update_node_for_mysql(
276
/*=============================*/
277
/* out, own: update node */
278
dict_table_t* table, /* in: table to update */
279
mem_heap_t* heap); /* in: mem heap from which allocated */
280
/**************************************************************************
281
Does a cascaded delete or set null in a foreign key operation. */
284
row_update_cascade_for_mysql(
285
/*=========================*/
286
/* out: error code or DB_SUCCESS */
287
que_thr_t* thr, /* in: query thread */
288
upd_node_t* node, /* in: update node used in the cascade
289
or set null operation */
290
dict_table_t* table); /* in: table where we do the operation */
291
/*************************************************************************
292
Locks the data dictionary exclusively for performing a table create or other
293
data dictionary modification operation. */
296
row_mysql_lock_data_dictionary(
297
/*===========================*/
298
trx_t* trx); /* in: transaction */
299
/*************************************************************************
300
Unlocks the data dictionary exclusive lock. */
303
row_mysql_unlock_data_dictionary(
304
/*=============================*/
305
trx_t* trx); /* in: transaction */
306
/*************************************************************************
307
Locks the data dictionary in shared mode from modifications, for performing
308
foreign key check, rollback, or other operation invisible to MySQL. */
311
row_mysql_freeze_data_dictionary(
312
/*=============================*/
313
trx_t* trx); /* in: transaction */
314
/*************************************************************************
315
Unlocks the data dictionary shared lock. */
318
row_mysql_unfreeze_data_dictionary(
319
/*===============================*/
320
trx_t* trx); /* in: transaction */
321
/*************************************************************************
322
Drops a table for MySQL. If the name of the table ends in
323
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
324
"innodb_table_monitor", then this will also start the printing of monitor
325
output by the master thread. If the table name ends in "innodb_mem_validate",
326
InnoDB will try to invoke mem_validate(). */
329
row_create_table_for_mysql(
330
/*=======================*/
331
/* out: error code or DB_SUCCESS */
332
dict_table_t* table, /* in: table definition */
333
trx_t* trx); /* in: transaction handle */
334
/*************************************************************************
335
Does an index creation operation for MySQL. TODO: currently failure
336
to create an index results in dropping the whole table! This is no problem
337
currently as all indexes must be created at the same time as the table. */
340
row_create_index_for_mysql(
341
/*=======================*/
342
/* out: error number or DB_SUCCESS */
343
dict_index_t* index, /* in: index definition */
344
trx_t* trx, /* in: transaction handle */
345
const ulint* field_lengths); /* in: if not NULL, must contain
346
dict_index_get_n_fields(index)
347
actual field lengths for the
348
index columns, which are
349
then checked for not being too
351
/*************************************************************************
352
Scans a table create SQL string and adds to the data dictionary
353
the foreign key constraints declared in the string. This function
354
should be called after the indexes for a table have been created.
355
Each foreign key constraint must be accompanied with indexes in
356
bot participating tables. The indexes are allowed to contain more
357
fields than mentioned in the constraint. */
360
row_table_add_foreign_constraints(
361
/*==============================*/
362
/* out: error code or DB_SUCCESS */
363
trx_t* trx, /* in: transaction */
364
const char* sql_string, /* in: table create statement where
365
foreign keys are declared like:
366
FOREIGN KEY (a, b) REFERENCES table2(c, d),
367
table2 can be written also with the
368
database name before it: test.table2 */
369
const char* name, /* in: table full name in the
371
database_name/table_name */
372
ibool reject_fks); /* in: if TRUE, fail with error
373
code DB_CANNOT_ADD_CONSTRAINT if
374
any foreign keys are found. */
376
/*************************************************************************
377
The master thread in srv0srv.c calls this regularly to drop tables which
378
we must drop in background after queries to them have ended. Such lazy
379
dropping of tables is needed in ALTER TABLE on Unix. */
382
row_drop_tables_for_mysql_in_background(void);
383
/*=========================================*/
384
/* out: how many tables dropped
385
+ remaining tables in list */
386
/*************************************************************************
387
Get the background drop list length. NOTE: the caller must own the kernel
391
row_get_background_drop_list_len_low(void);
392
/*======================================*/
393
/* out: how many tables in list */
394
/*************************************************************************
395
Truncates a table for MySQL. */
398
row_truncate_table_for_mysql(
399
/*=========================*/
400
/* out: error code or DB_SUCCESS */
401
dict_table_t* table, /* in: table handle */
402
trx_t* trx); /* in: transaction handle */
403
/*************************************************************************
404
Drops a table for MySQL. If the name of the dropped table ends in
405
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
406
"innodb_table_monitor", then this will also stop the printing of monitor
407
output by the master thread. */
410
row_drop_table_for_mysql(
411
/*=====================*/
412
/* out: error code or DB_SUCCESS */
413
const char* name, /* in: table name */
414
trx_t* trx, /* in: transaction handle */
415
ibool drop_db);/* in: TRUE=dropping whole database */
417
/*************************************************************************
418
Discards the tablespace of a table which stored in an .ibd file. Discarding
419
means that this function deletes the .ibd file and assigns a new table id for
420
the table. Also the flag table->ibd_file_missing is set TRUE. */
423
row_discard_tablespace_for_mysql(
424
/*=============================*/
425
/* out: error code or DB_SUCCESS */
426
const char* name, /* in: table name */
427
trx_t* trx); /* in: transaction handle */
428
/*********************************************************************
429
Imports a tablespace. The space id in the .ibd file must match the space id
430
of the table in the data dictionary. */
433
row_import_tablespace_for_mysql(
434
/*============================*/
435
/* out: error code or DB_SUCCESS */
436
const char* name, /* in: table name */
437
trx_t* trx); /* in: transaction handle */
438
/*************************************************************************
439
Drops a database for MySQL. */
442
row_drop_database_for_mysql(
443
/*========================*/
444
/* out: error code or DB_SUCCESS */
445
const char* name, /* in: database name which ends to '/' */
446
trx_t* trx); /* in: transaction handle */
447
/*************************************************************************
448
Renames a table for MySQL. */
451
row_rename_table_for_mysql(
452
/*=======================*/
453
/* out: error code or DB_SUCCESS */
454
const char* old_name, /* in: old table name */
455
const char* new_name, /* in: new table name */
456
trx_t* trx); /* in: transaction handle */
457
/*************************************************************************
458
Checks a table for corruption. */
461
row_check_table_for_mysql(
462
/*======================*/
463
/* out: DB_ERROR or DB_SUCCESS */
464
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
467
/* A struct describing a place for an individual column in the MySQL
468
row format which is presented to the table handler in ha_innobase.
469
This template struct is used to speed up row transformations between
470
Innobase and MySQL. */
472
typedef struct mysql_row_templ_struct mysql_row_templ_t;
473
struct mysql_row_templ_struct {
474
ulint col_no; /* column number of the column */
475
ulint rec_field_no; /* field number of the column in an
476
Innobase record in the current index;
477
not defined if template_type is
478
ROW_MYSQL_WHOLE_ROW */
479
ulint mysql_col_offset; /* offset of the column in the MySQL
481
ulint mysql_col_len; /* length of the column in the MySQL
483
ulint mysql_null_byte_offset; /* MySQL NULL bit byte offset in a
485
ulint mysql_null_bit_mask; /* bit mask to get the NULL bit,
486
zero if column cannot be NULL */
487
ulint type; /* column type in Innobase mtype
488
numbers DATA_CHAR... */
489
ulint mysql_type; /* MySQL type code; this is always
491
ulint mysql_length_bytes; /* if mysql_type
492
== DATA_MYSQL_TRUE_VARCHAR, this tells
493
whether we should use 1 or 2 bytes to
494
store the MySQL true VARCHAR data
495
length at the start of row in the MySQL
496
format (NOTE that the MySQL key value
497
format always uses 2 bytes for the data
499
ulint charset; /* MySQL charset-collation code
500
of the column, or zero */
501
ulint mbminlen; /* minimum length of a char, in bytes,
502
or zero if not a char type */
503
ulint mbmaxlen; /* maximum length of a char, in bytes,
504
or zero if not a char type */
505
ulint is_unsigned; /* if a column type is an integer
506
type and this field is != 0, then
507
it is an unsigned integer type */
510
#define MYSQL_FETCH_CACHE_SIZE 8
511
/* After fetching this many rows, we start caching them in fetch_cache */
512
#define MYSQL_FETCH_CACHE_THRESHOLD 4
514
#define ROW_PREBUILT_ALLOCATED 78540783
515
#define ROW_PREBUILT_FREED 26423527
517
typedef my_bool (*index_cond_func_t)(void *param);
519
/* A struct for (sometimes lazily) prebuilt structures in an Innobase table
520
handle used within MySQL; these are used to save CPU time. */
522
struct row_prebuilt_struct {
523
ulint magic_n; /* this magic number is set to
524
ROW_PREBUILT_ALLOCATED when created
525
and to ROW_PREBUILT_FREED when the
526
struct has been freed; used in
528
dict_table_t* table; /* Innobase table handle */
529
trx_t* trx; /* current transaction handle */
530
ibool sql_stat_start; /* TRUE when we start processing of
531
an SQL statement: we may have to set
532
an intention lock on the table,
533
create a consistent read view etc. */
534
ibool mysql_has_locked; /* this is set TRUE when MySQL
535
calls external_lock on this handle
536
with a lock flag, and set FALSE when
537
with the F_UNLOCK flag */
538
ibool clust_index_was_generated;
539
/* if the user did not define a
540
primary key in MySQL, then Innobase
541
automatically generated a clustered
542
index where the ordering column is
543
the row id: in this case this flag
545
dict_index_t* index; /* current index for a search, if
547
ulint read_just_key; /* set to 1 when MySQL calls
548
ha_innobase::extra with the
549
argument HA_EXTRA_KEYREAD; it is enough
550
to read just columns defined in
551
the index (i.e., no read of the
552
clustered index record necessary) */
553
ibool used_in_HANDLER;/* TRUE if we have been using this
554
handle in a MySQL HANDLER low level
555
index cursor command: then we must
556
store the pcur position even in a
557
unique search from a clustered index,
558
because HANDLER allows NEXT and PREV
559
in such a situation */
560
ulint template_type; /* ROW_MYSQL_WHOLE_ROW,
561
ROW_MYSQL_REC_FIELDS,
562
ROW_MYSQL_DUMMY_TEMPLATE, or
563
ROW_MYSQL_NO_TEMPLATE */
564
ulint n_template; /* number of elements in the
566
ulint null_bitmap_len;/* number of bytes in the SQL NULL
567
bitmap at the start of a row in the
569
ibool need_to_access_clustered; /* if we are fetching
570
columns through a secondary index
571
and at least one column is not in
572
the secondary index, then this is
574
ibool templ_contains_blob;/* TRUE if the template contains
576
mysql_row_templ_t* mysql_template;/* template used to transform
577
rows fast between MySQL and Innobase
578
formats; memory for this template
579
is not allocated from 'heap' */
580
mem_heap_t* heap; /* memory heap from which
581
these auxiliary structures are
582
allocated when needed */
583
ins_node_t* ins_node; /* Innobase SQL insert node
584
used to perform inserts
586
byte* ins_upd_rec_buff;/* buffer for storing data converted
587
to the Innobase format from the MySQL
589
ulint hint_need_to_fetch_extra_cols;
590
/* normally this is set to 0; if this
591
is set to ROW_RETRIEVE_PRIMARY_KEY,
592
then we should at least retrieve all
593
columns in the primary key; if this
594
is set to ROW_RETRIEVE_ALL_COLS, then
595
we must retrieve all columns in the
596
key (if read_just_key == 1), or all
597
columns in the table */
598
upd_node_t* upd_node; /* Innobase SQL update node used
599
to perform updates and deletes */
600
que_fork_t* ins_graph; /* Innobase SQL query graph used
602
que_fork_t* upd_graph; /* Innobase SQL query graph used
603
in updates or deletes */
604
btr_pcur_t* pcur; /* persistent cursor used in selects
606
btr_pcur_t* clust_pcur; /* persistent cursor used in
607
some selects and updates */
608
que_fork_t* sel_graph; /* dummy query graph used in
610
dtuple_t* search_tuple; /* prebuilt dtuple used in selects */
611
byte row_id[DATA_ROW_ID_LEN];
612
/* if the clustered index was
613
generated, the row id of the
614
last row fetched is stored
616
dtuple_t* clust_ref; /* prebuilt dtuple used in
618
ulint select_lock_type;/* LOCK_NONE, LOCK_S, or LOCK_X */
619
ulint stored_select_lock_type;/* this field is used to
620
remember the original select_lock_type
621
that was decided in ha_innodb.cc,
622
::store_lock(), ::external_lock(),
624
ulint row_read_type; /* ROW_READ_WITH_LOCKS if row locks
625
should be the obtained for records
626
under an UPDATE or DELETE cursor.
627
If innodb_locks_unsafe_for_binlog
628
is TRUE, this can be set to
629
ROW_READ_TRY_SEMI_CONSISTENT, so that
630
if the row under an UPDATE or DELETE
631
cursor was locked by another
632
transaction, InnoDB will resort
633
to reading the last committed value
634
('semi-consistent read'). Then,
635
this field will be set to
636
ROW_READ_DID_SEMI_CONSISTENT to
637
indicate that. If the row does not
638
match the WHERE condition, MySQL will
639
invoke handler::unlock_row() to
640
clear the flag back to
641
ROW_READ_TRY_SEMI_CONSISTENT and
642
to simply skip the row. If
643
the row matches, the next call to
644
row_search_for_mysql() will lock
646
This eliminates lock waits in some
647
cases; note that this breaks
649
ulint mysql_prefix_len;/* byte offset of the end of
650
the last requested column */
651
ulint mysql_row_len; /* length in bytes of a row in the
653
ulint n_rows_fetched; /* number of rows fetched after
654
positioning the current cursor */
655
ulint fetch_direction;/* ROW_SEL_NEXT or ROW_SEL_PREV */
656
byte* fetch_cache[MYSQL_FETCH_CACHE_SIZE];
657
/* a cache for fetched rows if we
658
fetch many rows from the same cursor:
659
it saves CPU time to fetch them in a
660
batch; we reserve mysql_row_len
661
bytes for each such row; these
662
pointers point 4 bytes past the
663
allocated mem buf start, because
664
there is a 4 byte magic number at the
665
start and at the end */
666
ibool keep_other_fields_on_keyread; /* when using fetch
667
cache with HA_EXTRA_KEYREAD, don't
668
overwrite other fields in mysql row
670
ulint fetch_cache_first;/* position of the first not yet
671
fetched row in fetch_cache */
672
ulint n_fetch_cached; /* number of not yet fetched rows
674
mem_heap_t* blob_heap; /* in SELECTS BLOB fields are copied
676
mem_heap_t* old_vers_heap; /* memory heap where a previous
677
version is built in consistent read */
678
ulonglong last_value; /* last value of AUTO-INC interval */
680
index_cond_func_t idx_cond_func;/* Index Condition Pushdown function,
681
or NULL if there is none set */
682
void* idx_cond_func_arg;/* ICP function argument */
683
ulint n_index_fields; /* Number of fields at the start of
684
mysql_template. Valid only when using
686
ulint magic_n2; /* this should be the same as
690
#define ROW_PREBUILT_FETCH_MAGIC_N 465765687
692
#define ROW_MYSQL_WHOLE_ROW 0
693
#define ROW_MYSQL_REC_FIELDS 1
694
#define ROW_MYSQL_NO_TEMPLATE 2
695
#define ROW_MYSQL_DUMMY_TEMPLATE 3 /* dummy template used in
696
row_scan_and_check_index */
698
/* Values for hint_need_to_fetch_extra_cols */
699
#define ROW_RETRIEVE_PRIMARY_KEY 1
700
#define ROW_RETRIEVE_ALL_COLS 2
702
/* Values for row_read_type */
703
#define ROW_READ_WITH_LOCKS 0
704
#define ROW_READ_TRY_SEMI_CONSISTENT 1
705
#define ROW_READ_DID_SEMI_CONSISTENT 2
708
#include "row0mysql.ic"