dict0crea.c 38.6 KB
Newer Older
1 2
/*****************************************************************************

3
Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
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/dict0crea.c
osku's avatar
osku committed
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
Database object creation

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

#include "dict0crea.h"

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

#include "btr0pcur.h"
#include "btr0btr.h"
#include "page0page.h"
#include "mach0data.h"
#include "dict0boot.h"
#include "dict0dict.h"
#include "que0que.h"
#include "row0ins.h"
#include "row0mysql.h"
#include "pars0pars.h"
#include "trx0roll.h"
#include "usr0sess.h"
44
#include "ut0vec.h"
osku's avatar
osku committed
45

46
/*****************************************************************//**
osku's avatar
osku committed
47
Based on a table object, this function builds the entry to be inserted
48 49
in the SYS_TABLES system table.
@return	the tuple which should be inserted */
osku's avatar
osku committed
50 51 52 53
static
dtuple_t*
dict_create_sys_tables_tuple(
/*=========================*/
54 55 56 57
	const dict_table_t*	table,	/*!< in: table */
	mem_heap_t*		heap)	/*!< in: memory heap from
					which the memory for the built
					tuple is allocated */
osku's avatar
osku committed
58 59 60 61 62 63
{
	dict_table_t*	sys_tables;
	dtuple_t*	entry;
	dfield_t*	dfield;
	byte*		ptr;

64 65
	ut_ad(table);
	ut_ad(heap);
osku's avatar
osku committed
66 67

	sys_tables = dict_sys->sys_tables;
68

osku's avatar
osku committed
69 70
	entry = dtuple_create(heap, 8 + DATA_N_SYS_COLS);

71 72
	dict_table_copy_types(entry, sys_tables);

osku's avatar
osku committed
73
	/* 0: NAME -----------------------------*/
74
	dfield = dtuple_get_nth_field(entry, 0/*NAME*/);
osku's avatar
osku committed
75 76 77

	dfield_set_data(dfield, table->name, ut_strlen(table->name));
	/* 3: ID -------------------------------*/
78
	dfield = dtuple_get_nth_field(entry, 1/*ID*/);
osku's avatar
osku committed
79 80 81 82 83 84

	ptr = mem_heap_alloc(heap, 8);
	mach_write_to_8(ptr, table->id);

	dfield_set_data(dfield, ptr, 8);
	/* 4: N_COLS ---------------------------*/
85
	dfield = dtuple_get_nth_field(entry, 2/*N_COLS*/);
osku's avatar
osku committed
86

87 88 89 90
#if DICT_TF_COMPACT != 1
#error
#endif

osku's avatar
osku committed
91 92
	ptr = mem_heap_alloc(heap, 4);
	mach_write_to_4(ptr, table->n_def
93
			| ((table->flags & DICT_TF_COMPACT) << 31));
osku's avatar
osku committed
94 95
	dfield_set_data(dfield, ptr, 4);
	/* 5: TYPE -----------------------------*/
96
	dfield = dtuple_get_nth_field(entry, 3/*TYPE*/);
osku's avatar
osku committed
97 98

	ptr = mem_heap_alloc(heap, 4);
99
	if (table->flags & (~DICT_TF_COMPACT & ~(~0 << DICT_TF_BITS))) {
100
		ut_a(table->flags & DICT_TF_COMPACT);
101 102 103
		ut_a(dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);
		ut_a((table->flags & DICT_TF_ZSSIZE_MASK)
		     <= (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT));
104 105
		ut_a(!(table->flags & (~0 << DICT_TF2_BITS)));
		mach_write_to_4(ptr, table->flags & ~(~0 << DICT_TF_BITS));
106 107 108
	} else {
		mach_write_to_4(ptr, DICT_TABLE_ORDINARY);
	}
osku's avatar
osku committed
109 110

	dfield_set_data(dfield, ptr, 4);
111
	/* 6: MIX_ID (obsolete) ---------------------------*/
112
	dfield = dtuple_get_nth_field(entry, 4/*MIX_ID*/);
osku's avatar
osku committed
113

114
	ptr = mem_heap_zalloc(heap, 8);
osku's avatar
osku committed
115 116

	dfield_set_data(dfield, ptr, 8);
117
	/* 7: MIX_LEN (additional flags) --------------------------*/
osku's avatar
osku committed
118

119
	dfield = dtuple_get_nth_field(entry, 5/*MIX_LEN*/);
osku's avatar
osku committed
120

121 122
	ptr = mem_heap_alloc(heap, 4);
	mach_write_to_4(ptr, table->flags >> DICT_TF2_SHIFT);
osku's avatar
osku committed
123 124 125

	dfield_set_data(dfield, ptr, 4);
	/* 8: CLUSTER_NAME ---------------------*/
126
	dfield = dtuple_get_nth_field(entry, 6/*CLUSTER_NAME*/);
127
	dfield_set_null(dfield); /* not supported */
osku's avatar
osku committed
128 129

	/* 9: SPACE ----------------------------*/
130
	dfield = dtuple_get_nth_field(entry, 7/*SPACE*/);
osku's avatar
osku committed
131 132 133 134 135 136 137 138

	ptr = mem_heap_alloc(heap, 4);
	mach_write_to_4(ptr, table->space);

	dfield_set_data(dfield, ptr, 4);
	/*----------------------------------*/

	return(entry);
139
}
osku's avatar
osku committed
140

141
/*****************************************************************//**
osku's avatar
osku committed
142
Based on a table object, this function builds the entry to be inserted
143 144
in the SYS_COLUMNS system table.
@return	the tuple which should be inserted */
osku's avatar
osku committed
145 146 147 148
static
dtuple_t*
dict_create_sys_columns_tuple(
/*==========================*/
149 150 151 152 153
	const dict_table_t*	table,	/*!< in: table */
	ulint			i,	/*!< in: column number */
	mem_heap_t*		heap)	/*!< in: memory heap from
					which the memory for the built
					tuple is allocated */
osku's avatar
osku committed
154
{
155 156 157 158 159
	dict_table_t*		sys_columns;
	dtuple_t*		entry;
	const dict_col_t*	column;
	dfield_t*		dfield;
	byte*			ptr;
160
	const char*		col_name;
osku's avatar
osku committed
161

162 163
	ut_ad(table);
	ut_ad(heap);
osku's avatar
osku committed
164 165 166 167

	column = dict_table_get_nth_col(table, i);

	sys_columns = dict_sys->sys_columns;
168

osku's avatar
osku committed
169 170
	entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS);

171 172
	dict_table_copy_types(entry, sys_columns);

osku's avatar
osku committed
173
	/* 0: TABLE_ID -----------------------*/
174
	dfield = dtuple_get_nth_field(entry, 0/*TABLE_ID*/);
osku's avatar
osku committed
175 176 177 178 179 180

	ptr = mem_heap_alloc(heap, 8);
	mach_write_to_8(ptr, table->id);

	dfield_set_data(dfield, ptr, 8);
	/* 1: POS ----------------------------*/
181
	dfield = dtuple_get_nth_field(entry, 1/*POS*/);
osku's avatar
osku committed
182 183 184 185 186 187

	ptr = mem_heap_alloc(heap, 4);
	mach_write_to_4(ptr, i);

	dfield_set_data(dfield, ptr, 4);
	/* 4: NAME ---------------------------*/
188
	dfield = dtuple_get_nth_field(entry, 2/*NAME*/);
osku's avatar
osku committed
189

190 191
	col_name = dict_table_get_col_name(table, i);
	dfield_set_data(dfield, col_name, ut_strlen(col_name));
osku's avatar
osku committed
192
	/* 5: MTYPE --------------------------*/
193
	dfield = dtuple_get_nth_field(entry, 3/*MTYPE*/);
osku's avatar
osku committed
194 195

	ptr = mem_heap_alloc(heap, 4);
196
	mach_write_to_4(ptr, column->mtype);
osku's avatar
osku committed
197 198 199

	dfield_set_data(dfield, ptr, 4);
	/* 6: PRTYPE -------------------------*/
200
	dfield = dtuple_get_nth_field(entry, 4/*PRTYPE*/);
osku's avatar
osku committed
201 202

	ptr = mem_heap_alloc(heap, 4);
203
	mach_write_to_4(ptr, column->prtype);
osku's avatar
osku committed
204 205 206

	dfield_set_data(dfield, ptr, 4);
	/* 7: LEN ----------------------------*/
207
	dfield = dtuple_get_nth_field(entry, 5/*LEN*/);
osku's avatar
osku committed
208 209

	ptr = mem_heap_alloc(heap, 4);
210
	mach_write_to_4(ptr, column->len);
osku's avatar
osku committed
211 212 213

	dfield_set_data(dfield, ptr, 4);
	/* 8: PREC ---------------------------*/
214
	dfield = dtuple_get_nth_field(entry, 6/*PREC*/);
osku's avatar
osku committed
215 216

	ptr = mem_heap_alloc(heap, 4);
217
	mach_write_to_4(ptr, 0/* unused */);
osku's avatar
osku committed
218 219 220 221 222

	dfield_set_data(dfield, ptr, 4);
	/*---------------------------------*/

	return(entry);
223
}
osku's avatar
osku committed
224

225
/***************************************************************//**
226 227
Builds a table definition to insert.
@return	DB_SUCCESS or error code */
osku's avatar
osku committed
228 229 230 231
static
ulint
dict_build_table_def_step(
/*======================*/
232 233
	que_thr_t*	thr,	/*!< in: query thread */
	tab_node_t*	node)	/*!< in: table create node */
osku's avatar
osku committed
234 235 236 237
{
	dict_table_t*	table;
	dtuple_t*	row;
	ulint		error;
238
	ulint		flags;
osku's avatar
osku committed
239 240 241
	const char*	path_or_name;
	ibool		is_path;
	mtr_t		mtr;
242
	ulint		space = 0;
osku's avatar
osku committed
243 244 245 246 247

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

	table = node->table;

248 249
	dict_hdr_get_new_id(&table->id, NULL,
			    srv_file_per_table ? &space : NULL);
osku's avatar
osku committed
250 251 252 253

	thr_get_trx(thr)->table_id = table->id;

	if (srv_file_per_table) {
254 255 256 257
		if (UNIV_UNLIKELY(space == ULINT_UNDEFINED)) {
			return(DB_ERROR);
		}

osku's avatar
osku committed
258 259 260 261 262 263
		/* We create a new single-table tablespace for the table.
		We initially let it be 4 pages:
		- page 0 is the fsp header and an extent descriptor page,
		- page 1 is an ibuf bitmap page,
		- page 2 is the first inode page,
		- page 3 will contain the root of the clustered index of the
264
		table we create here. */
265

osku's avatar
osku committed
266 267 268 269 270 271 272 273 274 275 276
		if (table->dir_path_of_temp_table) {
			/* We place tables created with CREATE TEMPORARY
			TABLE in the tmp dir of mysqld server */

			path_or_name = table->dir_path_of_temp_table;
			is_path = TRUE;
		} else {
			path_or_name = table->name;
			is_path = FALSE;
		}

277 278 279 280
		ut_ad(dict_table_get_format(table) <= DICT_TF_FORMAT_MAX);
		ut_ad(!dict_table_zip_size(table)
		      || dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);

281
		flags = table->flags & ~(~0 << DICT_TF_BITS);
282
		error = fil_create_new_single_table_tablespace(
283
			space, path_or_name, is_path,
284
			flags == DICT_TF_COMPACT ? 0 : flags,
285
			FIL_IBD_FILE_INITIAL_SIZE);
286
		table->space = (unsigned int) space;
287

osku's avatar
osku committed
288 289 290 291 292 293 294
		if (error != DB_SUCCESS) {

			return(error);
		}

		mtr_start(&mtr);

295
		fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
296

osku's avatar
osku committed
297
		mtr_commit(&mtr);
298
	} else {
299
		/* Create in the system tablespace: disallow new features */
300
		table->flags &= (~0 << DICT_TF_BITS) | DICT_TF_COMPACT;
osku's avatar
osku committed
301 302 303 304 305 306 307 308 309
	}

	row = dict_create_sys_tables_tuple(table, node->heap);

	ins_node_set_new_row(node->tab_def, row);

	return(DB_SUCCESS);
}

310
/***************************************************************//**
311 312
Builds a column definition to insert.
@return	DB_SUCCESS */
osku's avatar
osku committed
313 314 315 316
static
ulint
dict_build_col_def_step(
/*====================*/
317
	tab_node_t*	node)	/*!< in: table create node */
osku's avatar
osku committed
318 319 320 321
{
	dtuple_t*	row;

	row = dict_create_sys_columns_tuple(node->table, node->col_no,
322
					    node->heap);
osku's avatar
osku committed
323
	ins_node_set_new_row(node->col_def, row);
324

osku's avatar
osku committed
325 326 327
	return(DB_SUCCESS);
}

328
/*****************************************************************//**
osku's avatar
osku committed
329
Based on an index object, this function builds the entry to be inserted
330 331
in the SYS_INDEXES system table.
@return	the tuple which should be inserted */
osku's avatar
osku committed
332 333 334 335
static
dtuple_t*
dict_create_sys_indexes_tuple(
/*==========================*/
336 337 338 339
	const dict_index_t*	index,	/*!< in: index */
	mem_heap_t*		heap)	/*!< in: memory heap from
					which the memory for the built
					tuple is allocated */
osku's avatar
osku committed
340 341 342 343 344 345 346 347
{
	dict_table_t*	sys_indexes;
	dict_table_t*	table;
	dtuple_t*	entry;
	dfield_t*	dfield;
	byte*		ptr;

	ut_ad(mutex_own(&(dict_sys->mutex)));
348 349
	ut_ad(index);
	ut_ad(heap);
osku's avatar
osku committed
350 351 352 353

	sys_indexes = dict_sys->sys_indexes;

	table = dict_table_get_low(index->table_name);
354

osku's avatar
osku committed
355 356
	entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS);

357 358
	dict_table_copy_types(entry, sys_indexes);

osku's avatar
osku committed
359
	/* 0: TABLE_ID -----------------------*/
360
	dfield = dtuple_get_nth_field(entry, 0/*TABLE_ID*/);
osku's avatar
osku committed
361 362 363 364 365 366

	ptr = mem_heap_alloc(heap, 8);
	mach_write_to_8(ptr, table->id);

	dfield_set_data(dfield, ptr, 8);
	/* 1: ID ----------------------------*/
367
	dfield = dtuple_get_nth_field(entry, 1/*ID*/);
osku's avatar
osku committed
368 369 370 371 372 373

	ptr = mem_heap_alloc(heap, 8);
	mach_write_to_8(ptr, index->id);

	dfield_set_data(dfield, ptr, 8);
	/* 4: NAME --------------------------*/
374
	dfield = dtuple_get_nth_field(entry, 2/*NAME*/);
osku's avatar
osku committed
375 376 377

	dfield_set_data(dfield, index->name, ut_strlen(index->name));
	/* 5: N_FIELDS ----------------------*/
378
	dfield = dtuple_get_nth_field(entry, 3/*N_FIELDS*/);
osku's avatar
osku committed
379 380 381 382 383 384

	ptr = mem_heap_alloc(heap, 4);
	mach_write_to_4(ptr, index->n_fields);

	dfield_set_data(dfield, ptr, 4);
	/* 6: TYPE --------------------------*/
385
	dfield = dtuple_get_nth_field(entry, 4/*TYPE*/);
osku's avatar
osku committed
386 387 388 389 390 391 392 393 394 395 396

	ptr = mem_heap_alloc(heap, 4);
	mach_write_to_4(ptr, index->type);

	dfield_set_data(dfield, ptr, 4);
	/* 7: SPACE --------------------------*/

#if DICT_SYS_INDEXES_SPACE_NO_FIELD != 7
#error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 7"
#endif

397
	dfield = dtuple_get_nth_field(entry, 5/*SPACE*/);
osku's avatar
osku committed
398 399 400 401 402 403 404 405 406 407 408

	ptr = mem_heap_alloc(heap, 4);
	mach_write_to_4(ptr, index->space);

	dfield_set_data(dfield, ptr, 4);
	/* 8: PAGE_NO --------------------------*/

#if DICT_SYS_INDEXES_PAGE_NO_FIELD != 8
#error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 8"
#endif

409
	dfield = dtuple_get_nth_field(entry, 6/*PAGE_NO*/);
osku's avatar
osku committed
410 411 412 413 414 415 416 417

	ptr = mem_heap_alloc(heap, 4);
	mach_write_to_4(ptr, FIL_NULL);

	dfield_set_data(dfield, ptr, 4);
	/*--------------------------------*/

	return(entry);
418
}
osku's avatar
osku committed
419

420
/*****************************************************************//**
osku's avatar
osku committed
421
Based on an index object, this function builds the entry to be inserted
422 423
in the SYS_FIELDS system table.
@return	the tuple which should be inserted */
osku's avatar
osku committed
424 425 426 427
static
dtuple_t*
dict_create_sys_fields_tuple(
/*=========================*/
428 429 430 431 432
	const dict_index_t*	index,	/*!< in: index */
	ulint			i,	/*!< in: field number */
	mem_heap_t*		heap)	/*!< in: memory heap from
					which the memory for the built
					tuple is allocated */
osku's avatar
osku committed
433 434 435 436 437 438 439 440 441
{
	dict_table_t*	sys_fields;
	dtuple_t*	entry;
	dict_field_t*	field;
	dfield_t*	dfield;
	byte*		ptr;
	ibool		index_contains_column_prefix_field	= FALSE;
	ulint		j;

442 443
	ut_ad(index);
	ut_ad(heap);
osku's avatar
osku committed
444 445

	for (j = 0; j < index->n_fields; j++) {
446 447
		if (dict_index_get_nth_field(index, j)->prefix_len > 0) {
			index_contains_column_prefix_field = TRUE;
448
			break;
osku's avatar
osku committed
449 450 451 452 453 454
		}
	}

	field = dict_index_get_nth_field(index, i);

	sys_fields = dict_sys->sys_fields;
455

osku's avatar
osku committed
456 457
	entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS);

458 459
	dict_table_copy_types(entry, sys_fields);

osku's avatar
osku committed
460
	/* 0: INDEX_ID -----------------------*/
461
	dfield = dtuple_get_nth_field(entry, 0/*INDEX_ID*/);
osku's avatar
osku committed
462 463 464 465 466 467 468

	ptr = mem_heap_alloc(heap, 8);
	mach_write_to_8(ptr, index->id);

	dfield_set_data(dfield, ptr, 8);
	/* 1: POS + PREFIX LENGTH ----------------------------*/

469
	dfield = dtuple_get_nth_field(entry, 1/*POS*/);
osku's avatar
osku committed
470 471

	ptr = mem_heap_alloc(heap, 4);
472

osku's avatar
osku committed
473 474 475 476 477
	if (index_contains_column_prefix_field) {
		/* If there are column prefix fields in the index, then
		we store the number of the field to the 2 HIGH bytes
		and the prefix length to the 2 low bytes, */

478
		mach_write_to_4(ptr, (i << 16) + field->prefix_len);
osku's avatar
osku committed
479
	} else {
480
		/* Else we store the number of the field to the 2 LOW bytes.
osku's avatar
osku committed
481 482
		This is to keep the storage format compatible with
		InnoDB versions < 4.0.14. */
483 484

		mach_write_to_4(ptr, i);
osku's avatar
osku committed
485 486 487 488
	}

	dfield_set_data(dfield, ptr, 4);
	/* 4: COL_NAME -------------------------*/
489
	dfield = dtuple_get_nth_field(entry, 2/*COL_NAME*/);
osku's avatar
osku committed
490 491

	dfield_set_data(dfield, field->name,
492
			ut_strlen(field->name));
osku's avatar
osku committed
493 494 495
	/*---------------------------------*/

	return(entry);
496
}
osku's avatar
osku committed
497

498
/*****************************************************************//**
osku's avatar
osku committed
499
Creates the tuple with which the index entry is searched for writing the index
500 501
tree root page number, if such a tree is created.
@return	the tuple for search */
osku's avatar
osku committed
502 503 504 505
static
dtuple_t*
dict_create_search_tuple(
/*=====================*/
506
	const dtuple_t*	tuple,	/*!< in: the tuple inserted in the SYS_INDEXES
osku's avatar
osku committed
507
				table */
508
	mem_heap_t*	heap)	/*!< in: memory heap from which the memory for
osku's avatar
osku committed
509 510 511
				the built tuple is allocated */
{
	dtuple_t*	search_tuple;
512
	const dfield_t*	field1;
osku's avatar
osku committed
513 514 515 516 517 518
	dfield_t*	field2;

	ut_ad(tuple && heap);

	search_tuple = dtuple_create(heap, 2);

519
	field1 = dtuple_get_nth_field(tuple, 0);
520
	field2 = dtuple_get_nth_field(search_tuple, 0);
osku's avatar
osku committed
521 522 523

	dfield_copy(field2, field1);

524
	field1 = dtuple_get_nth_field(tuple, 1);
525
	field2 = dtuple_get_nth_field(search_tuple, 1);
osku's avatar
osku committed
526 527 528 529 530 531 532 533

	dfield_copy(field2, field1);

	ut_ad(dtuple_validate(search_tuple));

	return(search_tuple);
}

534
/***************************************************************//**
535 536
Builds an index definition row to insert.
@return	DB_SUCCESS or error code */
osku's avatar
osku committed
537 538 539 540
static
ulint
dict_build_index_def_step(
/*======================*/
541 542
	que_thr_t*	thr,	/*!< in: query thread */
	ind_node_t*	node)	/*!< in: index create node */
osku's avatar
osku committed
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
{
	dict_table_t*	table;
	dict_index_t*	index;
	dtuple_t*	row;
	trx_t*		trx;

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

	trx = thr_get_trx(thr);

	index = node->index;

	table = dict_table_get_low(index->table_name);

	if (table == NULL) {
		return(DB_TABLE_NOT_FOUND);
	}

	trx->table_id = table->id;

	node->table = table;

	ut_ad((UT_LIST_GET_LEN(table->indexes) > 0)
566
	      || dict_index_is_clust(index));
567

568
	dict_hdr_get_new_id(NULL, &index->id, NULL);
osku's avatar
osku committed
569 570 571 572 573 574 575 576 577 578 579

	/* Inherit the space id from the table; we store all indexes of a
	table in the same tablespace */

	index->space = table->space;
	node->page_no = FIL_NULL;
	row = dict_create_sys_indexes_tuple(index, node->heap);
	node->ind_row = row;

	ins_node_set_new_row(node->ind_def, row);

580
	/* Note that the index was created by this transaction. */
581
	index->trx_id = (ib_uint64_t) ut_conv_dulint_to_longlong(trx->id);
582

osku's avatar
osku committed
583 584 585
	return(DB_SUCCESS);
}

586
/***************************************************************//**
587 588
Builds a field definition row to insert.
@return	DB_SUCCESS */
osku's avatar
osku committed
589 590 591 592
static
ulint
dict_build_field_def_step(
/*======================*/
593
	ind_node_t*	node)	/*!< in: index create node */
osku's avatar
osku committed
594 595 596 597 598
{
	dict_index_t*	index;
	dtuple_t*	row;

	index = node->index;
599

osku's avatar
osku committed
600 601 602 603 604 605 606
	row = dict_create_sys_fields_tuple(index, node->field_no, node->heap);

	ins_node_set_new_row(node->field_def, row);

	return(DB_SUCCESS);
}

607
/***************************************************************//**
608 609
Creates an index tree for the index if it is not a member of a cluster.
@return	DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
osku's avatar
osku committed
610 611 612 613
static
ulint
dict_create_index_tree_step(
/*========================*/
614
	ind_node_t*	node)	/*!< in: index create node */
osku's avatar
osku committed
615 616 617 618 619
{
	dict_index_t*	index;
	dict_table_t*	sys_indexes;
	dict_table_t*	table;
	dtuple_t*	search_tuple;
620
	ulint		zip_size;
osku's avatar
osku committed
621 622 623 624 625
	btr_pcur_t	pcur;
	mtr_t		mtr;

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

626
	index = node->index;
osku's avatar
osku committed
627 628 629 630 631 632 633 634 635 636 637
	table = node->table;

	sys_indexes = dict_sys->sys_indexes;

	/* Run a mini-transaction in which the index tree is allocated for
	the index and its root address is written to the index entry in
	sys_indexes */

	mtr_start(&mtr);

	search_tuple = dict_create_search_tuple(node->ind_row, node->heap);
638

osku's avatar
osku committed
639
	btr_pcur_open(UT_LIST_GET_FIRST(sys_indexes->indexes),
640 641
		      search_tuple, PAGE_CUR_L, BTR_MODIFY_LEAF,
		      &pcur, &mtr);
osku's avatar
osku committed
642 643 644

	btr_pcur_move_to_next_user_rec(&pcur, &mtr);

645 646 647
	zip_size = dict_table_zip_size(index->table);

	node->page_no = btr_create(index->type, index->space, zip_size,
648
				   index->id, index, &mtr);
osku's avatar
osku committed
649
	/* printf("Created a new index tree in space %lu root page %lu\n",
650
	index->space, index->page_no); */
osku's avatar
osku committed
651 652

	page_rec_write_index_page_no(btr_pcur_get_rec(&pcur),
653 654
				     DICT_SYS_INDEXES_PAGE_NO_FIELD,
				     node->page_no, &mtr);
osku's avatar
osku committed
655 656 657 658 659 660 661 662 663 664 665
	btr_pcur_close(&pcur);
	mtr_commit(&mtr);

	if (node->page_no == FIL_NULL) {

		return(DB_OUT_OF_FILE_SPACE);
	}

	return(DB_SUCCESS);
}

666
/*******************************************************************//**
osku's avatar
osku committed
667
Drops the index tree associated with a row in SYS_INDEXES table. */
668
UNIV_INTERN
osku's avatar
osku committed
669 670 671
void
dict_drop_index_tree(
/*=================*/
672
	rec_t*	rec,	/*!< in/out: record in the clustered index
673
			of SYS_INDEXES table */
674
	mtr_t*	mtr)	/*!< in: mtr having the latch on the record page */
osku's avatar
osku committed
675
{
676 677
	ulint		root_page_no;
	ulint		space;
678
	ulint		zip_size;
679 680
	const byte*	ptr;
	ulint		len;
681

osku's avatar
osku committed
682
	ut_ad(mutex_own(&(dict_sys->mutex)));
683
	ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
osku's avatar
osku committed
684 685 686
	ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);

	ut_ad(len == 4);
687

osku's avatar
osku committed
688 689 690 691 692 693 694 695 696
	root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);

	if (root_page_no == FIL_NULL) {
		/* The tree has already been freed */

		return;
	}

	ptr = rec_get_nth_field_old(rec,
697
				    DICT_SYS_INDEXES_SPACE_NO_FIELD, &len);
osku's avatar
osku committed
698 699 700 701

	ut_ad(len == 4);

	space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
702
	zip_size = fil_space_get_zip_size(space);
osku's avatar
osku committed
703

704
	if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
osku's avatar
osku committed
705 706 707 708 709 710 711 712 713
		/* It is a single table tablespace and the .ibd file is
		missing: do nothing */

		return;
	}

	/* We free all the pages but the root page first; this operation
	may span several mini-transactions */

714
	btr_free_but_not_root(space, zip_size, root_page_no);
osku's avatar
osku committed
715 716 717 718

	/* Then we free the root page in the same mini-transaction where
	we write FIL_NULL to the appropriate field in the SYS_INDEXES
	record: this mini-transaction marks the B-tree totally freed */
719

osku's avatar
osku committed
720
	/* printf("Dropping index tree in space %lu root page %lu\n", space,
721
	root_page_no); */
722
	btr_free_root(space, zip_size, root_page_no, mtr);
osku's avatar
osku committed
723 724

	page_rec_write_index_page_no(rec,
725 726
				     DICT_SYS_INDEXES_PAGE_NO_FIELD,
				     FIL_NULL, mtr);
osku's avatar
osku committed
727 728
}

729
/*******************************************************************//**
730 731
Truncates the index tree associated with a row in SYS_INDEXES table.
@return	new root page number, or FIL_NULL on failure */
732
UNIV_INTERN
osku's avatar
osku committed
733 734 735
ulint
dict_truncate_index_tree(
/*=====================*/
736 737
	dict_table_t*	table,	/*!< in: the table the index belongs to */
	ulint		space,	/*!< in: 0=truncate,
738 739
				nonzero=create the index tree in the
				given tablespace */
740
	btr_pcur_t*	pcur,	/*!< in/out: persistent cursor pointing to
marko's avatar
marko committed
741 742 743
				record in the clustered index of
				SYS_INDEXES table. The cursor may be
				repositioned in this call. */
744
	mtr_t*		mtr)	/*!< in: mtr having the latch
osku's avatar
osku committed
745 746 747 748
				on the record page. The mtr may be
				committed and restarted in this call. */
{
	ulint		root_page_no;
749
	ibool		drop = !space;
750
	ulint		zip_size;
osku's avatar
osku committed
751 752
	ulint		type;
	dulint		index_id;
marko's avatar
marko committed
753
	rec_t*		rec;
754
	const byte*	ptr;
osku's avatar
osku committed
755 756 757 758
	ulint		len;
	dict_index_t*	index;

	ut_ad(mutex_own(&(dict_sys->mutex)));
759
	ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
marko's avatar
marko committed
760
	rec = btr_pcur_get_rec(pcur);
osku's avatar
osku committed
761 762 763 764 765 766
	ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);

	ut_ad(len == 4);

	root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);

767
	if (drop && root_page_no == FIL_NULL) {
osku's avatar
osku committed
768 769 770 771 772
		/* The tree has been freed. */

		ut_print_timestamp(stderr);
		fprintf(stderr, "  InnoDB: Trying to TRUNCATE"
			" a missing index of table %s!\n", table->name);
773
		drop = FALSE;
osku's avatar
osku committed
774 775 776
	}

	ptr = rec_get_nth_field_old(rec,
777
				    DICT_SYS_INDEXES_SPACE_NO_FIELD, &len);
osku's avatar
osku committed
778 779 780

	ut_ad(len == 4);

781 782 783 784
	if (drop) {
		space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
	}

785
	zip_size = fil_space_get_zip_size(space);
osku's avatar
osku committed
786

787
	if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
osku's avatar
osku committed
788 789 790 791 792 793 794 795 796 797
		/* It is a single table tablespace and the .ibd file is
		missing: do nothing */

		ut_print_timestamp(stderr);
		fprintf(stderr, "  InnoDB: Trying to TRUNCATE"
			" a missing .ibd file of table %s!\n", table->name);
		return(FIL_NULL);
	}

	ptr = rec_get_nth_field_old(rec,
798
				    DICT_SYS_INDEXES_TYPE_FIELD, &len);
osku's avatar
osku committed
799 800 801 802 803 804 805
	ut_ad(len == 4);
	type = mach_read_from_4(ptr);

	ptr = rec_get_nth_field_old(rec, 1, &len);
	ut_ad(len == 8);
	index_id = mach_read_from_8(ptr);

806 807 808 809 810
	if (!drop) {

		goto create;
	}

osku's avatar
osku committed
811 812 813
	/* We free all the pages but the root page first; this operation
	may span several mini-transactions */

814
	btr_free_but_not_root(space, zip_size, root_page_no);
osku's avatar
osku committed
815 816 817 818 819 820

	/* Then we free the root page in the same mini-transaction where
	we create the b-tree and write its new root page number to the
	appropriate field in the SYS_INDEXES record: this mini-transaction
	marks the B-tree totally truncated */

821
	btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
osku's avatar
osku committed
822

823
	btr_free_root(space, zip_size, root_page_no, mtr);
824
create:
osku's avatar
osku committed
825 826 827 828 829
	/* We will temporarily write FIL_NULL to the PAGE_NO field
	in SYS_INDEXES, so that the database will not get into an
	inconsistent state in case it crashes between the mtr_commit()
	below and the following mtr_commit() call. */
	page_rec_write_index_page_no(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
830
				     FIL_NULL, mtr);
osku's avatar
osku committed
831 832 833 834

	/* We will need to commit the mini-transaction in order to avoid
	deadlocks in the btr_create() call, because otherwise we would
	be freeing and allocating pages in the same mini-transaction. */
marko's avatar
marko committed
835
	btr_pcur_store_position(pcur, mtr);
osku's avatar
osku committed
836
	mtr_commit(mtr);
marko's avatar
marko committed
837

osku's avatar
osku committed
838
	mtr_start(mtr);
marko's avatar
marko committed
839
	btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
osku's avatar
osku committed
840 841 842

	/* Find the index corresponding to this SYS_INDEXES record. */
	for (index = UT_LIST_GET_FIRST(table->indexes);
843 844
	     index;
	     index = UT_LIST_GET_NEXT(indexes, index)) {
osku's avatar
osku committed
845
		if (!ut_dulint_cmp(index->id, index_id)) {
846 847 848 849
			root_page_no = btr_create(type, space, zip_size,
						  index_id, index, mtr);
			index->page = (unsigned int) root_page_no;
			return(root_page_no);
osku's avatar
osku committed
850 851 852
		}
	}

853 854 855 856 857 858 859
	ut_print_timestamp(stderr);
	fprintf(stderr,
		"  InnoDB: Index %lu %lu of table %s is missing\n"
		"InnoDB: from the data dictionary during TRUNCATE!\n",
		ut_dulint_get_high(index_id),
		ut_dulint_get_low(index_id),
		table->name);
osku's avatar
osku committed
860

861
	return(FIL_NULL);
osku's avatar
osku committed
862 863
}

864
/*********************************************************************//**
865 866
Creates a table create graph.
@return	own: table create node */
867
UNIV_INTERN
osku's avatar
osku committed
868 869 870
tab_node_t*
tab_create_graph_create(
/*====================*/
871
	dict_table_t*	table,	/*!< in: table to create, built as a memory data
osku's avatar
osku committed
872
				structure */
873
	mem_heap_t*	heap)	/*!< in: heap where created */
osku's avatar
osku committed
874 875 876 877
{
	tab_node_t*	node;

	node = mem_heap_alloc(heap, sizeof(tab_node_t));
878

osku's avatar
osku committed
879 880 881 882 883 884 885 886
	node->common.type = QUE_NODE_CREATE_TABLE;

	node->table = table;

	node->state = TABLE_BUILD_TABLE_DEF;
	node->heap = mem_heap_create(256);

	node->tab_def = ins_node_create(INS_DIRECT, dict_sys->sys_tables,
887
					heap);
osku's avatar
osku committed
888
	node->tab_def->common.parent = node;
889

osku's avatar
osku committed
890
	node->col_def = ins_node_create(INS_DIRECT, dict_sys->sys_columns,
891
					heap);
osku's avatar
osku committed
892 893 894 895 896 897 898 899
	node->col_def->common.parent = node;

	node->commit_node = commit_node_create(heap);
	node->commit_node->common.parent = node;

	return(node);
}

900
/*********************************************************************//**
901 902
Creates an index create graph.
@return	own: index create node */
903
UNIV_INTERN
osku's avatar
osku committed
904 905 906
ind_node_t*
ind_create_graph_create(
/*====================*/
907
	dict_index_t*	index,	/*!< in: index to create, built as a memory data
osku's avatar
osku committed
908
				structure */
909
	mem_heap_t*	heap)	/*!< in: heap where created */
osku's avatar
osku committed
910 911 912 913 914 915 916 917 918 919 920 921 922 923
{
	ind_node_t*	node;

	node = mem_heap_alloc(heap, sizeof(ind_node_t));

	node->common.type = QUE_NODE_CREATE_INDEX;

	node->index = index;

	node->state = INDEX_BUILD_INDEX_DEF;
	node->page_no = FIL_NULL;
	node->heap = mem_heap_create(256);

	node->ind_def = ins_node_create(INS_DIRECT,
924
					dict_sys->sys_indexes, heap);
osku's avatar
osku committed
925 926 927
	node->ind_def->common.parent = node;

	node->field_def = ins_node_create(INS_DIRECT,
928
					  dict_sys->sys_fields, heap);
osku's avatar
osku committed
929 930 931 932 933 934 935 936
	node->field_def->common.parent = node;

	node->commit_node = commit_node_create(heap);
	node->commit_node->common.parent = node;

	return(node);
}

937
/***********************************************************//**
938 939
Creates a table. This is a high-level function used in SQL execution graphs.
@return	query thread to run next or NULL */
940
UNIV_INTERN
osku's avatar
osku committed
941 942 943
que_thr_t*
dict_create_table_step(
/*===================*/
944
	que_thr_t*	thr)	/*!< in: query thread */
osku's avatar
osku committed
945 946 947 948 949 950 951 952 953
{
	tab_node_t*	node;
	ulint		err	= DB_ERROR;
	trx_t*		trx;

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

	trx = thr_get_trx(thr);
954

osku's avatar
osku committed
955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
	node = thr->run_node;

	ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_TABLE);

	if (thr->prev_node == que_node_get_parent(node)) {
		node->state = TABLE_BUILD_TABLE_DEF;
	}

	if (node->state == TABLE_BUILD_TABLE_DEF) {

		/* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */

		err = dict_build_table_def_step(thr, node);

		if (err != DB_SUCCESS) {

			goto function_exit;
		}
973

osku's avatar
osku committed
974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993
		node->state = TABLE_BUILD_COL_DEF;
		node->col_no = 0;

		thr->run_node = node->tab_def;

		return(thr);
	}

	if (node->state == TABLE_BUILD_COL_DEF) {

		if (node->col_no < (node->table)->n_def) {

			err = dict_build_col_def_step(node);

			if (err != DB_SUCCESS) {

				goto function_exit;
			}

			node->col_no++;
994

osku's avatar
osku committed
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
			thr->run_node = node->col_def;

			return(thr);
		} else {
			node->state = TABLE_COMMIT_WORK;
		}
	}

	if (node->state == TABLE_COMMIT_WORK) {

		/* Table was correctly defined: do NOT commit the transaction
		(CREATE TABLE does NOT do an implicit commit of the current
		transaction) */
1008

osku's avatar
osku committed
1009 1010 1011 1012 1013 1014 1015 1016 1017
		node->state = TABLE_ADD_TO_CACHE;

		/* thr->run_node = node->commit_node;

		return(thr); */
	}

	if (node->state == TABLE_ADD_TO_CACHE) {

1018
		dict_table_add_to_cache(node->table, node->heap);
osku's avatar
osku committed
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040

		err = DB_SUCCESS;
	}

function_exit:
	trx->error_state = err;

	if (err == DB_SUCCESS) {
		/* Ok: do nothing */

	} else if (err == DB_LOCK_WAIT) {

		return(NULL);
	} else {
		/* SQL error detected */

		return(NULL);
	}

	thr->run_node = que_node_get_parent(node);

	return(thr);
1041
}
osku's avatar
osku committed
1042

1043
/***********************************************************//**
osku's avatar
osku committed
1044
Creates an index. This is a high-level function used in SQL execution
1045 1046
graphs.
@return	query thread to run next or NULL */
1047
UNIV_INTERN
osku's avatar
osku committed
1048 1049 1050
que_thr_t*
dict_create_index_step(
/*===================*/
1051
	que_thr_t*	thr)	/*!< in: query thread */
osku's avatar
osku committed
1052 1053 1054 1055 1056 1057 1058 1059 1060
{
	ind_node_t*	node;
	ulint		err	= DB_ERROR;
	trx_t*		trx;

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

	trx = thr_get_trx(thr);
1061

osku's avatar
osku committed
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
	node = thr->run_node;

	ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_INDEX);

	if (thr->prev_node == que_node_get_parent(node)) {
		node->state = INDEX_BUILD_INDEX_DEF;
	}

	if (node->state == INDEX_BUILD_INDEX_DEF) {
		/* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
		err = dict_build_index_def_step(thr, node);

		if (err != DB_SUCCESS) {

			goto function_exit;
		}
1078

osku's avatar
osku committed
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
		node->state = INDEX_BUILD_FIELD_DEF;
		node->field_no = 0;

		thr->run_node = node->ind_def;

		return(thr);
	}

	if (node->state == INDEX_BUILD_FIELD_DEF) {

		if (node->field_no < (node->index)->n_fields) {

			err = dict_build_field_def_step(node);

			if (err != DB_SUCCESS) {

				goto function_exit;
			}

			node->field_no++;
1099

osku's avatar
osku committed
1100 1101 1102 1103
			thr->run_node = node->field_def;

			return(thr);
		} else {
1104
			node->state = INDEX_ADD_TO_CACHE;
osku's avatar
osku committed
1105 1106 1107
		}
	}

1108 1109 1110 1111
	if (node->state == INDEX_ADD_TO_CACHE) {

		dulint	index_id = node->index->id;

1112 1113 1114 1115 1116
		err = dict_index_add_to_cache(
			node->table, node->index, FIL_NULL,
			trx_is_strict(trx)
			|| dict_table_get_format(node->table)
			>= DICT_TF_FORMAT_ZIP);
1117 1118

		node->index = dict_index_get_if_in_cache_low(index_id);
1119
		ut_a(!node->index == (err != DB_SUCCESS));
1120

1121 1122 1123 1124
		if (err != DB_SUCCESS) {

			goto function_exit;
		}
1125 1126 1127 1128

		node->state = INDEX_CREATE_INDEX_TREE;
	}

osku's avatar
osku committed
1129 1130 1131 1132 1133
	if (node->state == INDEX_CREATE_INDEX_TREE) {

		err = dict_create_index_tree_step(node);

		if (err != DB_SUCCESS) {
1134 1135
			dict_index_remove_from_cache(node->table, node->index);
			node->index = NULL;
osku's avatar
osku committed
1136 1137 1138 1139

			goto function_exit;
		}

1140
		node->index->page = node->page_no;
osku's avatar
osku committed
1141 1142 1143 1144 1145 1146 1147 1148
		node->state = INDEX_COMMIT_WORK;
	}

	if (node->state == INDEX_COMMIT_WORK) {

		/* Index was correctly defined: do NOT commit the transaction
		(CREATE INDEX does NOT currently do an implicit commit of
		the current transaction) */
1149

1150
		node->state = INDEX_CREATE_INDEX_TREE;
osku's avatar
osku committed
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174

		/* thr->run_node = node->commit_node;

		return(thr); */
	}

function_exit:
	trx->error_state = err;

	if (err == DB_SUCCESS) {
		/* Ok: do nothing */

	} else if (err == DB_LOCK_WAIT) {

		return(NULL);
	} else {
		/* SQL error detected */

		return(NULL);
	}

	thr->run_node = que_node_get_parent(node);

	return(thr);
1175
}
osku's avatar
osku committed
1176

1177
/****************************************************************//**
osku's avatar
osku committed
1178 1179
Creates the foreign key constraints system tables inside InnoDB
at database creation or database start if they are not found or are
1180 1181
not of the right form.
@return	DB_SUCCESS or error code */
1182
UNIV_INTERN
osku's avatar
osku committed
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
ulint
dict_create_or_check_foreign_constraint_tables(void)
/*================================================*/
{
	dict_table_t*	table1;
	dict_table_t*	table2;
	ulint		error;
	trx_t*		trx;

	mutex_enter(&(dict_sys->mutex));

	table1 = dict_table_get_low("SYS_FOREIGN");
	table2 = dict_table_get_low("SYS_FOREIGN_COLS");
1196

osku's avatar
osku committed
1197
	if (table1 && table2
1198 1199
	    && UT_LIST_GET_LEN(table1->indexes) == 3
	    && UT_LIST_GET_LEN(table2->indexes) == 1) {
osku's avatar
osku committed
1200

1201 1202
		/* Foreign constraint system tables have already been
		created, and they are ok */
osku's avatar
osku committed
1203 1204 1205

		mutex_exit(&(dict_sys->mutex));

1206 1207
		return(DB_SUCCESS);
	}
osku's avatar
osku committed
1208 1209 1210 1211

	mutex_exit(&(dict_sys->mutex));

	trx = trx_allocate_for_mysql();
1212

osku's avatar
osku committed
1213 1214 1215 1216 1217 1218
	trx->op_info = "creating foreign key sys tables";

	row_mysql_lock_data_dictionary(trx);

	if (table1) {
		fprintf(stderr,
1219 1220
			"InnoDB: dropping incompletely created"
			" SYS_FOREIGN table\n");
osku's avatar
osku committed
1221 1222 1223 1224 1225
		row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
	}

	if (table2) {
		fprintf(stderr,
1226 1227
			"InnoDB: dropping incompletely created"
			" SYS_FOREIGN_COLS table\n");
osku's avatar
osku committed
1228 1229 1230 1231 1232 1233 1234 1235 1236
		row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
	}

	fprintf(stderr,
		"InnoDB: Creating foreign key constraint system tables\n");

	/* NOTE: in dict_load_foreigns we use the fact that
	there are 2 secondary indexes on SYS_FOREIGN, and they
	are defined just like below */
1237

osku's avatar
osku committed
1238 1239 1240 1241 1242 1243
	/* NOTE: when designing InnoDB's foreign key support in 2001, we made
	an error and made the table names and the foreign key id of type
	'CHAR' (internally, really a VARCHAR). We should have made the type
	VARBINARY, like in other InnoDB system tables, to get a clean
	design. */

1244
	error = que_eval_sql(NULL,
1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
			     "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
			     "BEGIN\n"
			     "CREATE TABLE\n"
			     "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR,"
			     " REF_NAME CHAR, N_COLS INT);\n"
			     "CREATE UNIQUE CLUSTERED INDEX ID_IND"
			     " ON SYS_FOREIGN (ID);\n"
			     "CREATE INDEX FOR_IND"
			     " ON SYS_FOREIGN (FOR_NAME);\n"
			     "CREATE INDEX REF_IND"
			     " ON SYS_FOREIGN (REF_NAME);\n"
			     "CREATE TABLE\n"
			     "SYS_FOREIGN_COLS(ID CHAR, POS INT,"
			     " FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
			     "CREATE UNIQUE CLUSTERED INDEX ID_IND"
			     " ON SYS_FOREIGN_COLS (ID, POS);\n"
			     "END;\n"
			     , FALSE, trx);
osku's avatar
osku committed
1263 1264 1265 1266

	if (error != DB_SUCCESS) {
		fprintf(stderr, "InnoDB: error %lu in creation\n",
			(ulong) error);
1267

1268 1269
		ut_a(error == DB_OUT_OF_FILE_SPACE
		     || error == DB_TOO_MANY_CONCURRENT_TRXS);
osku's avatar
osku committed
1270 1271

		fprintf(stderr,
1272 1273 1274 1275
			"InnoDB: creation failed\n"
			"InnoDB: tablespace is full\n"
			"InnoDB: dropping incompletely created"
			" SYS_FOREIGN tables\n");
osku's avatar
osku committed
1276 1277 1278 1279 1280 1281 1282

		row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
		row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);

		error = DB_MUST_GET_MORE_FILE_SPACE;
	}

1283
	trx_commit_for_mysql(trx);
osku's avatar
osku committed
1284 1285 1286

	row_mysql_unlock_data_dictionary(trx);

1287
	trx_free_for_mysql(trx);
osku's avatar
osku committed
1288

1289
	if (error == DB_SUCCESS) {
osku's avatar
osku committed
1290
		fprintf(stderr,
1291 1292
			"InnoDB: Foreign key constraint system tables"
			" created\n");
osku's avatar
osku committed
1293 1294 1295 1296 1297
	}

	return(error);
}

1298
/****************************************************************//**
1299 1300
Evaluate the given foreign key SQL statement.
@return	error code or DB_SUCCESS */
1301
static
osku's avatar
osku committed
1302
ulint
1303 1304
dict_foreign_eval_sql(
/*==================*/
1305 1306 1307 1308 1309
	pars_info_t*	info,	/*!< in: info struct, or NULL */
	const char*	sql,	/*!< in: SQL string to evaluate */
	dict_table_t*	table,	/*!< in: table */
	dict_foreign_t*	foreign,/*!< in: foreign */
	trx_t*		trx)	/*!< in: transaction */
osku's avatar
osku committed
1310 1311 1312 1313
{
	ulint		error;
	FILE*		ef	= dict_foreign_err_file;

1314
	error = que_eval_sql(info, sql, FALSE, trx);
osku's avatar
osku committed
1315 1316 1317 1318 1319 1320

	if (error == DB_DUPLICATE_KEY) {
		mutex_enter(&dict_foreign_err_mutex);
		rewind(ef);
		ut_print_timestamp(ef);
		fputs(" Error in foreign key constraint creation for table ",
1321
		      ef);
1322
		ut_print_name(ef, trx, TRUE, table->name);
osku's avatar
osku committed
1323
		fputs(".\nA foreign key constraint of name ", ef);
1324
		ut_print_name(ef, trx, TRUE, foreign->id);
osku's avatar
osku committed
1325
		fputs("\nalready exists."
1326 1327 1328
		      " (Note that internally InnoDB adds 'databasename'\n"
		      "in front of the user-defined constraint name.)\n"
		      "Note that InnoDB's FOREIGN KEY system tables store\n"
1329 1330 1331 1332 1333 1334 1335
		      "constraint names as case-insensitive, with the\n"
		      "MySQL standard latin1_swedish_ci collation. If you\n"
		      "create tables or databases whose names differ only in\n"
		      "the character case, then collisions in constraint\n"
		      "names can occur. Workaround: name your constraints\n"
		      "explicitly with unique names.\n",
		      ef);
osku's avatar
osku committed
1336 1337 1338 1339 1340 1341 1342

		mutex_exit(&dict_foreign_err_mutex);

		return(error);
	}

	if (error != DB_SUCCESS) {
1343
		fprintf(stderr,
osku's avatar
osku committed
1344 1345 1346 1347 1348 1349
			"InnoDB: Foreign key constraint creation failed:\n"
			"InnoDB: internal error number %lu\n", (ulong) error);

		mutex_enter(&dict_foreign_err_mutex);
		ut_print_timestamp(ef);
		fputs(" Internal error in foreign key constraint creation"
1350
		      " for table ", ef);
1351
		ut_print_name(ef, trx, TRUE, table->name);
osku's avatar
osku committed
1352
		fputs(".\n"
1353 1354
		      "See the MySQL .err log in the datadir"
		      " for more information.\n", ef);
osku's avatar
osku committed
1355 1356 1357 1358
		mutex_exit(&dict_foreign_err_mutex);

		return(error);
	}
1359

1360 1361 1362
	return(DB_SUCCESS);
}

1363
/********************************************************************//**
1364
Add a single foreign key field definition to the data dictionary tables in
1365 1366
the database.
@return	error code or DB_SUCCESS */
1367 1368 1369 1370
static
ulint
dict_create_add_foreign_field_to_dictionary(
/*========================================*/
1371 1372 1373 1374
	ulint		field_nr,	/*!< in: foreign field number */
	dict_table_t*	table,		/*!< in: table */
	dict_foreign_t*	foreign,	/*!< in: foreign */
	trx_t*		trx)		/*!< in: transaction */
1375 1376 1377 1378 1379 1380 1381 1382
{
	pars_info_t*	info = pars_info_create();

	pars_info_add_str_literal(info, "id", foreign->id);

	pars_info_add_int4_literal(info, "pos", field_nr);

	pars_info_add_str_literal(info, "for_col_name",
1383
				  foreign->foreign_col_names[field_nr]);
1384 1385

	pars_info_add_str_literal(info, "ref_col_name",
1386
				  foreign->referenced_col_names[field_nr]);
1387

1388 1389 1390 1391 1392 1393 1394 1395
	return(dict_foreign_eval_sql(
		       info,
		       "PROCEDURE P () IS\n"
		       "BEGIN\n"
		       "INSERT INTO SYS_FOREIGN_COLS VALUES"
		       "(:id, :pos, :for_col_name, :ref_col_name);\n"
		       "END;\n",
		       table, foreign, trx));
1396
}
osku's avatar
osku committed
1397

1398
/********************************************************************//**
1399 1400 1401
Add a single foreign key definition to the data dictionary tables in the
database. We also generate names to constraints that were not named by the
user. A generated constraint has a name of the format
1402
databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and
1403
are given locally for this table, that is, the number is not global, as in
1404 1405
the old format constraints < 4.0.18 it used to be.
@return	error code or DB_SUCCESS */
1406 1407 1408 1409
static
ulint
dict_create_add_foreign_to_dictionary(
/*==================================*/
1410
	ulint*		id_nr,	/*!< in/out: number to use in id generation;
1411
				incremented if used */
1412 1413 1414
	dict_table_t*	table,	/*!< in: table */
	dict_foreign_t*	foreign,/*!< in: foreign */
	trx_t*		trx)	/*!< in: transaction */
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434
{
	ulint		error;
	ulint		i;

	pars_info_t*	info = pars_info_create();

	if (foreign->id == NULL) {
		/* Generate a new constraint id */
		ulint	namelen	= strlen(table->name);
		char*	id	= mem_heap_alloc(foreign->heap, namelen + 20);
		/* no overflow if number < 1e13 */
		sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++);
		foreign->id = id;
	}

	pars_info_add_str_literal(info, "id", foreign->id);

	pars_info_add_str_literal(info, "for_name", table->name);

	pars_info_add_str_literal(info, "ref_name",
1435
				  foreign->referenced_table_name);
1436 1437

	pars_info_add_int4_literal(info, "n_cols",
1438
				   foreign->n_fields + (foreign->type << 24));
1439 1440

	error = dict_foreign_eval_sql(info,
1441 1442 1443 1444 1445 1446
				      "PROCEDURE P () IS\n"
				      "BEGIN\n"
				      "INSERT INTO SYS_FOREIGN VALUES"
				      "(:id, :for_name, :ref_name, :n_cols);\n"
				      "END;\n"
				      , table, foreign, trx);
1447 1448 1449 1450 1451 1452 1453

	if (error != DB_SUCCESS) {

		return(error);
	}

	for (i = 0; i < foreign->n_fields; i++) {
1454 1455
		error = dict_create_add_foreign_field_to_dictionary(
			i, table, foreign, trx);
1456 1457 1458 1459 1460 1461 1462 1463

		if (error != DB_SUCCESS) {

			return(error);
		}
	}

	error = dict_foreign_eval_sql(NULL,
1464 1465 1466 1467 1468
				      "PROCEDURE P () IS\n"
				      "BEGIN\n"
				      "COMMIT WORK;\n"
				      "END;\n"
				      , table, foreign, trx);
1469 1470 1471 1472

	return(error);
}

1473
/********************************************************************//**
1474 1475
Adds foreign key definitions to data dictionary tables in the database.
@return	error code or DB_SUCCESS */
1476
UNIV_INTERN
1477 1478 1479
ulint
dict_create_add_foreigns_to_dictionary(
/*===================================*/
1480
	ulint		start_id,/*!< in: if we are actually doing ALTER TABLE
1481 1482 1483 1484 1485 1486 1487
				ADD CONSTRAINT, we want to generate constraint
				numbers which are bigger than in the table so
				far; we number the constraints from
				start_id + 1 up; start_id should be set to 0 if
				we are creating a new table, or if the table
				so far has no constraints for which the name
				was generated here */
1488 1489
	dict_table_t*	table,	/*!< in: table */
	trx_t*		trx)	/*!< in: transaction */
1490 1491 1492 1493 1494 1495 1496 1497 1498
{
	dict_foreign_t*	foreign;
	ulint		number	= start_id + 1;
	ulint		error;

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

	if (NULL == dict_table_get_low("SYS_FOREIGN")) {
		fprintf(stderr,
1499 1500
			"InnoDB: table SYS_FOREIGN not found"
			" in internal data dictionary\n");
1501 1502 1503 1504 1505 1506 1507 1508

		return(DB_ERROR);
	}

	for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
	     foreign;
	     foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {

1509 1510
		error = dict_create_add_foreign_to_dictionary(&number, table,
							      foreign, trx);
1511 1512 1513 1514 1515 1516 1517 1518

		if (error != DB_SUCCESS) {

			return(error);
		}
	}

	return(DB_SUCCESS);
osku's avatar
osku committed
1519
}