dict0dict.c 127 KB
Newer Older
vasil's avatar
vasil committed
1 2
/*****************************************************************************

3
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
vasil's avatar
vasil committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA

*****************************************************************************/

19 20
/******************************************************************//**
@file dict/dict0dict.c
osku's avatar
osku committed
21 22 23 24 25 26 27 28 29 30 31
Data dictionary system

Created 1/8/1996 Heikki Tuuri
***********************************************************************/

#include "dict0dict.h"

#ifdef UNIV_NONINL
#include "dict0dict.ic"
#endif

32
/** dummy index for ROW_FORMAT=REDUNDANT supremum and infimum records */
33
UNIV_INTERN dict_index_t*	dict_ind_redundant;
34
/** dummy index for ROW_FORMAT=COMPACT supremum and infimum records */
35
UNIV_INTERN dict_index_t*	dict_ind_compact;
36

37
#ifndef UNIV_HOTBACKUP
osku's avatar
osku committed
38 39 40 41 42 43 44 45 46 47
#include "buf0buf.h"
#include "data0type.h"
#include "mach0data.h"
#include "dict0boot.h"
#include "dict0mem.h"
#include "dict0crea.h"
#include "trx0undo.h"
#include "btr0btr.h"
#include "btr0cur.h"
#include "btr0sea.h"
48 49
#include "page0zip.h"
#include "page0page.h"
osku's avatar
osku committed
50 51 52 53
#include "pars0pars.h"
#include "pars0sym.h"
#include "que0que.h"
#include "rem0cmp.h"
54
#include "row0merge.h"
55 56
#include "m_ctype.h" /* my_isspace() */
#include "ha_prototypes.h" /* innobase_strcasecmp() */
osku's avatar
osku committed
57

58 59
#include <ctype.h>

60
/** the dictionary system */
61 62
UNIV_INTERN dict_sys_t*	dict_sys	= NULL;

63 64 65
/** @brief the data dictionary rw-latch protecting dict_sys

table create, drop, etc. reserve this in X-mode; implicit or
66 67 68 69
backround operations purge, rollback, foreign key checks reserve this
in S-mode; we cannot trust that MySQL protects implicit or background
operations a table drop since MySQL does not know of them; therefore
we need this; NOTE: a transaction which reserves this must keep book
70
on the mode in trx_struct::dict_operation_lock_mode */
71
UNIV_INTERN rw_lock_t	dict_operation_lock;
osku's avatar
osku committed
72

73
#define	DICT_HEAP_SIZE		100	/*!< initial memory heap size when
osku's avatar
osku committed
74
					creating a table or index object */
75
#define DICT_POOL_PER_TABLE_HASH 512	/*!< buffer pool max size per table
osku's avatar
osku committed
76
					hash table fixed size in bytes */
77
#define DICT_POOL_PER_VARYING	4	/*!< buffer pool max size per data
osku's avatar
osku committed
78 79
					dictionary varying size in bytes */

80
/** Identifies generated InnoDB foreign key names */
osku's avatar
osku committed
81 82
static char	dict_ibfk[] = "_ibfk_";

83
/** array of mutexes protecting dict_index_t::stat_n_diff_key_vals[] */
84
#define DICT_INDEX_STAT_MUTEX_SIZE	32
85
static mutex_t	dict_index_stat_mutex[DICT_INDEX_STAT_MUTEX_SIZE];
86

87
/*******************************************************************//**
88
Tries to find column names for the index and sets the col field of the
89 90
index.
@return TRUE if the column names were found */
osku's avatar
osku committed
91
static
92
ibool
osku's avatar
osku committed
93 94
dict_index_find_cols(
/*=================*/
95 96
	dict_table_t*	table,	/*!< in: table */
	dict_index_t*	index);	/*!< in: index */
97
/*******************************************************************//**
osku's avatar
osku committed
98
Builds the internal dictionary cache representation for a clustered
99 100
index, containing also system fields not defined by the user.
@return	own: the internal representation of the clustered index */
osku's avatar
osku committed
101 102 103 104
static
dict_index_t*
dict_index_build_internal_clust(
/*============================*/
105 106
	const dict_table_t*	table,	/*!< in: table */
	dict_index_t*		index);	/*!< in: user representation of
107
					a clustered index */
108
/*******************************************************************//**
osku's avatar
osku committed
109
Builds the internal dictionary cache representation for a non-clustered
110 111
index, containing also system fields not defined by the user.
@return	own: the internal representation of the non-clustered index */
osku's avatar
osku committed
112 113 114 115
static
dict_index_t*
dict_index_build_internal_non_clust(
/*================================*/
116 117
	const dict_table_t*	table,	/*!< in: table */
	dict_index_t*		index);	/*!< in: user representation of
118
					a non-clustered index */
119
/**********************************************************************//**
osku's avatar
osku committed
120 121 122 123 124
Removes a foreign constraint struct from the dictionary cache. */
static
void
dict_foreign_remove_from_cache(
/*===========================*/
125
	dict_foreign_t*	foreign);	/*!< in, own: foreign constraint */
126
/**********************************************************************//**
osku's avatar
osku committed
127 128 129 130 131
Prints a column data. */
static
void
dict_col_print_low(
/*===============*/
132 133
	const dict_table_t*	table,	/*!< in: table */
	const dict_col_t*	col);	/*!< in: column */
134
/**********************************************************************//**
osku's avatar
osku committed
135 136 137 138 139
Prints an index data. */
static
void
dict_index_print_low(
/*=================*/
140
	dict_index_t*	index);	/*!< in: index */
141
/**********************************************************************//**
osku's avatar
osku committed
142 143 144 145 146
Prints a field data. */
static
void
dict_field_print_low(
/*=================*/
147
	const dict_field_t*	field);	/*!< in: field */
148
/*********************************************************************//**
osku's avatar
osku committed
149 150 151 152 153
Frees a foreign key struct. */
static
void
dict_foreign_free(
/*==============*/
154
	dict_foreign_t*	foreign);	/*!< in, own: foreign key struct */
osku's avatar
osku committed
155 156 157

/* Stream for storing detailed information about the latest foreign key
and unique key errors */
158 159 160
UNIV_INTERN FILE*	dict_foreign_err_file		= NULL;
/* mutex protecting the foreign and unique error buffers */
UNIV_INTERN mutex_t	dict_foreign_err_mutex;
161

162
/******************************************************************//**
osku's avatar
osku committed
163
Makes all characters in a NUL-terminated UTF-8 string lower case. */
164
UNIV_INTERN
osku's avatar
osku committed
165 166 167
void
dict_casedn_str(
/*============*/
168
	char*	a)	/*!< in/out: string to put in lower case */
osku's avatar
osku committed
169 170 171 172
{
	innobase_casedn_str(a);
}

173
/********************************************************************//**
174 175
Checks if the database name in two table names is the same.
@return	TRUE if same db name */
176
UNIV_INTERN
osku's avatar
osku committed
177 178 179
ibool
dict_tables_have_same_db(
/*=====================*/
180
	const char*	name1,	/*!< in: table name in the form
osku's avatar
osku committed
181
				dbname '/' tablename */
182
	const char*	name2)	/*!< in: table name in the form
osku's avatar
osku committed
183 184 185 186 187 188 189 190 191 192 193
				dbname '/' tablename */
{
	for (; *name1 == *name2; name1++, name2++) {
		if (*name1 == '/') {
			return(TRUE);
		}
		ut_a(*name1); /* the names must contain '/' */
	}
	return(FALSE);
}

194
/********************************************************************//**
195 196
Return the end of table name where we have removed dbname and '/'.
@return	table name */
197
UNIV_INTERN
osku's avatar
osku committed
198 199 200
const char*
dict_remove_db_name(
/*================*/
201
	const char*	name)	/*!< in: table name in the form
osku's avatar
osku committed
202 203
				dbname '/' tablename */
{
204
	const char*	s = strchr(name, '/');
osku's avatar
osku committed
205
	ut_a(s);
206 207

	return(s + 1);
osku's avatar
osku committed
208 209
}

210
/********************************************************************//**
211 212
Get the database name length in a table name.
@return	database name length */
213
UNIV_INTERN
osku's avatar
osku committed
214 215 216
ulint
dict_get_db_name_len(
/*=================*/
217
	const char*	name)	/*!< in: table name in the form
osku's avatar
osku committed
218 219 220 221 222 223 224
				dbname '/' tablename */
{
	const char*	s;
	s = strchr(name, '/');
	ut_a(s);
	return(s - name);
}
225

226
/********************************************************************//**
osku's avatar
osku committed
227
Reserves the dictionary system mutex for MySQL. */
228
UNIV_INTERN
osku's avatar
osku committed
229 230 231 232 233 234
void
dict_mutex_enter_for_mysql(void)
/*============================*/
{
	mutex_enter(&(dict_sys->mutex));
}
235

236
/********************************************************************//**
osku's avatar
osku committed
237
Releases the dictionary system mutex for MySQL. */
238
UNIV_INTERN
osku's avatar
osku committed
239 240 241 242 243 244
void
dict_mutex_exit_for_mysql(void)
/*===========================*/
{
	mutex_exit(&(dict_sys->mutex));
}
245

246 247 248 249
/** Get the mutex that protects index->stat_n_diff_key_vals[] */
#define GET_INDEX_STAT_MUTEX(index) \
	(&dict_index_stat_mutex[ut_fold_dulint(index->id) \
	 			% DICT_INDEX_STAT_MUTEX_SIZE])
250 251 252 253 254 255 256 257 258 259 260

/**********************************************************************//**
Lock the appropriate mutex to protect index->stat_n_diff_key_vals[].
index->id is used to pick the right mutex and it should not change
before dict_index_stat_mutex_exit() is called on this index. */
UNIV_INTERN
void
dict_index_stat_mutex_enter(
/*========================*/
	const dict_index_t*	index)	/*!< in: index */
{
261 262 263 264 265 266
	ut_ad(index != NULL);
	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
	ut_ad(index->cached);
	ut_ad(!index->to_be_dropped);

	mutex_enter(GET_INDEX_STAT_MUTEX(index));
267 268 269 270 271 272 273 274 275 276
}

/**********************************************************************//**
Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */
UNIV_INTERN
void
dict_index_stat_mutex_exit(
/*=======================*/
	const dict_index_t*	index)	/*!< in: index */
{
277 278 279 280 281
	ut_ad(index != NULL);
	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
	ut_ad(index->cached);
	ut_ad(!index->to_be_dropped);

282
	mutex_exit(GET_INDEX_STAT_MUTEX(index));
283 284
}

285
/********************************************************************//**
osku's avatar
osku committed
286
Decrements the count of open MySQL handles to a table. */
287
UNIV_INTERN
osku's avatar
osku committed
288 289 290
void
dict_table_decrement_handle_count(
/*==============================*/
291 292
	dict_table_t*	table,		/*!< in/out: table */
	ibool		dict_locked)	/*!< in: TRUE=data dictionary locked */
osku's avatar
osku committed
293
{
294 295 296
	if (!dict_locked) {
		mutex_enter(&dict_sys->mutex);
	}
osku's avatar
osku committed
297

298
	ut_ad(mutex_own(&dict_sys->mutex));
osku's avatar
osku committed
299 300 301
	ut_a(table->n_mysql_handles_opened > 0);

	table->n_mysql_handles_opened--;
302

303 304 305
	if (!dict_locked) {
		mutex_exit(&dict_sys->mutex);
	}
osku's avatar
osku committed
306
}
307
#endif /* !UNIV_HOTBACKUP */
osku's avatar
osku committed
308

309
/**********************************************************************//**
310
Returns a column's name.
311 312
@return column name. NOTE: not guaranteed to stay valid if table is
modified in any way (columns added, etc.). */
313
UNIV_INTERN
314 315 316
const char*
dict_table_get_col_name(
/*====================*/
317 318
	const dict_table_t*	table,	/*!< in: table */
	ulint			col_nr)	/*!< in: column number */
319 320 321 322 323 324 325 326 327
{
	ulint		i;
	const char*	s;

	ut_ad(table);
	ut_ad(col_nr < table->n_def);
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);

	s = table->col_names;
328 329 330 331
	if (s) {
		for (i = 0; i < col_nr; i++) {
			s += strlen(s) + 1;
		}
332 333 334 335 336
	}

	return(s);
}

337
#ifndef UNIV_HOTBACKUP
338
/********************************************************************//**
339
Acquire the autoinc lock. */
340
UNIV_INTERN
341 342 343
void
dict_table_autoinc_lock(
/*====================*/
344
	dict_table_t*	table)	/*!< in/out: table */
345 346 347 348
{
	mutex_enter(&table->autoinc_mutex);
}

349
/********************************************************************//**
350
Unconditionally set the autoinc counter. */
351
UNIV_INTERN
osku's avatar
osku committed
352 353 354
void
dict_table_autoinc_initialize(
/*==========================*/
355 356
	dict_table_t*	table,	/*!< in/out: table */
	ib_uint64_t	value)	/*!< in: next value to assign to a row */
osku's avatar
osku committed
357
{
358 359
	ut_ad(mutex_own(&table->autoinc_mutex));

osku's avatar
osku committed
360 361 362
	table->autoinc = value;
}

363
/********************************************************************//**
osku's avatar
osku committed
364
Reads the next autoinc value (== autoinc counter value), 0 if not yet
365 366
initialized.
@return	value for a new row, or 0 */
367
UNIV_INTERN
368
ib_uint64_t
osku's avatar
osku committed
369 370
dict_table_autoinc_read(
/*====================*/
371
	const dict_table_t*	table)	/*!< in: table */
osku's avatar
osku committed
372
{
373 374
	ut_ad(mutex_own(&table->autoinc_mutex));

375
	return(table->autoinc);
osku's avatar
osku committed
376 377
}

378
/********************************************************************//**
379
Updates the autoinc counter if the value supplied is greater than the
sunny's avatar
sunny committed
380
current value. */
381
UNIV_INTERN
osku's avatar
osku committed
382
void
383 384
dict_table_autoinc_update_if_greater(
/*=================================*/
osku's avatar
osku committed
385

386 387
	dict_table_t*	table,	/*!< in/out: table */
	ib_uint64_t	value)	/*!< in: value which was assigned to a row */
osku's avatar
osku committed
388
{
389
	ut_ad(mutex_own(&table->autoinc_mutex));
osku's avatar
osku committed
390

391
	if (value > table->autoinc) {
sunny's avatar
sunny committed
392

393
		table->autoinc = value;
394
	}
395 396
}

397
/********************************************************************//**
398
Release the autoinc lock. */
399
UNIV_INTERN
400 401 402
void
dict_table_autoinc_unlock(
/*======================*/
403
	dict_table_t*	table)	/*!< in/out: table */
404 405
{
	mutex_exit(&table->autoinc_mutex);
osku's avatar
osku committed
406 407
}

408
/**********************************************************************//**
409
Looks for an index with the given table and index id.
410 411
NOTE that we do not reserve the dictionary mutex.
@return	index or NULL if not found from cache */
412
UNIV_INTERN
413 414 415
dict_index_t*
dict_index_get_on_id_low(
/*=====================*/
416 417
	dict_table_t*	table,	/*!< in: table */
	dulint		id)	/*!< in: index id */
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
{
	dict_index_t*	index;

	index = dict_table_get_first_index(table);

	while (index) {
		if (0 == ut_dulint_cmp(id, index->id)) {
			/* Found */

			return(index);
		}

		index = dict_table_get_next_index(index);
	}

	return(NULL);
}
435
#endif /* !UNIV_HOTBACKUP */
436

437
/********************************************************************//**
438
Looks for column n in an index.
439 440
@return position in internal representation of the index;
ULINT_UNDEFINED if not contained */
441
UNIV_INTERN
osku's avatar
osku committed
442 443 444
ulint
dict_index_get_nth_col_pos(
/*=======================*/
445 446
	const dict_index_t*	index,	/*!< in: index */
	ulint			n)	/*!< in: column number */
osku's avatar
osku committed
447
{
448 449 450 451
	const dict_field_t*	field;
	const dict_col_t*	col;
	ulint			pos;
	ulint			n_fields;
452

osku's avatar
osku committed
453 454 455 456 457
	ut_ad(index);
	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);

	col = dict_table_get_nth_col(index->table, n);

458
	if (dict_index_is_clust(index)) {
osku's avatar
osku committed
459

460
		return(dict_col_get_clust_pos(col, index));
osku's avatar
osku committed
461 462 463
	}

	n_fields = dict_index_get_n_fields(index);
464

osku's avatar
osku committed
465 466 467 468 469 470 471 472 473 474 475 476
	for (pos = 0; pos < n_fields; pos++) {
		field = dict_index_get_nth_field(index, pos);

		if (col == field->col && field->prefix_len == 0) {

			return(pos);
		}
	}

	return(ULINT_UNDEFINED);
}

477
#ifndef UNIV_HOTBACKUP
478
/********************************************************************//**
479 480
Returns TRUE if the index contains a column or a prefix of that column.
@return	TRUE if contains the column or its prefix */
481
UNIV_INTERN
osku's avatar
osku committed
482 483 484
ibool
dict_index_contains_col_or_prefix(
/*==============================*/
485 486
	const dict_index_t*	index,	/*!< in: index */
	ulint			n)	/*!< in: column number */
osku's avatar
osku committed
487
{
488 489 490 491
	const dict_field_t*	field;
	const dict_col_t*	col;
	ulint			pos;
	ulint			n_fields;
492

osku's avatar
osku committed
493 494 495
	ut_ad(index);
	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);

496
	if (dict_index_is_clust(index)) {
osku's avatar
osku committed
497 498 499 500 501 502 503

		return(TRUE);
	}

	col = dict_table_get_nth_col(index->table, n);

	n_fields = dict_index_get_n_fields(index);
504

osku's avatar
osku committed
505 506 507 508 509 510 511 512 513 514 515 516
	for (pos = 0; pos < n_fields; pos++) {
		field = dict_index_get_nth_field(index, pos);

		if (col == field->col) {

			return(TRUE);
		}
	}

	return(FALSE);
}

517
/********************************************************************//**
osku's avatar
osku committed
518 519 520
Looks for a matching field in an index. The column has to be the same. The
column in index must be complete, or must contain a prefix longer than the
column in index2. That is, we must be able to construct the prefix in index2
521
from the prefix in index.
522 523
@return position in internal representation of the index;
ULINT_UNDEFINED if not contained */
524
UNIV_INTERN
osku's avatar
osku committed
525 526 527
ulint
dict_index_get_nth_field_pos(
/*=========================*/
528 529 530
	const dict_index_t*	index,	/*!< in: index from which to search */
	const dict_index_t*	index2,	/*!< in: index */
	ulint			n)	/*!< in: field number in index2 */
osku's avatar
osku committed
531
{
532 533 534 535
	const dict_field_t*	field;
	const dict_field_t*	field2;
	ulint			n_fields;
	ulint			pos;
536

osku's avatar
osku committed
537 538 539 540 541 542
	ut_ad(index);
	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);

	field2 = dict_index_get_nth_field(index2, n);

	n_fields = dict_index_get_n_fields(index);
543

osku's avatar
osku committed
544 545 546 547
	for (pos = 0; pos < n_fields; pos++) {
		field = dict_index_get_nth_field(index, pos);

		if (field->col == field2->col
548
		    && (field->prefix_len == 0
osku's avatar
osku committed
549
			|| (field->prefix_len >= field2->prefix_len
550
			    && field2->prefix_len != 0))) {
osku's avatar
osku committed
551 552 553 554 555 556 557 558

			return(pos);
		}
	}

	return(ULINT_UNDEFINED);
}

559
/**********************************************************************//**
560 561
Returns a table object based on table id.
@return	table, NULL if does not exist */
562
UNIV_INTERN
osku's avatar
osku committed
563 564 565
dict_table_t*
dict_table_get_on_id(
/*=================*/
566 567
	dulint	table_id,	/*!< in: table id */
	trx_t*	trx)		/*!< in: transaction handle */
osku's avatar
osku committed
568 569
{
	dict_table_t*	table;
570

osku's avatar
osku committed
571
	if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
572
	    || trx->dict_operation_lock_mode == RW_X_LATCH) {
osku's avatar
osku committed
573

574 575 576 577
		/* Note: An X latch implies that the transaction
		already owns the dictionary mutex. */

		ut_ad(mutex_own(&dict_sys->mutex));
osku's avatar
osku committed
578

579
		return(dict_table_get_on_id_low(table_id));
osku's avatar
osku committed
580 581 582 583
	}

	mutex_enter(&(dict_sys->mutex));

584
	table = dict_table_get_on_id_low(table_id);
585

osku's avatar
osku committed
586 587 588 589 590
	mutex_exit(&(dict_sys->mutex));

	return(table);
}

591
/********************************************************************//**
592 593
Looks for column n position in the clustered index.
@return	position in internal representation of the clustered index */
594
UNIV_INTERN
osku's avatar
osku committed
595 596 597
ulint
dict_table_get_nth_col_pos(
/*=======================*/
598 599
	const dict_table_t*	table,	/*!< in: table */
	ulint			n)	/*!< in: column number */
osku's avatar
osku committed
600 601
{
	return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
602
					  n));
osku's avatar
osku committed
603 604
}

605
/********************************************************************//**
osku's avatar
osku committed
606
Checks if a column is in the ordering columns of the clustered index of a
607 608
table. Column prefixes are treated like whole columns.
@return	TRUE if the column, or its prefix, is in the clustered key */
609
UNIV_INTERN
osku's avatar
osku committed
610 611 612
ibool
dict_table_col_in_clustered_key(
/*============================*/
613 614
	const dict_table_t*	table,	/*!< in: table */
	ulint			n)	/*!< in: column number */
osku's avatar
osku committed
615
{
616
	const dict_index_t*	index;
617 618 619 620
	const dict_field_t*	field;
	const dict_col_t*	col;
	ulint			pos;
	ulint			n_fields;
621

osku's avatar
osku committed
622 623 624 625 626 627 628
	ut_ad(table);

	col = dict_table_get_nth_col(table, n);

	index = dict_table_get_first_index(table);

	n_fields = dict_index_get_n_unique(index);
629

osku's avatar
osku committed
630 631 632 633 634 635 636 637 638 639 640 641
	for (pos = 0; pos < n_fields; pos++) {
		field = dict_index_get_nth_field(index, pos);

		if (col == field->col) {

			return(TRUE);
		}
	}

	return(FALSE);
}

642
/**********************************************************************//**
osku's avatar
osku committed
643
Inits the data dictionary module. */
644
UNIV_INTERN
osku's avatar
osku committed
645 646 647 648
void
dict_init(void)
/*===========*/
{
649 650
	int	i;

osku's avatar
osku committed
651 652
	dict_sys = mem_alloc(sizeof(dict_sys_t));

653
	mutex_create(&dict_sys->mutex, SYNC_DICT);
osku's avatar
osku committed
654

655
	dict_sys->table_hash = hash_create(buf_pool_get_curr_size()
656 657
					   / (DICT_POOL_PER_TABLE_HASH
					      * UNIV_WORD_SIZE));
658
	dict_sys->table_id_hash = hash_create(buf_pool_get_curr_size()
659 660
					      / (DICT_POOL_PER_TABLE_HASH
						 * UNIV_WORD_SIZE));
osku's avatar
osku committed
661 662 663 664
	dict_sys->size = 0;

	UT_LIST_INIT(dict_sys->table_LRU);

665
	rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
osku's avatar
osku committed
666 667 668

	dict_foreign_err_file = os_file_create_tmpfile();
	ut_a(dict_foreign_err_file);
669 670

	mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
671 672

	for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) {
673
		mutex_create(&dict_index_stat_mutex[i], SYNC_INDEX_TREE);
674
	}
osku's avatar
osku committed
675 676
}

677
/**********************************************************************//**
678 679 680
Returns a table object and optionally increment its MySQL open handle count.
NOTE! This is a high-level function to be used mainly from outside the
'dict' directory. Inside this directory dict_table_get_low is usually the
681 682
appropriate function.
@return	table, NULL if does not exist */
683
UNIV_INTERN
osku's avatar
osku committed
684 685 686
dict_table_t*
dict_table_get(
/*===========*/
687 688
	const char*	table_name,	/*!< in: table name */
	ibool		inc_mysql_count)/*!< in: whether to increment the open
689
					handle count on the table */
osku's avatar
osku committed
690 691 692 693
{
	dict_table_t*	table;

	mutex_enter(&(dict_sys->mutex));
694

osku's avatar
osku committed
695 696
	table = dict_table_get_low(table_name);

697
	if (inc_mysql_count && table) {
698
		table->n_mysql_handles_opened++;
osku's avatar
osku committed
699 700 701 702 703
	}

	mutex_exit(&(dict_sys->mutex));

	if (table != NULL) {
704 705 706 707
		if (!table->stat_initialized) {
			/* If table->ibd_file_missing == TRUE, this will
			print an error message and return without doing
			anything. */
osku's avatar
osku committed
708 709 710
			dict_update_statistics(table);
		}
	}
711

osku's avatar
osku committed
712 713
	return(table);
}
714
#endif /* !UNIV_HOTBACKUP */
osku's avatar
osku committed
715

716
/**********************************************************************//**
717
Adds system columns to a table object. */
718
UNIV_INTERN
osku's avatar
osku committed
719
void
720 721
dict_table_add_system_columns(
/*==========================*/
722 723
	dict_table_t*	table,	/*!< in/out: table */
	mem_heap_t*	heap)	/*!< in: temporary heap */
osku's avatar
osku committed
724 725 726 727
{
	ut_ad(table);
	ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
728
	ut_ad(!table->cached);
729

osku's avatar
osku committed
730 731 732 733 734 735
	/* NOTE: the system columns MUST be added in the following order
	(so that they can be indexed by the numerical value of DATA_ROW_ID,
	etc.) and as the last columns of the table memory object.
	The clustered index will not always physically contain all
	system columns. */

736
	dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
737
			       DATA_ROW_ID | DATA_NOT_NULL,
738
			       DATA_ROW_ID_LEN);
osku's avatar
osku committed
739 740 741
#if DATA_ROW_ID != 0
#error "DATA_ROW_ID != 0"
#endif
742
	dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
743
			       DATA_TRX_ID | DATA_NOT_NULL,
744
			       DATA_TRX_ID_LEN);
osku's avatar
osku committed
745 746 747
#if DATA_TRX_ID != 1
#error "DATA_TRX_ID != 1"
#endif
748
	dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
749
			       DATA_ROLL_PTR | DATA_NOT_NULL,
750
			       DATA_ROLL_PTR_LEN);
osku's avatar
osku committed
751 752 753 754 755
#if DATA_ROLL_PTR != 2
#error "DATA_ROLL_PTR != 2"
#endif

	/* This check reminds that if a new system column is added to
756
	the program, it should be dealt with here */
757 758
#if DATA_N_SYS_COLS != 3
#error "DATA_N_SYS_COLS != 3"
osku's avatar
osku committed
759
#endif
760 761
}

762
#ifndef UNIV_HOTBACKUP
763
/**********************************************************************//**
764
Adds a table object to the dictionary cache. */
765
UNIV_INTERN
766 767 768
void
dict_table_add_to_cache(
/*====================*/
769 770
	dict_table_t*	table,	/*!< in: table */
	mem_heap_t*	heap)	/*!< in: temporary heap */
771 772 773 774
{
	ulint	fold;
	ulint	id_fold;
	ulint	i;
775
	ulint	row_len;
776

777 778 779
	/* The lower limit for what we consider a "big" row */
#define BIG_ROW_SIZE 1024

780
	ut_ad(mutex_own(&(dict_sys->mutex)));
781

782
	dict_table_add_system_columns(table, heap);
783 784 785 786 787

	table->cached = TRUE;

	fold = ut_fold_string(table->name);
	id_fold = ut_fold_dulint(table->id);
osku's avatar
osku committed
788

789 790
	row_len = 0;
	for (i = 0; i < table->n_def; i++) {
791 792 793 794
		ulint	col_len = dict_col_get_max_size(
			dict_table_get_nth_col(table, i));

		row_len += col_len;
795 796

		/* If we have a single unbounded field, or several gigantic
797 798 799
		fields, mark the maximum row size as BIG_ROW_SIZE. */
		if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
			row_len = BIG_ROW_SIZE;
800 801 802 803 804

			break;
		}
	}

805
	table->big_rows = row_len >= BIG_ROW_SIZE;
806

osku's avatar
osku committed
807 808 809
	/* Look for a table with the same name: error if such exists */
	{
		dict_table_t*	table2;
810
		HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
811 812
			    dict_table_t*, table2, ut_ad(table2->cached),
			    ut_strcmp(table2->name, table->name) == 0);
osku's avatar
osku committed
813
		ut_a(table2 == NULL);
814 815 816 817 818 819 820 821

#ifdef UNIV_DEBUG
		/* Look for the same table pointer with a different name */
		HASH_SEARCH_ALL(name_hash, dict_sys->table_hash,
				dict_table_t*, table2, ut_ad(table2->cached),
				table2 == table);
		ut_ad(table2 == NULL);
#endif /* UNIV_DEBUG */
osku's avatar
osku committed
822 823 824 825 826
	}

	/* Look for a table with the same id: error if such exists */
	{
		dict_table_t*	table2;
827
		HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
828 829
			    dict_table_t*, table2, ut_ad(table2->cached),
			    ut_dulint_cmp(table2->id, table->id) == 0);
osku's avatar
osku committed
830
		ut_a(table2 == NULL);
831 832 833 834 835 836 837 838

#ifdef UNIV_DEBUG
		/* Look for the same table pointer with a different id */
		HASH_SEARCH_ALL(id_hash, dict_sys->table_id_hash,
				dict_table_t*, table2, ut_ad(table2->cached),
				table2 == table);
		ut_ad(table2 == NULL);
#endif /* UNIV_DEBUG */
osku's avatar
osku committed
839 840 841 842
	}

	/* Add table to hash table of tables */
	HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
843
		    table);
osku's avatar
osku committed
844 845 846

	/* Add table to hash table of tables based on table id */
	HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
847
		    table);
osku's avatar
osku committed
848 849 850
	/* Add table to LRU list of tables */
	UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);

851 852
	dict_sys->size += mem_heap_get_size(table->heap)
		+ strlen(table->name) + 1;
osku's avatar
osku committed
853 854
}

855
/**********************************************************************//**
osku's avatar
osku committed
856 857
Looks for an index with the given id. NOTE that we do not reserve
the dictionary mutex: this function is for emergency purposes like
858 859
printing info of a corrupt database page!
@return	index or NULL if not found from cache */
860
UNIV_INTERN
osku's avatar
osku committed
861 862 863
dict_index_t*
dict_index_find_on_id_low(
/*======================*/
864
	dulint	id)	/*!< in: index id */
osku's avatar
osku committed
865 866 867
{
	dict_table_t*	table;
	dict_index_t*	index;
868

osku's avatar
osku committed
869 870 871 872 873 874
	table = UT_LIST_GET_FIRST(dict_sys->table_LRU);

	while (table) {
		index = dict_table_get_first_index(table);

		while (index) {
875
			if (0 == ut_dulint_cmp(id, index->id)) {
osku's avatar
osku committed
876 877 878 879 880 881 882 883 884 885 886 887 888 889
				/* Found */

				return(index);
			}

			index = dict_table_get_next_index(index);
		}

		table = UT_LIST_GET_NEXT(table_LRU, table);
	}

	return(NULL);
}

890
/**********************************************************************//**
891 892
Renames a table object.
@return	TRUE if success */
893
UNIV_INTERN
osku's avatar
osku committed
894 895 896
ibool
dict_table_rename_in_cache(
/*=======================*/
897 898 899
	dict_table_t*	table,		/*!< in/out: table */
	const char*	new_name,	/*!< in: new name */
	ibool		rename_also_foreigns)/*!< in: in ALTER TABLE we want
osku's avatar
osku committed
900 901 902 903 904 905
					to preserve the original table name
					in constraints which reference it */
{
	dict_foreign_t*	foreign;
	dict_index_t*	index;
	ulint		fold;
906
	char		old_name[MAX_TABLE_NAME_LEN + 1];
907

osku's avatar
osku committed
908 909 910
	ut_ad(table);
	ut_ad(mutex_own(&(dict_sys->mutex)));

911 912 913 914 915 916 917 918 919 920
	/* store the old/current name to an automatic variable */
	if (strlen(table->name) + 1 <= sizeof(old_name)) {
		memcpy(old_name, table->name, strlen(table->name) + 1);
	} else {
		ut_print_timestamp(stderr);
		fprintf(stderr, "InnoDB: too long table name: '%s', "
			"max length is %d\n", table->name,
			MAX_TABLE_NAME_LEN);
		ut_error;
	}
921

osku's avatar
osku committed
922
	fold = ut_fold_string(new_name);
923

osku's avatar
osku committed
924 925 926
	/* Look for a table with the same name: error if such exists */
	{
		dict_table_t*	table2;
927
		HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
928
			    dict_table_t*, table2, ut_ad(table2->cached),
929
			    (ut_strcmp(table2->name, new_name) == 0));
930 931 932 933 934 935 936 937 938
		if (UNIV_LIKELY_NULL(table2)) {
			ut_print_timestamp(stderr);
			fputs("  InnoDB: Error: dictionary cache"
			      " already contains a table ", stderr);
			ut_print_name(stderr, NULL, TRUE, new_name);
			fputs("\n"
			      "InnoDB: cannot rename table ", stderr);
			ut_print_name(stderr, NULL, TRUE, old_name);
			putc('\n', stderr);
osku's avatar
osku committed
939 940 941 942 943 944 945 946 947
			return(FALSE);
		}
	}

	/* If the table is stored in a single-table tablespace, rename the
	.ibd file */

	if (table->space != 0) {
		if (table->dir_path_of_temp_table != NULL) {
948 949 950 951 952 953 954 955 956 957 958
			ut_print_timestamp(stderr);
			fputs("  InnoDB: Error: trying to rename a"
			      " TEMPORARY TABLE ", stderr);
			ut_print_name(stderr, NULL, TRUE, old_name);
			fputs(" (", stderr);
			ut_print_filename(stderr,
					  table->dir_path_of_temp_table);
			fputs(" )\n", stderr);
			return(FALSE);
		} else if (!fil_rename_tablespace(old_name, table->space,
						  new_name)) {
osku's avatar
osku committed
959 960 961 962 963 964
			return(FALSE);
		}
	}

	/* Remove table from the hash tables of tables */
	HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
965
		    ut_fold_string(old_name), table);
966 967 968 969 970 971 972 973 974

	if (strlen(new_name) > strlen(table->name)) {
		/* We allocate MAX_TABLE_NAME_LEN+1 bytes here to avoid
		memory fragmentation, we assume a repeated calls of
		ut_realloc() with the same size do not cause fragmentation */
		ut_a(strlen(new_name) <= MAX_TABLE_NAME_LEN);
		table->name = ut_realloc(table->name, MAX_TABLE_NAME_LEN + 1);
	}
	memcpy(table->name, new_name, strlen(new_name) + 1);
osku's avatar
osku committed
975 976 977

	/* Add table to hash table of tables */
	HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
978
		    table);
979 980 981

	dict_sys->size += strlen(new_name) - strlen(old_name);
	ut_a(dict_sys->size > 0);
osku's avatar
osku committed
982 983 984 985 986 987

	/* Update the table_name field in indexes */
	index = dict_table_get_first_index(table);

	while (index != NULL) {
		index->table_name = table->name;
988

osku's avatar
osku committed
989 990 991 992 993 994 995 996 997 998 999
		index = dict_table_get_next_index(index);
	}

	if (!rename_also_foreigns) {
		/* In ALTER TABLE we think of the rename table operation
		in the direction table -> temporary table (#sql...)
		as dropping the table with the old name and creating
		a new with the new name. Thus we kind of drop the
		constraints from the dictionary cache here. The foreign key
		constraints will be inherited to the new table from the
		system tables through a call of dict_load_foreigns. */
1000

osku's avatar
osku committed
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
		/* Remove the foreign constraints from the cache */
		foreign = UT_LIST_GET_LAST(table->foreign_list);

		while (foreign != NULL) {
			dict_foreign_remove_from_cache(foreign);
			foreign = UT_LIST_GET_LAST(table->foreign_list);
		}

		/* Reset table field in referencing constraints */

		foreign = UT_LIST_GET_FIRST(table->referenced_list);

		while (foreign != NULL) {
			foreign->referenced_table = NULL;
			foreign->referenced_index = NULL;
1016

osku's avatar
osku committed
1017 1018 1019 1020 1021 1022
			foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
		}

		/* Make the list of referencing constraints empty */

		UT_LIST_INIT(table->referenced_list);
1023

osku's avatar
osku committed
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
		return(TRUE);
	}

	/* Update the table name fields in foreign constraints, and update also
	the constraint id of new format >= 4.0.18 constraints. Note that at
	this point we have already changed table->name to the new name. */

	foreign = UT_LIST_GET_FIRST(table->foreign_list);

	while (foreign != NULL) {
1034 1035
		if (ut_strlen(foreign->foreign_table_name)
		    < ut_strlen(table->name)) {
osku's avatar
osku committed
1036 1037 1038
			/* Allocate a longer name buffer;
			TODO: store buf len to save memory */

1039 1040 1041
			foreign->foreign_table_name
				= mem_heap_alloc(foreign->heap,
						 ut_strlen(table->name) + 1);
osku's avatar
osku committed
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054
		}

		strcpy(foreign->foreign_table_name, table->name);

		if (strchr(foreign->id, '/')) {
			ulint	db_len;
			char*	old_id;

			/* This is a >= 4.0.18 format id */

			old_id = mem_strdup(foreign->id);

			if (ut_strlen(foreign->id) > ut_strlen(old_name)
1055 1056 1057 1058 1059
			    + ((sizeof dict_ibfk) - 1)
			    && !memcmp(foreign->id, old_name,
				       ut_strlen(old_name))
			    && !memcmp(foreign->id + ut_strlen(old_name),
				       dict_ibfk, (sizeof dict_ibfk) - 1)) {
osku's avatar
osku committed
1060 1061 1062

				/* This is a generated >= 4.0.18 format id */

1063
				if (strlen(table->name) > strlen(old_name)) {
1064 1065 1066 1067
					foreign->id = mem_heap_alloc(
						foreign->heap,
						strlen(table->name)
						+ strlen(old_id) + 1);
osku's avatar
osku committed
1068
				}
1069

osku's avatar
osku committed
1070 1071 1072 1073
				/* Replace the prefix 'databasename/tablename'
				with the new names */
				strcpy(foreign->id, table->name);
				strcat(foreign->id,
1074
				       old_id + ut_strlen(old_name));
osku's avatar
osku committed
1075 1076 1077 1078 1079 1080
			} else {
				/* This is a >= 4.0.18 format id where the user
				gave the id name */
				db_len = dict_get_db_name_len(table->name) + 1;

				if (dict_get_db_name_len(table->name)
1081
				    > dict_get_db_name_len(foreign->id)) {
osku's avatar
osku committed
1082

1083 1084 1085
					foreign->id = mem_heap_alloc(
						foreign->heap,
						db_len + strlen(old_id) + 1);
osku's avatar
osku committed
1086 1087 1088 1089
				}

				/* Replace the database prefix in id with the
				one from table->name */
1090

osku's avatar
osku committed
1091 1092 1093
				ut_memcpy(foreign->id, table->name, db_len);

				strcpy(foreign->id + db_len,
1094
				       dict_remove_db_name(old_id));
osku's avatar
osku committed
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
			}

			mem_free(old_id);
		}

		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
	}

	foreign = UT_LIST_GET_FIRST(table->referenced_list);

	while (foreign != NULL) {
1106 1107
		if (ut_strlen(foreign->referenced_table_name)
		    < ut_strlen(table->name)) {
osku's avatar
osku committed
1108 1109 1110
			/* Allocate a longer name buffer;
			TODO: store buf len to save memory */

1111 1112
			foreign->referenced_table_name = mem_heap_alloc(
				foreign->heap, strlen(table->name) + 1);
osku's avatar
osku committed
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
		}

		strcpy(foreign->referenced_table_name, table->name);

		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
	}

	return(TRUE);
}

1123
/**********************************************************************//**
osku's avatar
osku committed
1124 1125
Change the id of a table object in the dictionary cache. This is used in
DISCARD TABLESPACE. */
1126
UNIV_INTERN
osku's avatar
osku committed
1127 1128 1129
void
dict_table_change_id_in_cache(
/*==========================*/
1130 1131
	dict_table_t*	table,	/*!< in/out: table object already in cache */
	dulint		new_id)	/*!< in: new id to set */
osku's avatar
osku committed
1132 1133 1134 1135 1136 1137 1138 1139
{
	ut_ad(table);
	ut_ad(mutex_own(&(dict_sys->mutex)));
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);

	/* Remove the table from the hash table of id's */

	HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1140
		    ut_fold_dulint(table->id), table);
osku's avatar
osku committed
1141 1142 1143 1144
	table->id = new_id;

	/* Add the table back to the hash table */
	HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1145
		    ut_fold_dulint(table->id), table);
osku's avatar
osku committed
1146 1147
}

1148
/**********************************************************************//**
osku's avatar
osku committed
1149
Removes a table object from the dictionary cache. */
1150
UNIV_INTERN
osku's avatar
osku committed
1151 1152 1153
void
dict_table_remove_from_cache(
/*=========================*/
1154
	dict_table_t*	table)	/*!< in, own: table */
osku's avatar
osku committed
1155 1156 1157 1158
{
	dict_foreign_t*	foreign;
	dict_index_t*	index;
	ulint		size;
1159

osku's avatar
osku committed
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184
	ut_ad(table);
	ut_ad(mutex_own(&(dict_sys->mutex)));
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);

#if 0
	fputs("Removing table ", stderr);
	ut_print_name(stderr, table->name, ULINT_UNDEFINED);
	fputs(" from dictionary cache\n", stderr);
#endif

	/* Remove the foreign constraints from the cache */
	foreign = UT_LIST_GET_LAST(table->foreign_list);

	while (foreign != NULL) {
		dict_foreign_remove_from_cache(foreign);
		foreign = UT_LIST_GET_LAST(table->foreign_list);
	}

	/* Reset table field in referencing constraints */

	foreign = UT_LIST_GET_FIRST(table->referenced_list);

	while (foreign != NULL) {
		foreign->referenced_table = NULL;
		foreign->referenced_index = NULL;
1185

osku's avatar
osku committed
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
	}

	/* Remove the indexes from the cache */
	index = UT_LIST_GET_LAST(table->indexes);

	while (index != NULL) {
		dict_index_remove_from_cache(table, index);
		index = UT_LIST_GET_LAST(table->indexes);
	}

	/* Remove table from the hash tables of tables */
	HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1199
		    ut_fold_string(table->name), table);
osku's avatar
osku committed
1200
	HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1201
		    ut_fold_dulint(table->id), table);
osku's avatar
osku committed
1202 1203 1204 1205

	/* Remove table from LRU list of tables */
	UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);

1206
	size = mem_heap_get_size(table->heap) + strlen(table->name) + 1;
osku's avatar
osku committed
1207 1208 1209 1210 1211

	ut_ad(dict_sys->size >= size);

	dict_sys->size -= size;

1212
	dict_mem_table_free(table);
osku's avatar
osku committed
1213 1214
}

1215
/****************************************************************//**
1216
If the given column name is reserved for InnoDB system columns, return
1217 1218
TRUE.
@return	TRUE if name is reserved */
1219
UNIV_INTERN
1220 1221 1222
ibool
dict_col_name_is_reserved(
/*======================*/
1223
	const char*	name)	/*!< in: column name */
1224 1225 1226
{
	/* This check reminds that if a new system column is added to
	the program, it should be dealt with here. */
1227 1228
#if DATA_N_SYS_COLS != 3
#error "DATA_N_SYS_COLS != 3"
1229 1230 1231
#endif

	static const char*	reserved_names[] = {
1232
		"DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
1233 1234 1235 1236 1237
	};

	ulint			i;

	for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
1238
		if (innobase_strcasecmp(name, reserved_names[i]) == 0) {
1239 1240 1241 1242 1243 1244 1245 1246

			return(TRUE);
		}
	}

	return(FALSE);
}

1247
/****************************************************************//**
1248
If an undo log record for this table might not fit on a single page,
1249 1250
return TRUE.
@return	TRUE if the undo log record could become too big */
1251 1252 1253 1254
static
ibool
dict_index_too_big_for_undo(
/*========================*/
1255 1256
	const dict_table_t*	table,		/*!< in: table */
	const dict_index_t*	new_index)	/*!< in: index */
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267
{
	/* Make sure that all column prefixes will fit in the undo log record
	in trx_undo_page_report_modify() right after trx_undo_page_init(). */

	ulint			i;
	const dict_index_t*	clust_index
		= dict_table_get_first_index(table);
	ulint			undo_page_len
		= TRX_UNDO_PAGE_HDR - TRX_UNDO_PAGE_HDR_SIZE
		+ 2 /* next record pointer */
		+ 1 /* type_cmpl */
1268
		+ 11 /* trx->undo_no */ + 11 /* table->id */
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
		+ 1 /* rec_get_info_bits() */
		+ 11 /* DB_TRX_ID */
		+ 11 /* DB_ROLL_PTR */
		+ 10 + FIL_PAGE_DATA_END /* trx_undo_left() */
		+ 2/* pointer to previous undo log record */;

	if (UNIV_UNLIKELY(!clust_index)) {
		ut_a(dict_index_is_clust(new_index));
		clust_index = new_index;
	}

	/* Add the size of the ordering columns in the
	clustered index. */
	for (i = 0; i < clust_index->n_uniq; i++) {
		const dict_col_t*	col
			= dict_index_get_nth_col(clust_index, i);

		/* Use the maximum output size of
		mach_write_compressed(), although the encoded
		length should always fit in 2 bytes. */
		undo_page_len += 5 + dict_col_get_max_size(col);
	}

	/* Add the old values of the columns to be updated.
	First, the amount and the numbers of the columns.
	These are written by mach_write_compressed() whose
	maximum output length is 5 bytes.  However, given that
	the quantities are below REC_MAX_N_FIELDS (10 bits),
	the maximum length is 2 bytes per item. */
	undo_page_len += 2 * (dict_table_get_n_cols(table) + 1);

	for (i = 0; i < clust_index->n_def; i++) {
		const dict_col_t*	col
			= dict_index_get_nth_col(clust_index, i);
		ulint			max_size
			= dict_col_get_max_size(col);
		ulint			fixed_size
1306 1307
			= dict_col_get_fixed_size(col,
						  dict_table_is_comp(table));
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348

		if (fixed_size) {
			/* Fixed-size columns are stored locally. */
			max_size = fixed_size;
		} else if (max_size <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
			/* Short columns are stored locally. */
		} else if (!col->ord_part) {
			/* See if col->ord_part would be set
			because of new_index. */
			ulint	j;

			for (j = 0; j < new_index->n_uniq; j++) {
				if (dict_index_get_nth_col(
					    new_index, j) == col) {

					goto is_ord_part;
				}
			}

			/* This is not an ordering column in any index.
			Thus, it can be stored completely externally. */
			max_size = BTR_EXTERN_FIELD_REF_SIZE;
		} else {
is_ord_part:
			/* This is an ordering column in some index.
			A long enough prefix must be written to the
			undo log.  See trx_undo_page_fetch_ext(). */

			if (max_size > REC_MAX_INDEX_COL_LEN) {
				max_size = REC_MAX_INDEX_COL_LEN;
			}

			max_size += BTR_EXTERN_FIELD_REF_SIZE;
		}

		undo_page_len += 5 + max_size;
	}

	return(undo_page_len >= UNIV_PAGE_SIZE);
}

1349
/****************************************************************//**
1350
If a record of this index might not fit on a single B-tree page,
1351 1352
return TRUE.
@return	TRUE if the index record could become too big */
1353 1354 1355 1356
static
ibool
dict_index_too_big_for_tree(
/*========================*/
1357 1358
	const dict_table_t*	table,		/*!< in: table */
	const dict_index_t*	new_index)	/*!< in: index */
1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435
{
	ulint	zip_size;
	ulint	comp;
	ulint	i;
	/* maximum possible storage size of a record */
	ulint	rec_max_size;
	/* maximum allowed size of a record on a leaf page */
	ulint	page_rec_max;
	/* maximum allowed size of a node pointer record */
	ulint	page_ptr_max;

	comp = dict_table_is_comp(table);
	zip_size = dict_table_zip_size(table);

	if (zip_size && zip_size < UNIV_PAGE_SIZE) {
		/* On a compressed page, two records must fit in the
		uncompressed page modification log.  On compressed
		pages with zip_size == UNIV_PAGE_SIZE, this limit will
		never be reached. */
		ut_ad(comp);
		/* The maximum allowed record size is the size of
		an empty page, minus a byte for recoding the heap
		number in the page modification log.  The maximum
		allowed node pointer size is half that. */
		page_rec_max = page_zip_empty_size(new_index->n_fields,
						   zip_size) - 1;
		page_ptr_max = page_rec_max / 2;
		/* On a compressed page, there is a two-byte entry in
		the dense page directory for every record.  But there
		is no record header. */
		rec_max_size = 2;
	} else {
		/* The maximum allowed record size is half a B-tree
		page.  No additional sparse page directory entry will
		be generated for the first few user records. */
		page_rec_max = page_get_free_space_of_empty(comp) / 2;
		page_ptr_max = page_rec_max;
		/* Each record has a header. */
		rec_max_size = comp
			? REC_N_NEW_EXTRA_BYTES
			: REC_N_OLD_EXTRA_BYTES;
	}

	if (comp) {
		/* Include the "null" flags in the
		maximum possible record size. */
		rec_max_size += UT_BITS_IN_BYTES(new_index->n_nullable);
	} else {
		/* For each column, include a 2-byte offset and a
		"null" flag.  The 1-byte format is only used in short
		records that do not contain externally stored columns.
		Such records could never exceed the page limit, even
		when using the 2-byte format. */
		rec_max_size += 2 * new_index->n_fields;
	}

	/* Compute the maximum possible record size. */
	for (i = 0; i < new_index->n_fields; i++) {
		const dict_field_t*	field
			= dict_index_get_nth_field(new_index, i);
		const dict_col_t*	col
			= dict_field_get_col(field);
		ulint			field_max_size;
		ulint			field_ext_max_size;

		/* In dtuple_convert_big_rec(), variable-length columns
		that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
		may be chosen for external storage.

		Fixed-length columns, and all columns of secondary
		index records are always stored inline. */

		/* Determine the maximum length of the index field.
		The field_ext_max_size should be computed as the worst
		case in rec_get_converted_size_comp() for
		REC_STATUS_ORDINARY records. */

1436
		field_max_size = dict_col_get_fixed_size(col, comp);
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497
		if (field_max_size) {
			/* dict_index_add_col() should guarantee this */
			ut_ad(!field->prefix_len
			      || field->fixed_len == field->prefix_len);
			/* Fixed lengths are not encoded
			in ROW_FORMAT=COMPACT. */
			field_ext_max_size = 0;
			goto add_field_size;
		}

		field_max_size = dict_col_get_max_size(col);
		field_ext_max_size = field_max_size < 256 ? 1 : 2;

		if (field->prefix_len) {
			if (field->prefix_len < field_max_size) {
				field_max_size = field->prefix_len;
			}
		} else if (field_max_size > BTR_EXTERN_FIELD_REF_SIZE * 2
			   && dict_index_is_clust(new_index)) {

			/* In the worst case, we have a locally stored
			column of BTR_EXTERN_FIELD_REF_SIZE * 2 bytes.
			The length can be stored in one byte.  If the
			column were stored externally, the lengths in
			the clustered index page would be
			BTR_EXTERN_FIELD_REF_SIZE and 2. */
			field_max_size = BTR_EXTERN_FIELD_REF_SIZE * 2;
			field_ext_max_size = 1;
		}

		if (comp) {
			/* Add the extra size for ROW_FORMAT=COMPACT.
			For ROW_FORMAT=REDUNDANT, these bytes were
			added to rec_max_size before this loop. */
			rec_max_size += field_ext_max_size;
		}
add_field_size:
		rec_max_size += field_max_size;

		/* Check the size limit on leaf pages. */
		if (UNIV_UNLIKELY(rec_max_size >= page_rec_max)) {

			return(TRUE);
		}

		/* Check the size limit on non-leaf pages.  Records
		stored in non-leaf B-tree pages consist of the unique
		columns of the record (the key columns of the B-tree)
		and a node pointer field.  When we have processed the
		unique columns, rec_max_size equals the size of the
		node pointer record minus the node pointer column. */
		if (i + 1 == dict_index_get_n_unique_in_tree(new_index)
		    && rec_max_size + REC_NODE_PTR_SIZE >= page_ptr_max) {

			return(TRUE);
		}
	}

	return(FALSE);
}

1498
/**********************************************************************//**
1499
Adds an index to the dictionary cache.
1500
@return	DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */
1501
UNIV_INTERN
1502
ulint
osku's avatar
osku committed
1503 1504
dict_index_add_to_cache(
/*====================*/
1505 1506
	dict_table_t*	table,	/*!< in: table on which the index is */
	dict_index_t*	index,	/*!< in, own: index; NOTE! The index memory
osku's avatar
osku committed
1507
				object is freed in this function! */
1508 1509
	ulint		page_no,/*!< in: root page number of the index */
	ibool		strict)	/*!< in: TRUE=refuse to create the index
1510 1511
				if records could be too big to fit in
				an B-tree page */
osku's avatar
osku committed
1512 1513 1514 1515
{
	dict_index_t*	new_index;
	ulint		n_ord;
	ulint		i;
1516

osku's avatar
osku committed
1517 1518 1519 1520
	ut_ad(index);
	ut_ad(mutex_own(&(dict_sys->mutex)));
	ut_ad(index->n_def == index->n_fields);
	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1521

osku's avatar
osku committed
1522
	ut_ad(mem_heap_validate(index->heap));
1523
	ut_a(!dict_index_is_clust(index)
1524
	     || UT_LIST_GET_LEN(table->indexes) == 0);
osku's avatar
osku committed
1525

1526 1527
	if (!dict_index_find_cols(table, index)) {

1528
		dict_mem_index_free(index);
1529 1530
		return(DB_CORRUPTION);
	}
1531

osku's avatar
osku committed
1532 1533 1534
	/* Build the cache internal representation of the index,
	containing also the added system fields */

1535
	if (dict_index_is_clust(index)) {
osku's avatar
osku committed
1536 1537 1538 1539 1540 1541 1542 1543 1544
		new_index = dict_index_build_internal_clust(table, index);
	} else {
		new_index = dict_index_build_internal_non_clust(table, index);
	}

	/* Set the n_fields value in new_index to the actual defined
	number of fields in the cache internal representation */

	new_index->n_fields = new_index->n_def;
1545

1546 1547 1548 1549 1550 1551 1552
	if (strict && dict_index_too_big_for_tree(table, new_index)) {
too_big:
		dict_mem_index_free(new_index);
		dict_mem_index_free(index);
		return(DB_TOO_BIG_RECORD);
	}

osku's avatar
osku committed
1553 1554 1555
	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
		n_ord = new_index->n_fields;
	} else {
1556
		n_ord = new_index->n_uniq;
osku's avatar
osku committed
1557 1558
	}

1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581
	switch (dict_table_get_format(table)) {
	case DICT_TF_FORMAT_51:
		/* ROW_FORMAT=REDUNDANT and ROW_FORMAT=COMPACT store
		prefixes of externally stored columns locally within
		the record.  There are no special considerations for
		the undo log record size. */
		goto undo_size_ok;

	case DICT_TF_FORMAT_ZIP:
		/* In ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED,
		column prefix indexes require that prefixes of
		externally stored columns are written to the undo log.
		This may make the undo log record bigger than the
		record on the B-tree page.  The maximum size of an
		undo log record is the page size.  That must be
		checked for below. */
		break;

#if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
# error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
#endif
	}

1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
	for (i = 0; i < n_ord; i++) {
		const dict_field_t*	field
			= dict_index_get_nth_field(new_index, i);
		const dict_col_t*	col
			= dict_field_get_col(field);

		/* In dtuple_convert_big_rec(), variable-length columns
		that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
		may be chosen for external storage.  If the column appears
		in an ordering column of an index, a longer prefix of
		REC_MAX_INDEX_COL_LEN will be copied to the undo log
		by trx_undo_page_report_modify() and
		trx_undo_page_fetch_ext().  It suffices to check the
		capacity of the undo log whenever new_index includes
		a column prefix on a column that may be stored externally. */

		if (field->prefix_len /* prefix index */
		    && !col->ord_part /* not yet ordering column */
1600
		    && !dict_col_get_fixed_size(col, TRUE) /* variable-length */
1601 1602 1603 1604 1605 1606
		    && dict_col_get_max_size(col)
		    > BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {

			if (dict_index_too_big_for_undo(table, new_index)) {
				/* An undo log record might not fit in
				a single page.  Refuse to create this index. */
1607 1608

				goto too_big;
1609 1610 1611 1612 1613 1614
			}

			break;
		}
	}

1615
undo_size_ok:
1616 1617
	/* Flag the ordering columns */

osku's avatar
osku committed
1618 1619
	for (i = 0; i < n_ord; i++) {

1620
		dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
osku's avatar
osku committed
1621 1622
	}

1623 1624 1625 1626 1627 1628 1629 1630
	/* Add the new index as the last index for the table */

	UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
	new_index->table = table;
	new_index->table_name = table->name;

	new_index->search_info = btr_search_info_create(new_index->heap);

1631 1632 1633 1634
	new_index->stat_index_size = 1;
	new_index->stat_n_leaf_pages = 1;

	new_index->page = page_no;
1635
	rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
osku's avatar
osku committed
1636 1637 1638

	if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {

1639 1640 1641
		new_index->stat_n_diff_key_vals = mem_heap_alloc(
			new_index->heap,
			(1 + dict_index_get_n_unique(new_index))
1642
			* sizeof(ib_int64_t));
osku's avatar
osku committed
1643 1644 1645 1646 1647 1648 1649 1650
		/* Give some sensible values to stat_n_... in case we do
		not calculate statistics quickly enough */

		for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {

			new_index->stat_n_diff_key_vals[i] = 100;
		}
	}
1651

osku's avatar
osku committed
1652 1653 1654
	dict_sys->size += mem_heap_get_size(new_index->heap);

	dict_mem_index_free(index);
1655 1656

	return(DB_SUCCESS);
osku's avatar
osku committed
1657 1658
}

1659
/**********************************************************************//**
osku's avatar
osku committed
1660
Removes an index from the dictionary cache. */
1661
UNIV_INTERN
osku's avatar
osku committed
1662 1663 1664
void
dict_index_remove_from_cache(
/*=========================*/
1665 1666
	dict_table_t*	table,	/*!< in/out: table */
	dict_index_t*	index)	/*!< in, own: index */
osku's avatar
osku committed
1667 1668
{
	ulint		size;
1669 1670
	ulint		retries = 0;
	btr_search_t*	info;
osku's avatar
osku committed
1671 1672 1673 1674 1675 1676

	ut_ad(table && index);
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
	ut_ad(mutex_own(&(dict_sys->mutex)));

1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
	/* We always create search info whether or not adaptive
	hash index is enabled or not. */
	info = index->search_info;
	ut_ad(info);

	/* We are not allowed to free the in-memory index struct
 	dict_index_t until all entries in the adaptive hash index
	that point to any of the page belonging to his b-tree index
	are dropped. This is so because dropping of these entries
	require access to dict_index_t struct. To avoid such scenario
	We keep a count of number of such pages in the search_info and
	only free the dict_index_t struct when this count drops to
	zero. */

	for (;;) {
		ulint ref_count = btr_search_info_get_ref_count(info);
		if (ref_count == 0) {
			break;
		}

		/* Sleep for 10ms before trying again. */
		os_thread_sleep(10000);
		++retries;

		if (retries % 500 == 0) {
			/* No luck after 5 seconds of wait. */
			fprintf(stderr, "InnoDB: Error: Waited for"
					" %lu secs for hash index"
					" ref_count (%lu) to drop"
					" to 0.\n"
					"index: \"%s\""
					" table: \"%s\"\n",
					retries/100,
					ref_count,
					index->name,
					table->name);
		}

		/* To avoid a hang here we commit suicide if the
		ref_count doesn't drop to zero in 600 seconds. */
		if (retries >= 60000) {
			ut_error;
		}
	}

1722
	rw_lock_free(&index->lock);
osku's avatar
osku committed
1723 1724 1725 1726 1727 1728 1729 1730 1731 1732

	/* Remove the index from the list of indexes of the table */
	UT_LIST_REMOVE(indexes, table->indexes, index);

	size = mem_heap_get_size(index->heap);

	ut_ad(dict_sys->size >= size);

	dict_sys->size -= size;

1733
	dict_mem_index_free(index);
osku's avatar
osku committed
1734 1735
}

1736
/*******************************************************************//**
1737
Tries to find column names for the index and sets the col field of the
1738 1739
index.
@return TRUE if the column names were found */
osku's avatar
osku committed
1740
static
1741
ibool
osku's avatar
osku committed
1742 1743
dict_index_find_cols(
/*=================*/
1744 1745
	dict_table_t*	table,	/*!< in: table */
	dict_index_t*	index)	/*!< in: index */
osku's avatar
osku committed
1746 1747
{
	ulint		i;
1748

osku's avatar
osku committed
1749 1750 1751 1752 1753
	ut_ad(table && index);
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
	ut_ad(mutex_own(&(dict_sys->mutex)));

	for (i = 0; i < index->n_fields; i++) {
1754 1755
		ulint		j;
		dict_field_t*	field = dict_index_get_nth_field(index, i);
osku's avatar
osku committed
1756

1757 1758 1759
		for (j = 0; j < table->n_cols; j++) {
			if (!strcmp(dict_table_get_col_name(table, j),
				    field->name)) {
1760
				field->col = dict_table_get_nth_col(table, j);
1761

1762 1763
				goto found;
			}
osku's avatar
osku committed
1764 1765
		}

1766
#ifdef UNIV_DEBUG
1767
		/* It is an error not to find a matching column. */
1768 1769 1770 1771 1772
		fputs("InnoDB: Error: no matching column for ", stderr);
		ut_print_name(stderr, NULL, FALSE, field->name);
		fputs(" in ", stderr);
		dict_index_name_print(stderr, NULL, index);
		fputs("!\n", stderr);
1773 1774
#endif /* UNIV_DEBUG */
		return(FALSE);
1775

1776
found:
1777 1778
		;
	}
1779 1780

	return(TRUE);
osku's avatar
osku committed
1781
}
1782
#endif /* !UNIV_HOTBACKUP */
1783

1784
/*******************************************************************//**
osku's avatar
osku committed
1785
Adds a column to index. */
1786
UNIV_INTERN
osku's avatar
osku committed
1787 1788 1789
void
dict_index_add_col(
/*===============*/
1790 1791 1792 1793
	dict_index_t*		index,		/*!< in/out: index */
	const dict_table_t*	table,		/*!< in: table */
	dict_col_t*		col,		/*!< in: column */
	ulint			prefix_len)	/*!< in: column prefix length */
osku's avatar
osku committed
1794 1795
{
	dict_field_t*	field;
1796
	const char*	col_name;
osku's avatar
osku committed
1797

1798 1799 1800
	col_name = dict_table_get_col_name(table, dict_col_get_no(col));

	dict_mem_index_add_field(index, col_name, prefix_len);
osku's avatar
osku committed
1801 1802 1803 1804

	field = dict_index_get_nth_field(index, index->n_def - 1);

	field->col = col;
1805 1806
	field->fixed_len = (unsigned int) dict_col_get_fixed_size(
		col, dict_table_is_comp(table));
osku's avatar
osku committed
1807 1808

	if (prefix_len && field->fixed_len > prefix_len) {
1809
		field->fixed_len = (unsigned int) prefix_len;
osku's avatar
osku committed
1810 1811 1812 1813 1814 1815 1816 1817 1818
	}

	/* Long fixed-length fields that need external storage are treated as
	variable-length fields, so that the extern flag can be embedded in
	the length word. */

	if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
		field->fixed_len = 0;
	}
1819 1820 1821 1822 1823 1824
#if DICT_MAX_INDEX_COL_LEN != 768
	/* The comparison limit above must be constant.  If it were
	changed, the disk format of some fixed-length columns would
	change, which would be a disaster. */
# error "DICT_MAX_INDEX_COL_LEN != 768"
#endif
osku's avatar
osku committed
1825

1826
	if (!(col->prtype & DATA_NOT_NULL)) {
osku's avatar
osku committed
1827 1828 1829 1830
		index->n_nullable++;
	}
}

1831
#ifndef UNIV_HOTBACKUP
1832
/*******************************************************************//**
osku's avatar
osku committed
1833 1834 1835 1836 1837
Copies fields contained in index2 to index1. */
static
void
dict_index_copy(
/*============*/
1838 1839 1840 1841 1842
	dict_index_t*		index1,	/*!< in: index to copy to */
	dict_index_t*		index2,	/*!< in: index to copy from */
	const dict_table_t*	table,	/*!< in: table */
	ulint			start,	/*!< in: first position to copy */
	ulint			end)	/*!< in: last position to copy */
osku's avatar
osku committed
1843 1844 1845
{
	dict_field_t*	field;
	ulint		i;
1846

osku's avatar
osku committed
1847 1848 1849 1850 1851
	/* Copy fields contained in index2 */

	for (i = start; i < end; i++) {

		field = dict_index_get_nth_field(index2, i);
1852 1853
		dict_index_add_col(index1, table, field->col,
				   field->prefix_len);
osku's avatar
osku committed
1854 1855 1856
	}
}

1857
/*******************************************************************//**
osku's avatar
osku committed
1858
Copies types of fields contained in index to tuple. */
1859
UNIV_INTERN
osku's avatar
osku committed
1860 1861 1862
void
dict_index_copy_types(
/*==================*/
1863 1864 1865
	dtuple_t*		tuple,		/*!< in/out: data tuple */
	const dict_index_t*	index,		/*!< in: index */
	ulint			n_fields)	/*!< in: number of
1866
						field types to copy */
osku's avatar
osku committed
1867 1868 1869 1870 1871 1872 1873 1874 1875 1876
{
	ulint		i;

	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
		dtuple_set_types_binary(tuple, n_fields);

		return;
	}

	for (i = 0; i < n_fields; i++) {
1877 1878
		const dict_field_t*	ifield;
		dtype_t*		dfield_type;
1879 1880

		ifield = dict_index_get_nth_field(index, i);
1881
		dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1882
		dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
osku's avatar
osku committed
1883 1884 1885
	}
}

1886
/*******************************************************************//**
1887 1888 1889
Copies types of columns contained in table to tuple and sets all
fields of the tuple to the SQL NULL value.  This function should
be called right after dtuple_create(). */
1890
UNIV_INTERN
osku's avatar
osku committed
1891 1892 1893
void
dict_table_copy_types(
/*==================*/
1894 1895
	dtuple_t*		tuple,	/*!< in/out: data tuple */
	const dict_table_t*	table)	/*!< in: table */
osku's avatar
osku committed
1896 1897 1898 1899 1900
{
	ulint		i;

	for (i = 0; i < dtuple_get_n_fields(tuple); i++) {

1901 1902 1903 1904 1905
		dfield_t*	dfield	= dtuple_get_nth_field(tuple, i);
		dtype_t*	dtype	= dfield_get_type(dfield);

		dfield_set_null(dfield);
		dict_col_copy_type(dict_table_get_nth_col(table, i), dtype);
osku's avatar
osku committed
1906 1907 1908
	}
}

1909
/*******************************************************************//**
osku's avatar
osku committed
1910
Builds the internal dictionary cache representation for a clustered
1911 1912
index, containing also system fields not defined by the user.
@return	own: the internal representation of the clustered index */
osku's avatar
osku committed
1913 1914 1915 1916
static
dict_index_t*
dict_index_build_internal_clust(
/*============================*/
1917 1918
	const dict_table_t*	table,	/*!< in: table */
	dict_index_t*		index)	/*!< in: user representation of
1919
					a clustered index */
osku's avatar
osku committed
1920 1921 1922 1923 1924 1925
{
	dict_index_t*	new_index;
	dict_field_t*	field;
	ulint		fixed_size;
	ulint		trx_id_pos;
	ulint		i;
1926
	ibool*		indexed;
osku's avatar
osku committed
1927 1928

	ut_ad(table && index);
1929
	ut_ad(dict_index_is_clust(index));
osku's avatar
osku committed
1930 1931 1932 1933 1934
	ut_ad(mutex_own(&(dict_sys->mutex)));
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);

	/* Create a new index object with certainly enough fields */
	new_index = dict_mem_index_create(table->name,
1935 1936 1937
					  index->name, table->space,
					  index->type,
					  index->n_fields + table->n_cols);
osku's avatar
osku committed
1938 1939 1940 1941 1942

	/* Copy other relevant data from the old index struct to the new
	struct: it inherits the values */

	new_index->n_user_defined_cols = index->n_fields;
1943

osku's avatar
osku committed
1944 1945
	new_index->id = index->id;

1946
	/* Copy the fields of index */
1947
	dict_index_copy(new_index, index, table, 0, index->n_fields);
osku's avatar
osku committed
1948 1949 1950 1951

	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
		/* No fixed number of fields determines an entry uniquely */

1952
		new_index->n_uniq = REC_MAX_N_FIELDS;
1953

1954
	} else if (dict_index_is_unique(index)) {
osku's avatar
osku committed
1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965
		/* Only the fields defined so far are needed to identify
		the index entry uniquely */

		new_index->n_uniq = new_index->n_def;
	} else {
		/* Also the row id is needed to identify the entry */
		new_index->n_uniq = 1 + new_index->n_def;
	}

	new_index->trx_id_offset = 0;

1966
	if (!dict_index_is_ibuf(index)) {
osku's avatar
osku committed
1967 1968 1969 1970
		/* Add system columns, trx id first */

		trx_id_pos = new_index->n_def;

1971 1972 1973 1974 1975 1976 1977 1978 1979
#if DATA_ROW_ID != 0
# error "DATA_ROW_ID != 0"
#endif
#if DATA_TRX_ID != 1
# error "DATA_TRX_ID != 1"
#endif
#if DATA_ROLL_PTR != 2
# error "DATA_ROLL_PTR != 2"
#endif
osku's avatar
osku committed
1980

1981
		if (!dict_index_is_unique(index)) {
1982
			dict_index_add_col(new_index, table,
1983 1984 1985
					   dict_table_get_sys_col(
						   table, DATA_ROW_ID),
					   0);
osku's avatar
osku committed
1986 1987 1988
			trx_id_pos++;
		}

1989
		dict_index_add_col(new_index, table,
1990 1991
				   dict_table_get_sys_col(table, DATA_TRX_ID),
				   0);
1992

1993
		dict_index_add_col(new_index, table,
1994 1995 1996
				   dict_table_get_sys_col(table,
							  DATA_ROLL_PTR),
				   0);
osku's avatar
osku committed
1997 1998 1999

		for (i = 0; i < trx_id_pos; i++) {

2000
			fixed_size = dict_col_get_fixed_size(
2001 2002
				dict_index_get_nth_col(new_index, i),
				dict_table_is_comp(table));
osku's avatar
osku committed
2003 2004 2005 2006 2007 2008 2009 2010

			if (fixed_size == 0) {
				new_index->trx_id_offset = 0;

				break;
			}

			if (dict_index_get_nth_field(new_index, i)->prefix_len
2011
			    > 0) {
osku's avatar
osku committed
2012 2013 2014 2015 2016
				new_index->trx_id_offset = 0;

				break;
			}

2017
			new_index->trx_id_offset += (unsigned int) fixed_size;
osku's avatar
osku committed
2018 2019 2020 2021
		}

	}

2022
	/* Remember the table columns already contained in new_index */
2023
	indexed = mem_zalloc(table->n_cols * sizeof *indexed);
osku's avatar
osku committed
2024

2025
	/* Mark the table columns already contained in new_index */
osku's avatar
osku committed
2026 2027 2028 2029 2030 2031 2032 2033 2034
	for (i = 0; i < new_index->n_def; i++) {

		field = dict_index_get_nth_field(new_index, i);

		/* If there is only a prefix of the column in the index
		field, do not mark the column as contained in the index */

		if (field->prefix_len == 0) {

2035
			indexed[field->col->ind] = TRUE;
osku's avatar
osku committed
2036 2037
		}
	}
2038

osku's avatar
osku committed
2039 2040
	/* Add to new_index non-system columns of table not yet included
	there */
2041
	for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
osku's avatar
osku committed
2042

2043
		dict_col_t*	col = dict_table_get_nth_col(table, i);
2044
		ut_ad(col->mtype != DATA_SYS);
osku's avatar
osku committed
2045

2046
		if (!indexed[col->ind]) {
2047
			dict_index_add_col(new_index, table, col, 0);
osku's avatar
osku committed
2048 2049 2050
		}
	}

2051 2052
	mem_free(indexed);

2053
	ut_ad(dict_index_is_ibuf(index)
2054
	      || (UT_LIST_GET_LEN(table->indexes) == 0));
osku's avatar
osku committed
2055 2056 2057 2058

	new_index->cached = TRUE;

	return(new_index);
2059
}
osku's avatar
osku committed
2060

2061
/*******************************************************************//**
osku's avatar
osku committed
2062
Builds the internal dictionary cache representation for a non-clustered
2063 2064
index, containing also system fields not defined by the user.
@return	own: the internal representation of the non-clustered index */
osku's avatar
osku committed
2065 2066 2067 2068
static
dict_index_t*
dict_index_build_internal_non_clust(
/*================================*/
2069 2070
	const dict_table_t*	table,	/*!< in: table */
	dict_index_t*		index)	/*!< in: user representation of
2071
					a non-clustered index */
osku's avatar
osku committed
2072 2073 2074 2075 2076
{
	dict_field_t*	field;
	dict_index_t*	new_index;
	dict_index_t*	clust_index;
	ulint		i;
2077
	ibool*		indexed;
osku's avatar
osku committed
2078 2079

	ut_ad(table && index);
2080
	ut_ad(!dict_index_is_clust(index));
osku's avatar
osku committed
2081 2082 2083 2084 2085
	ut_ad(mutex_own(&(dict_sys->mutex)));
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);

	/* The clustered index should be the first in the list of indexes */
	clust_index = UT_LIST_GET_FIRST(table->indexes);
2086

osku's avatar
osku committed
2087
	ut_ad(clust_index);
2088
	ut_ad(dict_index_is_clust(clust_index));
osku's avatar
osku committed
2089 2090 2091
	ut_ad(!(clust_index->type & DICT_UNIVERSAL));

	/* Create a new index */
2092 2093 2094
	new_index = dict_mem_index_create(
		table->name, index->name, index->space, index->type,
		index->n_fields + 1 + clust_index->n_uniq);
osku's avatar
osku committed
2095 2096 2097 2098 2099

	/* Copy other relevant data from the old index
	struct to the new struct: it inherits the values */

	new_index->n_user_defined_cols = index->n_fields;
2100

osku's avatar
osku committed
2101 2102 2103
	new_index->id = index->id;

	/* Copy fields from index to new_index */
2104
	dict_index_copy(new_index, index, table, 0, index->n_fields);
osku's avatar
osku committed
2105

2106
	/* Remember the table columns already contained in new_index */
2107
	indexed = mem_zalloc(table->n_cols * sizeof *indexed);
osku's avatar
osku committed
2108

2109
	/* Mark the table columns already contained in new_index */
osku's avatar
osku committed
2110 2111 2112 2113 2114 2115 2116 2117 2118
	for (i = 0; i < new_index->n_def; i++) {

		field = dict_index_get_nth_field(new_index, i);

		/* If there is only a prefix of the column in the index
		field, do not mark the column as contained in the index */

		if (field->prefix_len == 0) {

2119
			indexed[field->col->ind] = TRUE;
osku's avatar
osku committed
2120 2121 2122 2123 2124 2125 2126 2127 2128 2129
		}
	}

	/* Add to new_index the columns necessary to determine the clustered
	index entry uniquely */

	for (i = 0; i < clust_index->n_uniq; i++) {

		field = dict_index_get_nth_field(clust_index, i);

2130
		if (!indexed[field->col->ind]) {
2131
			dict_index_add_col(new_index, table, field->col,
2132
					   field->prefix_len);
osku's avatar
osku committed
2133 2134 2135
		}
	}

2136 2137
	mem_free(indexed);

2138
	if (dict_index_is_unique(index)) {
osku's avatar
osku committed
2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151
		new_index->n_uniq = index->n_fields;
	} else {
		new_index->n_uniq = new_index->n_def;
	}

	/* Set the n_fields value in new_index to the actual defined
	number of fields */

	new_index->n_fields = new_index->n_def;

	new_index->cached = TRUE;

	return(new_index);
2152
}
osku's avatar
osku committed
2153 2154 2155

/*====================== FOREIGN KEY PROCESSING ========================*/

2156
/*********************************************************************//**
2157 2158
Checks if a table is referenced by foreign keys.
@return	TRUE if table is referenced by a foreign key */
2159
UNIV_INTERN
osku's avatar
osku committed
2160
ibool
2161 2162
dict_table_is_referenced_by_foreign_key(
/*====================================*/
2163
	const dict_table_t*	table)	/*!< in: InnoDB table */
2164 2165 2166 2167
{
	return(UT_LIST_GET_LEN(table->referenced_list) > 0);
}

2168
/*********************************************************************//**
2169
Check if the index is referenced by a foreign key, if TRUE return foreign
2170
else return NULL
2171 2172
@return pointer to foreign key struct if index is defined for foreign
key, otherwise NULL */
2173
UNIV_INTERN
2174 2175
dict_foreign_t*
dict_table_get_referenced_constraint(
osku's avatar
osku committed
2176
/*=================================*/
2177 2178
	dict_table_t*	table,	/*!< in: InnoDB table */
	dict_index_t*	index)	/*!< in: InnoDB index */
osku's avatar
osku committed
2179
{
marko's avatar
marko committed
2180
	dict_foreign_t*	foreign;
2181

inaam's avatar
inaam committed
2182
	ut_ad(index != NULL);
marko's avatar
marko committed
2183
	ut_ad(table != NULL);
osku's avatar
osku committed
2184

marko's avatar
marko committed
2185 2186 2187
	for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
	     foreign;
	     foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
2188

marko's avatar
marko committed
2189
		if (foreign->referenced_index == index) {
2190 2191 2192 2193 2194 2195 2196 2197

			return(foreign);
		}
	}

	return(NULL);
}

2198
/*********************************************************************//**
2199 2200
Checks if a index is defined for a foreign key constraint. Index is a part
of a foreign key constraint if the index is referenced by foreign key
2201
or index is a foreign key index.
2202 2203
@return pointer to foreign key struct if index is defined for foreign
key, otherwise NULL */
2204
UNIV_INTERN
2205 2206 2207
dict_foreign_t*
dict_table_get_foreign_constraint(
/*==============================*/
2208 2209
	dict_table_t*	table,	/*!< in: InnoDB table */
	dict_index_t*	index)	/*!< in: InnoDB index */
2210
{
marko's avatar
marko committed
2211
	dict_foreign_t*	foreign;
2212

marko's avatar
marko committed
2213 2214
	ut_ad(index != NULL);
	ut_ad(table != NULL);
2215

marko's avatar
marko committed
2216 2217 2218
	for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
	     foreign;
	     foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
2219 2220 2221 2222 2223 2224 2225 2226 2227

		if (foreign->foreign_index == index
		    || foreign->referenced_index == index) {

			return(foreign);
		}
	}

	return(NULL);
osku's avatar
osku committed
2228 2229
}

2230
/*********************************************************************//**
osku's avatar
osku committed
2231 2232 2233 2234 2235
Frees a foreign key struct. */
static
void
dict_foreign_free(
/*==============*/
2236
	dict_foreign_t*	foreign)	/*!< in, own: foreign key struct */
osku's avatar
osku committed
2237 2238 2239 2240
{
	mem_heap_free(foreign->heap);
}

2241
/**********************************************************************//**
osku's avatar
osku committed
2242 2243 2244 2245 2246
Removes a foreign constraint struct from the dictionary cache. */
static
void
dict_foreign_remove_from_cache(
/*===========================*/
2247
	dict_foreign_t*	foreign)	/*!< in, own: foreign constraint */
osku's avatar
osku committed
2248 2249 2250
{
	ut_ad(mutex_own(&(dict_sys->mutex)));
	ut_a(foreign);
2251

osku's avatar
osku committed
2252 2253
	if (foreign->referenced_table) {
		UT_LIST_REMOVE(referenced_list,
2254 2255
			       foreign->referenced_table->referenced_list,
			       foreign);
osku's avatar
osku committed
2256 2257 2258 2259
	}

	if (foreign->foreign_table) {
		UT_LIST_REMOVE(foreign_list,
2260 2261
			       foreign->foreign_table->foreign_list,
			       foreign);
osku's avatar
osku committed
2262 2263 2264 2265 2266
	}

	dict_foreign_free(foreign);
}

2267
/**********************************************************************//**
osku's avatar
osku committed
2268
Looks for the foreign constraint from the foreign and referenced lists
2269 2270
of a table.
@return	foreign constraint */
osku's avatar
osku committed
2271 2272 2273 2274
static
dict_foreign_t*
dict_foreign_find(
/*==============*/
2275 2276
	dict_table_t*	table,	/*!< in: table object */
	const char*	id)	/*!< in: foreign constraint id */
osku's avatar
osku committed
2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291
{
	dict_foreign_t*	foreign;

	ut_ad(mutex_own(&(dict_sys->mutex)));

	foreign = UT_LIST_GET_FIRST(table->foreign_list);

	while (foreign) {
		if (ut_strcmp(id, foreign->id) == 0) {

			return(foreign);
		}

		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
	}
2292

osku's avatar
osku committed
2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304
	foreign = UT_LIST_GET_FIRST(table->referenced_list);

	while (foreign) {
		if (ut_strcmp(id, foreign->id) == 0) {

			return(foreign);
		}

		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
	}

	return(NULL);
2305
}
osku's avatar
osku committed
2306

2307
/*********************************************************************//**
osku's avatar
osku committed
2308
Tries to find an index whose first fields are the columns in the array,
2309
in the same order and is not marked for deletion and is not the same
2310 2311
as types_idx.
@return	matching index, NULL if not found */
osku's avatar
osku committed
2312 2313 2314 2315
static
dict_index_t*
dict_foreign_find_index(
/*====================*/
2316 2317 2318 2319
	dict_table_t*	table,	/*!< in: table */
	const char**	columns,/*!< in: array of column names */
	ulint		n_cols,	/*!< in: number of columns */
	dict_index_t*	types_idx, /*!< in: NULL or an index to whose types the
2320
				   column types must match */
2321
	ibool		check_charsets,
2322
				/*!< in: whether to check charsets.
2323
				only has an effect if types_idx != NULL */
2324
	ulint		check_null)
2325
				/*!< in: nonzero if none of the columns must
2326
				be declared NOT NULL */
osku's avatar
osku committed
2327 2328
{
	dict_index_t*	index;
2329

osku's avatar
osku committed
2330 2331 2332
	index = dict_table_get_first_index(table);

	while (index != NULL) {
2333 2334 2335 2336 2337 2338 2339 2340
		/* Ignore matches that refer to the same instance
		or the index is to be dropped */
		if (index->to_be_dropped || types_idx == index) {

			goto next_rec;

		} else if (dict_index_get_n_fields(index) >= n_cols) {
			ulint		i;
osku's avatar
osku committed
2341 2342

			for (i = 0; i < n_cols; i++) {
2343 2344 2345
				dict_field_t*	field;
				const char*	col_name;

2346 2347 2348 2349 2350 2351
				field = dict_index_get_nth_field(index, i);

				col_name = dict_table_get_col_name(
					table, dict_col_get_no(field->col));

				if (field->prefix_len != 0) {
osku's avatar
osku committed
2352 2353
					/* We do not accept column prefix
					indexes here */
2354

osku's avatar
osku committed
2355 2356 2357 2358
					break;
				}

				if (0 != innobase_strcasecmp(columns[i],
2359
							     col_name)) {
2360
					break;
osku's avatar
osku committed
2361 2362
				}

2363 2364 2365 2366 2367 2368
				if (check_null
				    && (field->col->prtype & DATA_NOT_NULL)) {

					return(NULL);
				}

2369 2370 2371 2372 2373
				if (types_idx && !cmp_cols_are_equal(
					    dict_index_get_nth_col(index, i),
					    dict_index_get_nth_col(types_idx,
								   i),
					    check_charsets)) {
osku's avatar
osku committed
2374

2375 2376
					break;
				}
osku's avatar
osku committed
2377 2378 2379 2380 2381 2382 2383 2384 2385
			}

			if (i == n_cols) {
				/* We found a matching index */

				return(index);
			}
		}

2386
next_rec:
osku's avatar
osku committed
2387 2388 2389 2390 2391 2392
		index = dict_table_get_next_index(index);
	}

	return(NULL);
}

2393
/**********************************************************************//**
2394
Find an index that is equivalent to the one passed in and is not marked
2395 2396
for deletion.
@return	index equivalent to foreign->foreign_index, or NULL */
2397 2398 2399 2400
UNIV_INTERN
dict_index_t*
dict_foreign_find_equiv_index(
/*==========================*/
2401
	dict_foreign_t*	foreign)/*!< in: foreign key */
2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415
{
	ut_a(foreign != NULL);

	/* Try to find an index which contains the columns as the
	first fields and in the right order, and the types are the
	same as in foreign->foreign_index */

	return(dict_foreign_find_index(
		       foreign->foreign_table,
		       foreign->foreign_col_names, foreign->n_fields,
		       foreign->foreign_index, TRUE, /* check types */
		       FALSE/* allow columns to be NULL */));
}

2416
/**********************************************************************//**
marko's avatar
marko committed
2417
Returns an index object by matching on the name and column names and
2418 2419
if more than one index matches return the index with the max id
@return	matching index, NULL if not found */
2420
UNIV_INTERN
2421
dict_index_t*
marko's avatar
marko committed
2422 2423
dict_table_get_index_by_max_id(
/*===========================*/
2424 2425 2426 2427
	dict_table_t*	table,	/*!< in: table */
	const char*	name,	/*!< in: the index name to find */
	const char**	columns,/*!< in: array of column names */
	ulint		n_cols)	/*!< in: number of columns */
2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475
{
	dict_index_t*	index;
	dict_index_t*	found;

	found = NULL;
	index = dict_table_get_first_index(table);

	while (index != NULL) {
		if (ut_strcmp(index->name, name) == 0
		    && dict_index_get_n_ordering_defined_by_user(index)
		    == n_cols) {

			ulint		i;

			for (i = 0; i < n_cols; i++) {
				dict_field_t*	field;
				const char*	col_name;

				field = dict_index_get_nth_field(index, i);

				col_name = dict_table_get_col_name(
					table, dict_col_get_no(field->col));

				if (0 != innobase_strcasecmp(
					    columns[i], col_name)) {

					break;
				}
			}

			if (i == n_cols) {
				/* We found a matching index, select
				the index with the higher id*/

				if (!found
				    || ut_dulint_cmp(index->id, found->id) > 0) {

					found = index;
				}
			}
		}

		index = dict_table_get_next_index(index);
	}

	return(found);
}

2476
/**********************************************************************//**
osku's avatar
osku committed
2477 2478 2479 2480 2481
Report an error in a foreign key definition. */
static
void
dict_foreign_error_report_low(
/*==========================*/
2482 2483
	FILE*		file,	/*!< in: output stream */
	const char*	name)	/*!< in: table name */
osku's avatar
osku committed
2484 2485 2486 2487 2488 2489 2490
{
	rewind(file);
	ut_print_timestamp(file);
	fprintf(file, " Error in foreign key constraint of table %s:\n",
		name);
}

2491
/**********************************************************************//**
osku's avatar
osku committed
2492 2493 2494 2495 2496
Report an error in a foreign key definition. */
static
void
dict_foreign_error_report(
/*======================*/
2497 2498 2499
	FILE*		file,	/*!< in: output stream */
	dict_foreign_t*	fk,	/*!< in: foreign key constraint */
	const char*	msg)	/*!< in: the error message */
osku's avatar
osku committed
2500 2501 2502 2503 2504 2505
{
	mutex_enter(&dict_foreign_err_mutex);
	dict_foreign_error_report_low(file, fk->foreign_table_name);
	fputs(msg, file);
	fputs(" Constraint:\n", file);
	dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
2506
	putc('\n', file);
osku's avatar
osku committed
2507
	if (fk->foreign_index) {
2508
		fputs("The index in the foreign key in table is ", file);
2509
		ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
2510
		fputs("\n"
2511
		      "See " REFMAN "innodb-foreign-key-constraints.html\n"
2512 2513
		      "for correct foreign key definition.\n",
		      file);
osku's avatar
osku committed
2514 2515 2516 2517
	}
	mutex_exit(&dict_foreign_err_mutex);
}

2518
/**********************************************************************//**
osku's avatar
osku committed
2519 2520 2521
Adds a foreign key constraint object to the dictionary cache. May free
the object if there already is an object with the same identifier in.
At least one of the foreign table and the referenced table must already
2522 2523
be in the dictionary cache!
@return	DB_SUCCESS or error code */
2524
UNIV_INTERN
osku's avatar
osku committed
2525 2526 2527
ulint
dict_foreign_add_to_cache(
/*======================*/
2528 2529
	dict_foreign_t*	foreign,	/*!< in, own: foreign key constraint */
	ibool		check_charsets)	/*!< in: TRUE=check charset
2530
					compatibility */
osku's avatar
osku committed
2531 2532 2533 2534 2535 2536
{
	dict_table_t*	for_table;
	dict_table_t*	ref_table;
	dict_foreign_t*	for_in_cache		= NULL;
	dict_index_t*	index;
	ibool		added_to_referenced_list= FALSE;
2537
	FILE*		ef			= dict_foreign_err_file;
osku's avatar
osku committed
2538 2539 2540

	ut_ad(mutex_own(&(dict_sys->mutex)));

2541 2542
	for_table = dict_table_check_if_in_cache_low(
		foreign->foreign_table_name);
2543

2544 2545
	ref_table = dict_table_check_if_in_cache_low(
		foreign->referenced_table_name);
osku's avatar
osku committed
2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563
	ut_a(for_table || ref_table);

	if (for_table) {
		for_in_cache = dict_foreign_find(for_table, foreign->id);
	}

	if (!for_in_cache && ref_table) {
		for_in_cache = dict_foreign_find(ref_table, foreign->id);
	}

	if (for_in_cache) {
		/* Free the foreign object */
		mem_heap_free(foreign->heap);
	} else {
		for_in_cache = foreign;
	}

	if (for_in_cache->referenced_table == NULL && ref_table) {
2564 2565
		index = dict_foreign_find_index(
			ref_table,
2566
			for_in_cache->referenced_col_names,
2567
			for_in_cache->n_fields, for_in_cache->foreign_index,
2568
			check_charsets, FALSE);
osku's avatar
osku committed
2569 2570

		if (index == NULL) {
2571 2572 2573 2574 2575 2576 2577 2578
			dict_foreign_error_report(
				ef, for_in_cache,
				"there is no index in referenced table"
				" which would contain\n"
				"the columns as the first columns,"
				" or the data types in the\n"
				"referenced table do not match"
				" the ones in table.");
osku's avatar
osku committed
2579 2580 2581 2582 2583

			if (for_in_cache == foreign) {
				mem_heap_free(foreign->heap);
			}

2584
			return(DB_CANNOT_ADD_CONSTRAINT);
osku's avatar
osku committed
2585 2586 2587 2588 2589
		}

		for_in_cache->referenced_table = ref_table;
		for_in_cache->referenced_index = index;
		UT_LIST_ADD_LAST(referenced_list,
2590 2591
				 ref_table->referenced_list,
				 for_in_cache);
osku's avatar
osku committed
2592 2593 2594 2595
		added_to_referenced_list = TRUE;
	}

	if (for_in_cache->foreign_table == NULL && for_table) {
2596 2597
		index = dict_foreign_find_index(
			for_table,
2598
			for_in_cache->foreign_col_names,
2599
			for_in_cache->n_fields,
2600 2601 2602 2603
			for_in_cache->referenced_index, check_charsets,
			for_in_cache->type
			& (DICT_FOREIGN_ON_DELETE_SET_NULL
			   | DICT_FOREIGN_ON_UPDATE_SET_NULL));
osku's avatar
osku committed
2604 2605

		if (index == NULL) {
2606 2607 2608 2609 2610 2611 2612
			dict_foreign_error_report(
				ef, for_in_cache,
				"there is no index in the table"
				" which would contain\n"
				"the columns as the first columns,"
				" or the data types in the\n"
				"table do not match"
2613 2614 2615
				" the ones in the referenced table\n"
				"or one of the ON ... SET NULL columns"
				" is declared NOT NULL.");
osku's avatar
osku committed
2616 2617 2618

			if (for_in_cache == foreign) {
				if (added_to_referenced_list) {
2619 2620 2621 2622
					UT_LIST_REMOVE(
						referenced_list,
						ref_table->referenced_list,
						for_in_cache);
osku's avatar
osku committed
2623
				}
2624

osku's avatar
osku committed
2625 2626 2627
				mem_heap_free(foreign->heap);
			}

2628
			return(DB_CANNOT_ADD_CONSTRAINT);
osku's avatar
osku committed
2629 2630 2631 2632 2633
		}

		for_in_cache->foreign_table = for_table;
		for_in_cache->foreign_index = index;
		UT_LIST_ADD_LAST(foreign_list,
2634 2635
				 for_table->foreign_list,
				 for_in_cache);
osku's avatar
osku committed
2636 2637 2638 2639 2640
	}

	return(DB_SUCCESS);
}

2641
/*********************************************************************//**
osku's avatar
osku committed
2642 2643
Scans from pointer onwards. Stops if is at the start of a copy of
'string' where characters are compared without case sensitivity, and
2644
only outside `` or "" quotes. Stops also at NUL.
2645
@return	scanned up to this */
2646
static
osku's avatar
osku committed
2647 2648 2649
const char*
dict_scan_to(
/*=========*/
2650 2651
	const char*	ptr,	/*!< in: scan from */
	const char*	string)	/*!< in: look for this */
osku's avatar
osku committed
2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669
{
	char	quote	= '\0';

	for (; *ptr; ptr++) {
		if (*ptr == quote) {
			/* Closing quote character: do not look for
			starting quote or the keyword. */
			quote = '\0';
		} else if (quote) {
			/* Within quotes: do nothing. */
		} else if (*ptr == '`' || *ptr == '"') {
			/* Starting quote: remember the quote character. */
			quote = *ptr;
		} else {
			/* Outside quotes: look for the keyword. */
			ulint	i;
			for (i = 0; string[i]; i++) {
				if (toupper((int)(unsigned char)(ptr[i]))
2670 2671
				    != toupper((int)(unsigned char)
					       (string[i]))) {
osku's avatar
osku committed
2672 2673 2674 2675
					goto nomatch;
				}
			}
			break;
2676
nomatch:
osku's avatar
osku committed
2677 2678 2679 2680 2681 2682 2683
			;
		}
	}

	return(ptr);
}

2684
/*********************************************************************//**
2685
Accepts a specified string. Comparisons are case-insensitive.
2686 2687
@return if string was accepted, the pointer is moved after that, else
ptr is returned */
2688
static
osku's avatar
osku committed
2689 2690 2691
const char*
dict_accept(
/*========*/
2692 2693 2694
	struct charset_info_st*	cs,/*!< in: the character set of ptr */
	const char*	ptr,	/*!< in: scan from this */
	const char*	string,	/*!< in: accept only this string as the next
osku's avatar
osku committed
2695
				non-whitespace string */
2696
	ibool*		success)/*!< out: TRUE if accepted */
osku's avatar
osku committed
2697 2698 2699 2700 2701
{
	const char*	old_ptr = ptr;
	const char*	old_ptr2;

	*success = FALSE;
2702

2703
	while (my_isspace(cs, *ptr)) {
osku's avatar
osku committed
2704 2705 2706 2707
		ptr++;
	}

	old_ptr2 = ptr;
2708

osku's avatar
osku committed
2709
	ptr = dict_scan_to(ptr, string);
2710

osku's avatar
osku committed
2711 2712 2713 2714 2715 2716 2717 2718 2719
	if (*ptr == '\0' || old_ptr2 != ptr) {
		return(old_ptr);
	}

	*success = TRUE;

	return(ptr + ut_strlen(string));
}

2720
/*********************************************************************//**
osku's avatar
osku committed
2721
Scans an id. For the lexical definition of an 'id', see the code below.
2722 2723
Strips backquotes or double quotes from around the id.
@return	scanned to */
osku's avatar
osku committed
2724 2725 2726 2727
static
const char*
dict_scan_id(
/*=========*/
2728 2729 2730
	struct charset_info_st*	cs,/*!< in: the character set of ptr */
	const char*	ptr,	/*!< in: scanned to */
	mem_heap_t*	heap,	/*!< in: heap where to allocate the id
osku's avatar
osku committed
2731 2732
				(NULL=id will not be allocated, but it
				will point to string near ptr) */
2733
	const char**	id,	/*!< out,own: the id; NULL if no id was
osku's avatar
osku committed
2734
				scannable */
2735
	ibool		table_id,/*!< in: TRUE=convert the allocated id
2736
				as a table name; FALSE=convert to UTF-8 */
osku's avatar
osku committed
2737
	ibool		accept_also_dot)
2738
				/*!< in: TRUE if also a dot can appear in a
osku's avatar
osku committed
2739 2740 2741 2742 2743 2744
				non-quoted id; in a quoted id it can appear
				always */
{
	char		quote	= '\0';
	ulint		len	= 0;
	const char*	s;
2745 2746
	char*		str;
	char*		dst;
osku's avatar
osku committed
2747 2748 2749

	*id = NULL;

2750
	while (my_isspace(cs, *ptr)) {
osku's avatar
osku committed
2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780
		ptr++;
	}

	if (*ptr == '\0') {

		return(ptr);
	}

	if (*ptr == '`' || *ptr == '"') {
		quote = *ptr++;
	}

	s = ptr;

	if (quote) {
		for (;;) {
			if (!*ptr) {
				/* Syntax error */
				return(ptr);
			}
			if (*ptr == quote) {
				ptr++;
				if (*ptr != quote) {
					break;
				}
			}
			ptr++;
			len++;
		}
	} else {
2781
		while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
2782 2783
		       && (accept_also_dot || *ptr != '.')
		       && *ptr != ',' && *ptr != '\0') {
osku's avatar
osku committed
2784 2785 2786 2787 2788 2789 2790

			ptr++;
		}

		len = ptr - s;
	}

2791 2792 2793 2794 2795 2796 2797 2798 2799
	if (UNIV_UNLIKELY(!heap)) {
		/* no heap given: id will point to source string */
		*id = s;
		return(ptr);
	}

	if (quote) {
		char*	d;
		str = d = mem_heap_alloc(heap, len + 1);
osku's avatar
osku committed
2800 2801 2802 2803 2804 2805
		while (len--) {
			if ((*d++ = *s++) == quote) {
				s++;
			}
		}
		*d++ = 0;
2806 2807 2808
		len = d - str;
		ut_ad(*s == quote);
		ut_ad(s + 1 == ptr);
osku's avatar
osku committed
2809
	} else {
2810 2811 2812 2813 2814 2815 2816 2817 2818 2819
		str = mem_heap_strdupl(heap, s, len);
	}

	if (!table_id) {
convert_id:
		/* Convert the identifier from connection character set
		to UTF-8. */
		len = 3 * len + 1;
		*id = dst = mem_heap_alloc(heap, len);

2820
		innobase_convert_from_id(cs, dst, str, len);
2821
	} else if (!strncmp(str, srv_mysql50_table_name_prefix,
2822
			    sizeof srv_mysql50_table_name_prefix)) {
2823 2824 2825 2826 2827 2828 2829 2830 2831 2832
		/* This is a pre-5.1 table name
		containing chars other than [A-Za-z0-9].
		Discard the prefix and use raw UTF-8 encoding. */
		str += sizeof srv_mysql50_table_name_prefix;
		len -= sizeof srv_mysql50_table_name_prefix;
		goto convert_id;
	} else {
		/* Encode using filename-safe characters. */
		len = 5 * len + 1;
		*id = dst = mem_heap_alloc(heap, len);
osku's avatar
osku committed
2833

2834
		innobase_convert_from_table_id(cs, dst, str, len);
osku's avatar
osku committed
2835 2836 2837 2838 2839
	}

	return(ptr);
}

2840
/*********************************************************************//**
2841 2842
Tries to scan a column name.
@return	scanned to */
osku's avatar
osku committed
2843 2844 2845 2846
static
const char*
dict_scan_col(
/*==========*/
2847 2848 2849 2850 2851 2852 2853
	struct charset_info_st*	cs,	/*!< in: the character set of ptr */
	const char*		ptr,	/*!< in: scanned to */
	ibool*			success,/*!< out: TRUE if success */
	dict_table_t*		table,	/*!< in: table in which the column is */
	const dict_col_t**	column,	/*!< out: pointer to column if success */
	mem_heap_t*		heap,	/*!< in: heap where to allocate */
	const char**		name)	/*!< out,own: the column name;
2854
					NULL if no name was scannable */
osku's avatar
osku committed
2855 2856 2857 2858 2859
{
	ulint		i;

	*success = FALSE;

2860
	ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
osku's avatar
osku committed
2861 2862 2863 2864 2865 2866 2867 2868 2869 2870

	if (*name == NULL) {

		return(ptr);	/* Syntax error */
	}

	if (table == NULL) {
		*success = TRUE;
		*column = NULL;
	} else {
2871
		for (i = 0; i < dict_table_get_n_cols(table); i++) {
osku's avatar
osku committed
2872

2873 2874
			const char*	col_name = dict_table_get_col_name(
				table, i);
osku's avatar
osku committed
2875

2876
			if (0 == innobase_strcasecmp(col_name, *name)) {
2877
				/* Found */
osku's avatar
osku committed
2878

2879
				*success = TRUE;
2880 2881
				*column = dict_table_get_nth_col(table, i);
				strcpy((char*) *name, col_name);
osku's avatar
osku committed
2882

2883
				break;
osku's avatar
osku committed
2884 2885 2886
			}
		}
	}
2887

osku's avatar
osku committed
2888 2889 2890
	return(ptr);
}

2891
/*********************************************************************//**
2892 2893
Scans a table name from an SQL string.
@return	scanned to */
osku's avatar
osku committed
2894 2895 2896 2897
static
const char*
dict_scan_table_name(
/*=================*/
2898 2899 2900 2901 2902 2903 2904
	struct charset_info_st*	cs,/*!< in: the character set of ptr */
	const char*	ptr,	/*!< in: scanned to */
	dict_table_t**	table,	/*!< out: table object or NULL */
	const char*	name,	/*!< in: foreign key table name */
	ibool*		success,/*!< out: TRUE if ok name found */
	mem_heap_t*	heap,	/*!< in: heap where to allocate the id */
	const char**	ref_name)/*!< out,own: the table name;
osku's avatar
osku committed
2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915
				NULL if no name was scannable */
{
	const char*	database_name	= NULL;
	ulint		database_name_len = 0;
	const char*	table_name	= NULL;
	ulint		table_name_len;
	const char*	scan_name;
	char*		ref;

	*success = FALSE;
	*table = NULL;
2916

2917
	ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
osku's avatar
osku committed
2918 2919

	if (scan_name == NULL) {
2920

osku's avatar
osku committed
2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931
		return(ptr);	/* Syntax error */
	}

	if (*ptr == '.') {
		/* We scanned the database name; scan also the table name */

		ptr++;

		database_name = scan_name;
		database_name_len = strlen(database_name);

2932
		ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
osku's avatar
osku committed
2933 2934 2935 2936 2937 2938 2939 2940 2941 2942

		if (table_name == NULL) {

			return(ptr);	/* Syntax error */
		}
	} else {
		/* To be able to read table dumps made with InnoDB-4.0.17 or
		earlier, we must allow the dot separator between the database
		name and the table name also to appear within a quoted
		identifier! InnoDB used to print a constraint as:
2943
		... REFERENCES `databasename.tablename` ...
osku's avatar
osku committed
2944
		starting from 4.0.18 it is
2945
		... REFERENCES `databasename`.`tablename` ... */
osku's avatar
osku committed
2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989
		const char* s;

		for (s = scan_name; *s; s++) {
			if (*s == '.') {
				database_name = scan_name;
				database_name_len = s - scan_name;
				scan_name = ++s;
				break;/* to do: multiple dots? */
			}
		}

		table_name = scan_name;
	}

	if (database_name == NULL) {
		/* Use the database name of the foreign key table */

		database_name = name;
		database_name_len = dict_get_db_name_len(name);
	}

	table_name_len = strlen(table_name);

	/* Copy database_name, '/', table_name, '\0' */
	ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
	memcpy(ref, database_name, database_name_len);
	ref[database_name_len] = '/';
	memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
#ifndef __WIN__
	if (srv_lower_case_table_names) {
#endif /* !__WIN__ */
		/* The table name is always put to lower case on Windows. */
		innobase_casedn_str(ref);
#ifndef __WIN__
	}
#endif /* !__WIN__ */

	*success = TRUE;
	*ref_name = ref;
	*table = dict_table_get_low(ref);

	return(ptr);
}

2990
/*********************************************************************//**
2991 2992
Skips one id. The id is allowed to contain also '.'.
@return	scanned to */
osku's avatar
osku committed
2993 2994 2995 2996
static
const char*
dict_skip_word(
/*===========*/
2997 2998 2999
	struct charset_info_st*	cs,/*!< in: the character set of ptr */
	const char*	ptr,	/*!< in: scanned to */
	ibool*		success)/*!< out: TRUE if success, FALSE if just spaces
osku's avatar
osku committed
3000 3001 3002
				left in string or a syntax error */
{
	const char*	start;
3003

osku's avatar
osku committed
3004 3005
	*success = FALSE;

3006
	ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
osku's avatar
osku committed
3007 3008 3009 3010

	if (start) {
		*success = TRUE;
	}
3011

osku's avatar
osku committed
3012 3013 3014
	return(ptr);
}

3015
/*********************************************************************//**
osku's avatar
osku committed
3016 3017
Removes MySQL comments from an SQL string. A comment is either
(a) '#' to the end of the line,
3018 3019
(b) '--[space]' to the end of the line, or
(c) '[slash][asterisk]' till the next '[asterisk][slash]' (like the familiar
3020
C comment syntax).
3021 3022
@return own: SQL string stripped from comments; the caller must free
this with mem_free()! */
osku's avatar
osku committed
3023 3024 3025 3026
static
char*
dict_strip_comments(
/*================*/
3027 3028
	const char*	sql_string,	/*!< in: SQL string */
	size_t		sql_length)	/*!< in: length of sql_string */
osku's avatar
osku committed
3029 3030 3031
{
	char*		str;
	const char*	sptr;
3032
	const char*	eptr	= sql_string + sql_length;
osku's avatar
osku committed
3033
	char*		ptr;
3034 3035
	/* unclosed quote character (0 if none) */
	char		quote	= 0;
osku's avatar
osku committed
3036

3037
	str = mem_alloc(sql_length + 1);
osku's avatar
osku committed
3038 3039 3040 3041 3042 3043

	sptr = sql_string;
	ptr = str;

	for (;;) {
scan_more:
3044 3045
		if (sptr >= eptr || *sptr == '\0') {
end_of_string:
osku's avatar
osku committed
3046 3047
			*ptr = '\0';

3048
			ut_a(ptr <= str + sql_length);
osku's avatar
osku committed
3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059

			return(str);
		}

		if (*sptr == quote) {
			/* Closing quote character: do not look for
			starting quote or comments. */
			quote = 0;
		} else if (quote) {
			/* Within quotes: do not look for
			starting quotes or comments. */
3060
		} else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
osku's avatar
osku committed
3061 3062 3063
			/* Starting quote: remember the quote character. */
			quote = *sptr;
		} else if (*sptr == '#'
3064 3065
			   || (sptr[0] == '-' && sptr[1] == '-'
			       && sptr[2] == ' ')) {
osku's avatar
osku committed
3066
			for (;;) {
3067 3068 3069 3070
				if (++sptr >= eptr) {
					goto end_of_string;
				}

osku's avatar
osku committed
3071 3072 3073
				/* In Unix a newline is 0x0A while in Windows
				it is 0x0D followed by 0x0A */

3074 3075 3076 3077
				switch (*sptr) {
				case (char) 0X0A:
				case (char) 0x0D:
				case '\0':
osku's avatar
osku committed
3078 3079 3080 3081
					goto scan_more;
				}
			}
		} else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
3082
			sptr += 2;
osku's avatar
osku committed
3083
			for (;;) {
3084 3085
				if (sptr >= eptr) {
					goto end_of_string;
osku's avatar
osku committed
3086 3087
				}

3088 3089
				switch (*sptr) {
				case '\0':
osku's avatar
osku committed
3090
					goto scan_more;
3091 3092 3093 3094 3095
				case '*':
					if (sptr[1] == '/') {
						sptr += 2;
						goto scan_more;
					}
osku's avatar
osku committed
3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108
				}

				sptr++;
			}
		}

		*ptr = *sptr;

		ptr++;
		sptr++;
	}
}

3109
/*********************************************************************//**
3110
Finds the highest [number] for foreign key constraints of the table. Looks
osku's avatar
osku committed
3111
only at the >= 4.0.18-format id's, which are of the form
3112
databasename/tablename_ibfk_[number].
3113
@return	highest number, 0 if table has no new format foreign key constraints */
osku's avatar
osku committed
3114 3115 3116 3117
static
ulint
dict_table_get_highest_foreign_id(
/*==============================*/
3118
	dict_table_t*	table)	/*!< in: table in the dictionary memory cache */
osku's avatar
osku committed
3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132
{
	dict_foreign_t*	foreign;
	char*		endp;
	ulint		biggest_id	= 0;
	ulint		id;
	ulint		len;

	ut_a(table);

	len = ut_strlen(table->name);
	foreign = UT_LIST_GET_FIRST(table->foreign_list);

	while (foreign) {
		if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
3133 3134 3135 3136
		    && 0 == ut_memcmp(foreign->id, table->name, len)
		    && 0 == ut_memcmp(foreign->id + len,
				      dict_ibfk, (sizeof dict_ibfk) - 1)
		    && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
osku's avatar
osku committed
3137 3138
			/* It is of the >= 4.0.18 format */

3139 3140 3141
			id = strtoul(foreign->id + len
				     + ((sizeof dict_ibfk) - 1),
				     &endp, 10);
osku's avatar
osku committed
3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156
			if (*endp == '\0') {
				ut_a(id != biggest_id);

				if (id > biggest_id) {
					biggest_id = id;
				}
			}
		}

		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
	}

	return(biggest_id);
}

3157
/*********************************************************************//**
osku's avatar
osku committed
3158 3159 3160 3161 3162
Reports a simple foreign key create clause syntax error. */
static
void
dict_foreign_report_syntax_err(
/*===========================*/
3163
	const char*	name,		/*!< in: table name */
osku's avatar
osku committed
3164
	const char*	start_of_latest_foreign,
3165
					/*!< in: start of the foreign key clause
osku's avatar
osku committed
3166
					in the SQL string */
3167
	const char*	ptr)		/*!< in: place of the syntax error */
osku's avatar
osku committed
3168
{
3169
	FILE*	ef = dict_foreign_err_file;
osku's avatar
osku committed
3170 3171 3172 3173 3174 3175 3176 3177

	mutex_enter(&dict_foreign_err_mutex);
	dict_foreign_error_report_low(ef, name);
	fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
		start_of_latest_foreign, ptr);
	mutex_exit(&dict_foreign_err_mutex);
}

3178
/*********************************************************************//**
osku's avatar
osku committed
3179 3180 3181 3182
Scans a table create SQL string and adds to the data dictionary the foreign
key constraints declared in the string. This function should be called after
the indexes for a table have been created. Each foreign key constraint must
be accompanied with indexes in both participating tables. The indexes are
3183 3184
allowed to contain more fields than mentioned in the constraint.
@return	error code or DB_SUCCESS */
osku's avatar
osku committed
3185 3186 3187 3188
static
ulint
dict_create_foreign_constraints_low(
/*================================*/
3189 3190 3191
	trx_t*		trx,	/*!< in: transaction */
	mem_heap_t*	heap,	/*!< in: memory heap */
	struct charset_info_st*	cs,/*!< in: the character set of sql_string */
osku's avatar
osku committed
3192
	const char*	sql_string,
3193
				/*!< in: CREATE TABLE or ALTER TABLE statement
osku's avatar
osku committed
3194 3195 3196 3197 3198
				where foreign keys are declared like:
				FOREIGN KEY (a, b) REFERENCES table2(c, d),
				table2 can be written also with the database
				name before it: test.table2; the default
				database is the database of parameter name */
3199
	const char*	name,	/*!< in: table full name in the normalized form
osku's avatar
osku committed
3200 3201
				database_name/table_name */
	ibool		reject_fks)
3202
				/*!< in: if TRUE, fail with error code
osku's avatar
osku committed
3203 3204 3205 3206 3207 3208 3209 3210 3211
				DB_CANNOT_ADD_CONSTRAINT if any foreign
				keys are found. */
{
	dict_table_t*	table;
	dict_table_t*	referenced_table;
	dict_table_t*	table_to_alter;
	ulint		highest_id_so_far	= 0;
	dict_index_t*	index;
	dict_foreign_t*	foreign;
3212
	const char*	ptr			= sql_string;
osku's avatar
osku committed
3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224
	const char*	start_of_latest_foreign	= sql_string;
	FILE*		ef			= dict_foreign_err_file;
	const char*	constraint_name;
	ibool		success;
	ulint		error;
	const char*	ptr1;
	const char*	ptr2;
	ulint		i;
	ulint		j;
	ibool		is_on_delete;
	ulint		n_on_deletes;
	ulint		n_on_updates;
3225
	const dict_col_t*columns[500];
osku's avatar
osku committed
3226 3227
	const char*	column_names[500];
	const char*	referenced_table_name;
3228

osku's avatar
osku committed
3229 3230 3231 3232 3233 3234 3235 3236
	ut_ad(mutex_own(&(dict_sys->mutex)));

	table = dict_table_get_low(name);

	if (table == NULL) {
		mutex_enter(&dict_foreign_err_mutex);
		dict_foreign_error_report_low(ef, name);
		fprintf(ef,
3237 3238 3239
			"Cannot find the table in the internal"
			" data dictionary of InnoDB.\n"
			"Create table statement:\n%s\n", sql_string);
osku's avatar
osku committed
3240 3241 3242 3243 3244 3245 3246 3247
		mutex_exit(&dict_foreign_err_mutex);

		return(DB_ERROR);
	}

	/* First check if we are actually doing an ALTER TABLE, and in that
	case look for the table being altered */

3248
	ptr = dict_accept(cs, ptr, "ALTER", &success);
osku's avatar
osku committed
3249 3250 3251 3252 3253 3254

	if (!success) {

		goto loop;
	}

3255
	ptr = dict_accept(cs, ptr, "TABLE", &success);
osku's avatar
osku committed
3256 3257 3258 3259 3260 3261 3262 3263

	if (!success) {

		goto loop;
	}

	/* We are doing an ALTER TABLE: scan the table name we are altering */

3264
	ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
3265
				   &success, heap, &referenced_table_name);
osku's avatar
osku committed
3266 3267
	if (!success) {
		fprintf(stderr,
3268 3269 3270
			"InnoDB: Error: could not find"
			" the table being ALTERED in:\n%s\n",
			sql_string);
osku's avatar
osku committed
3271 3272 3273 3274 3275

		return(DB_ERROR);
	}

	/* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
3276 3277
	format databasename/tablename_ibfk_[number], where [number] is local
	to the table; look for the highest [number] for table_to_alter, so
osku's avatar
osku committed
3278 3279 3280 3281 3282 3283 3284 3285 3286
	that we can assign to new constraints higher numbers. */

	/* If we are altering a temporary table, the table name after ALTER
	TABLE does not correspond to the internal table name, and
	table_to_alter is NULL. TODO: should we fix this somehow? */

	if (table_to_alter == NULL) {
		highest_id_so_far = 0;
	} else {
3287 3288
		highest_id_so_far = dict_table_get_highest_foreign_id(
			table_to_alter);
osku's avatar
osku committed
3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305
	}

	/* Scan for foreign key declarations in a loop */
loop:
	/* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */

	ptr1 = dict_scan_to(ptr, "CONSTRAINT");
	ptr2 = dict_scan_to(ptr, "FOREIGN");

	constraint_name = NULL;

	if (ptr1 < ptr2) {
		/* The user may have specified a constraint name. Pick it so
		that we can store 'databasename/constraintname' as the id of
		of the constraint to system tables. */
		ptr = ptr1;

3306
		ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
osku's avatar
osku committed
3307 3308 3309

		ut_a(success);

3310
		if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
3311
			goto loop;
osku's avatar
osku committed
3312 3313
		}

3314
		while (my_isspace(cs, *ptr)) {
osku's avatar
osku committed
3315 3316 3317 3318 3319
			ptr++;
		}

		/* read constraint name unless got "CONSTRAINT FOREIGN" */
		if (ptr != ptr2) {
3320
			ptr = dict_scan_id(cs, ptr, heap,
3321
					   &constraint_name, FALSE, FALSE);
osku's avatar
osku committed
3322 3323 3324 3325 3326 3327 3328
		}
	} else {
		ptr = ptr2;
	}

	if (*ptr == '\0') {
		/* The proper way to reject foreign keys for temporary
3329 3330 3331 3332 3333 3334
		tables would be to split the lexing and syntactical
		analysis of foreign key clauses from the actual adding
		of them, so that ha_innodb.cc could first parse the SQL
		command, determine if there are any foreign keys, and
		if so, immediately reject the command if the table is a
		temporary one. For now, this kludge will work. */
3335
		if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
3336 3337

			return(DB_CANNOT_ADD_CONSTRAINT);
osku's avatar
osku committed
3338
		}
3339

osku's avatar
osku committed
3340 3341 3342
		/**********************************************************/
		/* The following call adds the foreign key constraints
		to the data dictionary system tables on disk */
3343

3344 3345
		error = dict_create_add_foreigns_to_dictionary(
			highest_id_so_far, table, trx);
osku's avatar
osku committed
3346 3347 3348 3349 3350
		return(error);
	}

	start_of_latest_foreign = ptr;

3351
	ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3352

osku's avatar
osku committed
3353 3354 3355 3356
	if (!success) {
		goto loop;
	}

3357
	if (!my_isspace(cs, *ptr)) {
3358
		goto loop;
osku's avatar
osku committed
3359 3360
	}

3361
	ptr = dict_accept(cs, ptr, "KEY", &success);
osku's avatar
osku committed
3362 3363 3364 3365 3366

	if (!success) {
		goto loop;
	}

3367
	ptr = dict_accept(cs, ptr, "(", &success);
osku's avatar
osku committed
3368 3369 3370 3371

	if (!success) {
		/* MySQL allows also an index id before the '('; we
		skip it */
3372
		ptr = dict_skip_word(cs, ptr, &success);
osku's avatar
osku committed
3373 3374

		if (!success) {
3375 3376
			dict_foreign_report_syntax_err(
				name, start_of_latest_foreign, ptr);
osku's avatar
osku committed
3377 3378 3379 3380

			return(DB_CANNOT_ADD_CONSTRAINT);
		}

3381
		ptr = dict_accept(cs, ptr, "(", &success);
osku's avatar
osku committed
3382 3383 3384 3385 3386

		if (!success) {
			/* We do not flag a syntax error here because in an
			ALTER TABLE we may also have DROP FOREIGN KEY abc */

3387
			goto loop;
osku's avatar
osku committed
3388 3389 3390 3391 3392 3393 3394 3395
		}
	}

	i = 0;

	/* Scan the columns in the first list */
col_loop1:
	ut_a(i < (sizeof column_names) / sizeof *column_names);
3396
	ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
3397
			    heap, column_names + i);
osku's avatar
osku committed
3398 3399 3400 3401
	if (!success) {
		mutex_enter(&dict_foreign_err_mutex);
		dict_foreign_error_report_low(ef, name);
		fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
3402
			start_of_latest_foreign, ptr);
osku's avatar
osku committed
3403 3404 3405 3406 3407 3408
		mutex_exit(&dict_foreign_err_mutex);

		return(DB_CANNOT_ADD_CONSTRAINT);
	}

	i++;
3409

3410
	ptr = dict_accept(cs, ptr, ",", &success);
osku's avatar
osku committed
3411 3412 3413 3414

	if (success) {
		goto col_loop1;
	}
3415

3416
	ptr = dict_accept(cs, ptr, ")", &success);
osku's avatar
osku committed
3417 3418

	if (!success) {
3419 3420
		dict_foreign_report_syntax_err(
			name, start_of_latest_foreign, ptr);
osku's avatar
osku committed
3421 3422 3423 3424 3425 3426
		return(DB_CANNOT_ADD_CONSTRAINT);
	}

	/* Try to find an index which contains the columns
	as the first fields and in the right order */

3427 3428
	index = dict_foreign_find_index(table, column_names, i,
					NULL, TRUE, FALSE);
osku's avatar
osku committed
3429 3430 3431 3432 3433

	if (!index) {
		mutex_enter(&dict_foreign_err_mutex);
		dict_foreign_error_report_low(ef, name);
		fputs("There is no index in table ", ef);
3434
		ut_print_name(ef, NULL, TRUE, name);
osku's avatar
osku committed
3435
		fprintf(ef, " where the columns appear\n"
3436
			"as the first columns. Constraint:\n%s\n"
3437
			"See " REFMAN "innodb-foreign-key-constraints.html\n"
3438
			"for correct foreign key definition.\n",
osku's avatar
osku committed
3439 3440 3441 3442 3443
			start_of_latest_foreign);
		mutex_exit(&dict_foreign_err_mutex);

		return(DB_CANNOT_ADD_CONSTRAINT);
	}
3444
	ptr = dict_accept(cs, ptr, "REFERENCES", &success);
osku's avatar
osku committed
3445

3446
	if (!success || !my_isspace(cs, *ptr)) {
3447 3448
		dict_foreign_report_syntax_err(
			name, start_of_latest_foreign, ptr);
osku's avatar
osku committed
3449 3450 3451 3452 3453 3454 3455 3456
		return(DB_CANNOT_ADD_CONSTRAINT);
	}

	/* Let us create a constraint struct */

	foreign = dict_mem_foreign_create();

	if (constraint_name) {
3457
		ulint	db_len;
osku's avatar
osku committed
3458 3459 3460 3461 3462 3463 3464 3465

		/* Catenate 'databasename/' to the constraint name specified
		by the user: we conceive the constraint as belonging to the
		same MySQL 'database' as the table itself. We store the name
		to foreign->id. */

		db_len = dict_get_db_name_len(table->name);

3466 3467
		foreign->id = mem_heap_alloc(
			foreign->heap, db_len + strlen(constraint_name) + 2);
osku's avatar
osku committed
3468 3469 3470 3471 3472 3473 3474 3475

		ut_memcpy(foreign->id, table->name, db_len);
		foreign->id[db_len] = '/';
		strcpy(foreign->id + db_len + 1, constraint_name);
	}

	foreign->foreign_table = table;
	foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
3476
						      table->name);
osku's avatar
osku committed
3477
	foreign->foreign_index = index;
3478
	foreign->n_fields = (unsigned int) i;
osku's avatar
osku committed
3479
	foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
3480
						    i * sizeof(void*));
osku's avatar
osku committed
3481
	for (i = 0; i < foreign->n_fields; i++) {
3482 3483 3484 3485
		foreign->foreign_col_names[i] = mem_heap_strdup(
			foreign->heap,
			dict_table_get_col_name(table,
						dict_col_get_no(columns[i])));
osku's avatar
osku committed
3486
	}
3487

3488
	ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
3489
				   &success, heap, &referenced_table_name);
osku's avatar
osku committed
3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505

	/* Note that referenced_table can be NULL if the user has suppressed
	checking of foreign key constraints! */

	if (!success || (!referenced_table && trx->check_foreigns)) {
		dict_foreign_free(foreign);

		mutex_enter(&dict_foreign_err_mutex);
		dict_foreign_error_report_low(ef, name);
		fprintf(ef, "%s:\nCannot resolve table name close to:\n"
			"%s\n",
			start_of_latest_foreign, ptr);
		mutex_exit(&dict_foreign_err_mutex);

		return(DB_CANNOT_ADD_CONSTRAINT);
	}
3506

3507
	ptr = dict_accept(cs, ptr, "(", &success);
osku's avatar
osku committed
3508 3509 3510 3511

	if (!success) {
		dict_foreign_free(foreign);
		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3512
					       ptr);
osku's avatar
osku committed
3513 3514 3515 3516 3517 3518 3519
		return(DB_CANNOT_ADD_CONSTRAINT);
	}

	/* Scan the columns in the second list */
	i = 0;

col_loop2:
3520
	ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
3521
			    heap, column_names + i);
osku's avatar
osku committed
3522
	i++;
3523

osku's avatar
osku committed
3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536
	if (!success) {
		dict_foreign_free(foreign);

		mutex_enter(&dict_foreign_err_mutex);
		dict_foreign_error_report_low(ef, name);
		fprintf(ef, "%s:\nCannot resolve column name close to:\n"
			"%s\n",
			start_of_latest_foreign, ptr);
		mutex_exit(&dict_foreign_err_mutex);

		return(DB_CANNOT_ADD_CONSTRAINT);
	}

3537
	ptr = dict_accept(cs, ptr, ",", &success);
osku's avatar
osku committed
3538 3539 3540 3541

	if (success) {
		goto col_loop2;
	}
3542

3543
	ptr = dict_accept(cs, ptr, ")", &success);
osku's avatar
osku committed
3544 3545 3546

	if (!success || foreign->n_fields != i) {
		dict_foreign_free(foreign);
3547

osku's avatar
osku committed
3548
		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3549
					       ptr);
osku's avatar
osku committed
3550 3551 3552 3553 3554
		return(DB_CANNOT_ADD_CONSTRAINT);
	}

	n_on_deletes = 0;
	n_on_updates = 0;
3555

osku's avatar
osku committed
3556 3557 3558
scan_on_conditions:
	/* Loop here as long as we can find ON ... conditions */

3559
	ptr = dict_accept(cs, ptr, "ON", &success);
osku's avatar
osku committed
3560 3561 3562 3563 3564 3565

	if (!success) {

		goto try_find_index;
	}

3566
	ptr = dict_accept(cs, ptr, "DELETE", &success);
osku's avatar
osku committed
3567 3568

	if (!success) {
3569
		ptr = dict_accept(cs, ptr, "UPDATE", &success);
osku's avatar
osku committed
3570 3571 3572

		if (!success) {
			dict_foreign_free(foreign);
3573

3574 3575
			dict_foreign_report_syntax_err(
				name, start_of_latest_foreign, ptr);
osku's avatar
osku committed
3576 3577 3578 3579 3580 3581 3582 3583 3584 3585
			return(DB_CANNOT_ADD_CONSTRAINT);
		}

		is_on_delete = FALSE;
		n_on_updates++;
	} else {
		is_on_delete = TRUE;
		n_on_deletes++;
	}

3586
	ptr = dict_accept(cs, ptr, "RESTRICT", &success);
osku's avatar
osku committed
3587 3588 3589 3590 3591

	if (success) {
		goto scan_on_conditions;
	}

3592
	ptr = dict_accept(cs, ptr, "CASCADE", &success);
osku's avatar
osku committed
3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603

	if (success) {
		if (is_on_delete) {
			foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
		} else {
			foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
		}

		goto scan_on_conditions;
	}

3604
	ptr = dict_accept(cs, ptr, "NO", &success);
osku's avatar
osku committed
3605 3606

	if (success) {
3607
		ptr = dict_accept(cs, ptr, "ACTION", &success);
osku's avatar
osku committed
3608 3609 3610

		if (!success) {
			dict_foreign_free(foreign);
3611 3612
			dict_foreign_report_syntax_err(
				name, start_of_latest_foreign, ptr);
3613

osku's avatar
osku committed
3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625
			return(DB_CANNOT_ADD_CONSTRAINT);
		}

		if (is_on_delete) {
			foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
		} else {
			foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
		}

		goto scan_on_conditions;
	}

3626
	ptr = dict_accept(cs, ptr, "SET", &success);
osku's avatar
osku committed
3627 3628 3629 3630

	if (!success) {
		dict_foreign_free(foreign);
		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3631
					       ptr);
osku's avatar
osku committed
3632 3633 3634
		return(DB_CANNOT_ADD_CONSTRAINT);
	}

3635
	ptr = dict_accept(cs, ptr, "NULL", &success);
osku's avatar
osku committed
3636 3637 3638 3639

	if (!success) {
		dict_foreign_free(foreign);
		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3640
					       ptr);
osku's avatar
osku committed
3641 3642 3643 3644
		return(DB_CANNOT_ADD_CONSTRAINT);
	}

	for (j = 0; j < foreign->n_fields; j++) {
3645
		if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
3646
		    & DATA_NOT_NULL) {
osku's avatar
osku committed
3647 3648 3649 3650 3651 3652 3653 3654 3655

			/* It is not sensible to define SET NULL
			if the column is not allowed to be NULL! */

			dict_foreign_free(foreign);

			mutex_enter(&dict_foreign_err_mutex);
			dict_foreign_error_report_low(ef, name);
			fprintf(ef, "%s:\n"
3656 3657 3658 3659
				"You have defined a SET NULL condition"
				" though some of the\n"
				"columns are defined as NOT NULL.\n",
				start_of_latest_foreign);
osku's avatar
osku committed
3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670
			mutex_exit(&dict_foreign_err_mutex);

			return(DB_CANNOT_ADD_CONSTRAINT);
		}
	}

	if (is_on_delete) {
		foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
	} else {
		foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
	}
3671

osku's avatar
osku committed
3672 3673 3674 3675 3676
	goto scan_on_conditions;

try_find_index:
	if (n_on_deletes > 1 || n_on_updates > 1) {
		/* It is an error to define more than 1 action */
3677

osku's avatar
osku committed
3678 3679 3680 3681 3682
		dict_foreign_free(foreign);

		mutex_enter(&dict_foreign_err_mutex);
		dict_foreign_error_report_low(ef, name);
		fprintf(ef, "%s:\n"
3683 3684
			"You have twice an ON DELETE clause"
			" or twice an ON UPDATE clause.\n",
osku's avatar
osku committed
3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696
			start_of_latest_foreign);
		mutex_exit(&dict_foreign_err_mutex);

		return(DB_CANNOT_ADD_CONSTRAINT);
	}

	/* Try to find an index which contains the columns as the first fields
	and in the right order, and the types are the same as in
	foreign->foreign_index */

	if (referenced_table) {
		index = dict_foreign_find_index(referenced_table,
3697
						column_names, i,
3698 3699
						foreign->foreign_index,
						TRUE, FALSE);
osku's avatar
osku committed
3700 3701 3702 3703 3704
		if (!index) {
			dict_foreign_free(foreign);
			mutex_enter(&dict_foreign_err_mutex);
			dict_foreign_error_report_low(ef, name);
			fprintf(ef, "%s:\n"
3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716
				"Cannot find an index in the"
				" referenced table where the\n"
				"referenced columns appear as the"
				" first columns, or column types\n"
				"in the table and the referenced table"
				" do not match for constraint.\n"
				"Note that the internal storage type of"
				" ENUM and SET changed in\n"
				"tables created with >= InnoDB-4.1.12,"
				" and such columns in old tables\n"
				"cannot be referenced by such columns"
				" in new tables.\n"
3717
				"See " REFMAN
3718 3719
				"innodb-foreign-key-constraints.html\n"
				"for correct foreign key definition.\n",
osku's avatar
osku committed
3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732
				start_of_latest_foreign);
			mutex_exit(&dict_foreign_err_mutex);

			return(DB_CANNOT_ADD_CONSTRAINT);
		}
	} else {
		ut_a(trx->check_foreigns == FALSE);
		index = NULL;
	}

	foreign->referenced_index = index;
	foreign->referenced_table = referenced_table;

3733 3734
	foreign->referenced_table_name
		= mem_heap_strdup(foreign->heap, referenced_table_name);
3735

osku's avatar
osku committed
3736
	foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
3737
						       i * sizeof(void*));
osku's avatar
osku committed
3738 3739 3740 3741 3742 3743
	for (i = 0; i < foreign->n_fields; i++) {
		foreign->referenced_col_names[i]
			= mem_heap_strdup(foreign->heap, column_names[i]);
	}

	/* We found an ok constraint definition: add to the lists */
3744

osku's avatar
osku committed
3745 3746 3747 3748
	UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);

	if (referenced_table) {
		UT_LIST_ADD_LAST(referenced_list,
3749 3750
				 referenced_table->referenced_list,
				 foreign);
osku's avatar
osku committed
3751 3752 3753 3754 3755
	}

	goto loop;
}

3756
/*********************************************************************//**
osku's avatar
osku committed
3757 3758 3759 3760
Scans a table create SQL string and adds to the data dictionary the foreign
key constraints declared in the string. This function should be called after
the indexes for a table have been created. Each foreign key constraint must
be accompanied with indexes in both participating tables. The indexes are
3761 3762
allowed to contain more fields than mentioned in the constraint.
@return	error code or DB_SUCCESS */
3763
UNIV_INTERN
osku's avatar
osku committed
3764 3765 3766
ulint
dict_create_foreign_constraints(
/*============================*/
3767 3768
	trx_t*		trx,		/*!< in: transaction */
	const char*	sql_string,	/*!< in: table create statement where
osku's avatar
osku committed
3769 3770 3771 3772 3773 3774 3775
					foreign keys are declared like:
					FOREIGN KEY (a, b) REFERENCES
					table2(c, d), table2 can be written
					also with the database
					name before it: test.table2; the
					default database id the database of
					parameter name */
3776
	size_t		sql_length,	/*!< in: length of sql_string */
3777
	const char*	name,		/*!< in: table full name in the
osku's avatar
osku committed
3778 3779
					normalized form
					database_name/table_name */
3780
	ibool		reject_fks)	/*!< in: if TRUE, fail with error
osku's avatar
osku committed
3781 3782 3783
					code DB_CANNOT_ADD_CONSTRAINT if
					any foreign keys are found. */
{
3784 3785 3786 3787
	char*			str;
	ulint			err;
	mem_heap_t*		heap;

3788 3789
	ut_a(trx);
	ut_a(trx->mysql_thd);
osku's avatar
osku committed
3790

3791
	str = dict_strip_comments(sql_string, sql_length);
osku's avatar
osku committed
3792 3793
	heap = mem_heap_create(10000);

3794 3795 3796
	err = dict_create_foreign_constraints_low(
		trx, heap, innobase_get_charset(trx->mysql_thd), str, name,
		reject_fks);
osku's avatar
osku committed
3797 3798 3799 3800

	mem_heap_free(heap);
	mem_free(str);

3801
	return(err);
osku's avatar
osku committed
3802 3803
}

3804
/**********************************************************************//**
3805
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement.
3806 3807
@return DB_SUCCESS or DB_CANNOT_DROP_CONSTRAINT if syntax error or the
constraint id does not match */
3808
UNIV_INTERN
osku's avatar
osku committed
3809 3810 3811
ulint
dict_foreign_parse_drop_constraints(
/*================================*/
3812
	mem_heap_t*	heap,			/*!< in: heap from which we can
osku's avatar
osku committed
3813
						allocate memory */
3814 3815 3816
	trx_t*		trx,			/*!< in: transaction */
	dict_table_t*	table,			/*!< in: table */
	ulint*		n,			/*!< out: number of constraints
osku's avatar
osku committed
3817
						to drop */
3818
	const char***	constraints_to_drop)	/*!< out: id's of the
osku's avatar
osku committed
3819 3820
						constraints to drop */
{
3821 3822 3823
	dict_foreign_t*		foreign;
	ibool			success;
	char*			str;
3824
	size_t			len;
3825 3826 3827 3828 3829
	const char*		ptr;
	const char*		id;
	FILE*			ef	= dict_foreign_err_file;
	struct charset_info_st*	cs;

3830 3831
	ut_a(trx);
	ut_a(trx->mysql_thd);
3832 3833

	cs = innobase_get_charset(trx->mysql_thd);
3834

osku's avatar
osku committed
3835 3836 3837 3838
	*n = 0;

	*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));

3839 3840 3841 3842
	ptr = innobase_get_stmt(trx->mysql_thd, &len);

	str = dict_strip_comments(ptr, len);

osku's avatar
osku committed
3843 3844 3845 3846 3847 3848 3849 3850
	ptr = str;

	ut_ad(mutex_own(&(dict_sys->mutex)));
loop:
	ptr = dict_scan_to(ptr, "DROP");

	if (*ptr == '\0') {
		mem_free(str);
3851

osku's avatar
osku committed
3852 3853 3854
		return(DB_SUCCESS);
	}

3855
	ptr = dict_accept(cs, ptr, "DROP", &success);
osku's avatar
osku committed
3856

3857
	if (!my_isspace(cs, *ptr)) {
osku's avatar
osku committed
3858

3859
		goto loop;
osku's avatar
osku committed
3860 3861
	}

3862
	ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3863

3864
	if (!success || !my_isspace(cs, *ptr)) {
osku's avatar
osku committed
3865

3866
		goto loop;
osku's avatar
osku committed
3867 3868
	}

3869
	ptr = dict_accept(cs, ptr, "KEY", &success);
osku's avatar
osku committed
3870 3871 3872 3873 3874 3875

	if (!success) {

		goto syntax_error;
	}

3876
	ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
osku's avatar
osku committed
3877 3878 3879 3880 3881 3882 3883 3884 3885

	if (id == NULL) {

		goto syntax_error;
	}

	ut_a(*n < 1000);
	(*constraints_to_drop)[*n] = id;
	(*n)++;
3886

osku's avatar
osku committed
3887 3888 3889 3890 3891 3892
	/* Look for the given constraint id */

	foreign = UT_LIST_GET_FIRST(table->foreign_list);

	while (foreign != NULL) {
		if (0 == strcmp(foreign->id, id)
3893 3894 3895
		    || (strchr(foreign->id, '/')
			&& 0 == strcmp(id,
				       dict_remove_db_name(foreign->id)))) {
osku's avatar
osku committed
3896 3897 3898
			/* Found */
			break;
		}
3899

osku's avatar
osku committed
3900 3901 3902 3903 3904 3905 3906
		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
	}

	if (foreign == NULL) {
		mutex_enter(&dict_foreign_err_mutex);
		rewind(ef);
		ut_print_timestamp(ef);
3907 3908
		fputs(" Error in dropping of a foreign key constraint"
		      " of table ", ef);
3909
		ut_print_name(ef, NULL, TRUE, table->name);
osku's avatar
osku committed
3910
		fputs(",\n"
3911
		      "in SQL command\n", ef);
osku's avatar
osku committed
3912 3913
		fputs(str, ef);
		fputs("\nCannot find a constraint with the given id ", ef);
3914
		ut_print_name(ef, NULL, FALSE, id);
osku's avatar
osku committed
3915 3916 3917 3918 3919 3920 3921 3922
		fputs(".\n", ef);
		mutex_exit(&dict_foreign_err_mutex);

		mem_free(str);

		return(DB_CANNOT_DROP_CONSTRAINT);
	}

3923
	goto loop;
osku's avatar
osku committed
3924 3925 3926 3927 3928

syntax_error:
	mutex_enter(&dict_foreign_err_mutex);
	rewind(ef);
	ut_print_timestamp(ef);
3929 3930
	fputs(" Syntax error in dropping of a"
	      " foreign key constraint of table ", ef);
3931
	ut_print_name(ef, NULL, TRUE, table->name);
osku's avatar
osku committed
3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942
	fprintf(ef, ",\n"
		"close to:\n%s\n in SQL command\n%s\n", ptr, str);
	mutex_exit(&dict_foreign_err_mutex);

	mem_free(str);

	return(DB_CANNOT_DROP_CONSTRAINT);
}

/*==================== END OF FOREIGN KEY PROCESSING ====================*/

3943
/**********************************************************************//**
3944
Returns an index object if it is found in the dictionary cache.
3945 3946
Assumes that dict_sys->mutex is already being held.
@return	index, NULL if not found */
3947
UNIV_INTERN
osku's avatar
osku committed
3948
dict_index_t*
3949 3950
dict_index_get_if_in_cache_low(
/*===========================*/
3951
	dulint	index_id)	/*!< in: index id */
osku's avatar
osku committed
3952
{
3953
	ut_ad(mutex_own(&(dict_sys->mutex)));
osku's avatar
osku committed
3954

3955 3956 3957
	return(dict_index_find_on_id_low(index_id));
}

3958
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
3959
/**********************************************************************//**
3960 3961
Returns an index object if it is found in the dictionary cache.
@return	index, NULL if not found */
3962
UNIV_INTERN
3963 3964 3965
dict_index_t*
dict_index_get_if_in_cache(
/*=======================*/
3966
	dulint	index_id)	/*!< in: index id */
3967 3968 3969 3970 3971 3972 3973 3974 3975 3976
{
	dict_index_t*	index;

	if (dict_sys == NULL) {
		return(NULL);
	}

	mutex_enter(&(dict_sys->mutex));

	index = dict_index_get_if_in_cache_low(index_id);
3977

osku's avatar
osku committed
3978 3979 3980 3981
	mutex_exit(&(dict_sys->mutex));

	return(index);
}
3982
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
osku's avatar
osku committed
3983

3984
#ifdef UNIV_DEBUG
3985
/**********************************************************************//**
osku's avatar
osku committed
3986
Checks that a tuple has n_fields_cmp value in a sensible range, so that
3987 3988
no comparison can occur with the page number field in a node pointer.
@return	TRUE if ok */
3989
UNIV_INTERN
osku's avatar
osku committed
3990
ibool
3991 3992
dict_index_check_search_tuple(
/*==========================*/
3993 3994
	const dict_index_t*	index,	/*!< in: index tree */
	const dtuple_t*		tuple)	/*!< in: tuple used in a search */
osku's avatar
osku committed
3995
{
3996
	ut_a(index);
osku's avatar
osku committed
3997
	ut_a(dtuple_get_n_fields_cmp(tuple)
3998
	     <= dict_index_get_n_unique_in_tree(index));
osku's avatar
osku committed
3999 4000
	return(TRUE);
}
4001
#endif /* UNIV_DEBUG */
osku's avatar
osku committed
4002

4003
/**********************************************************************//**
4004 4005
Builds a node pointer out of a physical record and a page number.
@return	own: node pointer */
4006
UNIV_INTERN
osku's avatar
osku committed
4007
dtuple_t*
4008 4009
dict_index_build_node_ptr(
/*======================*/
4010 4011
	const dict_index_t*	index,	/*!< in: index */
	const rec_t*		rec,	/*!< in: record for which to build node
4012
					pointer */
4013
	ulint			page_no,/*!< in: page number to put in node
4014
					pointer */
4015
	mem_heap_t*		heap,	/*!< in: memory heap where pointer
4016
					created */
4017
	ulint			level)	/*!< in: level of rec in tree:
4018
					0 means leaf level */
osku's avatar
osku committed
4019 4020 4021 4022 4023 4024
{
	dtuple_t*	tuple;
	dfield_t*	field;
	byte*		buf;
	ulint		n_unique;

4025
	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
osku's avatar
osku committed
4026
		/* In a universal index tree, we take the whole record as
4027
		the node pointer if the record is on the leaf level,
osku's avatar
osku committed
4028 4029 4030
		on non-leaf levels we remove the last field, which
		contains the page number of the child page */

4031
		ut_a(!dict_table_is_comp(index->table));
osku's avatar
osku committed
4032 4033 4034
		n_unique = rec_get_n_fields_old(rec);

		if (level > 0) {
4035 4036
			ut_a(n_unique > 1);
			n_unique--;
osku's avatar
osku committed
4037
		}
4038
	} else {
4039
		n_unique = dict_index_get_n_unique_in_tree(index);
osku's avatar
osku committed
4040 4041 4042 4043 4044 4045 4046 4047 4048
	}

	tuple = dtuple_create(heap, n_unique + 1);

	/* When searching in the tree for the node pointer, we must not do
	comparison on the last field, the page number field, as on upper
	levels in the tree there may be identical node pointers with a
	different page number; therefore, we set the n_fields_cmp to one
	less: */
4049

osku's avatar
osku committed
4050 4051
	dtuple_set_n_fields_cmp(tuple, n_unique);

4052
	dict_index_copy_types(tuple, index, n_unique);
4053

osku's avatar
osku committed
4054 4055 4056
	buf = mem_heap_alloc(heap, 4);

	mach_write_to_4(buf, page_no);
4057

4058
	field = dtuple_get_nth_field(tuple, n_unique);
osku's avatar
osku committed
4059 4060
	dfield_set_data(field, buf, 4);

4061
	dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
osku's avatar
osku committed
4062

4063
	rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
4064 4065
	dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
			     | REC_STATUS_NODE_PTR);
osku's avatar
osku committed
4066 4067 4068 4069

	ut_ad(dtuple_check_typed(tuple));

	return(tuple);
4070 4071
}

4072
/**********************************************************************//**
osku's avatar
osku committed
4073
Copies an initial segment of a physical record, long enough to specify an
4074 4075
index entry uniquely.
@return	pointer to the prefix record */
4076
UNIV_INTERN
osku's avatar
osku committed
4077
rec_t*
4078 4079
dict_index_copy_rec_order_prefix(
/*=============================*/
4080 4081
	const dict_index_t*	index,	/*!< in: index */
	const rec_t*		rec,	/*!< in: record for which to
4082
					copy prefix */
4083 4084
	ulint*			n_fields,/*!< out: number of fields copied */
	byte**			buf,	/*!< in/out: memory buffer for the
4085
					copied prefix, or NULL */
4086
	ulint*			buf_size)/*!< in/out: buffer size */
osku's avatar
osku committed
4087 4088 4089 4090 4091
{
	ulint		n;

	UNIV_PREFETCH_R(rec);

4092
	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
4093
		ut_a(!dict_table_is_comp(index->table));
osku's avatar
osku committed
4094 4095 4096 4097 4098 4099 4100 4101 4102
		n = rec_get_n_fields_old(rec);
	} else {
		n = dict_index_get_n_unique_in_tree(index);
	}

	*n_fields = n;
	return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
}

4103
/**********************************************************************//**
4104 4105
Builds a typed data tuple out of a physical record.
@return	own: data tuple */
4106
UNIV_INTERN
osku's avatar
osku committed
4107
dtuple_t*
4108 4109
dict_index_build_data_tuple(
/*========================*/
4110 4111 4112 4113
	dict_index_t*	index,	/*!< in: index tree */
	rec_t*		rec,	/*!< in: record for which to build data tuple */
	ulint		n_fields,/*!< in: number of data fields */
	mem_heap_t*	heap)	/*!< in: memory heap where tuple created */
osku's avatar
osku committed
4114 4115 4116
{
	dtuple_t*	tuple;

4117
	ut_ad(dict_table_is_comp(index->table)
4118
	      || n_fields <= rec_get_n_fields_old(rec));
4119 4120

	tuple = dtuple_create(heap, n_fields);
osku's avatar
osku committed
4121

4122
	dict_index_copy_types(tuple, index, n_fields);
osku's avatar
osku committed
4123

4124
	rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
osku's avatar
osku committed
4125 4126 4127 4128

	ut_ad(dtuple_check_typed(tuple));

	return(tuple);
4129 4130
}

4131
/*********************************************************************//**
osku's avatar
osku committed
4132
Calculates the minimum record length in an index. */
4133
UNIV_INTERN
osku's avatar
osku committed
4134 4135 4136
ulint
dict_index_calc_min_rec_len(
/*========================*/
4137
	const dict_index_t*	index)	/*!< in: index */
osku's avatar
osku committed
4138 4139 4140
{
	ulint	sum	= 0;
	ulint	i;
4141
	ulint	comp	= dict_table_is_comp(index->table);
osku's avatar
osku committed
4142

4143
	if (comp) {
osku's avatar
osku committed
4144 4145 4146
		ulint nullable = 0;
		sum = REC_N_NEW_EXTRA_BYTES;
		for (i = 0; i < dict_index_get_n_fields(index); i++) {
4147 4148
			const dict_col_t*	col
				= dict_index_get_nth_col(index, i);
4149
			ulint	size = dict_col_get_fixed_size(col, comp);
osku's avatar
osku committed
4150 4151
			sum += size;
			if (!size) {
4152
				size = col->len;
osku's avatar
osku committed
4153 4154
				sum += size < 128 ? 1 : 2;
			}
4155
			if (!(col->prtype & DATA_NOT_NULL)) {
osku's avatar
osku committed
4156
				nullable++;
4157
			}
osku's avatar
osku committed
4158 4159 4160
		}

		/* round the NULL flags up to full bytes */
4161
		sum += UT_BITS_IN_BYTES(nullable);
osku's avatar
osku committed
4162 4163 4164 4165 4166

		return(sum);
	}

	for (i = 0; i < dict_index_get_n_fields(index); i++) {
4167
		sum += dict_col_get_fixed_size(
4168
			dict_index_get_nth_col(index, i), comp);
osku's avatar
osku committed
4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181
	}

	if (sum > 127) {
		sum += 2 * dict_index_get_n_fields(index);
	} else {
		sum += dict_index_get_n_fields(index);
	}

	sum += REC_N_OLD_EXTRA_BYTES;

	return(sum);
}

4182
/*********************************************************************//**
osku's avatar
osku committed
4183 4184
Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */
4185
UNIV_INTERN
osku's avatar
osku committed
4186 4187 4188
void
dict_update_statistics_low(
/*=======================*/
4189
	dict_table_t*	table,		/*!< in/out: table */
osku's avatar
osku committed
4190
	ibool		has_dict_mutex __attribute__((unused)))
4191
					/*!< in: TRUE if the caller has the
4192
					dictionary mutex */
osku's avatar
osku committed
4193 4194 4195 4196 4197 4198 4199 4200 4201
{
	dict_index_t*	index;
	ulint		size;
	ulint		sum_of_index_sizes	= 0;

	if (table->ibd_file_missing) {
		ut_print_timestamp(stderr);
		fprintf(stderr,
			"  InnoDB: cannot calculate statistics for table %s\n"
4202 4203
			"InnoDB: because the .ibd file is missing.  For help,"
			" please refer to\n"
4204
			"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
osku's avatar
osku committed
4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220
			table->name);

		return;
	}

	/* If we have set a high innodb_force_recovery level, do not calculate
	statistics, as a badly corrupted index can cause a crash in it. */

	if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {

		return;
	}

	/* Find out the sizes of the indexes and how many different values
	for the key they approximately have */

4221
	index = dict_table_get_first_index(table);
osku's avatar
osku committed
4222 4223 4224

	if (index == NULL) {
		/* Table definition is corrupt */
4225

osku's avatar
osku committed
4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243
		return;
	}

	while (index) {
		size = btr_get_size(index, BTR_TOTAL_SIZE);

		index->stat_index_size = size;

		sum_of_index_sizes += size;

		size = btr_get_size(index, BTR_N_LEAF_PAGES);

		if (size == 0) {
			/* The root node of the tree is a leaf */
			size = 1;
		}

		index->stat_n_leaf_pages = size;
4244

osku's avatar
osku committed
4245 4246 4247 4248 4249 4250 4251
		btr_estimate_number_of_different_key_vals(index);

		index = dict_table_get_next_index(index);
	}

	index = dict_table_get_first_index(table);

4252 4253
	dict_index_stat_mutex_enter(index);

4254 4255
	table->stat_n_rows = index->stat_n_diff_key_vals[
		dict_index_get_n_unique(index)];
osku's avatar
osku committed
4256

4257 4258
	dict_index_stat_mutex_exit(index);

osku's avatar
osku committed
4259 4260 4261
	table->stat_clustered_index_size = index->stat_index_size;

	table->stat_sum_of_other_index_sizes = sum_of_index_sizes
4262
		- index->stat_index_size;
osku's avatar
osku committed
4263 4264 4265

	table->stat_initialized = TRUE;

4266
	table->stat_modified_counter = 0;
osku's avatar
osku committed
4267 4268
}

4269
/*********************************************************************//**
osku's avatar
osku committed
4270 4271
Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */
4272
UNIV_INTERN
osku's avatar
osku committed
4273 4274 4275
void
dict_update_statistics(
/*===================*/
4276
	dict_table_t*	table)	/*!< in/out: table */
osku's avatar
osku committed
4277 4278 4279 4280
{
	dict_update_statistics_low(table, FALSE);
}

4281
/**********************************************************************//**
osku's avatar
osku committed
4282 4283 4284 4285 4286
Prints info of a foreign key constraint. */
static
void
dict_foreign_print_low(
/*===================*/
4287
	dict_foreign_t*	foreign)	/*!< in: foreign key constraint */
osku's avatar
osku committed
4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300
{
	ulint	i;

	ut_ad(mutex_own(&(dict_sys->mutex)));

	fprintf(stderr, "  FOREIGN KEY CONSTRAINT %s: %s (",
		foreign->id, foreign->foreign_table_name);

	for (i = 0; i < foreign->n_fields; i++) {
		fprintf(stderr, " %s", foreign->foreign_col_names[i]);
	}

	fprintf(stderr, " )\n"
4301
		"             REFERENCES %s (",
osku's avatar
osku committed
4302
		foreign->referenced_table_name);
4303

osku's avatar
osku committed
4304 4305 4306 4307 4308 4309 4310
	for (i = 0; i < foreign->n_fields; i++) {
		fprintf(stderr, " %s", foreign->referenced_col_names[i]);
	}

	fputs(" )\n", stderr);
}

4311
/**********************************************************************//**
osku's avatar
osku committed
4312
Prints a table data. */
4313
UNIV_INTERN
osku's avatar
osku committed
4314 4315 4316
void
dict_table_print(
/*=============*/
4317
	dict_table_t*	table)	/*!< in: table */
osku's avatar
osku committed
4318 4319 4320 4321 4322 4323
{
	mutex_enter(&(dict_sys->mutex));
	dict_table_print_low(table);
	mutex_exit(&(dict_sys->mutex));
}

4324
/**********************************************************************//**
osku's avatar
osku committed
4325
Prints a table data when we know the table name. */
4326
UNIV_INTERN
osku's avatar
osku committed
4327 4328 4329
void
dict_table_print_by_name(
/*=====================*/
4330
	const char*	name)	/*!< in: table name */
osku's avatar
osku committed
4331 4332 4333 4334 4335 4336 4337 4338
{
	dict_table_t*	table;

	mutex_enter(&(dict_sys->mutex));

	table = dict_table_get_low(name);

	ut_a(table);
4339

osku's avatar
osku committed
4340 4341 4342 4343
	dict_table_print_low(table);
	mutex_exit(&(dict_sys->mutex));
}

4344
/**********************************************************************//**
osku's avatar
osku committed
4345
Prints a table data. */
4346
UNIV_INTERN
osku's avatar
osku committed
4347 4348 4349
void
dict_table_print_low(
/*=================*/
4350
	dict_table_t*	table)	/*!< in: table */
osku's avatar
osku committed
4351 4352 4353 4354 4355 4356 4357 4358
{
	dict_index_t*	index;
	dict_foreign_t*	foreign;
	ulint		i;

	ut_ad(mutex_own(&(dict_sys->mutex)));

	dict_update_statistics_low(table, TRUE);
4359

osku's avatar
osku committed
4360
	fprintf(stderr,
4361
		"--------------------------------------\n"
4362 4363
		"TABLE: name %s, id %lu %lu, flags %lx, columns %lu,"
		" indexes %lu, appr.rows %lu\n"
4364 4365 4366 4367
		"  COLUMNS: ",
		table->name,
		(ulong) ut_dulint_get_high(table->id),
		(ulong) ut_dulint_get_low(table->id),
4368
		(ulong) table->flags,
4369 4370 4371
		(ulong) table->n_cols,
		(ulong) UT_LIST_GET_LEN(table->indexes),
		(ulong) table->stat_n_rows);
osku's avatar
osku committed
4372

4373
	for (i = 0; i < (ulint) table->n_cols; i++) {
4374
		dict_col_print_low(table, dict_table_get_nth_col(table, i));
osku's avatar
osku committed
4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401
		fputs("; ", stderr);
	}

	putc('\n', stderr);

	index = UT_LIST_GET_FIRST(table->indexes);

	while (index != NULL) {
		dict_index_print_low(index);
		index = UT_LIST_GET_NEXT(indexes, index);
	}

	foreign = UT_LIST_GET_FIRST(table->foreign_list);

	while (foreign != NULL) {
		dict_foreign_print_low(foreign);
		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
	}

	foreign = UT_LIST_GET_FIRST(table->referenced_list);

	while (foreign != NULL) {
		dict_foreign_print_low(foreign);
		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
	}
}

4402
/**********************************************************************//**
osku's avatar
osku committed
4403 4404 4405 4406 4407
Prints a column data. */
static
void
dict_col_print_low(
/*===============*/
4408 4409
	const dict_table_t*	table,	/*!< in: table */
	const dict_col_t*	col)	/*!< in: column */
osku's avatar
osku committed
4410
{
4411
	dtype_t	type;
osku's avatar
osku committed
4412 4413 4414

	ut_ad(mutex_own(&(dict_sys->mutex)));

4415 4416 4417
	dict_col_copy_type(col, &type);
	fprintf(stderr, "%s: ", dict_table_get_col_name(table,
							dict_col_get_no(col)));
osku's avatar
osku committed
4418

4419
	dtype_print(&type);
osku's avatar
osku committed
4420 4421
}

4422
/**********************************************************************//**
osku's avatar
osku committed
4423 4424 4425 4426 4427
Prints an index data. */
static
void
dict_index_print_low(
/*=================*/
4428
	dict_index_t*	index)	/*!< in: index */
osku's avatar
osku committed
4429
{
4430
	ib_int64_t	n_vals;
osku's avatar
osku committed
4431
	ulint		i;
4432
	const char*	type_string;
osku's avatar
osku committed
4433 4434 4435

	ut_ad(mutex_own(&(dict_sys->mutex)));

4436 4437
	dict_index_stat_mutex_enter(index);

osku's avatar
osku committed
4438
	if (index->n_user_defined_cols > 0) {
4439 4440
		n_vals = index->stat_n_diff_key_vals[
			index->n_user_defined_cols];
osku's avatar
osku committed
4441 4442 4443 4444
	} else {
		n_vals = index->stat_n_diff_key_vals[1];
	}

4445 4446
	dict_index_stat_mutex_exit(index);

4447
	if (dict_index_is_clust(index)) {
4448
		type_string = "clustered index";
4449
	} else if (dict_index_is_unique(index)) {
4450 4451 4452 4453 4454
		type_string = "unique index";
	} else {
		type_string = "secondary index";
	}

osku's avatar
osku committed
4455
	fprintf(stderr,
4456 4457
		"  INDEX: name %s, id %lu %lu, fields %lu/%lu,"
		" uniq %lu, type %lu\n"
osku's avatar
osku committed
4458 4459 4460 4461
		"   root page %lu, appr.key vals %lu,"
		" leaf pages %lu, size pages %lu\n"
		"   FIELDS: ",
		index->name,
4462 4463
		(ulong) ut_dulint_get_high(index->id),
		(ulong) ut_dulint_get_low(index->id),
osku's avatar
osku committed
4464
		(ulong) index->n_user_defined_cols,
4465 4466 4467
		(ulong) index->n_fields,
		(ulong) index->n_uniq,
		(ulong) index->type,
4468
		(ulong) index->page,
osku's avatar
osku committed
4469 4470 4471
		(ulong) n_vals,
		(ulong) index->stat_n_leaf_pages,
		(ulong) index->stat_index_size);
4472

osku's avatar
osku committed
4473 4474 4475 4476 4477 4478 4479
	for (i = 0; i < index->n_fields; i++) {
		dict_field_print_low(dict_index_get_nth_field(index, i));
	}

	putc('\n', stderr);

#ifdef UNIV_BTR_PRINT
4480
	btr_print_size(index);
osku's avatar
osku committed
4481

4482
	btr_print_index(index, 7);
osku's avatar
osku committed
4483 4484 4485
#endif /* UNIV_BTR_PRINT */
}

4486
/**********************************************************************//**
osku's avatar
osku committed
4487 4488 4489 4490 4491
Prints a field data. */
static
void
dict_field_print_low(
/*=================*/
4492
	const dict_field_t*	field)	/*!< in: field */
osku's avatar
osku committed
4493 4494
{
	ut_ad(mutex_own(&(dict_sys->mutex)));
4495

osku's avatar
osku committed
4496 4497 4498 4499 4500 4501 4502
	fprintf(stderr, " %s", field->name);

	if (field->prefix_len != 0) {
		fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
	}
}

4503
/**********************************************************************//**
osku's avatar
osku committed
4504 4505
Outputs info on a foreign key of a table in a format suitable for
CREATE TABLE. */
4506
UNIV_INTERN
osku's avatar
osku committed
4507 4508 4509
void
dict_print_info_on_foreign_key_in_create_format(
/*============================================*/
4510 4511 4512 4513
	FILE*		file,		/*!< in: file where to print */
	trx_t*		trx,		/*!< in: transaction */
	dict_foreign_t*	foreign,	/*!< in: foreign key constraint */
	ibool		add_newline)	/*!< in: whether to add a newline */
osku's avatar
osku committed
4514 4515 4516
{
	const char*	stripped_id;
	ulint	i;
4517

osku's avatar
osku committed
4518 4519 4520
	if (strchr(foreign->id, '/')) {
		/* Strip the preceding database name from the constraint id */
		stripped_id = foreign->id + 1
4521
			+ dict_get_db_name_len(foreign->id);
osku's avatar
osku committed
4522 4523 4524 4525 4526
	} else {
		stripped_id = foreign->id;
	}

	putc(',', file);
4527

osku's avatar
osku committed
4528 4529 4530 4531 4532 4533
	if (add_newline) {
		/* SHOW CREATE TABLE wants constraints each printed nicely
		on its own line, while error messages want no newlines
		inserted. */
		fputs("\n ", file);
	}
4534

osku's avatar
osku committed
4535
	fputs(" CONSTRAINT ", file);
4536
	ut_print_name(file, trx, FALSE, stripped_id);
osku's avatar
osku committed
4537 4538 4539
	fputs(" FOREIGN KEY (", file);

	for (i = 0;;) {
4540
		ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
osku's avatar
osku committed
4541 4542
		if (++i < foreign->n_fields) {
			fputs(", ", file);
4543
		} else {
osku's avatar
osku committed
4544 4545 4546 4547 4548 4549 4550
			break;
		}
	}

	fputs(") REFERENCES ", file);

	if (dict_tables_have_same_db(foreign->foreign_table_name,
4551
				     foreign->referenced_table_name)) {
osku's avatar
osku committed
4552
		/* Do not print the database name of the referenced table */
4553 4554 4555
		ut_print_name(file, trx, TRUE,
			      dict_remove_db_name(
				      foreign->referenced_table_name));
osku's avatar
osku committed
4556
	} else {
4557
		ut_print_name(file, trx, TRUE,
4558
			      foreign->referenced_table_name);
osku's avatar
osku committed
4559 4560 4561 4562 4563 4564
	}

	putc(' ', file);
	putc('(', file);

	for (i = 0;;) {
4565
		ut_print_name(file, trx, FALSE,
4566
			      foreign->referenced_col_names[i]);
osku's avatar
osku committed
4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578
		if (++i < foreign->n_fields) {
			fputs(", ", file);
		} else {
			break;
		}
	}

	putc(')', file);

	if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
		fputs(" ON DELETE CASCADE", file);
	}
4579

osku's avatar
osku committed
4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590
	if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
		fputs(" ON DELETE SET NULL", file);
	}

	if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
		fputs(" ON DELETE NO ACTION", file);
	}

	if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
		fputs(" ON UPDATE CASCADE", file);
	}
4591

osku's avatar
osku committed
4592 4593 4594 4595 4596 4597 4598 4599 4600
	if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
		fputs(" ON UPDATE SET NULL", file);
	}

	if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
		fputs(" ON UPDATE NO ACTION", file);
	}
}

4601
/**********************************************************************//**
osku's avatar
osku committed
4602
Outputs info on foreign keys of a table. */
4603
UNIV_INTERN
osku's avatar
osku committed
4604 4605 4606
void
dict_print_info_on_foreign_keys(
/*============================*/
4607
	ibool		create_table_format, /*!< in: if TRUE then print in
osku's avatar
osku committed
4608 4609 4610
				a format suitable to be inserted into
				a CREATE TABLE, otherwise in the format
				of SHOW TABLE STATUS */
4611 4612 4613
	FILE*		file,	/*!< in: file where to print */
	trx_t*		trx,	/*!< in: transaction */
	dict_table_t*	table)	/*!< in: table */
osku's avatar
osku committed
4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628
{
	dict_foreign_t*	foreign;

	mutex_enter(&(dict_sys->mutex));

	foreign = UT_LIST_GET_FIRST(table->foreign_list);

	if (foreign == NULL) {
		mutex_exit(&(dict_sys->mutex));

		return;
	}

	while (foreign != NULL) {
		if (create_table_format) {
4629 4630
			dict_print_info_on_foreign_key_in_create_format(
				file, trx, foreign, TRUE);
osku's avatar
osku committed
4631 4632 4633 4634 4635 4636 4637 4638 4639
		} else {
			ulint	i;
			fputs("; (", file);

			for (i = 0; i < foreign->n_fields; i++) {
				if (i) {
					putc(' ', file);
				}

4640
				ut_print_name(file, trx, FALSE,
4641
					      foreign->foreign_col_names[i]);
osku's avatar
osku committed
4642 4643 4644
			}

			fputs(") REFER ", file);
4645
			ut_print_name(file, trx, TRUE,
4646
				      foreign->referenced_table_name);
osku's avatar
osku committed
4647 4648 4649 4650 4651 4652
			putc('(', file);

			for (i = 0; i < foreign->n_fields; i++) {
				if (i) {
					putc(' ', file);
				}
4653 4654 4655
				ut_print_name(
					file, trx, FALSE,
					foreign->referenced_col_names[i]);
osku's avatar
osku committed
4656 4657 4658 4659 4660 4661 4662
			}

			putc(')', file);

			if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
				fputs(" ON DELETE CASCADE", file);
			}
4663

osku's avatar
osku committed
4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674
			if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
				fputs(" ON DELETE SET NULL", file);
			}

			if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
				fputs(" ON DELETE NO ACTION", file);
			}

			if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
				fputs(" ON UPDATE CASCADE", file);
			}
4675

osku's avatar
osku committed
4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690
			if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
				fputs(" ON UPDATE SET NULL", file);
			}

			if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
				fputs(" ON UPDATE NO ACTION", file);
			}
		}

		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
	}

	mutex_exit(&(dict_sys->mutex));
}

4691
/********************************************************************//**
osku's avatar
osku committed
4692
Displays the names of the index and the table. */
4693
UNIV_INTERN
osku's avatar
osku committed
4694 4695 4696
void
dict_index_name_print(
/*==================*/
4697 4698 4699
	FILE*			file,	/*!< in: output stream */
	trx_t*			trx,	/*!< in: transaction */
	const dict_index_t*	index)	/*!< in: index to print */
osku's avatar
osku committed
4700 4701
{
	fputs("index ", file);
4702
	ut_print_name(file, trx, FALSE, index->name);
osku's avatar
osku committed
4703
	fputs(" of table ", file);
4704
	ut_print_name(file, trx, TRUE, index->table_name);
osku's avatar
osku committed
4705
}
4706
#endif /* !UNIV_HOTBACKUP */
4707

4708
/**********************************************************************//**
4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741
Inits dict_ind_redundant and dict_ind_compact. */
UNIV_INTERN
void
dict_ind_init(void)
/*===============*/
{
	dict_table_t*		table;

	/* create dummy table and index for REDUNDANT infimum and supremum */
	table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0);
	dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
			       DATA_ENGLISH | DATA_NOT_NULL, 8);

	dict_ind_redundant = dict_mem_index_create("SYS_DUMMY1", "SYS_DUMMY1",
						   DICT_HDR_SPACE, 0, 1);
	dict_index_add_col(dict_ind_redundant, table,
			   dict_table_get_nth_col(table, 0), 0);
	dict_ind_redundant->table = table;
	/* create dummy table and index for COMPACT infimum and supremum */
	table = dict_mem_table_create("SYS_DUMMY2",
				      DICT_HDR_SPACE, 1, DICT_TF_COMPACT);
	dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
			       DATA_ENGLISH | DATA_NOT_NULL, 8);
	dict_ind_compact = dict_mem_index_create("SYS_DUMMY2", "SYS_DUMMY2",
						 DICT_HDR_SPACE, 0, 1);
	dict_index_add_col(dict_ind_compact, table,
			   dict_table_get_nth_col(table, 0), 0);
	dict_ind_compact->table = table;

	/* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
	dict_ind_redundant->cached = dict_ind_compact->cached = TRUE;
}

4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761
/**********************************************************************//**
Frees dict_ind_redundant and dict_ind_compact. */
static
void
dict_ind_free(void)
/*===============*/
{
	dict_table_t*	table;

	table = dict_ind_compact->table;
	dict_mem_index_free(dict_ind_compact);
	dict_ind_compact = NULL;
	dict_mem_table_free(table);

	table = dict_ind_redundant->table;
	dict_mem_index_free(dict_ind_redundant);
	dict_ind_redundant = NULL;
	dict_mem_table_free(table);
}

4762
#ifndef UNIV_HOTBACKUP
4763
/**********************************************************************//**
4764 4765
Get index by name
@return	index, NULL if does not exist */
4766
UNIV_INTERN
4767 4768 4769
dict_index_t*
dict_table_get_index_on_name(
/*=========================*/
4770 4771
	dict_table_t*	table,	/*!< in: table */
	const char*	name)	/*!< in: name of the index to find */
4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789
{
	dict_index_t*	index;

	index = dict_table_get_first_index(table);

	while (index != NULL) {
		if (ut_strcmp(index->name, name) == 0) {

			return(index);
		}

		index = dict_table_get_next_index(index);
	}

	return(NULL);

}

4790
/**********************************************************************//**
4791 4792
Replace the index passed in with another equivalent index in the tables
foreign key list. */
4793
UNIV_INTERN
4794 4795 4796
void
dict_table_replace_index_in_foreign_list(
/*=====================================*/
4797 4798
	dict_table_t*	table,  /*!< in/out: table */
	dict_index_t*	index)	/*!< in: index to be replaced */
4799
{
4800
	dict_foreign_t*	foreign;
4801

4802 4803 4804
	for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
	     foreign;
	     foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
4805

4806 4807 4808 4809
		if (foreign->foreign_index == index) {
			dict_index_t*	new_index
				= dict_foreign_find_equiv_index(foreign);
			ut_a(new_index);
4810

4811
			foreign->foreign_index = new_index;
4812 4813 4814 4815
		}
	}
}

4816
/**********************************************************************//**
4817
In case there is more than one index with the same name return the index
4818 4819
with the min(id).
@return	index, NULL if does not exist */
4820
UNIV_INTERN
4821 4822 4823
dict_index_t*
dict_table_get_index_on_name_and_min_id(
/*=====================================*/
4824 4825
	dict_table_t*	table,	/*!< in: table */
	const char*	name)	/*!< in: name of the index to find */
4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848
{
	dict_index_t*	index;
	dict_index_t*	min_index; /* Index with matching name and min(id) */

	min_index = NULL;
	index = dict_table_get_first_index(table);

	while (index != NULL) {
		if (ut_strcmp(index->name, name) == 0) {
			if (!min_index
			    || ut_dulint_cmp(index->id, min_index->id) < 0) {

				min_index = index;
			}
		}

		index = dict_table_get_next_index(index);
	}

	return(min_index);

}

4849
#ifdef UNIV_DEBUG
4850
/**********************************************************************//**
4851
Check for duplicate index entries in a table [using the index name] */
4852
UNIV_INTERN
4853 4854 4855
void
dict_table_check_for_dup_indexes(
/*=============================*/
4856
	const dict_table_t*	table,	/*!< in: Check for dup indexes
4857
					in this table */
4858 4859
	ibool			tmp_ok)	/*!< in: TRUE=allow temporary
					index names */
4860 4861 4862 4863
{
	/* Check for duplicates, ignoring indexes that are marked
	as to be dropped */

4864 4865
	const dict_index_t*	index1;
	const dict_index_t*	index2;
4866

4867 4868
	ut_ad(mutex_own(&dict_sys->mutex));

4869 4870 4871 4872 4873
	/* The primary index _must_ exist */
	ut_a(UT_LIST_GET_LEN(table->indexes) > 0);

	index1 = UT_LIST_GET_FIRST(table->indexes);

4874 4875 4876 4877
	do {
		ut_ad(tmp_ok || *index1->name != TEMP_INDEX_PREFIX);

		index2 = UT_LIST_GET_NEXT(indexes, index1);
4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888

		while (index2) {

			if (!index2->to_be_dropped) {
				ut_ad(ut_strcmp(index1->name, index2->name));
			}

			index2 = UT_LIST_GET_NEXT(indexes, index2);
		}

		index1 = UT_LIST_GET_NEXT(indexes, index1);
4889
	} while (index1);
4890 4891
}
#endif /* UNIV_DEBUG */
4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941

/**************************************************************************
Closes the data dictionary module. */
UNIV_INTERN
void
dict_close(void)
/*============*/
{
	ulint	i;

	/* Free the hash elements. We don't remove them from the table
	because we are going to destroy the table anyway. */
	for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) {
		dict_table_t*	table;

		table = HASH_GET_FIRST(dict_sys->table_hash, i);

		while (table) {
			dict_table_t*	prev_table = table;

			table = HASH_GET_NEXT(name_hash, prev_table);
#ifdef UNIV_DEBUG
			ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N);
#endif
			/* Acquire only because it's a pre-condition. */
			mutex_enter(&dict_sys->mutex);

			dict_table_remove_from_cache(prev_table);

			mutex_exit(&dict_sys->mutex);
		}
	}

	hash_table_free(dict_sys->table_hash);

	/* The elements are the same instance as in dict_sys->table_hash,
	therefore we don't delete the individual elements. */
	hash_table_free(dict_sys->table_id_hash);

	dict_ind_free();

	mutex_free(&dict_sys->mutex);

	rw_lock_free(&dict_operation_lock);
	memset(&dict_operation_lock, 0x0, sizeof(dict_operation_lock));

	mutex_free(&dict_foreign_err_mutex);

	mem_free(dict_sys);
	dict_sys = NULL;
4942 4943 4944 4945

	for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) {
		mutex_free(&dict_index_stat_mutex[i]);
	}
4946
}
4947
#endif /* !UNIV_HOTBACKUP */