~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/******************************************************
2
Loads to the memory cache database object definitions
3
from dictionary tables
4
5
(c) 1996 Innobase Oy
6
7
Created 4/24/1996 Heikki Tuuri
8
*******************************************************/
9
10
#include "dict0load.h"
11
12
#ifdef UNIV_NONINL
13
#include "dict0load.ic"
14
#endif
15
16
#include "btr0pcur.h"
17
#include "btr0btr.h"
18
#include "page0page.h"
19
#include "mach0data.h"
20
#include "dict0dict.h"
21
#include "dict0boot.h"
22
#include "rem0cmp.h"
23
#include "srv0start.h"
24
#include "srv0srv.h"
25
26
/********************************************************************
27
Returns TRUE if index's i'th column's name is 'name' .*/
28
static
29
ibool
30
name_of_col_is(
31
/*===========*/
32
				/* out: */
33
	dict_table_t*	table,	/* in: table */
34
	dict_index_t*	index,	/* in: index */
35
	ulint		i,	/* in:  */
36
	const char*	name)	/* in: name to compare to */
37
{
38
	ulint	tmp = dict_col_get_no(dict_field_get_col(
39
					      dict_index_get_nth_field(
40
						      index, i)));
41
42
	return(strcmp(name, dict_table_get_col_name(table, tmp)) == 0);
43
}
44
45
/************************************************************************
46
Finds the first table name in the given database. */
47
48
char*
49
dict_get_first_table_name_in_db(
50
/*============================*/
51
				/* out, own: table name, NULL if
52
				does not exist; the caller must
53
				free the memory in the string! */
54
	const char*	name)	/* in: database name which ends in '/' */
55
{
56
	dict_table_t*	sys_tables;
57
	btr_pcur_t	pcur;
58
	dict_index_t*	sys_index;
59
	dtuple_t*	tuple;
60
	mem_heap_t*	heap;
61
	dfield_t*	dfield;
62
	rec_t*		rec;
63
	byte*		field;
64
	ulint		len;
65
	mtr_t		mtr;
66
67
	ut_ad(mutex_own(&(dict_sys->mutex)));
68
69
	heap = mem_heap_create(1000);
70
71
	mtr_start(&mtr);
72
73
	sys_tables = dict_table_get_low("SYS_TABLES");
74
	sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
75
	ut_a(!dict_table_is_comp(sys_tables));
76
77
	tuple = dtuple_create(heap, 1);
78
	dfield = dtuple_get_nth_field(tuple, 0);
79
80
	dfield_set_data(dfield, name, ut_strlen(name));
81
	dict_index_copy_types(tuple, sys_index, 1);
82
83
	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
84
				  BTR_SEARCH_LEAF, &pcur, &mtr);
85
loop:
86
	rec = btr_pcur_get_rec(&pcur);
87
88
	if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
89
		/* Not found */
90
91
		btr_pcur_close(&pcur);
92
		mtr_commit(&mtr);
93
		mem_heap_free(heap);
94
95
		return(NULL);
96
	}
97
98
	field = rec_get_nth_field_old(rec, 0, &len);
99
100
	if (len < strlen(name)
101
	    || ut_memcmp(name, field, strlen(name)) != 0) {
102
		/* Not found */
103
104
		btr_pcur_close(&pcur);
105
		mtr_commit(&mtr);
106
		mem_heap_free(heap);
107
108
		return(NULL);
109
	}
110
111
	if (!rec_get_deleted_flag(rec, 0)) {
112
113
		/* We found one */
114
115
		char*	table_name = mem_strdupl((char*) field, len);
116
117
		btr_pcur_close(&pcur);
118
		mtr_commit(&mtr);
119
		mem_heap_free(heap);
120
121
		return(table_name);
122
	}
123
124
	btr_pcur_move_to_next_user_rec(&pcur, &mtr);
125
126
	goto loop;
127
}
128
129
/************************************************************************
130
Prints to the standard output information on all tables found in the data
131
dictionary system table. */
132
133
void
134
dict_print(void)
135
/*============*/
136
{
137
	dict_table_t*	sys_tables;
138
	dict_index_t*	sys_index;
139
	dict_table_t*	table;
140
	btr_pcur_t	pcur;
141
	rec_t*		rec;
142
	byte*		field;
143
	ulint		len;
144
	mtr_t		mtr;
145
146
	/* Enlarge the fatal semaphore wait timeout during the InnoDB table
147
	monitor printout */
148
149
	mutex_enter(&kernel_mutex);
150
	srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
151
	mutex_exit(&kernel_mutex);
152
153
	mutex_enter(&(dict_sys->mutex));
154
155
	mtr_start(&mtr);
156
157
	sys_tables = dict_table_get_low("SYS_TABLES");
158
	sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
159
160
	btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
161
				    TRUE, &mtr);
162
loop:
163
	btr_pcur_move_to_next_user_rec(&pcur, &mtr);
164
165
	rec = btr_pcur_get_rec(&pcur);
166
167
	if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
168
		/* end of index */
169
170
		btr_pcur_close(&pcur);
171
		mtr_commit(&mtr);
172
173
		mutex_exit(&(dict_sys->mutex));
174
175
		/* Restore the fatal semaphore wait timeout */
176
177
		mutex_enter(&kernel_mutex);
178
		srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
179
		mutex_exit(&kernel_mutex);
180
181
		return;
182
	}
183
184
	field = rec_get_nth_field_old(rec, 0, &len);
185
186
	if (!rec_get_deleted_flag(rec, 0)) {
187
188
		/* We found one */
189
190
		char*	table_name = mem_strdupl((char*) field, len);
191
192
		btr_pcur_store_position(&pcur, &mtr);
193
194
		mtr_commit(&mtr);
195
196
		table = dict_table_get_low(table_name);
197
		mem_free(table_name);
198
199
		if (table == NULL) {
200
			fputs("InnoDB: Failed to load table ", stderr);
201
			ut_print_namel(stderr, NULL, TRUE, (char*) field, len);
202
			putc('\n', stderr);
203
		} else {
204
			/* The table definition was corrupt if there
205
			is no index */
206
207
			if (dict_table_get_first_index(table)) {
208
				dict_update_statistics_low(table, TRUE);
209
			}
210
211
			dict_table_print_low(table);
212
		}
213
214
		mtr_start(&mtr);
215
216
		btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
217
	}
218
219
	goto loop;
220
}
221
222
/************************************************************************
223
In a crash recovery we already have all the tablespace objects created.
224
This function compares the space id information in the InnoDB data dictionary
225
to what we already read with fil_load_single_table_tablespaces().
226
227
In a normal startup, we create the tablespace objects for every table in
228
InnoDB's data dictionary, if the corresponding .ibd file exists.
229
We also scan the biggest space id, and store it to fil_system. */
230
231
void
232
dict_check_tablespaces_and_store_max_id(
233
/*====================================*/
234
	ibool	in_crash_recovery)	/* in: are we doing a crash recovery */
235
{
236
	dict_table_t*	sys_tables;
237
	dict_index_t*	sys_index;
238
	btr_pcur_t	pcur;
239
	rec_t*		rec;
240
	byte*		field;
241
	ulint		len;
242
	ulint		space_id;
243
	ulint		max_space_id	= 0;
244
	mtr_t		mtr;
245
246
	mutex_enter(&(dict_sys->mutex));
247
248
	mtr_start(&mtr);
249
250
	sys_tables = dict_table_get_low("SYS_TABLES");
251
	sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
252
	ut_a(!dict_table_is_comp(sys_tables));
253
254
	btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
255
				    TRUE, &mtr);
256
loop:
257
	btr_pcur_move_to_next_user_rec(&pcur, &mtr);
258
259
	rec = btr_pcur_get_rec(&pcur);
260
261
	if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
262
		/* end of index */
263
264
		btr_pcur_close(&pcur);
265
		mtr_commit(&mtr);
266
267
		/* We must make the tablespace cache aware of the biggest
268
		known space id */
269
270
		/* printf("Biggest space id in data dictionary %lu\n",
271
		max_space_id); */
272
		fil_set_max_space_id_if_bigger(max_space_id);
273
274
		mutex_exit(&(dict_sys->mutex));
275
276
		return;
277
	}
278
279
	field = rec_get_nth_field_old(rec, 0, &len);
280
281
	if (!rec_get_deleted_flag(rec, 0)) {
282
283
		/* We found one */
284
285
		char*	name = mem_strdupl((char*) field, len);
286
287
		field = rec_get_nth_field_old(rec, 9, &len);
288
		ut_a(len == 4);
289
290
		space_id = mach_read_from_4(field);
291
292
		btr_pcur_store_position(&pcur, &mtr);
293
294
		mtr_commit(&mtr);
295
296
		if (space_id != 0 && in_crash_recovery) {
297
			/* Check that the tablespace (the .ibd file) really
298
			exists; print a warning to the .err log if not */
299
300
			fil_space_for_table_exists_in_mem(space_id, name,
301
							  FALSE, TRUE, TRUE);
302
		}
303
304
		if (space_id != 0 && !in_crash_recovery) {
305
			/* It is a normal database startup: create the space
306
			object and check that the .ibd file exists. */
307
308
			fil_open_single_table_tablespace(FALSE, space_id,
309
							 name);
310
		}
311
312
		mem_free(name);
313
314
		if (space_id > max_space_id) {
315
			max_space_id = space_id;
316
		}
317
318
		mtr_start(&mtr);
319
320
		btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
321
	}
322
323
	goto loop;
324
}
325
326
/************************************************************************
327
Loads definitions for table columns. */
328
static
329
void
330
dict_load_columns(
331
/*==============*/
332
	dict_table_t*	table,	/* in: table */
333
	mem_heap_t*	heap)	/* in: memory heap for temporary storage */
334
{
335
	dict_table_t*	sys_columns;
336
	dict_index_t*	sys_index;
337
	btr_pcur_t	pcur;
338
	dtuple_t*	tuple;
339
	dfield_t*	dfield;
340
	rec_t*		rec;
341
	byte*		field;
342
	ulint		len;
343
	byte*		buf;
344
	char*		name;
345
	ulint		mtype;
346
	ulint		prtype;
347
	ulint		col_len;
348
	ulint		i;
349
	mtr_t		mtr;
350
351
	ut_ad(mutex_own(&(dict_sys->mutex)));
352
353
	mtr_start(&mtr);
354
355
	sys_columns = dict_table_get_low("SYS_COLUMNS");
356
	sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
357
	ut_a(!dict_table_is_comp(sys_columns));
358
359
	tuple = dtuple_create(heap, 1);
360
	dfield = dtuple_get_nth_field(tuple, 0);
361
362
	buf = mem_heap_alloc(heap, 8);
363
	mach_write_to_8(buf, table->id);
364
365
	dfield_set_data(dfield, buf, 8);
366
	dict_index_copy_types(tuple, sys_index, 1);
367
368
	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
369
				  BTR_SEARCH_LEAF, &pcur, &mtr);
370
	for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
371
372
		rec = btr_pcur_get_rec(&pcur);
373
374
		ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
375
376
		ut_a(!rec_get_deleted_flag(rec, 0));
377
378
		field = rec_get_nth_field_old(rec, 0, &len);
379
		ut_ad(len == 8);
380
		ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0);
381
382
		field = rec_get_nth_field_old(rec, 1, &len);
383
		ut_ad(len == 4);
384
		ut_a(i == mach_read_from_4(field));
385
386
		ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME"));
387
388
		field = rec_get_nth_field_old(rec, 4, &len);
389
		name = mem_heap_strdupl(heap, (char*) field, len);
390
391
		field = rec_get_nth_field_old(rec, 5, &len);
392
		mtype = mach_read_from_4(field);
393
394
		field = rec_get_nth_field_old(rec, 6, &len);
395
		prtype = mach_read_from_4(field);
396
397
		if (dtype_get_charset_coll(prtype) == 0
398
		    && dtype_is_string_type(mtype)) {
399
			/* The table was created with < 4.1.2. */
400
401
			if (dtype_is_binary_string_type(mtype, prtype)) {
402
				/* Use the binary collation for
403
				string columns of binary type. */
404
405
				prtype = dtype_form_prtype(
406
					prtype,
319.1.1 by Grant Limberg
renamed all instances of MYSQL_ to DRIZZLE_
407
					DATA_DRIZZLE_BINARY_CHARSET_COLL);
1 by brian
clean slate
408
			} else {
409
				/* Use the default charset for
410
				other than binary columns. */
411
412
				prtype = dtype_form_prtype(
413
					prtype,
414
					data_mysql_default_charset_coll);
415
			}
416
		}
417
418
		field = rec_get_nth_field_old(rec, 7, &len);
419
		col_len = mach_read_from_4(field);
420
421
		ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC"));
422
423
		dict_mem_table_add_col(table, heap, name,
424
				       mtype, prtype, col_len);
425
		btr_pcur_move_to_next_user_rec(&pcur, &mtr);
426
	}
427
428
	btr_pcur_close(&pcur);
429
	mtr_commit(&mtr);
430
}
431
432
/************************************************************************
433
Report that an index field or index for a table has been delete marked. */
434
static
435
void
436
dict_load_report_deleted_index(
437
/*===========================*/
438
	const char*	name,	/* in: table name */
439
	ulint		field)	/* in: index field, or ULINT_UNDEFINED */
440
{
441
	fprintf(stderr, "InnoDB: Error: data dictionary entry"
442
		" for table %s is corrupt!\n", name);
443
	if (field != ULINT_UNDEFINED) {
444
		fprintf(stderr,
445
			"InnoDB: Index field %lu is delete marked.\n", field);
446
	} else {
447
		fputs("InnoDB: An index is delete marked.\n", stderr);
448
	}
449
}
450
451
/************************************************************************
452
Loads definitions for index fields. */
453
static
454
void
455
dict_load_fields(
456
/*=============*/
457
	dict_table_t*	table,	/* in: table */
458
	dict_index_t*	index,	/* in: index whose fields to load */
459
	mem_heap_t*	heap)	/* in: memory heap for temporary storage */
460
{
461
	dict_table_t*	sys_fields;
462
	dict_index_t*	sys_index;
463
	btr_pcur_t	pcur;
464
	dtuple_t*	tuple;
465
	dfield_t*	dfield;
466
	ulint		pos_and_prefix_len;
467
	ulint		prefix_len;
468
	rec_t*		rec;
469
	byte*		field;
470
	ulint		len;
471
	byte*		buf;
472
	ulint		i;
473
	mtr_t		mtr;
474
475
	ut_ad(mutex_own(&(dict_sys->mutex)));
476
477
	mtr_start(&mtr);
478
479
	sys_fields = dict_table_get_low("SYS_FIELDS");
480
	sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
481
	ut_a(!dict_table_is_comp(sys_fields));
482
483
	tuple = dtuple_create(heap, 1);
484
	dfield = dtuple_get_nth_field(tuple, 0);
485
486
	buf = mem_heap_alloc(heap, 8);
487
	mach_write_to_8(buf, index->id);
488
489
	dfield_set_data(dfield, buf, 8);
490
	dict_index_copy_types(tuple, sys_index, 1);
491
492
	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
493
				  BTR_SEARCH_LEAF, &pcur, &mtr);
494
	for (i = 0; i < index->n_fields; i++) {
495
496
		rec = btr_pcur_get_rec(&pcur);
497
498
		ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
499
		if (rec_get_deleted_flag(rec, 0)) {
500
			dict_load_report_deleted_index(table->name, i);
501
		}
502
503
		field = rec_get_nth_field_old(rec, 0, &len);
504
		ut_ad(len == 8);
505
		ut_a(ut_memcmp(buf, field, len) == 0);
506
507
		field = rec_get_nth_field_old(rec, 1, &len);
508
		ut_a(len == 4);
509
510
		/* The next field stores the field position in the index
511
		and a possible column prefix length if the index field
512
		does not contain the whole column. The storage format is
513
		like this: if there is at least one prefix field in the index,
514
		then the HIGH 2 bytes contain the field number (== i) and the
515
		low 2 bytes the prefix length for the field. Otherwise the
516
		field number (== i) is contained in the 2 LOW bytes. */
517
518
		pos_and_prefix_len = mach_read_from_4(field);
519
520
		ut_a((pos_and_prefix_len & 0xFFFFUL) == i
521
		     || (pos_and_prefix_len & 0xFFFF0000UL) == (i << 16));
522
523
		if ((i == 0 && pos_and_prefix_len > 0)
524
		    || (pos_and_prefix_len & 0xFFFF0000UL) > 0) {
525
526
			prefix_len = pos_and_prefix_len & 0xFFFFUL;
527
		} else {
528
			prefix_len = 0;
529
		}
530
531
		ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME"));
532
533
		field = rec_get_nth_field_old(rec, 4, &len);
534
535
		dict_mem_index_add_field(index,
536
					 mem_heap_strdupl(heap,
537
							  (char*) field, len),
538
					 prefix_len);
539
540
		btr_pcur_move_to_next_user_rec(&pcur, &mtr);
541
	}
542
543
	btr_pcur_close(&pcur);
544
	mtr_commit(&mtr);
545
}
546
547
/************************************************************************
548
Loads definitions for table indexes. Adds them to the data dictionary
549
cache. */
550
static
551
ulint
552
dict_load_indexes(
553
/*==============*/
554
				/* out: DB_SUCCESS if ok, DB_CORRUPTION
555
				if corruption of dictionary table or
556
				DB_UNSUPPORTED if table has unknown index
557
				type */
558
	dict_table_t*	table,	/* in: table */
559
	mem_heap_t*	heap)	/* in: memory heap for temporary storage */
560
{
561
	dict_table_t*	sys_indexes;
562
	dict_index_t*	sys_index;
563
	dict_index_t*	index;
564
	btr_pcur_t	pcur;
565
	dtuple_t*	tuple;
566
	dfield_t*	dfield;
567
	rec_t*		rec;
568
	byte*		field;
569
	ulint		len;
570
	ulint		name_len;
571
	char*		name_buf;
572
	ulint		type;
573
	ulint		space;
574
	ulint		page_no;
575
	ulint		n_fields;
576
	byte*		buf;
577
	ibool		is_sys_table;
578
	dulint		id;
579
	mtr_t		mtr;
580
	ulint		error = DB_SUCCESS;
581
582
	ut_ad(mutex_own(&(dict_sys->mutex)));
583
584
	if ((ut_dulint_get_high(table->id) == 0)
585
	    && (ut_dulint_get_low(table->id) < DICT_HDR_FIRST_ID)) {
586
		is_sys_table = TRUE;
587
	} else {
588
		is_sys_table = FALSE;
589
	}
590
591
	mtr_start(&mtr);
592
593
	sys_indexes = dict_table_get_low("SYS_INDEXES");
594
	sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
595
	ut_a(!dict_table_is_comp(sys_indexes));
596
597
	tuple = dtuple_create(heap, 1);
598
	dfield = dtuple_get_nth_field(tuple, 0);
599
600
	buf = mem_heap_alloc(heap, 8);
601
	mach_write_to_8(buf, table->id);
602
603
	dfield_set_data(dfield, buf, 8);
604
	dict_index_copy_types(tuple, sys_index, 1);
605
606
	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
607
				  BTR_SEARCH_LEAF, &pcur, &mtr);
608
	for (;;) {
609
		if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
610
611
			break;
612
		}
613
614
		rec = btr_pcur_get_rec(&pcur);
615
616
		field = rec_get_nth_field_old(rec, 0, &len);
617
		ut_ad(len == 8);
618
619
		if (ut_memcmp(buf, field, len) != 0) {
620
			break;
621
		}
622
623
		if (rec_get_deleted_flag(rec, 0)) {
624
			dict_load_report_deleted_index(table->name,
625
						       ULINT_UNDEFINED);
626
627
			error = DB_CORRUPTION;
628
			goto func_exit;
629
		}
630
631
		field = rec_get_nth_field_old(rec, 1, &len);
632
		ut_ad(len == 8);
633
		id = mach_read_from_8(field);
634
635
		ut_a(name_of_col_is(sys_indexes, sys_index, 4, "NAME"));
636
637
		field = rec_get_nth_field_old(rec, 4, &name_len);
638
		name_buf = mem_heap_strdupl(heap, (char*) field, name_len);
639
640
		field = rec_get_nth_field_old(rec, 5, &len);
641
		n_fields = mach_read_from_4(field);
642
643
		field = rec_get_nth_field_old(rec, 6, &len);
644
		type = mach_read_from_4(field);
645
646
		field = rec_get_nth_field_old(rec, 7, &len);
647
		space = mach_read_from_4(field);
648
649
		ut_a(name_of_col_is(sys_indexes, sys_index, 8, "PAGE_NO"));
650
651
		field = rec_get_nth_field_old(rec, 8, &len);
652
		page_no = mach_read_from_4(field);
653
654
		/* We check for unsupported types first, so that the
655
		subsequent checks are relevant for the supported types. */
656
		if (type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
657
658
			fprintf(stderr,
659
				"InnoDB: Error: unknown type %lu"
660
				" of index %s of table %s\n",
661
				(ulong) type, name_buf, table->name);
662
663
			error = DB_UNSUPPORTED;
664
			goto func_exit;
665
		} else if (page_no == FIL_NULL) {
666
667
			fprintf(stderr,
668
				"InnoDB: Error: trying to load index %s"
669
				" for table %s\n"
670
				"InnoDB: but the index tree has been freed!\n",
671
				name_buf, table->name);
672
673
			error = DB_CORRUPTION;
674
			goto func_exit;
675
		} else if ((type & DICT_CLUSTERED) == 0
676
			    && NULL == dict_table_get_first_index(table)) {
677
678
			fprintf(stderr,
679
				"InnoDB: Error: trying to load index %s"
680
				" for table %s\n"
681
				"InnoDB: but the first index"
682
				" is not clustered!\n",
683
				name_buf, table->name);
684
685
			error = DB_CORRUPTION;
686
			goto func_exit;
687
		} else if (is_sys_table
688
			   && ((type & DICT_CLUSTERED)
689
			       || ((table == dict_sys->sys_tables)
690
				   && (name_len == (sizeof "ID_IND") - 1)
691
				   && (0 == ut_memcmp(name_buf,
692
						      "ID_IND", name_len))))) {
693
694
			/* The index was created in memory already at booting
695
			of the database server */
696
		} else {
697
			index = dict_mem_index_create(table->name, name_buf,
698
						      space, type, n_fields);
699
			index->id = id;
700
701
			dict_load_fields(table, index, heap);
702
			dict_index_add_to_cache(table, index, page_no);
703
		}
704
705
		btr_pcur_move_to_next_user_rec(&pcur, &mtr);
706
	}
707
708
func_exit:
709
	btr_pcur_close(&pcur);
710
	mtr_commit(&mtr);
711
712
	return(error);
713
}
714
715
/************************************************************************
716
Loads a table definition and also all its index definitions, and also
717
the cluster definition if the table is a member in a cluster. Also loads
718
all foreign key constraints where the foreign key is in the table or where
719
a foreign key references columns in this table. Adds all these to the data
720
dictionary cache. */
721
722
dict_table_t*
723
dict_load_table(
724
/*============*/
725
				/* out: table, NULL if does not exist;
726
				if the table is stored in an .ibd file,
727
				but the file does not exist,
728
				then we set the ibd_file_missing flag TRUE
729
				in the table object we return */
730
	const char*	name)	/* in: table name in the
731
				databasename/tablename format */
732
{
733
	ibool		ibd_file_missing	= FALSE;
734
	dict_table_t*	table;
735
	dict_table_t*	sys_tables;
736
	btr_pcur_t	pcur;
737
	dict_index_t*	sys_index;
738
	dtuple_t*	tuple;
739
	mem_heap_t*	heap;
740
	dfield_t*	dfield;
741
	rec_t*		rec;
742
	byte*		field;
743
	ulint		len;
744
	ulint		space;
745
	ulint		n_cols;
746
	ulint		flags;
747
	ulint		err;
748
	mtr_t		mtr;
749
750
	ut_ad(mutex_own(&(dict_sys->mutex)));
751
752
	heap = mem_heap_create(32000);
753
754
	mtr_start(&mtr);
755
756
	sys_tables = dict_table_get_low("SYS_TABLES");
757
	sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
758
	ut_a(!dict_table_is_comp(sys_tables));
759
760
	tuple = dtuple_create(heap, 1);
761
	dfield = dtuple_get_nth_field(tuple, 0);
762
763
	dfield_set_data(dfield, name, ut_strlen(name));
764
	dict_index_copy_types(tuple, sys_index, 1);
765
766
	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
767
				  BTR_SEARCH_LEAF, &pcur, &mtr);
768
	rec = btr_pcur_get_rec(&pcur);
769
770
	if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
771
	    || rec_get_deleted_flag(rec, 0)) {
772
		/* Not found */
773
err_exit:
774
		btr_pcur_close(&pcur);
775
		mtr_commit(&mtr);
776
		mem_heap_free(heap);
777
778
		return(NULL);
779
	}
780
781
	field = rec_get_nth_field_old(rec, 0, &len);
782
783
	/* Check if the table name in record is the searched one */
784
	if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
785
786
		goto err_exit;
787
	}
788
789
	ut_a(name_of_col_is(sys_tables, sys_index, 9, "SPACE"));
790
791
	field = rec_get_nth_field_old(rec, 9, &len);
792
	space = mach_read_from_4(field);
793
794
	/* Check if the tablespace exists and has the right name */
795
	if (space != 0) {
796
		if (fil_space_for_table_exists_in_mem(space, name, FALSE,
797
						      FALSE, FALSE)) {
798
			/* Ok; (if we did a crash recovery then the tablespace
799
			can already be in the memory cache) */
800
		} else {
801
			/* In >= 4.1.9, InnoDB scans the data dictionary also
802
			at a normal mysqld startup. It is an error if the
803
			space object does not exist in memory. */
804
805
			ut_print_timestamp(stderr);
806
			fprintf(stderr,
807
				"  InnoDB: error: space object of table %s,\n"
808
				"InnoDB: space id %lu did not exist in memory."
809
				" Retrying an open.\n",
810
				name, (ulong)space);
811
			/* Try to open the tablespace */
812
			if (!fil_open_single_table_tablespace(TRUE,
813
							      space, name)) {
814
				/* We failed to find a sensible tablespace
815
				file */
816
817
				ibd_file_missing = TRUE;
818
			}
819
		}
820
	}
821
822
	ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS"));
823
824
	field = rec_get_nth_field_old(rec, 4, &len);
825
	n_cols = mach_read_from_4(field);
826
827
	flags = 0;
828
829
	/* The high-order bit of N_COLS is the "compact format" flag. */
830
	if (n_cols & 0x80000000UL) {
831
		flags |= DICT_TF_COMPACT;
832
	}
833
834
	table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL,
835
				      flags);
836
837
	table->ibd_file_missing = (unsigned int) ibd_file_missing;
838
839
	ut_a(name_of_col_is(sys_tables, sys_index, 3, "ID"));
840
841
	field = rec_get_nth_field_old(rec, 3, &len);
842
	table->id = mach_read_from_8(field);
843
844
	field = rec_get_nth_field_old(rec, 5, &len);
845
	if (UNIV_UNLIKELY(mach_read_from_4(field) != DICT_TABLE_ORDINARY)) {
846
		ut_print_timestamp(stderr);
847
		fprintf(stderr,
848
			"  InnoDB: table %s: unknown table type %lu\n",
849
			name, (ulong) mach_read_from_4(field));
850
		goto err_exit;
851
	}
852
853
	btr_pcur_close(&pcur);
854
	mtr_commit(&mtr);
855
856
	dict_load_columns(table, heap);
857
858
	dict_table_add_to_cache(table, heap);
859
860
	mem_heap_empty(heap);
861
862
	err = dict_load_indexes(table, heap);
863
864
	/* If the force recovery flag is set, we open the table irrespective
865
	of the error condition, since the user may want to dump data from the
866
	clustered index. However we load the foreign key information only if
867
	all indexes were loaded. */
868
	if (err != DB_SUCCESS && !srv_force_recovery) {
869
		dict_mem_table_free(table);
870
		table = NULL;
871
	} else if (err == DB_SUCCESS) {
872
		err = dict_load_foreigns(table->name, TRUE);
873
	}
874
#if 0
875
	if (err != DB_SUCCESS && table != NULL) {
876
877
		mutex_enter(&dict_foreign_err_mutex);
878
879
		ut_print_timestamp(stderr);
880
881
		fprintf(stderr,
882
			"  InnoDB: Error: could not make a foreign key"
883
			" definition to match\n"
884
			"InnoDB: the foreign key table"
885
			" or the referenced table!\n"
886
			"InnoDB: The data dictionary of InnoDB is corrupt."
887
			" You may need to drop\n"
888
			"InnoDB: and recreate the foreign key table"
889
			" or the referenced table.\n"
890
			"InnoDB: Submit a detailed bug report"
891
			" to http://bugs.mysql.com\n"
892
			"InnoDB: Latest foreign key error printout:\n%s\n",
893
			dict_foreign_err_buf);
894
895
		mutex_exit(&dict_foreign_err_mutex);
896
	}
897
#endif /* 0 */
898
	mem_heap_free(heap);
899
900
	return(table);
901
}
902
903
/***************************************************************************
904
Loads a table object based on the table id. */
905
906
dict_table_t*
907
dict_load_table_on_id(
908
/*==================*/
909
				/* out: table; NULL if table does not exist */
910
	dulint	table_id)	/* in: table id */
911
{
912
	byte		id_buf[8];
913
	btr_pcur_t	pcur;
914
	mem_heap_t*	heap;
915
	dtuple_t*	tuple;
916
	dfield_t*	dfield;
917
	dict_index_t*	sys_table_ids;
918
	dict_table_t*	sys_tables;
919
	rec_t*		rec;
920
	byte*		field;
921
	ulint		len;
922
	dict_table_t*	table;
923
	mtr_t		mtr;
924
925
	ut_ad(mutex_own(&(dict_sys->mutex)));
926
927
	/* NOTE that the operation of this function is protected by
928
	the dictionary mutex, and therefore no deadlocks can occur
929
	with other dictionary operations. */
930
931
	mtr_start(&mtr);
932
	/*---------------------------------------------------*/
933
	/* Get the secondary index based on ID for table SYS_TABLES */
934
	sys_tables = dict_sys->sys_tables;
935
	sys_table_ids = dict_table_get_next_index(
936
		dict_table_get_first_index(sys_tables));
937
	ut_a(!dict_table_is_comp(sys_tables));
938
	heap = mem_heap_create(256);
939
940
	tuple  = dtuple_create(heap, 1);
941
	dfield = dtuple_get_nth_field(tuple, 0);
942
943
	/* Write the table id in byte format to id_buf */
944
	mach_write_to_8(id_buf, table_id);
945
946
	dfield_set_data(dfield, id_buf, 8);
947
	dict_index_copy_types(tuple, sys_table_ids, 1);
948
949
	btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE,
950
				  BTR_SEARCH_LEAF, &pcur, &mtr);
951
	rec = btr_pcur_get_rec(&pcur);
952
953
	if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
954
	    || rec_get_deleted_flag(rec, 0)) {
955
		/* Not found */
956
957
		btr_pcur_close(&pcur);
958
		mtr_commit(&mtr);
959
		mem_heap_free(heap);
960
961
		return(NULL);
962
	}
963
964
	/*---------------------------------------------------*/
965
	/* Now we have the record in the secondary index containing the
966
	table ID and NAME */
967
968
	rec = btr_pcur_get_rec(&pcur);
969
	field = rec_get_nth_field_old(rec, 0, &len);
970
	ut_ad(len == 8);
971
972
	/* Check if the table id in record is the one searched for */
973
	if (ut_dulint_cmp(table_id, mach_read_from_8(field)) != 0) {
974
975
		btr_pcur_close(&pcur);
976
		mtr_commit(&mtr);
977
		mem_heap_free(heap);
978
979
		return(NULL);
980
	}
981
982
	/* Now we get the table name from the record */
983
	field = rec_get_nth_field_old(rec, 1, &len);
984
	/* Load the table definition to memory */
985
	table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len));
986
987
	btr_pcur_close(&pcur);
988
	mtr_commit(&mtr);
989
	mem_heap_free(heap);
990
991
	return(table);
992
}
993
994
/************************************************************************
995
This function is called when the database is booted. Loads system table
996
index definitions except for the clustered index which is added to the
997
dictionary cache at booting before calling this function. */
998
999
void
1000
dict_load_sys_table(
1001
/*================*/
1002
	dict_table_t*	table)	/* in: system table */
1003
{
1004
	mem_heap_t*	heap;
1005
1006
	ut_ad(mutex_own(&(dict_sys->mutex)));
1007
1008
	heap = mem_heap_create(1000);
1009
1010
	dict_load_indexes(table, heap);
1011
1012
	mem_heap_free(heap);
1013
}
1014
1015
/************************************************************************
1016
Loads foreign key constraint col names (also for the referenced table). */
1017
static
1018
void
1019
dict_load_foreign_cols(
1020
/*===================*/
1021
	const char*	id,	/* in: foreign constraint id as a
1022
				null-terminated string */
1023
	dict_foreign_t*	foreign)/* in: foreign constraint object */
1024
{
1025
	dict_table_t*	sys_foreign_cols;
1026
	dict_index_t*	sys_index;
1027
	btr_pcur_t	pcur;
1028
	dtuple_t*	tuple;
1029
	dfield_t*	dfield;
1030
	rec_t*		rec;
1031
	byte*		field;
1032
	ulint		len;
1033
	ulint		i;
1034
	mtr_t		mtr;
1035
1036
	ut_ad(mutex_own(&(dict_sys->mutex)));
1037
1038
	foreign->foreign_col_names = mem_heap_alloc(
1039
		foreign->heap, foreign->n_fields * sizeof(void*));
1040
1041
	foreign->referenced_col_names = mem_heap_alloc(
1042
		foreign->heap, foreign->n_fields * sizeof(void*));
1043
	mtr_start(&mtr);
1044
1045
	sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS");
1046
	sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes);
1047
	ut_a(!dict_table_is_comp(sys_foreign_cols));
1048
1049
	tuple = dtuple_create(foreign->heap, 1);
1050
	dfield = dtuple_get_nth_field(tuple, 0);
1051
1052
	dfield_set_data(dfield, id, ut_strlen(id));
1053
	dict_index_copy_types(tuple, sys_index, 1);
1054
1055
	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1056
				  BTR_SEARCH_LEAF, &pcur, &mtr);
1057
	for (i = 0; i < foreign->n_fields; i++) {
1058
1059
		rec = btr_pcur_get_rec(&pcur);
1060
1061
		ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
1062
		ut_a(!rec_get_deleted_flag(rec, 0));
1063
1064
		field = rec_get_nth_field_old(rec, 0, &len);
1065
		ut_a(len == ut_strlen(id));
1066
		ut_a(ut_memcmp(id, field, len) == 0);
1067
1068
		field = rec_get_nth_field_old(rec, 1, &len);
1069
		ut_a(len == 4);
1070
		ut_a(i == mach_read_from_4(field));
1071
1072
		field = rec_get_nth_field_old(rec, 4, &len);
1073
		foreign->foreign_col_names[i] = mem_heap_strdupl(
1074
			foreign->heap, (char*) field, len);
1075
1076
		field = rec_get_nth_field_old(rec, 5, &len);
1077
		foreign->referenced_col_names[i] = mem_heap_strdupl(
1078
			foreign->heap, (char*) field, len);
1079
1080
		btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1081
	}
1082
1083
	btr_pcur_close(&pcur);
1084
	mtr_commit(&mtr);
1085
}
1086
1087
/***************************************************************************
1088
Loads a foreign key constraint to the dictionary cache. */
1089
static
1090
ulint
1091
dict_load_foreign(
1092
/*==============*/
1093
				/* out: DB_SUCCESS or error code */
1094
	const char*	id,	/* in: foreign constraint id as a
1095
				null-terminated string */
1096
	ibool		check_charsets)
1097
				/* in: TRUE=check charset compatibility */
1098
{
1099
	dict_foreign_t*	foreign;
1100
	dict_table_t*	sys_foreign;
1101
	btr_pcur_t	pcur;
1102
	dict_index_t*	sys_index;
1103
	dtuple_t*	tuple;
1104
	mem_heap_t*	heap2;
1105
	dfield_t*	dfield;
1106
	rec_t*		rec;
1107
	byte*		field;
1108
	ulint		len;
1109
	ulint		n_fields_and_type;
1110
	mtr_t		mtr;
1111
1112
	ut_ad(mutex_own(&(dict_sys->mutex)));
1113
1114
	heap2 = mem_heap_create(1000);
1115
1116
	mtr_start(&mtr);
1117
1118
	sys_foreign = dict_table_get_low("SYS_FOREIGN");
1119
	sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes);
1120
	ut_a(!dict_table_is_comp(sys_foreign));
1121
1122
	tuple = dtuple_create(heap2, 1);
1123
	dfield = dtuple_get_nth_field(tuple, 0);
1124
1125
	dfield_set_data(dfield, id, ut_strlen(id));
1126
	dict_index_copy_types(tuple, sys_index, 1);
1127
1128
	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1129
				  BTR_SEARCH_LEAF, &pcur, &mtr);
1130
	rec = btr_pcur_get_rec(&pcur);
1131
1132
	if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
1133
	    || rec_get_deleted_flag(rec, 0)) {
1134
		/* Not found */
1135
1136
		fprintf(stderr,
1137
			"InnoDB: Error A: cannot load foreign constraint %s\n",
1138
			id);
1139
1140
		btr_pcur_close(&pcur);
1141
		mtr_commit(&mtr);
1142
		mem_heap_free(heap2);
1143
1144
		return(DB_ERROR);
1145
	}
1146
1147
	field = rec_get_nth_field_old(rec, 0, &len);
1148
1149
	/* Check if the id in record is the searched one */
1150
	if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) {
1151
1152
		fprintf(stderr,
1153
			"InnoDB: Error B: cannot load foreign constraint %s\n",
1154
			id);
1155
1156
		btr_pcur_close(&pcur);
1157
		mtr_commit(&mtr);
1158
		mem_heap_free(heap2);
1159
1160
		return(DB_ERROR);
1161
	}
1162
1163
	/* Read the table names and the number of columns associated
1164
	with the constraint */
1165
1166
	mem_heap_free(heap2);
1167
1168
	foreign = dict_mem_foreign_create();
1169
1170
	n_fields_and_type = mach_read_from_4(
1171
		rec_get_nth_field_old(rec, 5, &len));
1172
1173
	ut_a(len == 4);
1174
1175
	/* We store the type in the bits 24..29 of n_fields_and_type. */
1176
1177
	foreign->type = (unsigned int) (n_fields_and_type >> 24);
1178
	foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
1179
1180
	foreign->id = mem_heap_strdup(foreign->heap, id);
1181
1182
	field = rec_get_nth_field_old(rec, 3, &len);
1183
	foreign->foreign_table_name = mem_heap_strdupl(
1184
		foreign->heap, (char*) field, len);
1185
1186
	field = rec_get_nth_field_old(rec, 4, &len);
1187
	foreign->referenced_table_name = mem_heap_strdupl(
1188
		foreign->heap, (char*) field, len);
1189
1190
	btr_pcur_close(&pcur);
1191
	mtr_commit(&mtr);
1192
1193
	dict_load_foreign_cols(id, foreign);
1194
1195
	/* If the foreign table is not yet in the dictionary cache, we
1196
	have to load it so that we are able to make type comparisons
1197
	in the next function call. */
1198
1199
	dict_table_get_low(foreign->foreign_table_name);
1200
1201
	/* Note that there may already be a foreign constraint object in
1202
	the dictionary cache for this constraint: then the following
1203
	call only sets the pointers in it to point to the appropriate table
1204
	and index objects and frees the newly created object foreign.
1205
	Adding to the cache should always succeed since we are not creating
1206
	a new foreign key constraint but loading one from the data
1207
	dictionary. */
1208
1209
	return(dict_foreign_add_to_cache(foreign, check_charsets));
1210
}
1211
1212
/***************************************************************************
1213
Loads foreign key constraints where the table is either the foreign key
1214
holder or where the table is referenced by a foreign key. Adds these
1215
constraints to the data dictionary. Note that we know that the dictionary
1216
cache already contains all constraints where the other relevant table is
1217
already in the dictionary cache. */
1218
1219
ulint
1220
dict_load_foreigns(
1221
/*===============*/
1222
					/* out: DB_SUCCESS or error code */
1223
	const char*	table_name,	/* in: table name */
1224
	ibool		check_charsets)	/* in: TRUE=check charset
1225
					compatibility */
1226
{
1227
	btr_pcur_t	pcur;
1228
	mem_heap_t*	heap;
1229
	dtuple_t*	tuple;
1230
	dfield_t*	dfield;
1231
	dict_index_t*	sec_index;
1232
	dict_table_t*	sys_foreign;
1233
	rec_t*		rec;
1234
	byte*		field;
1235
	ulint		len;
1236
	char*		id ;
1237
	ulint		err;
1238
	mtr_t		mtr;
1239
1240
	ut_ad(mutex_own(&(dict_sys->mutex)));
1241
1242
	sys_foreign = dict_table_get_low("SYS_FOREIGN");
1243
1244
	if (sys_foreign == NULL) {
1245
		/* No foreign keys defined yet in this database */
1246
1247
		fprintf(stderr,
1248
			"InnoDB: Error: no foreign key system tables"
1249
			" in the database\n");
1250
1251
		return(DB_ERROR);
1252
	}
1253
1254
	ut_a(!dict_table_is_comp(sys_foreign));
1255
	mtr_start(&mtr);
1256
1257
	/* Get the secondary index based on FOR_NAME from table
1258
	SYS_FOREIGN */
1259
1260
	sec_index = dict_table_get_next_index(
1261
		dict_table_get_first_index(sys_foreign));
1262
start_load:
1263
	heap = mem_heap_create(256);
1264
1265
	tuple  = dtuple_create(heap, 1);
1266
	dfield = dtuple_get_nth_field(tuple, 0);
1267
1268
	dfield_set_data(dfield, table_name, ut_strlen(table_name));
1269
	dict_index_copy_types(tuple, sec_index, 1);
1270
1271
	btr_pcur_open_on_user_rec(sec_index, tuple, PAGE_CUR_GE,
1272
				  BTR_SEARCH_LEAF, &pcur, &mtr);
1273
loop:
1274
	rec = btr_pcur_get_rec(&pcur);
1275
1276
	if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
1277
		/* End of index */
1278
1279
		goto load_next_index;
1280
	}
1281
1282
	/* Now we have the record in the secondary index containing a table
1283
	name and a foreign constraint ID */
1284
1285
	rec = btr_pcur_get_rec(&pcur);
1286
	field = rec_get_nth_field_old(rec, 0, &len);
1287
1288
	/* Check if the table name in the record is the one searched for; the
1289
	following call does the comparison in the latin1_swedish_ci
1290
	charset-collation, in a case-insensitive way. */
1291
1292
	if (0 != cmp_data_data(dfield_get_type(dfield)->mtype,
1293
			       dfield_get_type(dfield)->prtype,
1294
			       dfield_get_data(dfield), dfield_get_len(dfield),
1295
			       field, len)) {
1296
1297
		goto load_next_index;
1298
	}
1299
1300
	/* Since table names in SYS_FOREIGN are stored in a case-insensitive
1301
	order, we have to check that the table name matches also in a binary
1302
	string comparison. On Unix, MySQL allows table names that only differ
1303
	in character case. */
1304
1305
	if (0 != ut_memcmp(field, table_name, len)) {
1306
1307
		goto next_rec;
1308
	}
1309
1310
	if (rec_get_deleted_flag(rec, 0)) {
1311
1312
		goto next_rec;
1313
	}
1314
1315
	/* Now we get a foreign key constraint id */
1316
	field = rec_get_nth_field_old(rec, 1, &len);
1317
	id = mem_heap_strdupl(heap, (char*) field, len);
1318
1319
	btr_pcur_store_position(&pcur, &mtr);
1320
1321
	mtr_commit(&mtr);
1322
1323
	/* Load the foreign constraint definition to the dictionary cache */
1324
1325
	err = dict_load_foreign(id, check_charsets);
1326
1327
	if (err != DB_SUCCESS) {
1328
		btr_pcur_close(&pcur);
1329
		mem_heap_free(heap);
1330
1331
		return(err);
1332
	}
1333
1334
	mtr_start(&mtr);
1335
1336
	btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
1337
next_rec:
1338
	btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1339
1340
	goto loop;
1341
1342
load_next_index:
1343
	btr_pcur_close(&pcur);
1344
	mtr_commit(&mtr);
1345
	mem_heap_free(heap);
1346
1347
	sec_index = dict_table_get_next_index(sec_index);
1348
1349
	if (sec_index != NULL) {
1350
1351
		mtr_start(&mtr);
1352
1353
		goto start_load;
1354
	}
1355
1356
	return(DB_SUCCESS);
1357
}