~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/**********************************************************************
2
Data dictionary system
3
4
(c) 1996 Innobase Oy
5
6
Created 1/8/1996 Heikki Tuuri
7
***********************************************************************/
8
9
#include "dict0dict.h"
10
11
#ifdef UNIV_NONINL
12
#include "dict0dict.ic"
13
#endif
14
15
#include "buf0buf.h"
16
#include "data0type.h"
17
#include "mach0data.h"
18
#include "dict0boot.h"
19
#include "dict0mem.h"
20
#include "dict0crea.h"
21
#include "trx0undo.h"
22
#include "btr0btr.h"
23
#include "btr0cur.h"
24
#include "btr0sea.h"
25
#include "pars0pars.h"
26
#include "pars0sym.h"
27
#include "que0que.h"
28
#include "rem0cmp.h"
29
#ifndef UNIV_HOTBACKUP
30
# include "m_ctype.h" /* my_isspace() */
31
#endif /* !UNIV_HOTBACKUP */
32
33
#include <ctype.h>
34
35
dict_sys_t*	dict_sys	= NULL;	/* the dictionary system */
36
37
rw_lock_t	dict_operation_lock;	/* table create, drop, etc. reserve
38
					this in X-mode; implicit or backround
39
					operations purge, rollback, foreign
40
					key checks reserve this in S-mode; we
41
					cannot trust that MySQL protects
42
					implicit or background operations
43
					a table drop since MySQL does not
44
					know of them; therefore we need this;
45
					NOTE: a transaction which reserves
46
					this must keep book on the mode in
47
					trx->dict_operation_lock_mode */
48
49
#define	DICT_HEAP_SIZE		100	/* initial memory heap size when
50
					creating a table or index object */
51
#define DICT_POOL_PER_TABLE_HASH 512	/* buffer pool max size per table
52
					hash table fixed size in bytes */
53
#define DICT_POOL_PER_VARYING	4	/* buffer pool max size per data
54
					dictionary varying size in bytes */
55
56
/* Identifies generated InnoDB foreign key names */
57
static char	dict_ibfk[] = "_ibfk_";
58
59
#ifndef UNIV_HOTBACKUP
60
/**********************************************************************
61
Converts an identifier to a table name.
62
63
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
64
this function, you MUST change also the prototype here! */
65
extern
66
void
67
innobase_convert_from_table_id(
68
/*===========================*/
69
	char*		to,	/* out: converted identifier */
70
	const char*	from,	/* in: identifier to convert */
71
	ulint		len);	/* in: length of 'to', in bytes;
72
				should be at least 5 * strlen(to) + 1 */
73
/**********************************************************************
74
Converts an identifier to UTF-8.
75
76
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
77
this function, you MUST change also the prototype here! */
78
extern
79
void
80
innobase_convert_from_id(
81
/*=====================*/
82
	char*		to,	/* out: converted identifier */
83
	const char*	from,	/* in: identifier to convert */
84
	ulint		len);	/* in: length of 'to', in bytes;
85
				should be at least 3 * strlen(to) + 1 */
86
/**********************************************************************
87
Compares NUL-terminated UTF-8 strings case insensitively.
88
89
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
90
this function, you MUST change also the prototype here! */
91
extern
92
int
93
innobase_strcasecmp(
94
/*================*/
95
				/* out: 0 if a=b, <0 if a<b, >1 if a>b */
96
	const char*	a,	/* in: first string to compare */
97
	const char*	b);	/* in: second string to compare */
98
99
/**********************************************************************
100
Makes all characters in a NUL-terminated UTF-8 string lower case.
101
102
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
103
this function, you MUST change also the prototype here! */
104
extern
105
void
106
innobase_casedn_str(
107
/*================*/
108
	char*	a);	/* in/out: string to put in lower case */
109
110
/**************************************************************************
111
Determines the connection character set.
112
113
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
114
this function, you MUST change also the prototype here! */
115
struct charset_info_st*
116
innobase_get_charset(
117
/*=================*/
118
				/* out: connection character set */
119
	void*	mysql_thd);	/* in: MySQL thread handle */
120
#endif /* !UNIV_HOTBACKUP */
121
122
/**************************************************************************
123
Removes an index from the dictionary cache. */
124
static
125
void
126
dict_index_remove_from_cache(
127
/*=========================*/
128
	dict_table_t*	table,	/* in: table */
129
	dict_index_t*	index);	/* in, own: index */
130
/***********************************************************************
131
Copies fields contained in index2 to index1. */
132
static
133
void
134
dict_index_copy(
135
/*============*/
136
	dict_index_t*	index1,	/* in: index to copy to */
137
	dict_index_t*	index2,	/* in: index to copy from */
138
	dict_table_t*	table,	/* in: table */
139
	ulint		start,	/* in: first position to copy */
140
	ulint		end);	/* in: last position to copy */
141
/***********************************************************************
142
Tries to find column names for the index and sets the col field of the
143
index. */
144
static
145
void
146
dict_index_find_cols(
147
/*=================*/
148
	dict_table_t*	table,	/* in: table */
149
	dict_index_t*	index);	/* in: index */
150
/***********************************************************************
151
Builds the internal dictionary cache representation for a clustered
152
index, containing also system fields not defined by the user. */
153
static
154
dict_index_t*
155
dict_index_build_internal_clust(
156
/*============================*/
157
				/* out, own: the internal representation
158
				of the clustered index */
159
	dict_table_t*	table,	/* in: table */
160
	dict_index_t*	index);	/* in: user representation of a clustered
161
				index */
162
/***********************************************************************
163
Builds the internal dictionary cache representation for a non-clustered
164
index, containing also system fields not defined by the user. */
165
static
166
dict_index_t*
167
dict_index_build_internal_non_clust(
168
/*================================*/
169
				/* out, own: the internal representation
170
				of the non-clustered index */
171
	dict_table_t*	table,	/* in: table */
172
	dict_index_t*	index);	/* in: user representation of a non-clustered
173
				index */
174
/**************************************************************************
175
Removes a foreign constraint struct from the dictionary cache. */
176
static
177
void
178
dict_foreign_remove_from_cache(
179
/*===========================*/
180
	dict_foreign_t*	foreign);	/* in, own: foreign constraint */
181
/**************************************************************************
182
Prints a column data. */
183
static
184
void
185
dict_col_print_low(
186
/*===============*/
187
	const dict_table_t*	table,	/* in: table */
188
	const dict_col_t*	col);	/* in: column */
189
/**************************************************************************
190
Prints an index data. */
191
static
192
void
193
dict_index_print_low(
194
/*=================*/
195
	dict_index_t*	index);	/* in: index */
196
/**************************************************************************
197
Prints a field data. */
198
static
199
void
200
dict_field_print_low(
201
/*=================*/
202
	dict_field_t*	field);	/* in: field */
203
/*************************************************************************
204
Frees a foreign key struct. */
205
static
206
void
207
dict_foreign_free(
208
/*==============*/
209
	dict_foreign_t*	foreign);	/* in, own: foreign key struct */
210
211
/* Stream for storing detailed information about the latest foreign key
212
and unique key errors */
213
FILE*	dict_foreign_err_file		= NULL;
214
mutex_t	dict_foreign_err_mutex;		/* mutex protecting the foreign
215
					and unique error buffers */
216
217
#ifndef UNIV_HOTBACKUP
218
/**********************************************************************
219
Makes all characters in a NUL-terminated UTF-8 string lower case. */
220
221
void
222
dict_casedn_str(
223
/*============*/
224
	char*	a)	/* in/out: string to put in lower case */
225
{
226
	innobase_casedn_str(a);
227
}
228
#endif /* !UNIV_HOTBACKUP */
229
230
/************************************************************************
231
Checks if the database name in two table names is the same. */
232
233
ibool
234
dict_tables_have_same_db(
235
/*=====================*/
236
				/* out: TRUE if same db name */
237
	const char*	name1,	/* in: table name in the form
238
				dbname '/' tablename */
239
	const char*	name2)	/* in: table name in the form
240
				dbname '/' tablename */
241
{
242
	for (; *name1 == *name2; name1++, name2++) {
243
		if (*name1 == '/') {
244
			return(TRUE);
245
		}
246
		ut_a(*name1); /* the names must contain '/' */
247
	}
248
	return(FALSE);
249
}
250
251
/************************************************************************
252
Return the end of table name where we have removed dbname and '/'. */
253
254
const char*
255
dict_remove_db_name(
256
/*================*/
257
				/* out: table name */
258
	const char*	name)	/* in: table name in the form
259
				dbname '/' tablename */
260
{
261
	const char*	s = strchr(name, '/');
262
	ut_a(s);
263
264
	return(s + 1);
265
}
266
267
/************************************************************************
268
Get the database name length in a table name. */
269
270
ulint
271
dict_get_db_name_len(
272
/*=================*/
273
				/* out: database name length */
274
	const char*	name)	/* in: table name in the form
275
				dbname '/' tablename */
276
{
277
	const char*	s;
278
	s = strchr(name, '/');
279
	ut_a(s);
280
	return(s - name);
281
}
282
283
/************************************************************************
284
Reserves the dictionary system mutex for MySQL. */
285
286
void
287
dict_mutex_enter_for_mysql(void)
288
/*============================*/
289
{
290
	mutex_enter(&(dict_sys->mutex));
291
}
292
293
/************************************************************************
294
Releases the dictionary system mutex for MySQL. */
295
296
void
297
dict_mutex_exit_for_mysql(void)
298
/*===========================*/
299
{
300
	mutex_exit(&(dict_sys->mutex));
301
}
302
303
/************************************************************************
304
Decrements the count of open MySQL handles to a table. */
305
306
void
307
dict_table_decrement_handle_count(
308
/*==============================*/
309
	dict_table_t*	table)	/* in: table */
310
{
311
	mutex_enter(&(dict_sys->mutex));
312
313
	ut_a(table->n_mysql_handles_opened > 0);
314
315
	table->n_mysql_handles_opened--;
316
317
	mutex_exit(&(dict_sys->mutex));
318
}
319
320
/*************************************************************************
321
Gets the column data type. */
322
323
void
324
dict_col_copy_type_noninline(
325
/*=========================*/
326
	const dict_col_t*	col,	/* in: column */
327
	dtype_t*		type)	/* out: data type */
328
{
329
	dict_col_copy_type(col, type);
330
}
331
332
/************************************************************************
333
Gets the nth column of a table. */
334
335
const dict_col_t*
336
dict_table_get_nth_col_noninline(
337
/*=============================*/
338
					/* out: pointer to column object */
339
	const dict_table_t*	table,	/* in: table */
340
	ulint			pos)	/* in: position of column */
341
{
342
	return(dict_table_get_nth_col(table, pos));
343
}
344
345
/************************************************************************
346
Gets the first index on the table (the clustered index). */
347
348
dict_index_t*
349
dict_table_get_first_index_noninline(
350
/*=================================*/
351
				/* out: index, NULL if none exists */
352
	dict_table_t*	table)	/* in: table */
353
{
354
	return(dict_table_get_first_index(table));
355
}
356
357
/************************************************************************
358
Gets the next index on the table. */
359
360
dict_index_t*
361
dict_table_get_next_index_noninline(
362
/*================================*/
363
				/* out: index, NULL if none left */
364
	dict_index_t*	index)	/* in: index */
365
{
366
	return(dict_table_get_next_index(index));
367
}
368
369
/**************************************************************************
370
Returns an index object. */
371
372
dict_index_t*
373
dict_table_get_index_noninline(
374
/*===========================*/
375
				/* out: index, NULL if does not exist */
376
	dict_table_t*	table,	/* in: table */
377
	const char*	name)	/* in: index name */
378
{
379
	return(dict_table_get_index(table, name));
380
}
381
382
/**************************************************************************
383
Returns a column's name. */
384
385
const char*
386
dict_table_get_col_name(
387
/*====================*/
388
					/* out: column name. NOTE: not
389
					guaranteed to stay valid if table is
390
					modified in any way (columns added,
391
					etc.). */
392
	const dict_table_t*	table,	/* in: table */
393
	ulint			col_nr)	/* in: column number */
394
{
395
	ulint		i;
396
	const char*	s;
397
398
	ut_ad(table);
399
	ut_ad(col_nr < table->n_def);
400
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
401
402
	s = table->col_names;
403
	if (s) {
404
		for (i = 0; i < col_nr; i++) {
405
			s += strlen(s) + 1;
406
		}
407
	}
408
409
	return(s);
410
}
411
412
413
/************************************************************************
414
Acquire the autoinc lock.*/
415
416
void
417
dict_table_autoinc_lock(
418
/*====================*/
419
	dict_table_t*	table)
420
{
421
	mutex_enter(&table->autoinc_mutex);
422
}
423
424
/************************************************************************
425
Initializes the autoinc counter. It is not an error to initialize an already
426
initialized counter. */
427
428
void
429
dict_table_autoinc_initialize(
430
/*==========================*/
431
	dict_table_t*	table,	/* in: table */
432
	ib_longlong	value)	/* in: next value to assign to a row */
433
{
434
	ut_ad(mutex_own(&table->autoinc_mutex));
435
436
	table->autoinc_inited = TRUE;
437
	table->autoinc = value;
438
}
439
440
/************************************************************************
441
Reads the next autoinc value (== autoinc counter value), 0 if not yet
442
initialized. */
443
444
ib_longlong
445
dict_table_autoinc_read(
446
/*====================*/
447
				/* out: value for a new row, or 0 */
448
	dict_table_t*	table)	/* in: table */
449
{
450
	ib_longlong	value;
451
452
	ut_ad(mutex_own(&table->autoinc_mutex));
453
454
	if (!table->autoinc_inited) {
455
456
		value = 0;
457
	} else {
458
		value = table->autoinc;
459
	}
460
461
	return(value);
462
}
463
464
/************************************************************************
465
Updates the autoinc counter if the value supplied is greater than the
466
current value. If not inited, does nothing. */
467
468
void
469
dict_table_autoinc_update(
470
/*======================*/
471
472
	dict_table_t*	table,	/* in: table */
473
	ib_longlong	value)	/* in: value which was assigned to a row */
474
{
475
	if (table->autoinc_inited && value > table->autoinc) {
476
477
		table->autoinc = value;
478
	}
479
}
480
481
/************************************************************************
482
Release the autoinc lock.*/
483
484
void
485
dict_table_autoinc_unlock(
486
/*======================*/
487
	dict_table_t*	table)	/* in: release autoinc lock for this table */
488
{
489
	mutex_exit(&table->autoinc_mutex);
490
}
491
492
/************************************************************************
493
Looks for column n in an index. */
494
495
ulint
496
dict_index_get_nth_col_pos(
497
/*=======================*/
498
				/* out: position in internal representation
499
				of the index; if not contained, returns
500
				ULINT_UNDEFINED */
501
	dict_index_t*	index,	/* in: index */
502
	ulint		n)	/* in: column number */
503
{
504
	const dict_field_t*	field;
505
	const dict_col_t*	col;
506
	ulint			pos;
507
	ulint			n_fields;
508
509
	ut_ad(index);
510
	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
511
512
	col = dict_table_get_nth_col(index->table, n);
513
514
	if (index->type & DICT_CLUSTERED) {
515
516
		return(dict_col_get_clust_pos(col, index));
517
	}
518
519
	n_fields = dict_index_get_n_fields(index);
520
521
	for (pos = 0; pos < n_fields; pos++) {
522
		field = dict_index_get_nth_field(index, pos);
523
524
		if (col == field->col && field->prefix_len == 0) {
525
526
			return(pos);
527
		}
528
	}
529
530
	return(ULINT_UNDEFINED);
531
}
532
533
/************************************************************************
534
Returns TRUE if the index contains a column or a prefix of that column. */
535
536
ibool
537
dict_index_contains_col_or_prefix(
538
/*==============================*/
539
				/* out: TRUE if contains the column or its
540
				prefix */
541
	dict_index_t*	index,	/* in: index */
542
	ulint		n)	/* in: column number */
543
{
544
	const dict_field_t*	field;
545
	const dict_col_t*	col;
546
	ulint			pos;
547
	ulint			n_fields;
548
549
	ut_ad(index);
550
	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
551
552
	if (index->type & DICT_CLUSTERED) {
553
554
		return(TRUE);
555
	}
556
557
	col = dict_table_get_nth_col(index->table, n);
558
559
	n_fields = dict_index_get_n_fields(index);
560
561
	for (pos = 0; pos < n_fields; pos++) {
562
		field = dict_index_get_nth_field(index, pos);
563
564
		if (col == field->col) {
565
566
			return(TRUE);
567
		}
568
	}
569
570
	return(FALSE);
571
}
572
573
/************************************************************************
574
Looks for a matching field in an index. The column has to be the same. The
575
column in index must be complete, or must contain a prefix longer than the
576
column in index2. That is, we must be able to construct the prefix in index2
577
from the prefix in index. */
578
579
ulint
580
dict_index_get_nth_field_pos(
581
/*=========================*/
582
				/* out: position in internal representation
583
				of the index; if not contained, returns
584
				ULINT_UNDEFINED */
585
	dict_index_t*	index,	/* in: index from which to search */
586
	dict_index_t*	index2,	/* in: index */
587
	ulint		n)	/* in: field number in index2 */
588
{
589
	dict_field_t*	field;
590
	dict_field_t*	field2;
591
	ulint		n_fields;
592
	ulint		pos;
593
594
	ut_ad(index);
595
	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
596
597
	field2 = dict_index_get_nth_field(index2, n);
598
599
	n_fields = dict_index_get_n_fields(index);
600
601
	for (pos = 0; pos < n_fields; pos++) {
602
		field = dict_index_get_nth_field(index, pos);
603
604
		if (field->col == field2->col
605
		    && (field->prefix_len == 0
606
			|| (field->prefix_len >= field2->prefix_len
607
			    && field2->prefix_len != 0))) {
608
609
			return(pos);
610
		}
611
	}
612
613
	return(ULINT_UNDEFINED);
614
}
615
616
/**************************************************************************
617
Returns a table object based on table id. */
618
619
dict_table_t*
620
dict_table_get_on_id(
621
/*=================*/
622
				/* out: table, NULL if does not exist */
623
	dulint	table_id,	/* in: table id */
624
	trx_t*	trx)		/* in: transaction handle */
625
{
626
	dict_table_t*	table;
627
628
	if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0
629
	    || trx->dict_operation_lock_mode == RW_X_LATCH) {
630
		/* It is a system table which will always exist in the table
631
		cache: we avoid acquiring the dictionary mutex, because
632
		if we are doing a rollback to handle an error in TABLE
633
		CREATE, for example, we already have the mutex! */
634
635
		ut_ad(mutex_own(&(dict_sys->mutex))
636
		      || trx->dict_operation_lock_mode == RW_X_LATCH);
637
638
		return(dict_table_get_on_id_low(table_id));
639
	}
640
641
	mutex_enter(&(dict_sys->mutex));
642
643
	table = dict_table_get_on_id_low(table_id);
644
645
	mutex_exit(&(dict_sys->mutex));
646
647
	return(table);
648
}
649
650
/************************************************************************
651
Looks for column n position in the clustered index. */
652
653
ulint
654
dict_table_get_nth_col_pos(
655
/*=======================*/
656
				/* out: position in internal representation
657
				of the clustered index */
658
	dict_table_t*	table,	/* in: table */
659
	ulint		n)	/* in: column number */
660
{
661
	return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
662
					  n));
663
}
664
665
/************************************************************************
666
Check whether the table uses the compact page format. */
667
668
ibool
669
dict_table_is_comp_noninline(
670
/*=========================*/
671
					/* out: TRUE if table uses the
672
					compact page format */
673
	const dict_table_t*	table)	/* in: table */
674
{
675
	return(dict_table_is_comp(table));
676
}
677
678
/************************************************************************
679
Checks if a column is in the ordering columns of the clustered index of a
680
table. Column prefixes are treated like whole columns. */
681
682
ibool
683
dict_table_col_in_clustered_key(
684
/*============================*/
685
				/* out: TRUE if the column, or its prefix, is
686
				in the clustered key */
687
	dict_table_t*	table,	/* in: table */
688
	ulint		n)	/* in: column number */
689
{
690
	dict_index_t*		index;
691
	const dict_field_t*	field;
692
	const dict_col_t*	col;
693
	ulint			pos;
694
	ulint			n_fields;
695
696
	ut_ad(table);
697
698
	col = dict_table_get_nth_col(table, n);
699
700
	index = dict_table_get_first_index(table);
701
702
	n_fields = dict_index_get_n_unique(index);
703
704
	for (pos = 0; pos < n_fields; pos++) {
705
		field = dict_index_get_nth_field(index, pos);
706
707
		if (col == field->col) {
708
709
			return(TRUE);
710
		}
711
	}
712
713
	return(FALSE);
714
}
715
716
/**************************************************************************
717
Inits the data dictionary module. */
718
719
void
720
dict_init(void)
721
/*===========*/
722
{
723
	dict_sys = mem_alloc(sizeof(dict_sys_t));
724
725
	mutex_create(&dict_sys->mutex, SYNC_DICT);
726
727
	dict_sys->table_hash = hash_create(buf_pool_get_max_size()
728
					   / (DICT_POOL_PER_TABLE_HASH
729
					      * UNIV_WORD_SIZE));
730
	dict_sys->table_id_hash = hash_create(buf_pool_get_max_size()
731
					      / (DICT_POOL_PER_TABLE_HASH
732
						 * UNIV_WORD_SIZE));
733
	dict_sys->size = 0;
734
735
	UT_LIST_INIT(dict_sys->table_LRU);
736
737
	rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
738
739
	dict_foreign_err_file = os_file_create_tmpfile();
740
	ut_a(dict_foreign_err_file);
741
742
	mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
743
}
744
745
/**************************************************************************
746
Returns a table object and optionally increment its MySQL open handle count.
747
NOTE! This is a high-level function to be used mainly from outside the
748
'dict' directory. Inside this directory dict_table_get_low is usually the
749
appropriate function. */
750
751
dict_table_t*
752
dict_table_get(
753
/*===========*/
754
					/* out: table, NULL if
755
					does not exist */
756
	const char*	table_name,	/* in: table name */
757
	ibool		inc_mysql_count)
758
     					/* in: whether to increment the open
759
					handle count on the table */
760
{
761
	dict_table_t*	table;
762
763
	mutex_enter(&(dict_sys->mutex));
764
765
	table = dict_table_get_low(table_name);
766
767
	if (inc_mysql_count && table) {
768
		table->n_mysql_handles_opened++;
769
	}
770
771
	mutex_exit(&(dict_sys->mutex));
772
773
	if (table != NULL) {
774
		if (!table->stat_initialized) {
775
			/* If table->ibd_file_missing == TRUE, this will
776
			print an error message and return without doing
777
			anything. */
778
			dict_update_statistics(table);
779
		}
780
	}
781
782
	return(table);
783
}
784
785
/**************************************************************************
786
Adds system columns to a table object. */
787
788
void
789
dict_table_add_system_columns(
790
/*==========================*/
791
	dict_table_t*	table,	/* in/out: table */
792
	mem_heap_t*	heap)	/* in: temporary heap */
793
{
794
	ut_ad(table);
795
	ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
796
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
797
	ut_ad(!table->cached);
798
799
	/* NOTE: the system columns MUST be added in the following order
800
	(so that they can be indexed by the numerical value of DATA_ROW_ID,
801
	etc.) and as the last columns of the table memory object.
802
	The clustered index will not always physically contain all
803
	system columns. */
804
805
	dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
806
			       DATA_ROW_ID | DATA_NOT_NULL,
807
			       DATA_ROW_ID_LEN);
808
#if DATA_ROW_ID != 0
809
#error "DATA_ROW_ID != 0"
810
#endif
811
	dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
812
			       DATA_TRX_ID | DATA_NOT_NULL,
813
			       DATA_TRX_ID_LEN);
814
#if DATA_TRX_ID != 1
815
#error "DATA_TRX_ID != 1"
816
#endif
817
	dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
818
			       DATA_ROLL_PTR | DATA_NOT_NULL,
819
			       DATA_ROLL_PTR_LEN);
820
#if DATA_ROLL_PTR != 2
821
#error "DATA_ROLL_PTR != 2"
822
#endif
823
824
	/* This check reminds that if a new system column is added to
825
	the program, it should be dealt with here */
826
#if DATA_N_SYS_COLS != 3
827
#error "DATA_N_SYS_COLS != 3"
828
#endif
829
}
830
831
/**************************************************************************
832
Adds a table object to the dictionary cache. */
833
834
void
835
dict_table_add_to_cache(
836
/*====================*/
837
	dict_table_t*	table,	/* in: table */
838
	mem_heap_t*	heap)	/* in: temporary heap */
839
{
840
	ulint	fold;
841
	ulint	id_fold;
842
	ulint	i;
843
	ulint	row_len;
844
845
	/* The lower limit for what we consider a "big" row */
846
#define BIG_ROW_SIZE 1024
847
848
	ut_ad(mutex_own(&(dict_sys->mutex)));
849
850
	dict_table_add_system_columns(table, heap);
851
852
	table->cached = TRUE;
853
854
	fold = ut_fold_string(table->name);
855
	id_fold = ut_fold_dulint(table->id);
856
857
	row_len = 0;
858
	for (i = 0; i < table->n_def; i++) {
859
		ulint	col_len = dict_col_get_max_size(
860
			dict_table_get_nth_col(table, i));
861
862
		row_len += col_len;
863
864
		/* If we have a single unbounded field, or several gigantic
865
		fields, mark the maximum row size as BIG_ROW_SIZE. */
866
		if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
867
			row_len = BIG_ROW_SIZE;
868
869
			break;
870
		}
871
	}
872
873
	table->big_rows = row_len >= BIG_ROW_SIZE;
874
875
	/* Look for a table with the same name: error if such exists */
876
	{
877
		dict_table_t*	table2;
878
		HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
879
			    (ut_strcmp(table2->name, table->name) == 0));
880
		ut_a(table2 == NULL);
881
	}
882
883
	/* Look for a table with the same id: error if such exists */
884
	{
885
		dict_table_t*	table2;
886
		HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold, table2,
887
			    (ut_dulint_cmp(table2->id, table->id) == 0));
888
		ut_a(table2 == NULL);
889
	}
890
891
	/* Add table to hash table of tables */
892
	HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
893
		    table);
894
895
	/* Add table to hash table of tables based on table id */
896
	HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
897
		    table);
898
	/* Add table to LRU list of tables */
899
	UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
900
901
	dict_sys->size += mem_heap_get_size(table->heap);
902
}
903
904
/**************************************************************************
905
Looks for an index with the given id. NOTE that we do not reserve
906
the dictionary mutex: this function is for emergency purposes like
907
printing info of a corrupt database page! */
908
909
dict_index_t*
910
dict_index_find_on_id_low(
911
/*======================*/
912
			/* out: index or NULL if not found from cache */
913
	dulint	id)	/* in: index id */
914
{
915
	dict_table_t*	table;
916
	dict_index_t*	index;
917
918
	table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
919
920
	while (table) {
921
		index = dict_table_get_first_index(table);
922
923
		while (index) {
924
			if (0 == ut_dulint_cmp(id, index->id)) {
925
				/* Found */
926
927
				return(index);
928
			}
929
930
			index = dict_table_get_next_index(index);
931
		}
932
933
		table = UT_LIST_GET_NEXT(table_LRU, table);
934
	}
935
936
	return(NULL);
937
}
938
939
/**************************************************************************
940
Renames a table object. */
941
942
ibool
943
dict_table_rename_in_cache(
944
/*=======================*/
945
					/* out: TRUE if success */
946
	dict_table_t*	table,		/* in: table */
947
	const char*	new_name,	/* in: new name */
948
	ibool		rename_also_foreigns)/* in: in ALTER TABLE we want
949
					to preserve the original table name
950
					in constraints which reference it */
951
{
952
	dict_foreign_t*	foreign;
953
	dict_index_t*	index;
954
	ulint		fold;
955
	ulint		old_size;
956
	char*		old_name;
957
	ibool		success;
958
959
	ut_ad(table);
960
	ut_ad(mutex_own(&(dict_sys->mutex)));
961
962
	old_size = mem_heap_get_size(table->heap);
963
964
	fold = ut_fold_string(new_name);
965
966
	/* Look for a table with the same name: error if such exists */
967
	{
968
		dict_table_t*	table2;
969
		HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
970
			    (ut_strcmp(table2->name, new_name) == 0));
971
		if (table2) {
972
			fprintf(stderr,
973
				"InnoDB: Error: dictionary cache"
974
				" already contains a table of name %s\n",
975
				new_name);
976
			return(FALSE);
977
		}
978
	}
979
980
	/* If the table is stored in a single-table tablespace, rename the
981
	.ibd file */
982
983
	if (table->space != 0) {
984
		if (table->dir_path_of_temp_table != NULL) {
985
			fprintf(stderr,
986
				"InnoDB: Error: trying to rename a table"
987
				" %s (%s) created with CREATE\n"
988
				"InnoDB: TEMPORARY TABLE\n",
989
				table->name, table->dir_path_of_temp_table);
990
			success = FALSE;
991
		} else {
992
			success = fil_rename_tablespace(
993
				table->name, table->space, new_name);
994
		}
995
996
		if (!success) {
997
998
			return(FALSE);
999
		}
1000
	}
1001
1002
	/* Remove table from the hash tables of tables */
1003
	HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1004
		    ut_fold_string(table->name), table);
1005
	old_name = mem_heap_strdup(table->heap, table->name);
1006
	table->name = mem_heap_strdup(table->heap, new_name);
1007
1008
	/* Add table to hash table of tables */
1009
	HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
1010
		    table);
1011
	dict_sys->size += (mem_heap_get_size(table->heap) - old_size);
1012
1013
	/* Update the table_name field in indexes */
1014
	index = dict_table_get_first_index(table);
1015
1016
	while (index != NULL) {
1017
		index->table_name = table->name;
1018
1019
		index = dict_table_get_next_index(index);
1020
	}
1021
1022
	if (!rename_also_foreigns) {
1023
		/* In ALTER TABLE we think of the rename table operation
1024
		in the direction table -> temporary table (#sql...)
1025
		as dropping the table with the old name and creating
1026
		a new with the new name. Thus we kind of drop the
1027
		constraints from the dictionary cache here. The foreign key
1028
		constraints will be inherited to the new table from the
1029
		system tables through a call of dict_load_foreigns. */
1030
1031
		/* Remove the foreign constraints from the cache */
1032
		foreign = UT_LIST_GET_LAST(table->foreign_list);
1033
1034
		while (foreign != NULL) {
1035
			dict_foreign_remove_from_cache(foreign);
1036
			foreign = UT_LIST_GET_LAST(table->foreign_list);
1037
		}
1038
1039
		/* Reset table field in referencing constraints */
1040
1041
		foreign = UT_LIST_GET_FIRST(table->referenced_list);
1042
1043
		while (foreign != NULL) {
1044
			foreign->referenced_table = NULL;
1045
			foreign->referenced_index = NULL;
1046
1047
			foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1048
		}
1049
1050
		/* Make the list of referencing constraints empty */
1051
1052
		UT_LIST_INIT(table->referenced_list);
1053
1054
		return(TRUE);
1055
	}
1056
1057
	/* Update the table name fields in foreign constraints, and update also
1058
	the constraint id of new format >= 4.0.18 constraints. Note that at
1059
	this point we have already changed table->name to the new name. */
1060
1061
	foreign = UT_LIST_GET_FIRST(table->foreign_list);
1062
1063
	while (foreign != NULL) {
1064
		if (ut_strlen(foreign->foreign_table_name)
1065
		    < ut_strlen(table->name)) {
1066
			/* Allocate a longer name buffer;
1067
			TODO: store buf len to save memory */
1068
1069
			foreign->foreign_table_name
1070
				= mem_heap_alloc(foreign->heap,
1071
						 ut_strlen(table->name) + 1);
1072
		}
1073
1074
		strcpy(foreign->foreign_table_name, table->name);
1075
1076
		if (strchr(foreign->id, '/')) {
1077
			ulint	db_len;
1078
			char*	old_id;
1079
1080
			/* This is a >= 4.0.18 format id */
1081
1082
			old_id = mem_strdup(foreign->id);
1083
1084
			if (ut_strlen(foreign->id) > ut_strlen(old_name)
1085
			    + ((sizeof dict_ibfk) - 1)
1086
			    && !memcmp(foreign->id, old_name,
1087
				       ut_strlen(old_name))
1088
			    && !memcmp(foreign->id + ut_strlen(old_name),
1089
				       dict_ibfk, (sizeof dict_ibfk) - 1)) {
1090
1091
				/* This is a generated >= 4.0.18 format id */
1092
1093
				if (strlen(table->name) > strlen(old_name)) {
1094
					foreign->id = mem_heap_alloc(
1095
						foreign->heap,
1096
						strlen(table->name)
1097
						+ strlen(old_id) + 1);
1098
				}
1099
1100
				/* Replace the prefix 'databasename/tablename'
1101
				with the new names */
1102
				strcpy(foreign->id, table->name);
1103
				strcat(foreign->id,
1104
				       old_id + ut_strlen(old_name));
1105
			} else {
1106
				/* This is a >= 4.0.18 format id where the user
1107
				gave the id name */
1108
				db_len = dict_get_db_name_len(table->name) + 1;
1109
1110
				if (dict_get_db_name_len(table->name)
1111
				    > dict_get_db_name_len(foreign->id)) {
1112
1113
					foreign->id = mem_heap_alloc(
1114
						foreign->heap,
1115
						db_len + strlen(old_id) + 1);
1116
				}
1117
1118
				/* Replace the database prefix in id with the
1119
				one from table->name */
1120
1121
				ut_memcpy(foreign->id, table->name, db_len);
1122
1123
				strcpy(foreign->id + db_len,
1124
				       dict_remove_db_name(old_id));
1125
			}
1126
1127
			mem_free(old_id);
1128
		}
1129
1130
		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1131
	}
1132
1133
	foreign = UT_LIST_GET_FIRST(table->referenced_list);
1134
1135
	while (foreign != NULL) {
1136
		if (ut_strlen(foreign->referenced_table_name)
1137
		    < ut_strlen(table->name)) {
1138
			/* Allocate a longer name buffer;
1139
			TODO: store buf len to save memory */
1140
1141
			foreign->referenced_table_name = mem_heap_alloc(
1142
				foreign->heap, strlen(table->name) + 1);
1143
		}
1144
1145
		strcpy(foreign->referenced_table_name, table->name);
1146
1147
		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1148
	}
1149
1150
	return(TRUE);
1151
}
1152
1153
/**************************************************************************
1154
Change the id of a table object in the dictionary cache. This is used in
1155
DISCARD TABLESPACE. */
1156
1157
void
1158
dict_table_change_id_in_cache(
1159
/*==========================*/
1160
	dict_table_t*	table,	/* in: table object already in cache */
1161
	dulint		new_id)	/* in: new id to set */
1162
{
1163
	ut_ad(table);
1164
	ut_ad(mutex_own(&(dict_sys->mutex)));
1165
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1166
1167
	/* Remove the table from the hash table of id's */
1168
1169
	HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1170
		    ut_fold_dulint(table->id), table);
1171
	table->id = new_id;
1172
1173
	/* Add the table back to the hash table */
1174
	HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1175
		    ut_fold_dulint(table->id), table);
1176
}
1177
1178
/**************************************************************************
1179
Removes a table object from the dictionary cache. */
1180
1181
void
1182
dict_table_remove_from_cache(
1183
/*=========================*/
1184
	dict_table_t*	table)	/* in, own: table */
1185
{
1186
	dict_foreign_t*	foreign;
1187
	dict_index_t*	index;
1188
	ulint		size;
1189
1190
	ut_ad(table);
1191
	ut_ad(mutex_own(&(dict_sys->mutex)));
1192
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1193
1194
#if 0
1195
	fputs("Removing table ", stderr);
1196
	ut_print_name(stderr, table->name, ULINT_UNDEFINED);
1197
	fputs(" from dictionary cache\n", stderr);
1198
#endif
1199
1200
	/* Remove the foreign constraints from the cache */
1201
	foreign = UT_LIST_GET_LAST(table->foreign_list);
1202
1203
	while (foreign != NULL) {
1204
		dict_foreign_remove_from_cache(foreign);
1205
		foreign = UT_LIST_GET_LAST(table->foreign_list);
1206
	}
1207
1208
	/* Reset table field in referencing constraints */
1209
1210
	foreign = UT_LIST_GET_FIRST(table->referenced_list);
1211
1212
	while (foreign != NULL) {
1213
		foreign->referenced_table = NULL;
1214
		foreign->referenced_index = NULL;
1215
1216
		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1217
	}
1218
1219
	/* Remove the indexes from the cache */
1220
	index = UT_LIST_GET_LAST(table->indexes);
1221
1222
	while (index != NULL) {
1223
		dict_index_remove_from_cache(table, index);
1224
		index = UT_LIST_GET_LAST(table->indexes);
1225
	}
1226
1227
	/* Remove table from the hash tables of tables */
1228
	HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1229
		    ut_fold_string(table->name), table);
1230
	HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1231
		    ut_fold_dulint(table->id), table);
1232
1233
	/* Remove table from LRU list of tables */
1234
	UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1235
1236
	size = mem_heap_get_size(table->heap);
1237
1238
	ut_ad(dict_sys->size >= size);
1239
1240
	dict_sys->size -= size;
1241
1242
	dict_mem_table_free(table);
1243
}
1244
1245
/*************************************************************************
1246
Gets the column position in the clustered index. */
1247
1248
ulint
1249
dict_col_get_clust_pos_noninline(
1250
/*=============================*/
1251
	const dict_col_t*	col,		/* in: table column */
1252
	const dict_index_t*	clust_index)	/* in: clustered index */
1253
{
1254
	return(dict_col_get_clust_pos(col, clust_index));
1255
}
1256
1257
/********************************************************************
1258
If the given column name is reserved for InnoDB system columns, return
1259
TRUE. */
1260
1261
ibool
1262
dict_col_name_is_reserved(
1263
/*======================*/
1264
				/* out: TRUE if name is reserved */
1265
	const char*	name)	/* in: column name */
1266
{
1267
	/* This check reminds that if a new system column is added to
1268
	the program, it should be dealt with here. */
1269
#if DATA_N_SYS_COLS != 3
1270
#error "DATA_N_SYS_COLS != 3"
1271
#endif
1272
1273
	static const char*	reserved_names[] = {
1274
		"DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
1275
	};
1276
1277
	ulint			i;
1278
1279
	for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
1280
		if (strcmp(name, reserved_names[i]) == 0) {
1281
1282
			return(TRUE);
1283
		}
1284
	}
1285
1286
	return(FALSE);
1287
}
1288
1289
/**************************************************************************
1290
Adds an index to the dictionary cache. */
1291
1292
void
1293
dict_index_add_to_cache(
1294
/*====================*/
1295
	dict_table_t*	table,	/* in: table on which the index is */
1296
	dict_index_t*	index,	/* in, own: index; NOTE! The index memory
1297
				object is freed in this function! */
1298
	ulint		page_no)/* in: root page number of the index */
1299
{
1300
	dict_index_t*	new_index;
1301
	ulint		n_ord;
1302
	ulint		i;
1303
1304
	ut_ad(index);
1305
	ut_ad(mutex_own(&(dict_sys->mutex)));
1306
	ut_ad(index->n_def == index->n_fields);
1307
	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1308
1309
	ut_ad(mem_heap_validate(index->heap));
1310
1311
#ifdef UNIV_DEBUG
1312
	{
1313
		dict_index_t*	index2;
1314
		index2 = UT_LIST_GET_FIRST(table->indexes);
1315
1316
		while (index2 != NULL) {
1317
			ut_ad(ut_strcmp(index->name, index2->name) != 0);
1318
1319
			index2 = UT_LIST_GET_NEXT(indexes, index2);
1320
		}
1321
	}
1322
#endif /* UNIV_DEBUG */
1323
1324
	ut_a(!(index->type & DICT_CLUSTERED)
1325
	     || UT_LIST_GET_LEN(table->indexes) == 0);
1326
1327
	dict_index_find_cols(table, index);
1328
1329
	/* Build the cache internal representation of the index,
1330
	containing also the added system fields */
1331
1332
	if (index->type & DICT_CLUSTERED) {
1333
		new_index = dict_index_build_internal_clust(table, index);
1334
	} else {
1335
		new_index = dict_index_build_internal_non_clust(table, index);
1336
	}
1337
1338
	new_index->search_info = btr_search_info_create(new_index->heap);
1339
1340
	/* Set the n_fields value in new_index to the actual defined
1341
	number of fields in the cache internal representation */
1342
1343
	new_index->n_fields = new_index->n_def;
1344
1345
	/* Add the new index as the last index for the table */
1346
1347
	UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
1348
	new_index->table = table;
1349
	new_index->table_name = table->name;
1350
1351
	/* Increment the ord_part counts in columns which are ordering */
1352
1353
	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1354
		n_ord = new_index->n_fields;
1355
	} else {
1356
		n_ord = dict_index_get_n_unique(new_index);
1357
	}
1358
1359
	for (i = 0; i < n_ord; i++) {
1360
1361
		dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
1362
	}
1363
1364
	new_index->page = (unsigned int) page_no;
1365
	rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
1366
1367
	if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1368
1369
		new_index->stat_n_diff_key_vals = mem_heap_alloc(
1370
			new_index->heap,
1371
			(1 + dict_index_get_n_unique(new_index))
1372
			* sizeof(ib_longlong));
1373
		/* Give some sensible values to stat_n_... in case we do
1374
		not calculate statistics quickly enough */
1375
1376
		for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {
1377
1378
			new_index->stat_n_diff_key_vals[i] = 100;
1379
		}
1380
	}
1381
1382
	dict_sys->size += mem_heap_get_size(new_index->heap);
1383
1384
	dict_mem_index_free(index);
1385
}
1386
1387
/**************************************************************************
1388
Removes an index from the dictionary cache. */
1389
static
1390
void
1391
dict_index_remove_from_cache(
1392
/*=========================*/
1393
	dict_table_t*	table,	/* in: table */
1394
	dict_index_t*	index)	/* in, own: index */
1395
{
1396
	ulint		size;
1397
1398
	ut_ad(table && index);
1399
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1400
	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1401
	ut_ad(mutex_own(&(dict_sys->mutex)));
1402
1403
	rw_lock_free(&index->lock);
1404
1405
	/* Remove the index from the list of indexes of the table */
1406
	UT_LIST_REMOVE(indexes, table->indexes, index);
1407
1408
	size = mem_heap_get_size(index->heap);
1409
1410
	ut_ad(dict_sys->size >= size);
1411
1412
	dict_sys->size -= size;
1413
1414
	dict_mem_index_free(index);
1415
}
1416
1417
/***********************************************************************
1418
Tries to find column names for the index and sets the col field of the
1419
index. */
1420
static
1421
void
1422
dict_index_find_cols(
1423
/*=================*/
1424
	dict_table_t*	table,	/* in: table */
1425
	dict_index_t*	index)	/* in: index */
1426
{
1427
	ulint		i;
1428
1429
	ut_ad(table && index);
1430
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1431
	ut_ad(mutex_own(&(dict_sys->mutex)));
1432
1433
	for (i = 0; i < index->n_fields; i++) {
1434
		ulint		j;
1435
		dict_field_t*	field = dict_index_get_nth_field(index, i);
1436
1437
		for (j = 0; j < table->n_cols; j++) {
1438
			if (!strcmp(dict_table_get_col_name(table, j),
1439
				    field->name)) {
1440
				field->col = (dict_col_t*)
1441
					dict_table_get_nth_col(table, j);
1442
1443
				goto found;
1444
			}
1445
		}
1446
1447
		/* It is an error not to find a matching column. */
1448
		ut_error;
1449
1450
	found:
1451
		;
1452
	}
1453
}
1454
1455
/***********************************************************************
1456
Adds a column to index. */
1457
1458
void
1459
dict_index_add_col(
1460
/*===============*/
1461
	dict_index_t*	index,		/* in: index */
1462
	dict_table_t*	table,		/* in: table */
1463
	dict_col_t*	col,		/* in: column */
1464
	ulint		prefix_len)	/* in: column prefix length */
1465
{
1466
	dict_field_t*	field;
1467
	const char*	col_name;
1468
1469
	col_name = dict_table_get_col_name(table, dict_col_get_no(col));
1470
1471
	dict_mem_index_add_field(index, col_name, prefix_len);
1472
1473
	field = dict_index_get_nth_field(index, index->n_def - 1);
1474
1475
	field->col = col;
1476
	field->fixed_len = (unsigned int) dict_col_get_fixed_size(col);
1477
1478
	if (prefix_len && field->fixed_len > prefix_len) {
1479
		field->fixed_len = (unsigned int) prefix_len;
1480
	}
1481
1482
	/* Long fixed-length fields that need external storage are treated as
1483
	variable-length fields, so that the extern flag can be embedded in
1484
	the length word. */
1485
1486
	if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
1487
		field->fixed_len = 0;
1488
	}
1489
#if DICT_MAX_INDEX_COL_LEN != 768
1490
	/* The comparison limit above must be constant.  If it were
1491
	changed, the disk format of some fixed-length columns would
1492
	change, which would be a disaster. */
1493
# error "DICT_MAX_INDEX_COL_LEN != 768"
1494
#endif
1495
1496
	if (!(col->prtype & DATA_NOT_NULL)) {
1497
		index->n_nullable++;
1498
	}
1499
}
1500
1501
/***********************************************************************
1502
Copies fields contained in index2 to index1. */
1503
static
1504
void
1505
dict_index_copy(
1506
/*============*/
1507
	dict_index_t*	index1,	/* in: index to copy to */
1508
	dict_index_t*	index2,	/* in: index to copy from */
1509
	dict_table_t*	table,	/* in: table */
1510
	ulint		start,	/* in: first position to copy */
1511
	ulint		end)	/* in: last position to copy */
1512
{
1513
	dict_field_t*	field;
1514
	ulint		i;
1515
1516
	/* Copy fields contained in index2 */
1517
1518
	for (i = start; i < end; i++) {
1519
1520
		field = dict_index_get_nth_field(index2, i);
1521
		dict_index_add_col(index1, table, field->col,
1522
				   field->prefix_len);
1523
	}
1524
}
1525
1526
/***********************************************************************
1527
Copies types of fields contained in index to tuple. */
1528
1529
void
1530
dict_index_copy_types(
1531
/*==================*/
1532
	dtuple_t*	tuple,		/* in: data tuple */
1533
	dict_index_t*	index,		/* in: index */
1534
	ulint		n_fields)	/* in: number of field types to copy */
1535
{
1536
	ulint		i;
1537
1538
	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1539
		dtuple_set_types_binary(tuple, n_fields);
1540
1541
		return;
1542
	}
1543
1544
	for (i = 0; i < n_fields; i++) {
1545
		dict_field_t*	ifield;
1546
		dtype_t*	dfield_type;
1547
1548
		ifield = dict_index_get_nth_field(index, i);
1549
		dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1550
		dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
1551
	}
1552
}
1553
1554
/***********************************************************************
1555
Copies types of columns contained in table to tuple. */
1556
1557
void
1558
dict_table_copy_types(
1559
/*==================*/
1560
	dtuple_t*	tuple,	/* in: data tuple */
1561
	dict_table_t*	table)	/* in: index */
1562
{
1563
	dtype_t*	dfield_type;
1564
	ulint		i;
1565
1566
	for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
1567
1568
		dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1569
		dict_col_copy_type(dict_table_get_nth_col(table, i),
1570
				   dfield_type);
1571
	}
1572
}
1573
1574
/***********************************************************************
1575
Builds the internal dictionary cache representation for a clustered
1576
index, containing also system fields not defined by the user. */
1577
static
1578
dict_index_t*
1579
dict_index_build_internal_clust(
1580
/*============================*/
1581
				/* out, own: the internal representation
1582
				of the clustered index */
1583
	dict_table_t*	table,	/* in: table */
1584
	dict_index_t*	index)	/* in: user representation of a clustered
1585
				index */
1586
{
1587
	dict_index_t*	new_index;
1588
	dict_field_t*	field;
1589
	ulint		fixed_size;
1590
	ulint		trx_id_pos;
1591
	ulint		i;
1592
	ibool*		indexed;
1593
1594
	ut_ad(table && index);
1595
	ut_ad(index->type & DICT_CLUSTERED);
1596
	ut_ad(mutex_own(&(dict_sys->mutex)));
1597
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1598
1599
	/* Create a new index object with certainly enough fields */
1600
	new_index = dict_mem_index_create(table->name,
1601
					  index->name, table->space,
1602
					  index->type,
1603
					  index->n_fields + table->n_cols);
1604
1605
	/* Copy other relevant data from the old index struct to the new
1606
	struct: it inherits the values */
1607
1608
	new_index->n_user_defined_cols = index->n_fields;
1609
1610
	new_index->id = index->id;
1611
1612
	/* Copy the fields of index */
1613
	dict_index_copy(new_index, index, table, 0, index->n_fields);
1614
1615
	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1616
		/* No fixed number of fields determines an entry uniquely */
1617
1618
		new_index->n_uniq = REC_MAX_N_FIELDS;
1619
1620
	} else if (index->type & DICT_UNIQUE) {
1621
		/* Only the fields defined so far are needed to identify
1622
		the index entry uniquely */
1623
1624
		new_index->n_uniq = new_index->n_def;
1625
	} else {
1626
		/* Also the row id is needed to identify the entry */
1627
		new_index->n_uniq = 1 + new_index->n_def;
1628
	}
1629
1630
	new_index->trx_id_offset = 0;
1631
1632
	if (!(index->type & DICT_IBUF)) {
1633
		/* Add system columns, trx id first */
1634
1635
		trx_id_pos = new_index->n_def;
1636
1637
#if DATA_ROW_ID != 0
1638
# error "DATA_ROW_ID != 0"
1639
#endif
1640
#if DATA_TRX_ID != 1
1641
# error "DATA_TRX_ID != 1"
1642
#endif
1643
#if DATA_ROLL_PTR != 2
1644
# error "DATA_ROLL_PTR != 2"
1645
#endif
1646
1647
		if (!(index->type & DICT_UNIQUE)) {
1648
			dict_index_add_col(new_index, table, (dict_col_t*)
1649
					   dict_table_get_sys_col(
1650
						   table, DATA_ROW_ID),
1651
					   0);
1652
			trx_id_pos++;
1653
		}
1654
1655
		dict_index_add_col(new_index, table, (dict_col_t*)
1656
				   dict_table_get_sys_col(table, DATA_TRX_ID),
1657
				   0);
1658
1659
		dict_index_add_col(new_index, table, (dict_col_t*)
1660
				   dict_table_get_sys_col(table,
1661
							  DATA_ROLL_PTR),
1662
				   0);
1663
1664
		for (i = 0; i < trx_id_pos; i++) {
1665
1666
			fixed_size = dict_col_get_fixed_size(
1667
				dict_index_get_nth_col(new_index, i));
1668
1669
			if (fixed_size == 0) {
1670
				new_index->trx_id_offset = 0;
1671
1672
				break;
1673
			}
1674
1675
			if (dict_index_get_nth_field(new_index, i)->prefix_len
1676
			    > 0) {
1677
				new_index->trx_id_offset = 0;
1678
1679
				break;
1680
			}
1681
1682
			new_index->trx_id_offset += (unsigned int) fixed_size;
1683
		}
1684
1685
	}
1686
1687
	/* Remember the table columns already contained in new_index */
1688
	indexed = mem_alloc(table->n_cols * sizeof *indexed);
1689
	memset(indexed, 0, table->n_cols * sizeof *indexed);
1690
1691
	/* Mark with 0 the table columns already contained in new_index */
1692
	for (i = 0; i < new_index->n_def; i++) {
1693
1694
		field = dict_index_get_nth_field(new_index, i);
1695
1696
		/* If there is only a prefix of the column in the index
1697
		field, do not mark the column as contained in the index */
1698
1699
		if (field->prefix_len == 0) {
1700
1701
			indexed[field->col->ind] = TRUE;
1702
		}
1703
	}
1704
1705
	/* Add to new_index non-system columns of table not yet included
1706
	there */
1707
	for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
1708
1709
		dict_col_t*	col = (dict_col_t*)
1710
			dict_table_get_nth_col(table, i);
1711
		ut_ad(col->mtype != DATA_SYS);
1712
1713
		if (!indexed[col->ind]) {
1714
			dict_index_add_col(new_index, table, col, 0);
1715
		}
1716
	}
1717
1718
	mem_free(indexed);
1719
1720
	ut_ad((index->type & DICT_IBUF)
1721
	      || (UT_LIST_GET_LEN(table->indexes) == 0));
1722
1723
	new_index->cached = TRUE;
1724
1725
	return(new_index);
1726
}
1727
1728
/***********************************************************************
1729
Builds the internal dictionary cache representation for a non-clustered
1730
index, containing also system fields not defined by the user. */
1731
static
1732
dict_index_t*
1733
dict_index_build_internal_non_clust(
1734
/*================================*/
1735
				/* out, own: the internal representation
1736
				of the non-clustered index */
1737
	dict_table_t*	table,	/* in: table */
1738
	dict_index_t*	index)	/* in: user representation of a non-clustered
1739
				index */
1740
{
1741
	dict_field_t*	field;
1742
	dict_index_t*	new_index;
1743
	dict_index_t*	clust_index;
1744
	ulint		i;
1745
	ibool*		indexed;
1746
1747
	ut_ad(table && index);
1748
	ut_ad(0 == (index->type & DICT_CLUSTERED));
1749
	ut_ad(mutex_own(&(dict_sys->mutex)));
1750
	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1751
1752
	/* The clustered index should be the first in the list of indexes */
1753
	clust_index = UT_LIST_GET_FIRST(table->indexes);
1754
1755
	ut_ad(clust_index);
1756
	ut_ad(clust_index->type & DICT_CLUSTERED);
1757
	ut_ad(!(clust_index->type & DICT_UNIVERSAL));
1758
1759
	/* Create a new index */
1760
	new_index = dict_mem_index_create(
1761
		table->name, index->name, index->space, index->type,
1762
		index->n_fields + 1 + clust_index->n_uniq);
1763
1764
	/* Copy other relevant data from the old index
1765
	struct to the new struct: it inherits the values */
1766
1767
	new_index->n_user_defined_cols = index->n_fields;
1768
1769
	new_index->id = index->id;
1770
1771
	/* Copy fields from index to new_index */
1772
	dict_index_copy(new_index, index, table, 0, index->n_fields);
1773
1774
	/* Remember the table columns already contained in new_index */
1775
	indexed = mem_alloc(table->n_cols * sizeof *indexed);
1776
	memset(indexed, 0, table->n_cols * sizeof *indexed);
1777
1778
	/* Mark with 0 table columns already contained in new_index */
1779
	for (i = 0; i < new_index->n_def; i++) {
1780
1781
		field = dict_index_get_nth_field(new_index, i);
1782
1783
		/* If there is only a prefix of the column in the index
1784
		field, do not mark the column as contained in the index */
1785
1786
		if (field->prefix_len == 0) {
1787
1788
			indexed[field->col->ind] = TRUE;
1789
		}
1790
	}
1791
1792
	/* Add to new_index the columns necessary to determine the clustered
1793
	index entry uniquely */
1794
1795
	for (i = 0; i < clust_index->n_uniq; i++) {
1796
1797
		field = dict_index_get_nth_field(clust_index, i);
1798
1799
		if (!indexed[field->col->ind]) {
1800
			dict_index_add_col(new_index, table, field->col,
1801
					   field->prefix_len);
1802
		}
1803
	}
1804
1805
	mem_free(indexed);
1806
1807
	if ((index->type) & DICT_UNIQUE) {
1808
		new_index->n_uniq = index->n_fields;
1809
	} else {
1810
		new_index->n_uniq = new_index->n_def;
1811
	}
1812
1813
	/* Set the n_fields value in new_index to the actual defined
1814
	number of fields */
1815
1816
	new_index->n_fields = new_index->n_def;
1817
1818
	new_index->cached = TRUE;
1819
1820
	return(new_index);
1821
}
1822
1823
/*====================== FOREIGN KEY PROCESSING ========================*/
1824
1825
/*************************************************************************
1826
Checks if a table is referenced by foreign keys. */
1827
1828
ibool
1829
dict_table_referenced_by_foreign_key(
1830
/*=================================*/
1831
				/* out: TRUE if table is referenced by a
1832
				foreign key */
1833
	dict_table_t*	table)	/* in: InnoDB table */
1834
{
1835
	if (UT_LIST_GET_LEN(table->referenced_list) > 0) {
1836
1837
		return(TRUE);
1838
	}
1839
1840
	return(FALSE);
1841
}
1842
1843
/*************************************************************************
1844
Frees a foreign key struct. */
1845
static
1846
void
1847
dict_foreign_free(
1848
/*==============*/
1849
	dict_foreign_t*	foreign)	/* in, own: foreign key struct */
1850
{
1851
	mem_heap_free(foreign->heap);
1852
}
1853
1854
/**************************************************************************
1855
Removes a foreign constraint struct from the dictionary cache. */
1856
static
1857
void
1858
dict_foreign_remove_from_cache(
1859
/*===========================*/
1860
	dict_foreign_t*	foreign)	/* in, own: foreign constraint */
1861
{
1862
	ut_ad(mutex_own(&(dict_sys->mutex)));
1863
	ut_a(foreign);
1864
1865
	if (foreign->referenced_table) {
1866
		UT_LIST_REMOVE(referenced_list,
1867
			       foreign->referenced_table->referenced_list,
1868
			       foreign);
1869
	}
1870
1871
	if (foreign->foreign_table) {
1872
		UT_LIST_REMOVE(foreign_list,
1873
			       foreign->foreign_table->foreign_list,
1874
			       foreign);
1875
	}
1876
1877
	dict_foreign_free(foreign);
1878
}
1879
1880
/**************************************************************************
1881
Looks for the foreign constraint from the foreign and referenced lists
1882
of a table. */
1883
static
1884
dict_foreign_t*
1885
dict_foreign_find(
1886
/*==============*/
1887
				/* out: foreign constraint */
1888
	dict_table_t*	table,	/* in: table object */
1889
	const char*	id)	/* in: foreign constraint id */
1890
{
1891
	dict_foreign_t*	foreign;
1892
1893
	ut_ad(mutex_own(&(dict_sys->mutex)));
1894
1895
	foreign = UT_LIST_GET_FIRST(table->foreign_list);
1896
1897
	while (foreign) {
1898
		if (ut_strcmp(id, foreign->id) == 0) {
1899
1900
			return(foreign);
1901
		}
1902
1903
		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1904
	}
1905
1906
	foreign = UT_LIST_GET_FIRST(table->referenced_list);
1907
1908
	while (foreign) {
1909
		if (ut_strcmp(id, foreign->id) == 0) {
1910
1911
			return(foreign);
1912
		}
1913
1914
		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1915
	}
1916
1917
	return(NULL);
1918
}
1919
1920
#ifndef UNIV_HOTBACKUP
1921
/*************************************************************************
1922
Tries to find an index whose first fields are the columns in the array,
1923
in the same order. */
1924
static
1925
dict_index_t*
1926
dict_foreign_find_index(
1927
/*====================*/
1928
				/* out: matching index, NULL if not found */
1929
	dict_table_t*	table,	/* in: table */
1930
	const char**	columns,/* in: array of column names */
1931
	ulint		n_cols,	/* in: number of columns */
1932
	dict_index_t*	types_idx, /* in: NULL or an index to whose types the
1933
				   column types must match */
1934
	ibool		check_charsets,
1935
				/* in: whether to check charsets.
1936
				only has an effect if types_idx != NULL */
1937
	ulint		check_null)
1938
				/* in: nonzero if none of the columns must
1939
				be declared NOT NULL */
1940
{
1941
	dict_index_t*	index;
1942
	dict_field_t*	field;
1943
	const char*	col_name;
1944
	ulint		i;
1945
1946
	index = dict_table_get_first_index(table);
1947
1948
	while (index != NULL) {
1949
		if (dict_index_get_n_fields(index) >= n_cols) {
1950
1951
			for (i = 0; i < n_cols; i++) {
1952
				field = dict_index_get_nth_field(index, i);
1953
1954
				col_name = dict_table_get_col_name(
1955
					table, dict_col_get_no(field->col));
1956
1957
				if (field->prefix_len != 0) {
1958
					/* We do not accept column prefix
1959
					indexes here */
1960
1961
					break;
1962
				}
1963
1964
				if (0 != innobase_strcasecmp(columns[i],
1965
							     col_name)) {
1966
					break;
1967
				}
1968
1969
				if (check_null
1970
				    && (field->col->prtype & DATA_NOT_NULL)) {
1971
1972
					return(NULL);
1973
				}
1974
1975
				if (types_idx && !cmp_cols_are_equal(
1976
					    dict_index_get_nth_col(index, i),
1977
					    dict_index_get_nth_col(types_idx,
1978
								   i),
1979
					    check_charsets)) {
1980
1981
					break;
1982
				}
1983
			}
1984
1985
			if (i == n_cols) {
1986
				/* We found a matching index */
1987
1988
				return(index);
1989
			}
1990
		}
1991
1992
		index = dict_table_get_next_index(index);
1993
	}
1994
1995
	return(NULL);
1996
}
1997
1998
/**************************************************************************
1999
Report an error in a foreign key definition. */
2000
static
2001
void
2002
dict_foreign_error_report_low(
2003
/*==========================*/
2004
	FILE*		file,	/* in: output stream */
2005
	const char*	name)	/* in: table name */
2006
{
2007
	rewind(file);
2008
	ut_print_timestamp(file);
2009
	fprintf(file, " Error in foreign key constraint of table %s:\n",
2010
		name);
2011
}
2012
2013
/**************************************************************************
2014
Report an error in a foreign key definition. */
2015
static
2016
void
2017
dict_foreign_error_report(
2018
/*======================*/
2019
	FILE*		file,	/* in: output stream */
2020
	dict_foreign_t*	fk,	/* in: foreign key constraint */
2021
	const char*	msg)	/* in: the error message */
2022
{
2023
	mutex_enter(&dict_foreign_err_mutex);
2024
	dict_foreign_error_report_low(file, fk->foreign_table_name);
2025
	fputs(msg, file);
2026
	fputs(" Constraint:\n", file);
2027
	dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
2028
	putc('\n', file);
2029
	if (fk->foreign_index) {
2030
		fputs("The index in the foreign key in table is ", file);
2031
		ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
2032
		fputs("\n"
2033
		      "See http://dev.mysql.com/doc/refman/5.1/en/"
2034
		      "innodb-foreign-key-constraints.html\n"
2035
		      "for correct foreign key definition.\n",
2036
		      file);
2037
	}
2038
	mutex_exit(&dict_foreign_err_mutex);
2039
}
2040
2041
/**************************************************************************
2042
Adds a foreign key constraint object to the dictionary cache. May free
2043
the object if there already is an object with the same identifier in.
2044
At least one of the foreign table and the referenced table must already
2045
be in the dictionary cache! */
2046
2047
ulint
2048
dict_foreign_add_to_cache(
2049
/*======================*/
2050
					/* out: DB_SUCCESS or error code */
2051
	dict_foreign_t*	foreign,	/* in, own: foreign key constraint */
2052
	ibool		check_charsets)	/* in: TRUE=check charset
2053
					compatibility */
2054
{
2055
	dict_table_t*	for_table;
2056
	dict_table_t*	ref_table;
2057
	dict_foreign_t*	for_in_cache		= NULL;
2058
	dict_index_t*	index;
2059
	ibool		added_to_referenced_list= FALSE;
2060
	FILE*		ef			= dict_foreign_err_file;
2061
2062
	ut_ad(mutex_own(&(dict_sys->mutex)));
2063
2064
	for_table = dict_table_check_if_in_cache_low(
2065
		foreign->foreign_table_name);
2066
2067
	ref_table = dict_table_check_if_in_cache_low(
2068
		foreign->referenced_table_name);
2069
	ut_a(for_table || ref_table);
2070
2071
	if (for_table) {
2072
		for_in_cache = dict_foreign_find(for_table, foreign->id);
2073
	}
2074
2075
	if (!for_in_cache && ref_table) {
2076
		for_in_cache = dict_foreign_find(ref_table, foreign->id);
2077
	}
2078
2079
	if (for_in_cache) {
2080
		/* Free the foreign object */
2081
		mem_heap_free(foreign->heap);
2082
	} else {
2083
		for_in_cache = foreign;
2084
	}
2085
2086
	if (for_in_cache->referenced_table == NULL && ref_table) {
2087
		index = dict_foreign_find_index(
2088
			ref_table,
2089
			(const char**) for_in_cache->referenced_col_names,
2090
			for_in_cache->n_fields, for_in_cache->foreign_index,
2091
			check_charsets, FALSE);
2092
2093
		if (index == NULL) {
2094
			dict_foreign_error_report(
2095
				ef, for_in_cache,
2096
				"there is no index in referenced table"
2097
				" which would contain\n"
2098
				"the columns as the first columns,"
2099
				" or the data types in the\n"
2100
				"referenced table do not match"
2101
				" the ones in table.");
2102
2103
			if (for_in_cache == foreign) {
2104
				mem_heap_free(foreign->heap);
2105
			}
2106
2107
			return(DB_CANNOT_ADD_CONSTRAINT);
2108
		}
2109
2110
		for_in_cache->referenced_table = ref_table;
2111
		for_in_cache->referenced_index = index;
2112
		UT_LIST_ADD_LAST(referenced_list,
2113
				 ref_table->referenced_list,
2114
				 for_in_cache);
2115
		added_to_referenced_list = TRUE;
2116
	}
2117
2118
	if (for_in_cache->foreign_table == NULL && for_table) {
2119
		index = dict_foreign_find_index(
2120
			for_table,
2121
			(const char**) for_in_cache->foreign_col_names,
2122
			for_in_cache->n_fields,
2123
			for_in_cache->referenced_index, check_charsets,
2124
			for_in_cache->type
2125
			& (DICT_FOREIGN_ON_DELETE_SET_NULL
2126
			   | DICT_FOREIGN_ON_UPDATE_SET_NULL));
2127
2128
		if (index == NULL) {
2129
			dict_foreign_error_report(
2130
				ef, for_in_cache,
2131
				"there is no index in the table"
2132
				" which would contain\n"
2133
				"the columns as the first columns,"
2134
				" or the data types in the\n"
2135
				"table do not match"
2136
				" the ones in the referenced table\n"
2137
				"or one of the ON ... SET NULL columns"
2138
				" is declared NOT NULL.");
2139
2140
			if (for_in_cache == foreign) {
2141
				if (added_to_referenced_list) {
2142
					UT_LIST_REMOVE(
2143
						referenced_list,
2144
						ref_table->referenced_list,
2145
						for_in_cache);
2146
				}
2147
2148
				mem_heap_free(foreign->heap);
2149
			}
2150
2151
			return(DB_CANNOT_ADD_CONSTRAINT);
2152
		}
2153
2154
		for_in_cache->foreign_table = for_table;
2155
		for_in_cache->foreign_index = index;
2156
		UT_LIST_ADD_LAST(foreign_list,
2157
				 for_table->foreign_list,
2158
				 for_in_cache);
2159
	}
2160
2161
	return(DB_SUCCESS);
2162
}
2163
2164
/*************************************************************************
2165
Scans from pointer onwards. Stops if is at the start of a copy of
2166
'string' where characters are compared without case sensitivity, and
2167
only outside `` or "" quotes. Stops also at '\0'. */
2168
2169
const char*
2170
dict_scan_to(
2171
/*=========*/
2172
				/* out: scanned up to this */
2173
	const char*	ptr,	/* in: scan from */
2174
	const char*	string)	/* in: look for this */
2175
{
2176
	char	quote	= '\0';
2177
2178
	for (; *ptr; ptr++) {
2179
		if (*ptr == quote) {
2180
			/* Closing quote character: do not look for
2181
			starting quote or the keyword. */
2182
			quote = '\0';
2183
		} else if (quote) {
2184
			/* Within quotes: do nothing. */
2185
		} else if (*ptr == '`' || *ptr == '"') {
2186
			/* Starting quote: remember the quote character. */
2187
			quote = *ptr;
2188
		} else {
2189
			/* Outside quotes: look for the keyword. */
2190
			ulint	i;
2191
			for (i = 0; string[i]; i++) {
2192
				if (toupper((int)(unsigned char)(ptr[i]))
2193
				    != toupper((int)(unsigned char)
2194
					       (string[i]))) {
2195
					goto nomatch;
2196
				}
2197
			}
2198
			break;
2199
nomatch:
2200
			;
2201
		}
2202
	}
2203
2204
	return(ptr);
2205
}
2206
2207
/*************************************************************************
2208
Accepts a specified string. Comparisons are case-insensitive. */
2209
static
2210
const char*
2211
dict_accept(
2212
/*========*/
2213
				/* out: if string was accepted, the pointer
2214
				is moved after that, else ptr is returned */
2215
	struct charset_info_st*	cs,/* in: the character set of ptr */
2216
	const char*	ptr,	/* in: scan from this */
2217
	const char*	string,	/* in: accept only this string as the next
2218
				non-whitespace string */
2219
	ibool*		success)/* out: TRUE if accepted */
2220
{
2221
	const char*	old_ptr = ptr;
2222
	const char*	old_ptr2;
2223
2224
	*success = FALSE;
2225
2226
	while (my_isspace(cs, *ptr)) {
2227
		ptr++;
2228
	}
2229
2230
	old_ptr2 = ptr;
2231
2232
	ptr = dict_scan_to(ptr, string);
2233
2234
	if (*ptr == '\0' || old_ptr2 != ptr) {
2235
		return(old_ptr);
2236
	}
2237
2238
	*success = TRUE;
2239
2240
	return(ptr + ut_strlen(string));
2241
}
2242
2243
/*************************************************************************
2244
Scans an id. For the lexical definition of an 'id', see the code below.
2245
Strips backquotes or double quotes from around the id. */
2246
static
2247
const char*
2248
dict_scan_id(
2249
/*=========*/
2250
				/* out: scanned to */
2251
	struct charset_info_st*	cs,/* in: the character set of ptr */
2252
	const char*	ptr,	/* in: scanned to */
2253
	mem_heap_t*	heap,	/* in: heap where to allocate the id
2254
				(NULL=id will not be allocated, but it
2255
				will point to string near ptr) */
2256
	const char**	id,	/* out,own: the id; NULL if no id was
2257
				scannable */
2258
	ibool		table_id,/* in: TRUE=convert the allocated id
2259
				as a table name; FALSE=convert to UTF-8 */
2260
	ibool		accept_also_dot)
2261
				/* in: TRUE if also a dot can appear in a
2262
				non-quoted id; in a quoted id it can appear
2263
				always */
2264
{
2265
	char		quote	= '\0';
2266
	ulint		len	= 0;
2267
	const char*	s;
2268
	char*		str;
2269
	char*		dst;
2270
2271
	*id = NULL;
2272
2273
	while (my_isspace(cs, *ptr)) {
2274
		ptr++;
2275
	}
2276
2277
	if (*ptr == '\0') {
2278
2279
		return(ptr);
2280
	}
2281
2282
	if (*ptr == '`' || *ptr == '"') {
2283
		quote = *ptr++;
2284
	}
2285
2286
	s = ptr;
2287
2288
	if (quote) {
2289
		for (;;) {
2290
			if (!*ptr) {
2291
				/* Syntax error */
2292
				return(ptr);
2293
			}
2294
			if (*ptr == quote) {
2295
				ptr++;
2296
				if (*ptr != quote) {
2297
					break;
2298
				}
2299
			}
2300
			ptr++;
2301
			len++;
2302
		}
2303
	} else {
2304
		while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
2305
		       && (accept_also_dot || *ptr != '.')
2306
		       && *ptr != ',' && *ptr != '\0') {
2307
2308
			ptr++;
2309
		}
2310
2311
		len = ptr - s;
2312
	}
2313
2314
	if (UNIV_UNLIKELY(!heap)) {
2315
		/* no heap given: id will point to source string */
2316
		*id = s;
2317
		return(ptr);
2318
	}
2319
2320
	if (quote) {
2321
		char*	d;
2322
		str = d = mem_heap_alloc(heap, len + 1);
2323
		while (len--) {
2324
			if ((*d++ = *s++) == quote) {
2325
				s++;
2326
			}
2327
		}
2328
		*d++ = 0;
2329
		len = d - str;
2330
		ut_ad(*s == quote);
2331
		ut_ad(s + 1 == ptr);
2332
	} else {
2333
		str = mem_heap_strdupl(heap, s, len);
2334
	}
2335
2336
	if (!table_id) {
2337
convert_id:
2338
		/* Convert the identifier from connection character set
2339
		to UTF-8. */
2340
		len = 3 * len + 1;
2341
		*id = dst = mem_heap_alloc(heap, len);
2342
2343
		innobase_convert_from_id(dst, str, len);
2344
	} else if (!strncmp(str, srv_mysql50_table_name_prefix,
2345
			    sizeof srv_mysql50_table_name_prefix)) {
2346
		/* This is a pre-5.1 table name
2347
		containing chars other than [A-Za-z0-9].
2348
		Discard the prefix and use raw UTF-8 encoding. */
2349
		str += sizeof srv_mysql50_table_name_prefix;
2350
		len -= sizeof srv_mysql50_table_name_prefix;
2351
		goto convert_id;
2352
	} else {
2353
		/* Encode using filename-safe characters. */
2354
		len = 5 * len + 1;
2355
		*id = dst = mem_heap_alloc(heap, len);
2356
2357
		innobase_convert_from_table_id(dst, str, len);
2358
	}
2359
2360
	return(ptr);
2361
}
2362
2363
/*************************************************************************
2364
Tries to scan a column name. */
2365
static
2366
const char*
2367
dict_scan_col(
2368
/*==========*/
2369
					/* out: scanned to */
2370
	struct charset_info_st*	cs,	/* in: the character set of ptr */
2371
	const char*		ptr,	/* in: scanned to */
2372
	ibool*			success,/* out: TRUE if success */
2373
	dict_table_t*		table,	/* in: table in which the column is */
2374
	const dict_col_t**	column,	/* out: pointer to column if success */
2375
	mem_heap_t*		heap,	/* in: heap where to allocate */
2376
	const char**		name)	/* out,own: the column name;
2377
					NULL if no name was scannable */
2378
{
2379
	ulint		i;
2380
2381
	*success = FALSE;
2382
2383
	ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
2384
2385
	if (*name == NULL) {
2386
2387
		return(ptr);	/* Syntax error */
2388
	}
2389
2390
	if (table == NULL) {
2391
		*success = TRUE;
2392
		*column = NULL;
2393
	} else {
2394
		for (i = 0; i < dict_table_get_n_cols(table); i++) {
2395
2396
			const char*	col_name = dict_table_get_col_name(
2397
				table, i);
2398
2399
			if (0 == innobase_strcasecmp(col_name, *name)) {
2400
				/* Found */
2401
2402
				*success = TRUE;
2403
				*column = dict_table_get_nth_col(table, i);
2404
				strcpy((char*) *name, col_name);
2405
2406
				break;
2407
			}
2408
		}
2409
	}
2410
2411
	return(ptr);
2412
}
2413
2414
/*************************************************************************
2415
Scans a table name from an SQL string. */
2416
static
2417
const char*
2418
dict_scan_table_name(
2419
/*=================*/
2420
				/* out: scanned to */
2421
	struct charset_info_st*	cs,/* in: the character set of ptr */
2422
	const char*	ptr,	/* in: scanned to */
2423
	dict_table_t**	table,	/* out: table object or NULL */
2424
	const char*	name,	/* in: foreign key table name */
2425
	ibool*		success,/* out: TRUE if ok name found */
2426
	mem_heap_t*	heap,	/* in: heap where to allocate the id */
2427
	const char**	ref_name)/* out,own: the table name;
2428
				NULL if no name was scannable */
2429
{
2430
	const char*	database_name	= NULL;
2431
	ulint		database_name_len = 0;
2432
	const char*	table_name	= NULL;
2433
	ulint		table_name_len;
2434
	const char*	scan_name;
2435
	char*		ref;
2436
2437
	*success = FALSE;
2438
	*table = NULL;
2439
2440
	ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
2441
2442
	if (scan_name == NULL) {
2443
2444
		return(ptr);	/* Syntax error */
2445
	}
2446
2447
	if (*ptr == '.') {
2448
		/* We scanned the database name; scan also the table name */
2449
2450
		ptr++;
2451
2452
		database_name = scan_name;
2453
		database_name_len = strlen(database_name);
2454
2455
		ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
2456
2457
		if (table_name == NULL) {
2458
2459
			return(ptr);	/* Syntax error */
2460
		}
2461
	} else {
2462
		/* To be able to read table dumps made with InnoDB-4.0.17 or
2463
		earlier, we must allow the dot separator between the database
2464
		name and the table name also to appear within a quoted
2465
		identifier! InnoDB used to print a constraint as:
2466
		... REFERENCES `databasename.tablename` ...
2467
		starting from 4.0.18 it is
2468
		... REFERENCES `databasename`.`tablename` ... */
2469
		const char* s;
2470
2471
		for (s = scan_name; *s; s++) {
2472
			if (*s == '.') {
2473
				database_name = scan_name;
2474
				database_name_len = s - scan_name;
2475
				scan_name = ++s;
2476
				break;/* to do: multiple dots? */
2477
			}
2478
		}
2479
2480
		table_name = scan_name;
2481
	}
2482
2483
	if (database_name == NULL) {
2484
		/* Use the database name of the foreign key table */
2485
2486
		database_name = name;
2487
		database_name_len = dict_get_db_name_len(name);
2488
	}
2489
2490
	table_name_len = strlen(table_name);
2491
2492
	/* Copy database_name, '/', table_name, '\0' */
2493
	ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
2494
	memcpy(ref, database_name, database_name_len);
2495
	ref[database_name_len] = '/';
2496
	memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
2497
#ifndef __WIN__
2498
	if (srv_lower_case_table_names) {
2499
#endif /* !__WIN__ */
2500
		/* The table name is always put to lower case on Windows. */
2501
		innobase_casedn_str(ref);
2502
#ifndef __WIN__
2503
	}
2504
#endif /* !__WIN__ */
2505
2506
	*success = TRUE;
2507
	*ref_name = ref;
2508
	*table = dict_table_get_low(ref);
2509
2510
	return(ptr);
2511
}
2512
2513
/*************************************************************************
2514
Skips one id. The id is allowed to contain also '.'. */
2515
static
2516
const char*
2517
dict_skip_word(
2518
/*===========*/
2519
				/* out: scanned to */
2520
	struct charset_info_st*	cs,/* in: the character set of ptr */
2521
	const char*	ptr,	/* in: scanned to */
2522
	ibool*		success)/* out: TRUE if success, FALSE if just spaces
2523
				left in string or a syntax error */
2524
{
2525
	const char*	start;
2526
2527
	*success = FALSE;
2528
2529
	ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
2530
2531
	if (start) {
2532
		*success = TRUE;
2533
	}
2534
2535
	return(ptr);
2536
}
2537
2538
/*************************************************************************
2539
Removes MySQL comments from an SQL string. A comment is either
2540
(a) '#' to the end of the line,
2541
(b) '--<space>' to the end of the line, or
2542
(c) '<slash><asterisk>' till the next '<asterisk><slash>' (like the familiar
2543
C comment syntax). */
2544
static
2545
char*
2546
dict_strip_comments(
2547
/*================*/
2548
					/* out, own: SQL string stripped from
2549
					comments; the caller must free this
2550
					with mem_free()! */
2551
	const char*	sql_string)	/* in: SQL string */
2552
{
2553
	char*		str;
2554
	const char*	sptr;
2555
	char*		ptr;
2556
	/* unclosed quote character (0 if none) */
2557
	char		quote	= 0;
2558
2559
	str = mem_alloc(strlen(sql_string) + 1);
2560
2561
	sptr = sql_string;
2562
	ptr = str;
2563
2564
	for (;;) {
2565
scan_more:
2566
		if (*sptr == '\0') {
2567
			*ptr = '\0';
2568
2569
			ut_a(ptr <= str + strlen(sql_string));
2570
2571
			return(str);
2572
		}
2573
2574
		if (*sptr == quote) {
2575
			/* Closing quote character: do not look for
2576
			starting quote or comments. */
2577
			quote = 0;
2578
		} else if (quote) {
2579
			/* Within quotes: do not look for
2580
			starting quotes or comments. */
2581
		} else if (*sptr == '"' || *sptr == '`') {
2582
			/* Starting quote: remember the quote character. */
2583
			quote = *sptr;
2584
		} else if (*sptr == '#'
2585
			   || (sptr[0] == '-' && sptr[1] == '-'
2586
			       && sptr[2] == ' ')) {
2587
			for (;;) {
2588
				/* In Unix a newline is 0x0A while in Windows
2589
				it is 0x0D followed by 0x0A */
2590
2591
				if (*sptr == (char)0x0A
2592
				    || *sptr == (char)0x0D
2593
				    || *sptr == '\0') {
2594
2595
					goto scan_more;
2596
				}
2597
2598
				sptr++;
2599
			}
2600
		} else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
2601
			for (;;) {
2602
				if (*sptr == '*' && *(sptr + 1) == '/') {
2603
2604
					sptr += 2;
2605
2606
					goto scan_more;
2607
				}
2608
2609
				if (*sptr == '\0') {
2610
2611
					goto scan_more;
2612
				}
2613
2614
				sptr++;
2615
			}
2616
		}
2617
2618
		*ptr = *sptr;
2619
2620
		ptr++;
2621
		sptr++;
2622
	}
2623
}
2624
2625
/*************************************************************************
2626
Finds the highest <number> for foreign key constraints of the table. Looks
2627
only at the >= 4.0.18-format id's, which are of the form
2628
databasename/tablename_ibfk_<number>. */
2629
static
2630
ulint
2631
dict_table_get_highest_foreign_id(
2632
/*==============================*/
2633
				/* out: highest number, 0 if table has no new
2634
				format foreign key constraints */
2635
	dict_table_t*	table)	/* in: table in the dictionary memory cache */
2636
{
2637
	dict_foreign_t*	foreign;
2638
	char*		endp;
2639
	ulint		biggest_id	= 0;
2640
	ulint		id;
2641
	ulint		len;
2642
2643
	ut_a(table);
2644
2645
	len = ut_strlen(table->name);
2646
	foreign = UT_LIST_GET_FIRST(table->foreign_list);
2647
2648
	while (foreign) {
2649
		if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
2650
		    && 0 == ut_memcmp(foreign->id, table->name, len)
2651
		    && 0 == ut_memcmp(foreign->id + len,
2652
				      dict_ibfk, (sizeof dict_ibfk) - 1)
2653
		    && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
2654
			/* It is of the >= 4.0.18 format */
2655
2656
			id = strtoul(foreign->id + len
2657
				     + ((sizeof dict_ibfk) - 1),
2658
				     &endp, 10);
2659
			if (*endp == '\0') {
2660
				ut_a(id != biggest_id);
2661
2662
				if (id > biggest_id) {
2663
					biggest_id = id;
2664
				}
2665
			}
2666
		}
2667
2668
		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
2669
	}
2670
2671
	return(biggest_id);
2672
}
2673
2674
/*************************************************************************
2675
Reports a simple foreign key create clause syntax error. */
2676
static
2677
void
2678
dict_foreign_report_syntax_err(
2679
/*===========================*/
2680
	const char*	name,		/* in: table name */
2681
	const char*	start_of_latest_foreign,
2682
					/* in: start of the foreign key clause
2683
					in the SQL string */
2684
	const char*	ptr)		/* in: place of the syntax error */
2685
{
2686
	FILE*	 ef = dict_foreign_err_file;
2687
2688
	mutex_enter(&dict_foreign_err_mutex);
2689
	dict_foreign_error_report_low(ef, name);
2690
	fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
2691
		start_of_latest_foreign, ptr);
2692
	mutex_exit(&dict_foreign_err_mutex);
2693
}
2694
2695
/*************************************************************************
2696
Scans a table create SQL string and adds to the data dictionary the foreign
2697
key constraints declared in the string. This function should be called after
2698
the indexes for a table have been created. Each foreign key constraint must
2699
be accompanied with indexes in both participating tables. The indexes are
2700
allowed to contain more fields than mentioned in the constraint. */
2701
static
2702
ulint
2703
dict_create_foreign_constraints_low(
2704
/*================================*/
2705
				/* out: error code or DB_SUCCESS */
2706
	trx_t*		trx,	/* in: transaction */
2707
	mem_heap_t*	heap,	/* in: memory heap */
2708
	struct charset_info_st*	cs,/* in: the character set of sql_string */
2709
	const char*	sql_string,
2710
				/* in: CREATE TABLE or ALTER TABLE statement
2711
				where foreign keys are declared like:
2712
				FOREIGN KEY (a, b) REFERENCES table2(c, d),
2713
				table2 can be written also with the database
2714
				name before it: test.table2; the default
2715
				database is the database of parameter name */
2716
	const char*	name,	/* in: table full name in the normalized form
2717
				database_name/table_name */
2718
	ibool		reject_fks)
2719
				/* in: if TRUE, fail with error code
2720
				DB_CANNOT_ADD_CONSTRAINT if any foreign
2721
				keys are found. */
2722
{
2723
	dict_table_t*	table;
2724
	dict_table_t*	referenced_table;
2725
	dict_table_t*	table_to_alter;
2726
	ulint		highest_id_so_far	= 0;
2727
	dict_index_t*	index;
2728
	dict_foreign_t*	foreign;
2729
	const char*	ptr			= sql_string;
2730
	const char*	start_of_latest_foreign	= sql_string;
2731
	FILE*		ef			= dict_foreign_err_file;
2732
	const char*	constraint_name;
2733
	ibool		success;
2734
	ulint		error;
2735
	const char*	ptr1;
2736
	const char*	ptr2;
2737
	ulint		i;
2738
	ulint		j;
2739
	ibool		is_on_delete;
2740
	ulint		n_on_deletes;
2741
	ulint		n_on_updates;
2742
	const dict_col_t*columns[500];
2743
	const char*	column_names[500];
2744
	const char*	referenced_table_name;
2745
2746
	ut_ad(mutex_own(&(dict_sys->mutex)));
2747
2748
	table = dict_table_get_low(name);
2749
2750
	if (table == NULL) {
2751
		mutex_enter(&dict_foreign_err_mutex);
2752
		dict_foreign_error_report_low(ef, name);
2753
		fprintf(ef,
2754
			"Cannot find the table in the internal"
2755
			" data dictionary of InnoDB.\n"
2756
			"Create table statement:\n%s\n", sql_string);
2757
		mutex_exit(&dict_foreign_err_mutex);
2758
2759
		return(DB_ERROR);
2760
	}
2761
2762
	/* First check if we are actually doing an ALTER TABLE, and in that
2763
	case look for the table being altered */
2764
2765
	ptr = dict_accept(cs, ptr, "ALTER", &success);
2766
2767
	if (!success) {
2768
2769
		goto loop;
2770
	}
2771
2772
	ptr = dict_accept(cs, ptr, "TABLE", &success);
2773
2774
	if (!success) {
2775
2776
		goto loop;
2777
	}
2778
2779
	/* We are doing an ALTER TABLE: scan the table name we are altering */
2780
2781
	ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
2782
				   &success, heap, &referenced_table_name);
2783
	if (!success) {
2784
		fprintf(stderr,
2785
			"InnoDB: Error: could not find"
2786
			" the table being ALTERED in:\n%s\n",
2787
			sql_string);
2788
2789
		return(DB_ERROR);
2790
	}
2791
2792
	/* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
2793
	format databasename/tablename_ibfk_<number>, where <number> is local
2794
	to the table; look for the highest <number> for table_to_alter, so
2795
	that we can assign to new constraints higher numbers. */
2796
2797
	/* If we are altering a temporary table, the table name after ALTER
2798
	TABLE does not correspond to the internal table name, and
2799
	table_to_alter is NULL. TODO: should we fix this somehow? */
2800
2801
	if (table_to_alter == NULL) {
2802
		highest_id_so_far = 0;
2803
	} else {
2804
		highest_id_so_far = dict_table_get_highest_foreign_id(
2805
			table_to_alter);
2806
	}
2807
2808
	/* Scan for foreign key declarations in a loop */
2809
loop:
2810
	/* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
2811
2812
	ptr1 = dict_scan_to(ptr, "CONSTRAINT");
2813
	ptr2 = dict_scan_to(ptr, "FOREIGN");
2814
2815
	constraint_name = NULL;
2816
2817
	if (ptr1 < ptr2) {
2818
		/* The user may have specified a constraint name. Pick it so
2819
		that we can store 'databasename/constraintname' as the id of
2820
		of the constraint to system tables. */
2821
		ptr = ptr1;
2822
2823
		ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
2824
2825
		ut_a(success);
2826
2827
		if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
2828
			goto loop;
2829
		}
2830
2831
		while (my_isspace(cs, *ptr)) {
2832
			ptr++;
2833
		}
2834
2835
		/* read constraint name unless got "CONSTRAINT FOREIGN" */
2836
		if (ptr != ptr2) {
2837
			ptr = dict_scan_id(cs, ptr, heap,
2838
					   &constraint_name, FALSE, FALSE);
2839
		}
2840
	} else {
2841
		ptr = ptr2;
2842
	}
2843
2844
	if (*ptr == '\0') {
2845
		/* The proper way to reject foreign keys for temporary
2846
		tables would be to split the lexing and syntactical
2847
		analysis of foreign key clauses from the actual adding
2848
		of them, so that ha_innodb.cc could first parse the SQL
2849
		command, determine if there are any foreign keys, and
2850
		if so, immediately reject the command if the table is a
2851
		temporary one. For now, this kludge will work. */
2852
		if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
2853
2854
			return(DB_CANNOT_ADD_CONSTRAINT);
2855
		}
2856
2857
		/**********************************************************/
2858
		/* The following call adds the foreign key constraints
2859
		to the data dictionary system tables on disk */
2860
2861
		error = dict_create_add_foreigns_to_dictionary(
2862
			highest_id_so_far, table, trx);
2863
		return(error);
2864
	}
2865
2866
	start_of_latest_foreign = ptr;
2867
2868
	ptr = dict_accept(cs, ptr, "FOREIGN", &success);
2869
2870
	if (!success) {
2871
		goto loop;
2872
	}
2873
2874
	if (!my_isspace(cs, *ptr)) {
2875
		goto loop;
2876
	}
2877
2878
	ptr = dict_accept(cs, ptr, "KEY", &success);
2879
2880
	if (!success) {
2881
		goto loop;
2882
	}
2883
2884
	ptr = dict_accept(cs, ptr, "(", &success);
2885
2886
	if (!success) {
2887
		/* MySQL allows also an index id before the '('; we
2888
		skip it */
2889
		ptr = dict_skip_word(cs, ptr, &success);
2890
2891
		if (!success) {
2892
			dict_foreign_report_syntax_err(
2893
				name, start_of_latest_foreign, ptr);
2894
2895
			return(DB_CANNOT_ADD_CONSTRAINT);
2896
		}
2897
2898
		ptr = dict_accept(cs, ptr, "(", &success);
2899
2900
		if (!success) {
2901
			/* We do not flag a syntax error here because in an
2902
			ALTER TABLE we may also have DROP FOREIGN KEY abc */
2903
2904
			goto loop;
2905
		}
2906
	}
2907
2908
	i = 0;
2909
2910
	/* Scan the columns in the first list */
2911
col_loop1:
2912
	ut_a(i < (sizeof column_names) / sizeof *column_names);
2913
	ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
2914
			    heap, column_names + i);
2915
	if (!success) {
2916
		mutex_enter(&dict_foreign_err_mutex);
2917
		dict_foreign_error_report_low(ef, name);
2918
		fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
2919
			start_of_latest_foreign, ptr);
2920
		mutex_exit(&dict_foreign_err_mutex);
2921
2922
		return(DB_CANNOT_ADD_CONSTRAINT);
2923
	}
2924
2925
	i++;
2926
2927
	ptr = dict_accept(cs, ptr, ",", &success);
2928
2929
	if (success) {
2930
		goto col_loop1;
2931
	}
2932
2933
	ptr = dict_accept(cs, ptr, ")", &success);
2934
2935
	if (!success) {
2936
		dict_foreign_report_syntax_err(
2937
			name, start_of_latest_foreign, ptr);
2938
		return(DB_CANNOT_ADD_CONSTRAINT);
2939
	}
2940
2941
	/* Try to find an index which contains the columns
2942
	as the first fields and in the right order */
2943
2944
	index = dict_foreign_find_index(table, column_names, i,
2945
					NULL, TRUE, FALSE);
2946
2947
	if (!index) {
2948
		mutex_enter(&dict_foreign_err_mutex);
2949
		dict_foreign_error_report_low(ef, name);
2950
		fputs("There is no index in table ", ef);
2951
		ut_print_name(ef, NULL, TRUE, name);
2952
		fprintf(ef, " where the columns appear\n"
2953
			"as the first columns. Constraint:\n%s\n"
2954
			"See http://dev.mysql.com/doc/refman/5.1/en/"
2955
			"innodb-foreign-key-constraints.html\n"
2956
			"for correct foreign key definition.\n",
2957
			start_of_latest_foreign);
2958
		mutex_exit(&dict_foreign_err_mutex);
2959
2960
		return(DB_CANNOT_ADD_CONSTRAINT);
2961
	}
2962
	ptr = dict_accept(cs, ptr, "REFERENCES", &success);
2963
2964
	if (!success || !my_isspace(cs, *ptr)) {
2965
		dict_foreign_report_syntax_err(
2966
			name, start_of_latest_foreign, ptr);
2967
		return(DB_CANNOT_ADD_CONSTRAINT);
2968
	}
2969
2970
	/* Let us create a constraint struct */
2971
2972
	foreign = dict_mem_foreign_create();
2973
2974
	if (constraint_name) {
2975
		ulint	db_len;
2976
2977
		/* Catenate 'databasename/' to the constraint name specified
2978
		by the user: we conceive the constraint as belonging to the
2979
		same MySQL 'database' as the table itself. We store the name
2980
		to foreign->id. */
2981
2982
		db_len = dict_get_db_name_len(table->name);
2983
2984
		foreign->id = mem_heap_alloc(
2985
			foreign->heap, db_len + strlen(constraint_name) + 2);
2986
2987
		ut_memcpy(foreign->id, table->name, db_len);
2988
		foreign->id[db_len] = '/';
2989
		strcpy(foreign->id + db_len + 1, constraint_name);
2990
	}
2991
2992
	foreign->foreign_table = table;
2993
	foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
2994
						      table->name);
2995
	foreign->foreign_index = index;
2996
	foreign->n_fields = (unsigned int) i;
2997
	foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
2998
						    i * sizeof(void*));
2999
	for (i = 0; i < foreign->n_fields; i++) {
3000
		foreign->foreign_col_names[i] = mem_heap_strdup(
3001
			foreign->heap,
3002
			dict_table_get_col_name(table,
3003
						dict_col_get_no(columns[i])));
3004
	}
3005
3006
	ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
3007
				   &success, heap, &referenced_table_name);
3008
3009
	/* Note that referenced_table can be NULL if the user has suppressed
3010
	checking of foreign key constraints! */
3011
3012
	if (!success || (!referenced_table && trx->check_foreigns)) {
3013
		dict_foreign_free(foreign);
3014
3015
		mutex_enter(&dict_foreign_err_mutex);
3016
		dict_foreign_error_report_low(ef, name);
3017
		fprintf(ef, "%s:\nCannot resolve table name close to:\n"
3018
			"%s\n",
3019
			start_of_latest_foreign, ptr);
3020
		mutex_exit(&dict_foreign_err_mutex);
3021
3022
		return(DB_CANNOT_ADD_CONSTRAINT);
3023
	}
3024
3025
	ptr = dict_accept(cs, ptr, "(", &success);
3026
3027
	if (!success) {
3028
		dict_foreign_free(foreign);
3029
		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3030
					       ptr);
3031
		return(DB_CANNOT_ADD_CONSTRAINT);
3032
	}
3033
3034
	/* Scan the columns in the second list */
3035
	i = 0;
3036
3037
col_loop2:
3038
	ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
3039
			    heap, column_names + i);
3040
	i++;
3041
3042
	if (!success) {
3043
		dict_foreign_free(foreign);
3044
3045
		mutex_enter(&dict_foreign_err_mutex);
3046
		dict_foreign_error_report_low(ef, name);
3047
		fprintf(ef, "%s:\nCannot resolve column name close to:\n"
3048
			"%s\n",
3049
			start_of_latest_foreign, ptr);
3050
		mutex_exit(&dict_foreign_err_mutex);
3051
3052
		return(DB_CANNOT_ADD_CONSTRAINT);
3053
	}
3054
3055
	ptr = dict_accept(cs, ptr, ",", &success);
3056
3057
	if (success) {
3058
		goto col_loop2;
3059
	}
3060
3061
	ptr = dict_accept(cs, ptr, ")", &success);
3062
3063
	if (!success || foreign->n_fields != i) {
3064
		dict_foreign_free(foreign);
3065
3066
		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3067
					       ptr);
3068
		return(DB_CANNOT_ADD_CONSTRAINT);
3069
	}
3070
3071
	n_on_deletes = 0;
3072
	n_on_updates = 0;
3073
3074
scan_on_conditions:
3075
	/* Loop here as long as we can find ON ... conditions */
3076
3077
	ptr = dict_accept(cs, ptr, "ON", &success);
3078
3079
	if (!success) {
3080
3081
		goto try_find_index;
3082
	}
3083
3084
	ptr = dict_accept(cs, ptr, "DELETE", &success);
3085
3086
	if (!success) {
3087
		ptr = dict_accept(cs, ptr, "UPDATE", &success);
3088
3089
		if (!success) {
3090
			dict_foreign_free(foreign);
3091
3092
			dict_foreign_report_syntax_err(
3093
				name, start_of_latest_foreign, ptr);
3094
			return(DB_CANNOT_ADD_CONSTRAINT);
3095
		}
3096
3097
		is_on_delete = FALSE;
3098
		n_on_updates++;
3099
	} else {
3100
		is_on_delete = TRUE;
3101
		n_on_deletes++;
3102
	}
3103
3104
	ptr = dict_accept(cs, ptr, "RESTRICT", &success);
3105
3106
	if (success) {
3107
		goto scan_on_conditions;
3108
	}
3109
3110
	ptr = dict_accept(cs, ptr, "CASCADE", &success);
3111
3112
	if (success) {
3113
		if (is_on_delete) {
3114
			foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
3115
		} else {
3116
			foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
3117
		}
3118
3119
		goto scan_on_conditions;
3120
	}
3121
3122
	ptr = dict_accept(cs, ptr, "NO", &success);
3123
3124
	if (success) {
3125
		ptr = dict_accept(cs, ptr, "ACTION", &success);
3126
3127
		if (!success) {
3128
			dict_foreign_free(foreign);
3129
			dict_foreign_report_syntax_err(
3130
				name, start_of_latest_foreign, ptr);
3131
3132
			return(DB_CANNOT_ADD_CONSTRAINT);
3133
		}
3134
3135
		if (is_on_delete) {
3136
			foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
3137
		} else {
3138
			foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
3139
		}
3140
3141
		goto scan_on_conditions;
3142
	}
3143
3144
	ptr = dict_accept(cs, ptr, "SET", &success);
3145
3146
	if (!success) {
3147
		dict_foreign_free(foreign);
3148
		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3149
					       ptr);
3150
		return(DB_CANNOT_ADD_CONSTRAINT);
3151
	}
3152
3153
	ptr = dict_accept(cs, ptr, "NULL", &success);
3154
3155
	if (!success) {
3156
		dict_foreign_free(foreign);
3157
		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3158
					       ptr);
3159
		return(DB_CANNOT_ADD_CONSTRAINT);
3160
	}
3161
3162
	for (j = 0; j < foreign->n_fields; j++) {
3163
		if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
3164
		    & DATA_NOT_NULL) {
3165
3166
			/* It is not sensible to define SET NULL
3167
			if the column is not allowed to be NULL! */
3168
3169
			dict_foreign_free(foreign);
3170
3171
			mutex_enter(&dict_foreign_err_mutex);
3172
			dict_foreign_error_report_low(ef, name);
3173
			fprintf(ef, "%s:\n"
3174
				"You have defined a SET NULL condition"
3175
				" though some of the\n"
3176
				"columns are defined as NOT NULL.\n",
3177
				start_of_latest_foreign);
3178
			mutex_exit(&dict_foreign_err_mutex);
3179
3180
			return(DB_CANNOT_ADD_CONSTRAINT);
3181
		}
3182
	}
3183
3184
	if (is_on_delete) {
3185
		foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
3186
	} else {
3187
		foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
3188
	}
3189
3190
	goto scan_on_conditions;
3191
3192
try_find_index:
3193
	if (n_on_deletes > 1 || n_on_updates > 1) {
3194
		/* It is an error to define more than 1 action */
3195
3196
		dict_foreign_free(foreign);
3197
3198
		mutex_enter(&dict_foreign_err_mutex);
3199
		dict_foreign_error_report_low(ef, name);
3200
		fprintf(ef, "%s:\n"
3201
			"You have twice an ON DELETE clause"
3202
			" or twice an ON UPDATE clause.\n",
3203
			start_of_latest_foreign);
3204
		mutex_exit(&dict_foreign_err_mutex);
3205
3206
		return(DB_CANNOT_ADD_CONSTRAINT);
3207
	}
3208
3209
	/* Try to find an index which contains the columns as the first fields
3210
	and in the right order, and the types are the same as in
3211
	foreign->foreign_index */
3212
3213
	if (referenced_table) {
3214
		index = dict_foreign_find_index(referenced_table,
3215
						column_names, i,
3216
						foreign->foreign_index,
3217
						TRUE, FALSE);
3218
		if (!index) {
3219
			dict_foreign_free(foreign);
3220
			mutex_enter(&dict_foreign_err_mutex);
3221
			dict_foreign_error_report_low(ef, name);
3222
			fprintf(ef, "%s:\n"
3223
				"Cannot find an index in the"
3224
				" referenced table where the\n"
3225
				"referenced columns appear as the"
3226
				" first columns, or column types\n"
3227
				"in the table and the referenced table"
3228
				" do not match for constraint.\n"
3229
				"Note that the internal storage type of"
3230
				" ENUM and SET changed in\n"
3231
				"tables created with >= InnoDB-4.1.12,"
3232
				" and such columns in old tables\n"
3233
				"cannot be referenced by such columns"
3234
				" in new tables.\n"
3235
				"See http://dev.mysql.com/doc/refman/5.1/en/"
3236
				"innodb-foreign-key-constraints.html\n"
3237
				"for correct foreign key definition.\n",
3238
				start_of_latest_foreign);
3239
			mutex_exit(&dict_foreign_err_mutex);
3240
3241
			return(DB_CANNOT_ADD_CONSTRAINT);
3242
		}
3243
	} else {
3244
		ut_a(trx->check_foreigns == FALSE);
3245
		index = NULL;
3246
	}
3247
3248
	foreign->referenced_index = index;
3249
	foreign->referenced_table = referenced_table;
3250
3251
	foreign->referenced_table_name
3252
		= mem_heap_strdup(foreign->heap, referenced_table_name);
3253
3254
	foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
3255
						       i * sizeof(void*));
3256
	for (i = 0; i < foreign->n_fields; i++) {
3257
		foreign->referenced_col_names[i]
3258
			= mem_heap_strdup(foreign->heap, column_names[i]);
3259
	}
3260
3261
	/* We found an ok constraint definition: add to the lists */
3262
3263
	UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
3264
3265
	if (referenced_table) {
3266
		UT_LIST_ADD_LAST(referenced_list,
3267
				 referenced_table->referenced_list,
3268
				 foreign);
3269
	}
3270
3271
	goto loop;
3272
}
3273
3274
/**************************************************************************
3275
Determines whether a string starts with the specified keyword. */
3276
3277
ibool
3278
dict_str_starts_with_keyword(
3279
/*=========================*/
3280
					/* out: TRUE if str starts
3281
					with keyword */
3282
	void*		mysql_thd,	/* in: MySQL thread handle */
3283
	const char*	str,		/* in: string to scan for keyword */
3284
	const char*	keyword)	/* in: keyword to look for */
3285
{
3286
	struct charset_info_st*	cs	= innobase_get_charset(mysql_thd);
3287
	ibool			success;
3288
3289
	dict_accept(cs, str, keyword, &success);
3290
	return(success);
3291
}
3292
3293
/*************************************************************************
3294
Scans a table create SQL string and adds to the data dictionary the foreign
3295
key constraints declared in the string. This function should be called after
3296
the indexes for a table have been created. Each foreign key constraint must
3297
be accompanied with indexes in both participating tables. The indexes are
3298
allowed to contain more fields than mentioned in the constraint. */
3299
3300
ulint
3301
dict_create_foreign_constraints(
3302
/*============================*/
3303
					/* out: error code or DB_SUCCESS */
3304
	trx_t*		trx,		/* in: transaction */
3305
	const char*	sql_string,	/* in: table create statement where
3306
					foreign keys are declared like:
3307
					FOREIGN KEY (a, b) REFERENCES
3308
					table2(c, d), table2 can be written
3309
					also with the database
3310
					name before it: test.table2; the
3311
					default database id the database of
3312
					parameter name */
3313
	const char*	name,		/* in: table full name in the
3314
					normalized form
3315
					database_name/table_name */
3316
	ibool		reject_fks)	/* in: if TRUE, fail with error
3317
					code DB_CANNOT_ADD_CONSTRAINT if
3318
					any foreign keys are found. */
3319
{
3320
	char*			str;
3321
	ulint			err;
3322
	mem_heap_t*		heap;
3323
3324
	ut_a(trx);
3325
	ut_a(trx->mysql_thd);
3326
3327
	str = dict_strip_comments(sql_string);
3328
	heap = mem_heap_create(10000);
3329
3330
	err = dict_create_foreign_constraints_low(
3331
		trx, heap, innobase_get_charset(trx->mysql_thd), str, name,
3332
		reject_fks);
3333
3334
	mem_heap_free(heap);
3335
	mem_free(str);
3336
3337
	return(err);
3338
}
3339
3340
/**************************************************************************
3341
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
3342
3343
ulint
3344
dict_foreign_parse_drop_constraints(
3345
/*================================*/
3346
						/* out: DB_SUCCESS or
3347
						DB_CANNOT_DROP_CONSTRAINT if
3348
						syntax error or the constraint
3349
						id does not match */
3350
	mem_heap_t*	heap,			/* in: heap from which we can
3351
						allocate memory */
3352
	trx_t*		trx,			/* in: transaction */
3353
	dict_table_t*	table,			/* in: table */
3354
	ulint*		n,			/* out: number of constraints
3355
						to drop */
3356
	const char***	constraints_to_drop)	/* out: id's of the
3357
						constraints to drop */
3358
{
3359
	dict_foreign_t*		foreign;
3360
	ibool			success;
3361
	char*			str;
3362
	const char*		ptr;
3363
	const char*		id;
3364
	FILE*			ef	= dict_foreign_err_file;
3365
	struct charset_info_st*	cs;
3366
3367
	ut_a(trx);
3368
	ut_a(trx->mysql_thd);
3369
3370
	cs = innobase_get_charset(trx->mysql_thd);
3371
3372
	*n = 0;
3373
3374
	*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
3375
3376
	str = dict_strip_comments(*(trx->mysql_query_str));
3377
	ptr = str;
3378
3379
	ut_ad(mutex_own(&(dict_sys->mutex)));
3380
loop:
3381
	ptr = dict_scan_to(ptr, "DROP");
3382
3383
	if (*ptr == '\0') {
3384
		mem_free(str);
3385
3386
		return(DB_SUCCESS);
3387
	}
3388
3389
	ptr = dict_accept(cs, ptr, "DROP", &success);
3390
3391
	if (!my_isspace(cs, *ptr)) {
3392
3393
		goto loop;
3394
	}
3395
3396
	ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3397
3398
	if (!success || !my_isspace(cs, *ptr)) {
3399
3400
		goto loop;
3401
	}
3402
3403
	ptr = dict_accept(cs, ptr, "KEY", &success);
3404
3405
	if (!success) {
3406
3407
		goto syntax_error;
3408
	}
3409
3410
	ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
3411
3412
	if (id == NULL) {
3413
3414
		goto syntax_error;
3415
	}
3416
3417
	ut_a(*n < 1000);
3418
	(*constraints_to_drop)[*n] = id;
3419
	(*n)++;
3420
3421
	/* Look for the given constraint id */
3422
3423
	foreign = UT_LIST_GET_FIRST(table->foreign_list);
3424
3425
	while (foreign != NULL) {
3426
		if (0 == strcmp(foreign->id, id)
3427
		    || (strchr(foreign->id, '/')
3428
			&& 0 == strcmp(id,
3429
				       dict_remove_db_name(foreign->id)))) {
3430
			/* Found */
3431
			break;
3432
		}
3433
3434
		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3435
	}
3436
3437
	if (foreign == NULL) {
3438
		mutex_enter(&dict_foreign_err_mutex);
3439
		rewind(ef);
3440
		ut_print_timestamp(ef);
3441
		fputs(" Error in dropping of a foreign key constraint"
3442
		      " of table ", ef);
3443
		ut_print_name(ef, NULL, TRUE, table->name);
3444
		fputs(",\n"
3445
		      "in SQL command\n", ef);
3446
		fputs(str, ef);
3447
		fputs("\nCannot find a constraint with the given id ", ef);
3448
		ut_print_name(ef, NULL, FALSE, id);
3449
		fputs(".\n", ef);
3450
		mutex_exit(&dict_foreign_err_mutex);
3451
3452
		mem_free(str);
3453
3454
		return(DB_CANNOT_DROP_CONSTRAINT);
3455
	}
3456
3457
	goto loop;
3458
3459
syntax_error:
3460
	mutex_enter(&dict_foreign_err_mutex);
3461
	rewind(ef);
3462
	ut_print_timestamp(ef);
3463
	fputs(" Syntax error in dropping of a"
3464
	      " foreign key constraint of table ", ef);
3465
	ut_print_name(ef, NULL, TRUE, table->name);
3466
	fprintf(ef, ",\n"
3467
		"close to:\n%s\n in SQL command\n%s\n", ptr, str);
3468
	mutex_exit(&dict_foreign_err_mutex);
3469
3470
	mem_free(str);
3471
3472
	return(DB_CANNOT_DROP_CONSTRAINT);
3473
}
3474
#endif /* UNIV_HOTBACKUP */
3475
3476
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
3477
3478
#ifdef UNIV_DEBUG
3479
/**************************************************************************
3480
Returns an index object if it is found in the dictionary cache. */
3481
3482
dict_index_t*
3483
dict_index_get_if_in_cache(
3484
/*=======================*/
3485
				/* out: index, NULL if not found */
3486
	dulint	index_id)	/* in: index id */
3487
{
3488
	dict_index_t*	index;
3489
3490
	if (dict_sys == NULL) {
3491
		return(NULL);
3492
	}
3493
3494
	mutex_enter(&(dict_sys->mutex));
3495
3496
	index = dict_index_find_on_id_low(index_id);
3497
3498
	mutex_exit(&(dict_sys->mutex));
3499
3500
	return(index);
3501
}
3502
#endif /* UNIV_DEBUG */
3503
3504
#ifdef UNIV_DEBUG
3505
/**************************************************************************
3506
Checks that a tuple has n_fields_cmp value in a sensible range, so that
3507
no comparison can occur with the page number field in a node pointer. */
3508
3509
ibool
3510
dict_index_check_search_tuple(
3511
/*==========================*/
3512
				/* out: TRUE if ok */
3513
	dict_index_t*	index,	/* in: index tree */
3514
	dtuple_t*	tuple)	/* in: tuple used in a search */
3515
{
3516
	ut_a(index);
3517
	ut_a(dtuple_get_n_fields_cmp(tuple)
3518
	     <= dict_index_get_n_unique_in_tree(index));
3519
	return(TRUE);
3520
}
3521
#endif /* UNIV_DEBUG */
3522
3523
/**************************************************************************
3524
Builds a node pointer out of a physical record and a page number. */
3525
3526
dtuple_t*
3527
dict_index_build_node_ptr(
3528
/*======================*/
3529
				/* out, own: node pointer */
3530
	dict_index_t*	index,	/* in: index tree */
3531
	rec_t*		rec,	/* in: record for which to build node
3532
				pointer */
3533
	ulint		page_no,/* in: page number to put in node pointer */
3534
	mem_heap_t*	heap,	/* in: memory heap where pointer created */
3535
	ulint		level)	/* in: level of rec in tree: 0 means leaf
3536
				level */
3537
{
3538
	dtuple_t*	tuple;
3539
	dfield_t*	field;
3540
	byte*		buf;
3541
	ulint		n_unique;
3542
3543
	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3544
		/* In a universal index tree, we take the whole record as
3545
		the node pointer if the record is on the leaf level,
3546
		on non-leaf levels we remove the last field, which
3547
		contains the page number of the child page */
3548
3549
		ut_a(!dict_table_is_comp(index->table));
3550
		n_unique = rec_get_n_fields_old(rec);
3551
3552
		if (level > 0) {
3553
			ut_a(n_unique > 1);
3554
			n_unique--;
3555
		}
3556
	} else {
3557
		n_unique = dict_index_get_n_unique_in_tree(index);
3558
	}
3559
3560
	tuple = dtuple_create(heap, n_unique + 1);
3561
3562
	/* When searching in the tree for the node pointer, we must not do
3563
	comparison on the last field, the page number field, as on upper
3564
	levels in the tree there may be identical node pointers with a
3565
	different page number; therefore, we set the n_fields_cmp to one
3566
	less: */
3567
3568
	dtuple_set_n_fields_cmp(tuple, n_unique);
3569
3570
	dict_index_copy_types(tuple, index, n_unique);
3571
3572
	buf = mem_heap_alloc(heap, 4);
3573
3574
	mach_write_to_4(buf, page_no);
3575
3576
	field = dtuple_get_nth_field(tuple, n_unique);
3577
	dfield_set_data(field, buf, 4);
3578
3579
	dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
3580
3581
	rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
3582
	dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
3583
			     | REC_STATUS_NODE_PTR);
3584
3585
	ut_ad(dtuple_check_typed(tuple));
3586
3587
	return(tuple);
3588
}
3589
3590
/**************************************************************************
3591
Copies an initial segment of a physical record, long enough to specify an
3592
index entry uniquely. */
3593
3594
rec_t*
3595
dict_index_copy_rec_order_prefix(
3596
/*=============================*/
3597
				/* out: pointer to the prefix record */
3598
	dict_index_t*	index,	/* in: index tree */
3599
	rec_t*		rec,	/* in: record for which to copy prefix */
3600
	ulint*		n_fields,/* out: number of fields copied */
3601
	byte**		buf,	/* in/out: memory buffer for the copied prefix,
3602
				or NULL */
3603
	ulint*		buf_size)/* in/out: buffer size */
3604
{
3605
	ulint		n;
3606
3607
	UNIV_PREFETCH_R(rec);
3608
3609
	if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
3610
		ut_a(!dict_table_is_comp(index->table));
3611
		n = rec_get_n_fields_old(rec);
3612
	} else {
3613
		n = dict_index_get_n_unique_in_tree(index);
3614
	}
3615
3616
	*n_fields = n;
3617
	return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
3618
}
3619
3620
/**************************************************************************
3621
Builds a typed data tuple out of a physical record. */
3622
3623
dtuple_t*
3624
dict_index_build_data_tuple(
3625
/*========================*/
3626
				/* out, own: data tuple */
3627
	dict_index_t*	index,	/* in: index tree */
3628
	rec_t*		rec,	/* in: record for which to build data tuple */
3629
	ulint		n_fields,/* in: number of data fields */
3630
	mem_heap_t*	heap)	/* in: memory heap where tuple created */
3631
{
3632
	dtuple_t*	tuple;
3633
3634
	ut_ad(dict_table_is_comp(index->table)
3635
	      || n_fields <= rec_get_n_fields_old(rec));
3636
3637
	tuple = dtuple_create(heap, n_fields);
3638
3639
	dict_index_copy_types(tuple, index, n_fields);
3640
3641
	rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
3642
3643
	ut_ad(dtuple_check_typed(tuple));
3644
3645
	return(tuple);
3646
}
3647
3648
/*************************************************************************
3649
Calculates the minimum record length in an index. */
3650
3651
ulint
3652
dict_index_calc_min_rec_len(
3653
/*========================*/
3654
	dict_index_t*	index)	/* in: index */
3655
{
3656
	ulint	sum	= 0;
3657
	ulint	i;
3658
3659
	if (dict_table_is_comp(index->table)) {
3660
		ulint nullable = 0;
3661
		sum = REC_N_NEW_EXTRA_BYTES;
3662
		for (i = 0; i < dict_index_get_n_fields(index); i++) {
3663
			const dict_col_t*	col
3664
				= dict_index_get_nth_col(index, i);
3665
			ulint	size = dict_col_get_fixed_size(col);
3666
			sum += size;
3667
			if (!size) {
3668
				size = col->len;
3669
				sum += size < 128 ? 1 : 2;
3670
			}
3671
			if (!(col->prtype & DATA_NOT_NULL)) {
3672
				nullable++;
3673
			}
3674
		}
3675
3676
		/* round the NULL flags up to full bytes */
3677
		sum += UT_BITS_IN_BYTES(nullable);
3678
3679
		return(sum);
3680
	}
3681
3682
	for (i = 0; i < dict_index_get_n_fields(index); i++) {
3683
		sum += dict_col_get_fixed_size(
3684
			dict_index_get_nth_col(index, i));
3685
	}
3686
3687
	if (sum > 127) {
3688
		sum += 2 * dict_index_get_n_fields(index);
3689
	} else {
3690
		sum += dict_index_get_n_fields(index);
3691
	}
3692
3693
	sum += REC_N_OLD_EXTRA_BYTES;
3694
3695
	return(sum);
3696
}
3697
3698
/*************************************************************************
3699
Calculates new estimates for table and index statistics. The statistics
3700
are used in query optimization. */
3701
3702
void
3703
dict_update_statistics_low(
3704
/*=======================*/
3705
	dict_table_t*	table,		/* in: table */
3706
	ibool		has_dict_mutex __attribute__((unused)))
3707
					/* in: TRUE if the caller has the
3708
					dictionary mutex */
3709
{
3710
	dict_index_t*	index;
3711
	ulint		size;
3712
	ulint		sum_of_index_sizes	= 0;
3713
3714
	if (table->ibd_file_missing) {
3715
		ut_print_timestamp(stderr);
3716
		fprintf(stderr,
3717
			"  InnoDB: cannot calculate statistics for table %s\n"
3718
			"InnoDB: because the .ibd file is missing.  For help,"
3719
			" please refer to\n"
3720
			"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3721
			"innodb-troubleshooting.html\n",
3722
			table->name);
3723
3724
		return;
3725
	}
3726
3727
	/* If we have set a high innodb_force_recovery level, do not calculate
3728
	statistics, as a badly corrupted index can cause a crash in it. */
3729
3730
	if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
3731
3732
		return;
3733
	}
3734
3735
	/* Find out the sizes of the indexes and how many different values
3736
	for the key they approximately have */
3737
3738
	index = dict_table_get_first_index(table);
3739
3740
	if (index == NULL) {
3741
		/* Table definition is corrupt */
3742
3743
		return;
3744
	}
3745
3746
	while (index) {
3747
		size = btr_get_size(index, BTR_TOTAL_SIZE);
3748
3749
		index->stat_index_size = size;
3750
3751
		sum_of_index_sizes += size;
3752
3753
		size = btr_get_size(index, BTR_N_LEAF_PAGES);
3754
3755
		if (size == 0) {
3756
			/* The root node of the tree is a leaf */
3757
			size = 1;
3758
		}
3759
3760
		index->stat_n_leaf_pages = size;
3761
3762
		btr_estimate_number_of_different_key_vals(index);
3763
3764
		index = dict_table_get_next_index(index);
3765
	}
3766
3767
	index = dict_table_get_first_index(table);
3768
3769
	table->stat_n_rows = index->stat_n_diff_key_vals[
3770
		dict_index_get_n_unique(index)];
3771
3772
	table->stat_clustered_index_size = index->stat_index_size;
3773
3774
	table->stat_sum_of_other_index_sizes = sum_of_index_sizes
3775
		- index->stat_index_size;
3776
3777
	table->stat_initialized = TRUE;
3778
3779
	table->stat_modified_counter = 0;
3780
}
3781
3782
/*************************************************************************
3783
Calculates new estimates for table and index statistics. The statistics
3784
are used in query optimization. */
3785
3786
void
3787
dict_update_statistics(
3788
/*===================*/
3789
	dict_table_t*	table)	/* in: table */
3790
{
3791
	dict_update_statistics_low(table, FALSE);
3792
}
3793
3794
/**************************************************************************
3795
A noninlined version of dict_table_get_low. */
3796
3797
dict_table_t*
3798
dict_table_get_low_noninlined(
3799
/*==========================*/
3800
					/* out: table, NULL if not found */
3801
	const char*	table_name)	/* in: table name */
3802
{
3803
	return(dict_table_get_low(table_name));
3804
}
3805
3806
/**************************************************************************
3807
Prints info of a foreign key constraint. */
3808
static
3809
void
3810
dict_foreign_print_low(
3811
/*===================*/
3812
	dict_foreign_t*	foreign)	/* in: foreign key constraint */
3813
{
3814
	ulint	i;
3815
3816
	ut_ad(mutex_own(&(dict_sys->mutex)));
3817
3818
	fprintf(stderr, "  FOREIGN KEY CONSTRAINT %s: %s (",
3819
		foreign->id, foreign->foreign_table_name);
3820
3821
	for (i = 0; i < foreign->n_fields; i++) {
3822
		fprintf(stderr, " %s", foreign->foreign_col_names[i]);
3823
	}
3824
3825
	fprintf(stderr, " )\n"
3826
		"             REFERENCES %s (",
3827
		foreign->referenced_table_name);
3828
3829
	for (i = 0; i < foreign->n_fields; i++) {
3830
		fprintf(stderr, " %s", foreign->referenced_col_names[i]);
3831
	}
3832
3833
	fputs(" )\n", stderr);
3834
}
3835
3836
/**************************************************************************
3837
Prints a table data. */
3838
3839
void
3840
dict_table_print(
3841
/*=============*/
3842
	dict_table_t*	table)	/* in: table */
3843
{
3844
	mutex_enter(&(dict_sys->mutex));
3845
	dict_table_print_low(table);
3846
	mutex_exit(&(dict_sys->mutex));
3847
}
3848
3849
/**************************************************************************
3850
Prints a table data when we know the table name. */
3851
3852
void
3853
dict_table_print_by_name(
3854
/*=====================*/
3855
	const char*	name)
3856
{
3857
	dict_table_t*	table;
3858
3859
	mutex_enter(&(dict_sys->mutex));
3860
3861
	table = dict_table_get_low(name);
3862
3863
	ut_a(table);
3864
3865
	dict_table_print_low(table);
3866
	mutex_exit(&(dict_sys->mutex));
3867
}
3868
3869
/**************************************************************************
3870
Prints a table data. */
3871
3872
void
3873
dict_table_print_low(
3874
/*=================*/
3875
	dict_table_t*	table)	/* in: table */
3876
{
3877
	dict_index_t*	index;
3878
	dict_foreign_t*	foreign;
3879
	ulint		i;
3880
3881
	ut_ad(mutex_own(&(dict_sys->mutex)));
3882
3883
	dict_update_statistics_low(table, TRUE);
3884
3885
	fprintf(stderr,
3886
		"--------------------------------------\n"
3887
		"TABLE: name %s, id %lu %lu, columns %lu, indexes %lu,"
3888
		" appr.rows %lu\n"
3889
		"  COLUMNS: ",
3890
		table->name,
3891
		(ulong) ut_dulint_get_high(table->id),
3892
		(ulong) ut_dulint_get_low(table->id),
3893
		(ulong) table->n_cols,
3894
		(ulong) UT_LIST_GET_LEN(table->indexes),
3895
		(ulong) table->stat_n_rows);
3896
3897
	for (i = 0; i + 1 < (ulint) table->n_cols; i++) {
3898
		dict_col_print_low(table, dict_table_get_nth_col(table, i));
3899
		fputs("; ", stderr);
3900
	}
3901
3902
	putc('\n', stderr);
3903
3904
	index = UT_LIST_GET_FIRST(table->indexes);
3905
3906
	while (index != NULL) {
3907
		dict_index_print_low(index);
3908
		index = UT_LIST_GET_NEXT(indexes, index);
3909
	}
3910
3911
	foreign = UT_LIST_GET_FIRST(table->foreign_list);
3912
3913
	while (foreign != NULL) {
3914
		dict_foreign_print_low(foreign);
3915
		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3916
	}
3917
3918
	foreign = UT_LIST_GET_FIRST(table->referenced_list);
3919
3920
	while (foreign != NULL) {
3921
		dict_foreign_print_low(foreign);
3922
		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3923
	}
3924
}
3925
3926
/**************************************************************************
3927
Prints a column data. */
3928
static
3929
void
3930
dict_col_print_low(
3931
/*===============*/
3932
	const dict_table_t*	table,	/* in: table */
3933
	const dict_col_t*	col)	/* in: column */
3934
{
3935
	dtype_t	type;
3936
3937
	ut_ad(mutex_own(&(dict_sys->mutex)));
3938
3939
	dict_col_copy_type(col, &type);
3940
	fprintf(stderr, "%s: ", dict_table_get_col_name(table,
3941
							dict_col_get_no(col)));
3942
3943
	dtype_print(&type);
3944
}
3945
3946
/**************************************************************************
3947
Prints an index data. */
3948
static
3949
void
3950
dict_index_print_low(
3951
/*=================*/
3952
	dict_index_t*	index)	/* in: index */
3953
{
3954
	ib_longlong	n_vals;
3955
	ulint		i;
3956
3957
	ut_ad(mutex_own(&(dict_sys->mutex)));
3958
3959
	if (index->n_user_defined_cols > 0) {
3960
		n_vals = index->stat_n_diff_key_vals[
3961
			index->n_user_defined_cols];
3962
	} else {
3963
		n_vals = index->stat_n_diff_key_vals[1];
3964
	}
3965
3966
	fprintf(stderr,
3967
		"  INDEX: name %s, id %lu %lu, fields %lu/%lu,"
3968
		" uniq %lu, type %lu\n"
3969
		"   root page %lu, appr.key vals %lu,"
3970
		" leaf pages %lu, size pages %lu\n"
3971
		"   FIELDS: ",
3972
		index->name,
3973
		(ulong) ut_dulint_get_high(index->id),
3974
		(ulong) ut_dulint_get_low(index->id),
3975
		(ulong) index->n_user_defined_cols,
3976
		(ulong) index->n_fields,
3977
		(ulong) index->n_uniq,
3978
		(ulong) index->type,
3979
		(ulong) index->page,
3980
		(ulong) n_vals,
3981
		(ulong) index->stat_n_leaf_pages,
3982
		(ulong) index->stat_index_size);
3983
3984
	for (i = 0; i < index->n_fields; i++) {
3985
		dict_field_print_low(dict_index_get_nth_field(index, i));
3986
	}
3987
3988
	putc('\n', stderr);
3989
3990
#ifdef UNIV_BTR_PRINT
3991
	btr_print_size(index);
3992
3993
	btr_print_index(index, 7);
3994
#endif /* UNIV_BTR_PRINT */
3995
}
3996
3997
/**************************************************************************
3998
Prints a field data. */
3999
static
4000
void
4001
dict_field_print_low(
4002
/*=================*/
4003
	dict_field_t*	field)	/* in: field */
4004
{
4005
	ut_ad(mutex_own(&(dict_sys->mutex)));
4006
4007
	fprintf(stderr, " %s", field->name);
4008
4009
	if (field->prefix_len != 0) {
4010
		fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
4011
	}
4012
}
4013
4014
/**************************************************************************
4015
Outputs info on a foreign key of a table in a format suitable for
4016
CREATE TABLE. */
4017
4018
void
4019
dict_print_info_on_foreign_key_in_create_format(
4020
/*============================================*/
4021
	FILE*		file,		/* in: file where to print */
4022
	trx_t*		trx,		/* in: transaction */
4023
	dict_foreign_t*	foreign,	/* in: foreign key constraint */
4024
	ibool		add_newline)	/* in: whether to add a newline */
4025
{
4026
	const char*	stripped_id;
4027
	ulint	i;
4028
4029
	if (strchr(foreign->id, '/')) {
4030
		/* Strip the preceding database name from the constraint id */
4031
		stripped_id = foreign->id + 1
4032
			+ dict_get_db_name_len(foreign->id);
4033
	} else {
4034
		stripped_id = foreign->id;
4035
	}
4036
4037
	putc(',', file);
4038
4039
	if (add_newline) {
4040
		/* SHOW CREATE TABLE wants constraints each printed nicely
4041
		on its own line, while error messages want no newlines
4042
		inserted. */
4043
		fputs("\n ", file);
4044
	}
4045
4046
	fputs(" CONSTRAINT ", file);
4047
	ut_print_name(file, trx, FALSE, stripped_id);
4048
	fputs(" FOREIGN KEY (", file);
4049
4050
	for (i = 0;;) {
4051
		ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
4052
		if (++i < foreign->n_fields) {
4053
			fputs(", ", file);
4054
		} else {
4055
			break;
4056
		}
4057
	}
4058
4059
	fputs(") REFERENCES ", file);
4060
4061
	if (dict_tables_have_same_db(foreign->foreign_table_name,
4062
				     foreign->referenced_table_name)) {
4063
		/* Do not print the database name of the referenced table */
4064
		ut_print_name(file, trx, TRUE,
4065
			      dict_remove_db_name(
4066
				      foreign->referenced_table_name));
4067
	} else {
4068
		ut_print_name(file, trx, TRUE,
4069
			      foreign->referenced_table_name);
4070
	}
4071
4072
	putc(' ', file);
4073
	putc('(', file);
4074
4075
	for (i = 0;;) {
4076
		ut_print_name(file, trx, FALSE,
4077
			      foreign->referenced_col_names[i]);
4078
		if (++i < foreign->n_fields) {
4079
			fputs(", ", file);
4080
		} else {
4081
			break;
4082
		}
4083
	}
4084
4085
	putc(')', file);
4086
4087
	if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
4088
		fputs(" ON DELETE CASCADE", file);
4089
	}
4090
4091
	if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
4092
		fputs(" ON DELETE SET NULL", file);
4093
	}
4094
4095
	if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4096
		fputs(" ON DELETE NO ACTION", file);
4097
	}
4098
4099
	if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4100
		fputs(" ON UPDATE CASCADE", file);
4101
	}
4102
4103
	if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4104
		fputs(" ON UPDATE SET NULL", file);
4105
	}
4106
4107
	if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4108
		fputs(" ON UPDATE NO ACTION", file);
4109
	}
4110
}
4111
4112
/**************************************************************************
4113
Outputs info on foreign keys of a table. */
4114
4115
void
4116
dict_print_info_on_foreign_keys(
4117
/*============================*/
4118
	ibool		create_table_format, /* in: if TRUE then print in
4119
				a format suitable to be inserted into
4120
				a CREATE TABLE, otherwise in the format
4121
				of SHOW TABLE STATUS */
4122
	FILE*		file,	/* in: file where to print */
4123
	trx_t*		trx,	/* in: transaction */
4124
	dict_table_t*	table)	/* in: table */
4125
{
4126
	dict_foreign_t*	foreign;
4127
4128
	mutex_enter(&(dict_sys->mutex));
4129
4130
	foreign = UT_LIST_GET_FIRST(table->foreign_list);
4131
4132
	if (foreign == NULL) {
4133
		mutex_exit(&(dict_sys->mutex));
4134
4135
		return;
4136
	}
4137
4138
	while (foreign != NULL) {
4139
		if (create_table_format) {
4140
			dict_print_info_on_foreign_key_in_create_format(
4141
				file, trx, foreign, TRUE);
4142
		} else {
4143
			ulint	i;
4144
			fputs("; (", file);
4145
4146
			for (i = 0; i < foreign->n_fields; i++) {
4147
				if (i) {
4148
					putc(' ', file);
4149
				}
4150
4151
				ut_print_name(file, trx, FALSE,
4152
					      foreign->foreign_col_names[i]);
4153
			}
4154
4155
			fputs(") REFER ", file);
4156
			ut_print_name(file, trx, TRUE,
4157
				      foreign->referenced_table_name);
4158
			putc('(', file);
4159
4160
			for (i = 0; i < foreign->n_fields; i++) {
4161
				if (i) {
4162
					putc(' ', file);
4163
				}
4164
				ut_print_name(
4165
					file, trx, FALSE,
4166
					foreign->referenced_col_names[i]);
4167
			}
4168
4169
			putc(')', file);
4170
4171
			if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
4172
				fputs(" ON DELETE CASCADE", file);
4173
			}
4174
4175
			if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
4176
				fputs(" ON DELETE SET NULL", file);
4177
			}
4178
4179
			if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4180
				fputs(" ON DELETE NO ACTION", file);
4181
			}
4182
4183
			if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4184
				fputs(" ON UPDATE CASCADE", file);
4185
			}
4186
4187
			if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4188
				fputs(" ON UPDATE SET NULL", file);
4189
			}
4190
4191
			if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4192
				fputs(" ON UPDATE NO ACTION", file);
4193
			}
4194
		}
4195
4196
		foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4197
	}
4198
4199
	mutex_exit(&(dict_sys->mutex));
4200
}
4201
4202
/************************************************************************
4203
Displays the names of the index and the table. */
4204
void
4205
dict_index_name_print(
4206
/*==================*/
4207
	FILE*			file,	/* in: output stream */
4208
	trx_t*			trx,	/* in: transaction */
4209
	const dict_index_t*	index)	/* in: index to print */
4210
{
4211
	fputs("index ", file);
4212
	ut_print_name(file, trx, FALSE, index->name);
4213
	fputs(" of table ", file);
4214
	ut_print_name(file, trx, TRUE, index->table_name);
4215
}