1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

Applied innodb-5.1-ss594 snapshot.

Fixed BUG#19542 "InnoDB doesn't increase the Handler_read_prev couter".
 Fixed BUG#19609 "Case sensitivity of innodb_data_file_path gives stupid error".
 Fixed BUG#19727 "InnoDB crashed server and crashed tables are ot recoverable".
 Also:
 * Remove remnants of the obsolete concept of memoryfixing tables and indexes.
 * Remove unused dict_table_LRU_trim().
 * Remove unused 'trx' parameter from dict_table_get_on_id_low(),
   dict_table_get(), dict_table_get_and_increment_handle_count().
 * Add a normal linked list implementation.
 * Add a work queue implementation.
 * Add 'level' parameter to mutex_create() and rw_lock_create().
   Remove mutex_set_level() and rw_lock_set_level().
 * Rename SYNC_LEVEL_NONE to SYNC_LEVEL_VARYING.
 * Add support for bound ids in InnoDB's parser.
 * Define UNIV_BTR_DEBUG for enabling consistency checks of
   FIL_PAGE_NEXT and FIL_PAGE_PREV when accessing sibling
   pages of B-tree indexes.
   btr_validate_level(): Check the validity of the doubly linked
   list formed by FIL_PAGE_NEXT and FIL_PAGE_PREV.
 * Adapt InnoDB to the new tablename to filename encoding in MySQL 5.1.
   ut_print_name(), ut_print_name1(): Add parameter 'table_id' for
   distinguishing names of tables from other identifiers.
   New: innobase_convert_from_table_id(), innobase_convert_from_id(),
        innobase_convert_from_filename(), innobase_get_charset.
   dict_accept(), dict_scan_id(), dict_scan_col(), dict_scan_table_name(),
   dict_skip_word(), dict_create_foreign_constraints_low(): Add
   parameter 'cs' so that isspace() can be replaced with my_isspace(),
   whose operation depends on the connection character set.
   dict_scan_id(): Convert identifier to UTF-8.
   dict_str_starts_with_keyword(): New extern function, to replace
   dict_accept() in row_search_for_mysql().
   mysql_get_identifier_quote_char(): Replaced with innobase_print_identifier().
   ha_innobase::create(): Remove the thd->convert_strin() call. Pass the
   statement to InnoDB in the connection character set and let InnoDB
   convert the identifier to UTF-8.
 * Add max_row_size to dict_table_t.
 * btr0cur.c
   btr_copy_externally_stored_field(): Only set the 'offset' variable
   when needed.
 * buf0buf.c
   buf_page_io_complete(): Write to the error log if the page number or
   the space id o the disk do not match those in memory. Also write to
   the error log if a page was read from the doublewrite buffer. The
   doublewrite buffer should be only read by the lower-level function
   fil_io() at database startup.
 * dict0dict.c
   dict_scan_table_name(): Remove fallback to differently encoded name
   when the table is not found. The encoding is handled at a higher level.
 * ha_innodb.cc
   Increment statistic counter in ha_innobase::index_prev() (bug 19542).
   Add innobase_convert_string wrapper function and a new file
   ha_prototypes.h.
   innobase_print_identifier(): Remove TODO comment before calling
   get_quote_char_for_identifier(). That function apparently assumes
   the identifier to be encoded in UTF-8.
 * ibuf0ibuf.c|h
   ibuf_count_get(), ibuf_counts[], ibuf_count_inited(): Define these
   only #ifdef UNIV_IBUF_DEBUG. Previously, when compiled without
   UNIV_IBUF_DEBUG, invoking ibuf_count_get() would crash InnoDB.
   The function is only being called #ifdef UNIV_IBUF_DEBUG.
 * innodb.result
   Adjust the results for changes in the foreign key error messages.
 * mem0mem.c|h
   New: mem_heap_dup(), mem_heap_printf(), mem_heap_cat().
 * os0file.c
   Check the page trailers also after writing to disk. This improves
   chances of diagnosing bug 18886.
   os_file_check_page_trailers(): New function for checking that the
   two copies of the LSN stamped on the page match.
   os_aio_simulated_handle(): Call os_file_check_page_trailers()
   before and after os_file_write().
 * row0mysql.c
   Move trx_commit_for_mysql(trx) calls before calls to
   row_mysql_unlock_data_dictionary(trx) (bug 19727).
 * row0sel.c
   row_fetch_print(): Handle SQL NULL values without crashing.
   row_sel_store_mysql_rec(): Remove useless call to rec_get_nth_field
   when handling an externally stored column.
   Fetch externally stored fields when using InnoDB's internal SQL
   parser.
   Optimize BLOB selects by using prebuilt->blob_heap directly instead
   of first reading BLOB data to a temporary heap and then copying it
   to prebuilt->blob_heap.
 * srv0srv.c
   srv_master_thread(): Remove unreachable code.
 * srv0start.c
   srv_parse_data_file_paths_and_sizes(): Accept lower-case 'm' and
   'g' as abbreviations of megabyte and gigabyte (bug 19609).
   srv_parse_megabytes(): New fuction.
 * ut0dbg.c|h
   Implement InnoDB assertions (ut_a and ut_error) with abort() when
   the code is compiled with GCC 3 or later on other platforms than
   Windows or Netware. Also disable the variable ut_dbg_stop_threads
   and the function ut_dbg_stop_thread() i this case, unless
   UNIV_SYC_DEBUG is defined. This should allow the compiler to
   generate more compact code for assertions.
 * ut0list.c|h
   Add ib_list_create_heap().
This commit is contained in:
aivanov@mysql.com
2006-06-01 10:34:04 +04:00
parent 321db8e349
commit 1d7de700e2
78 changed files with 2440 additions and 1247 deletions

View File

@@ -1378,9 +1378,9 @@ insert into `t2`values ( 1 ) ;
create table `t3` (`id` int( 11 ) not null default '0',key `id` ( `id` ) ,constraint `t2_id_fk` foreign key ( `id` ) references `t2` (`id` )) engine = innodb; create table `t3` (`id` int( 11 ) not null default '0',key `id` ( `id` ) ,constraint `t2_id_fk` foreign key ( `id` ) references `t2` (`id` )) engine = innodb;
insert into `t3`values ( 1 ) ; insert into `t3`values ( 1 ) ;
delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`))
update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`))
update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id;
ERROR 42S22: Unknown column 't1.id' in 'where clause' ERROR 42S22: Unknown column 't1.id' in 'where clause'
drop table t3,t2,t1; drop table t3,t2,t1;
@@ -1392,7 +1392,7 @@ foreign key(pid) references t1(id) on delete cascade) engine=innodb;
insert into t1 values(0,0),(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6), insert into t1 values(0,0),(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6),
(8,7),(9,8),(10,9),(11,10),(12,11),(13,12),(14,13),(15,14); (8,7),(9,8),(10,9),(11,10),(12,11),(13,12),(14,13),(15,14);
delete from t1 where id=0; delete from t1 where id=0;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `t1` (`id`) ON DELETE CASCADE) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `t1` (`id`) ON DELETE CASCADE)
delete from t1 where id=15; delete from t1 where id=15;
delete from t1 where id=0; delete from t1 where id=0;
drop table t1; drop table t1;
@@ -2633,18 +2633,18 @@ v INT,
CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id) CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
INSERT INTO t2 VALUES(2); INSERT INTO t2 VALUES(2);
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`)) ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`))
INSERT INTO t1 VALUES(1); INSERT INTO t1 VALUES(1);
INSERT INTO t2 VALUES(1); INSERT INTO t2 VALUES(1);
DELETE FROM t1 WHERE id = 1; DELETE FROM t1 WHERE id = 1;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`)) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`))
DROP TABLE t1; DROP TABLE t1;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
SET FOREIGN_KEY_CHECKS=0; SET FOREIGN_KEY_CHECKS=0;
DROP TABLE t1; DROP TABLE t1;
SET FOREIGN_KEY_CHECKS=1; SET FOREIGN_KEY_CHECKS=1;
INSERT INTO t2 VALUES(3); INSERT INTO t2 VALUES(3);
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`)) ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`))
DROP TABLE t2; DROP TABLE t2;
create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
insert into t1 values (1),(2); insert into t1 values (1),(2);
@@ -2922,23 +2922,23 @@ create table t4(a int primary key,constraint foreign key(a)references t3(a)) row
insert into t1 values(1); insert into t1 values(1);
insert into t3 values(1); insert into t3 values(1);
insert into t2 values(2); insert into t2 values(2);
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
insert into t4 values(2); insert into t4 values(2);
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`)) ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
insert into t2 values(1); insert into t2 values(1);
insert into t4 values(1); insert into t4 values(1);
update t1 set a=2; update t1 set a=2;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
update t2 set a=2; update t2 set a=2;
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
update t3 set a=2; update t3 set a=2;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`)) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
update t4 set a=2; update t4 set a=2;
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`)) ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
truncate t1; truncate t1;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
truncate t3; truncate t3;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`)) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
truncate t2; truncate t2;
truncate t4; truncate t4;
truncate t1; truncate t1;
@@ -2993,7 +2993,7 @@ create table t1 (a int primary key,s1 varbinary(3) not null unique) engine=innod
create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb;
insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42); insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42);
insert into t2 values(0x42); insert into t2 values(0x42);
ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
insert into t2 values(0x41); insert into t2 values(0x41);
select hex(s1) from t2; select hex(s1) from t2;
hex(s1) hex(s1)
@@ -3003,11 +3003,11 @@ select hex(s1) from t2;
hex(s1) hex(s1)
4100 4100
update t1 set s1=0x12 where a=1; update t1 set s1=0x12 where a=1;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
update t1 set s1=0x12345678 where a=1; update t1 set s1=0x12345678 where a=1;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
update t1 set s1=0x123457 where a=1; update t1 set s1=0x123457 where a=1;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
update t1 set s1=0x1220 where a=1; update t1 set s1=0x1220 where a=1;
select hex(s1) from t2; select hex(s1) from t2;
hex(s1) hex(s1)
@@ -3021,11 +3021,11 @@ select hex(s1) from t2;
hex(s1) hex(s1)
4200 4200
delete from t1 where a=1; delete from t1 where a=1;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
delete from t1 where a=2; delete from t1 where a=2;
update t2 set s1=0x4120; update t2 set s1=0x4120;
delete from t1; delete from t1;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
delete from t1 where a!=3; delete from t1 where a!=3;
select a,hex(s1) from t1; select a,hex(s1) from t1;
a hex(s1) a hex(s1)
@@ -3051,7 +3051,7 @@ hex(s1)
12 12
delete from t1 where a=1; delete from t1 where a=1;
delete from t1 where a=2; delete from t1 where a=2;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE)
select a,hex(s1) from t1; select a,hex(s1) from t1;
a hex(s1) a hex(s1)
2 12 2 12

View File

@@ -2510,3 +2510,16 @@ BEGIN;
INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (1);
OPTIMIZE TABLE t1; OPTIMIZE TABLE t1;
DROP TABLE t1; DROP TABLE t1;
#######################################################################
# #
# Please, DO NOT TOUCH this file as well as the innodb.result file. #
# These files are to be modified ONLY BY INNOBASE guys. #
# #
# Use innodb_mysql.[test|result] files instead. #
# #
# If nevertheless you need to make some changes here, please, forward #
# your commit message To: dev@innodb.com Cc: dev-innodb@mysql.com #
# (otherwise your changes may be erased). #
# #
#######################################################################

View File

@@ -134,6 +134,7 @@ extern "C" {
#include "../storage/innobase/include/fil0fil.h" #include "../storage/innobase/include/fil0fil.h"
#include "../storage/innobase/include/trx0xa.h" #include "../storage/innobase/include/trx0xa.h"
#include "../storage/innobase/include/thr0loc.h" #include "../storage/innobase/include/thr0loc.h"
#include "../storage/innobase/include/ha_prototypes.h"
} }
#define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */ #define HA_INNOBASE_ROWS_IN_TABLE 10000 /* to get optimization right */
@@ -705,6 +706,61 @@ innobase_get_cset_width(
} }
} }
/**********************************************************************
Converts an identifier to a table name.
NOTE that the exact prototype of this function has to be in
/innobase/dict/dict0dict.c! */
extern "C"
void
innobase_convert_from_table_id(
/*===========================*/
char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */
ulint len) /* in: length of 'to', in bytes */
{
uint errors;
strconvert(current_thd->charset(), from,
&my_charset_filename, to, len, &errors);
}
/**********************************************************************
Converts an identifier to UTF-8.
NOTE that the exact prototype of this function has to be in
/innobase/dict/dict0dict.c! */
extern "C"
void
innobase_convert_from_id(
/*=====================*/
char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */
ulint len) /* in: length of 'to', in bytes */
{
uint errors;
strconvert(current_thd->charset(), from,
system_charset_info, to, len, &errors);
}
/**********************************************************************
Removes the filename encoding of a table or database name.
NOTE that the exact prototype of this function has to be in
/innobase/dict/dict0dict.c! */
extern "C"
void
innobase_convert_from_filename(
/*===========================*/
char* s) /* in: identifier; out: decoded identifier */
{
uint errors;
strconvert(&my_charset_filename, s,
system_charset_info, s, strlen(s), &errors);
}
/********************************************************************** /**********************************************************************
Compares NUL-terminated UTF-8 strings case insensitively. Compares NUL-terminated UTF-8 strings case insensitively.
@@ -735,6 +791,21 @@ innobase_casedn_str(
my_casedn_str(system_charset_info, a); my_casedn_str(system_charset_info, a);
} }
/**************************************************************************
Determines the connection character set.
NOTE that the exact prototype of this function has to be in
/innobase/dict/dict0dict.c! */
extern "C"
struct charset_info_st*
innobase_get_charset(
/*=================*/
/* out: connection character set */
void* mysql_thd) /* in: MySQL thread handle */
{
return(((THD*) mysql_thd)->charset());
}
/************************************************************************* /*************************************************************************
Creates a temporary file. */ Creates a temporary file. */
extern "C" extern "C"
@@ -780,6 +851,25 @@ innobase_mysql_tmpfile(void)
return(fd2); return(fd2);
} }
/*************************************************************************
Wrapper around MySQL's copy_and_convert function, see it for
documentation. */
extern "C"
ulint
innobase_convert_string(
/*====================*/
void* to,
ulint to_length,
CHARSET_INFO* to_cs,
const void* from,
ulint from_length,
CHARSET_INFO* from_cs,
uint* errors)
{
return(copy_and_convert((char*)to, to_length, to_cs,
(const char*)from, from_length, from_cs, errors));
}
/************************************************************************* /*************************************************************************
Gets the InnoDB transaction handle for a MySQL handler object, creates Gets the InnoDB transaction handle for a MySQL handler object, creates
an InnoDB transaction struct if the corresponding MySQL thread struct still an InnoDB transaction struct if the corresponding MySQL thread struct still
@@ -1115,23 +1205,69 @@ innobase_invalidate_query_cache(
} }
/********************************************************************* /*********************************************************************
Get the quote character to be used in SQL identifiers. Display an SQL identifier.
This definition must match the one in innobase/ut/ut0ut.c! */ This definition must match the one in innobase/ut/ut0ut.c! */
extern "C" extern "C"
int void
mysql_get_identifier_quote_char( innobase_print_identifier(
/*============================*/ /*======================*/
/* out: quote character to be FILE* f, /* in: output stream */
used in SQL identifiers; EOF if none */
trx_t* trx, /* in: transaction */ trx_t* trx, /* in: transaction */
ibool table_id,/* in: TRUE=decode table name */
const char* name, /* in: name to print */ const char* name, /* in: name to print */
ulint namelen)/* in: length of name */ ulint namelen)/* in: length of name */
{ {
if (!trx || !trx->mysql_thd) { const char* s = name;
return(EOF); char* qname = NULL;
int q;
if (table_id) {
/* Decode the table name. The filename_to_tablename()
function expects a NUL-terminated string. The input and
output strings buffers must not be shared. The function
only produces more output when the name contains other
characters than [0-9A-Z_a-z]. */
char* temp_name = my_malloc(namelen + 1, MYF(MY_WME));
uint qnamelen = namelen
+ (1 + sizeof srv_mysql50_table_name_prefix);
if (temp_name) {
qname = my_malloc(qnamelen, MYF(MY_WME));
if (qname) {
memcpy(temp_name, name, namelen);
temp_name[namelen] = 0;
s = qname;
namelen = filename_to_tablename(temp_name,
qname, qnamelen);
}
my_free(temp_name, MYF(0));
}
} }
return(get_quote_char_for_identifier((THD*) trx->mysql_thd,
name, (int) namelen)); if (!trx || !trx->mysql_thd) {
q = '"';
} else {
q = get_quote_char_for_identifier((THD*) trx->mysql_thd,
s, (int) namelen);
}
if (q == EOF) {
fwrite(s, 1, namelen, f);
} else {
const char* e = s + namelen;
putc(q, f);
while (s < e) {
int c = *s++;
if (c == q) {
putc(c, f);
}
putc(c, f);
}
putc(q, f);
}
my_free(qname, MYF(MY_ALLOW_ZERO_PTR));
} }
/************************************************************************** /**************************************************************************
@@ -1247,6 +1383,24 @@ innobase_init(void)
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR); ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
#ifdef UNIV_DEBUG
static const char test_filename[] = "-@";
char test_tablename[sizeof test_filename
+ sizeof srv_mysql50_table_name_prefix];
if ((sizeof test_tablename) - 1
!= filename_to_tablename(test_filename, test_tablename,
sizeof test_tablename)
|| strncmp(test_tablename,
srv_mysql50_table_name_prefix,
sizeof srv_mysql50_table_name_prefix)
|| strcmp(test_tablename
+ sizeof srv_mysql50_table_name_prefix,
test_filename)) {
sql_print_error("tablename encoding has been changed");
goto error;
}
#endif /* UNIV_DEBUG */
/* Check that values don't overflow on 32-bit systems. */ /* Check that values don't overflow on 32-bit systems. */
if (sizeof(ulint) == 4) { if (sizeof(ulint) == 4) {
if (innobase_buffer_pool_size > UINT_MAX32) { if (innobase_buffer_pool_size > UINT_MAX32) {
@@ -2215,8 +2369,7 @@ ha_innobase::open(
/* Get pointer to a table object in InnoDB dictionary cache */ /* Get pointer to a table object in InnoDB dictionary cache */
ib_table = dict_table_get_and_increment_handle_count( ib_table = dict_table_get_and_increment_handle_count(norm_name);
norm_name, NULL);
if (NULL == ib_table) { if (NULL == ib_table) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
@@ -4132,6 +4285,9 @@ ha_innobase::index_prev(
mysql_byte* buf) /* in/out: buffer for previous row in MySQL mysql_byte* buf) /* in/out: buffer for previous row in MySQL
format */ format */
{ {
statistic_increment(current_thd->status_var.ha_read_prev_count,
&LOCK_status);
return(general_fetch(buf, ROW_SEL_PREV, 0)); return(general_fetch(buf, ROW_SEL_PREV, 0));
} }
@@ -4668,7 +4824,7 @@ ha_innobase::create(
/* Get the transaction associated with the current thd, or create one /* Get the transaction associated with the current thd, or create one
if not yet created */ if not yet created */
parent_trx = check_trx_exists(current_thd); parent_trx = check_trx_exists(thd);
/* In case MySQL calls this in the middle of a SELECT query, release /* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */ possible adaptive hash latch to avoid deadlocks of threads */
@@ -4764,20 +4920,9 @@ ha_innobase::create(
} }
} }
if (current_thd->query != NULL) { if (thd->query != NULL) {
LEX_STRING q;
if (thd->convert_string(&q, system_charset_info,
current_thd->query,
current_thd->query_length,
current_thd->charset())) {
error = HA_ERR_OUT_OF_MEM;
goto cleanup;
}
error = row_table_add_foreign_constraints(trx, error = row_table_add_foreign_constraints(trx,
q.str, norm_name, thd->query, norm_name,
create_info->options & HA_LEX_CREATE_TMP_TABLE); create_info->options & HA_LEX_CREATE_TMP_TABLE);
error = convert_error_code_to_mysql(error, NULL); error = convert_error_code_to_mysql(error, NULL);
@@ -4797,7 +4942,7 @@ ha_innobase::create(
log_buffer_flush_to_disk(); log_buffer_flush_to_disk();
innobase_table = dict_table_get(norm_name, NULL); innobase_table = dict_table_get(norm_name);
DBUG_ASSERT(innobase_table != 0); DBUG_ASSERT(innobase_table != 0);
@@ -4933,7 +5078,7 @@ ha_innobase::delete_table(
/* Get the transaction associated with the current thd, or create one /* Get the transaction associated with the current thd, or create one
if not yet created */ if not yet created */
parent_trx = check_trx_exists(current_thd); parent_trx = check_trx_exists(thd);
/* In case MySQL calls this in the middle of a SELECT query, release /* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */ possible adaptive hash latch to avoid deadlocks of threads */

View File

@@ -32,4 +32,4 @@ ADD_LIBRARY(innobase btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c
thr/thr0loc.c thr/thr0loc.c
trx/trx0purge.c trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c trx/trx0purge.c trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c
usr/usr0sess.c usr/usr0sess.c
ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c) ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c ut/ut0list.c ut/ut0wqueue.c)

View File

@@ -76,7 +76,7 @@ EXTRA_DIST = include/btr0btr.h include/btr0btr.ic include/btr0cur.h include/btr
include/univ.i include/usr0sess.h include/usr0sess.ic include/usr0types.h \ include/univ.i include/usr0sess.h include/usr0sess.ic include/usr0types.h \
include/ut0byte.h include/ut0byte.ic include/ut0dbg.h include/ut0lst.h \ include/ut0byte.h include/ut0byte.ic include/ut0dbg.h include/ut0lst.h \
include/ut0mem.h include/ut0mem.ic include/ut0rnd.h include/ut0rnd.ic \ include/ut0mem.h include/ut0mem.ic include/ut0rnd.h include/ut0rnd.ic \
include/ut0sort.h include/ut0ut.h include/ut0ut.ic include/ut0vec.h include/ut0vec.ic \ include/ut0sort.h include/ut0ut.h include/ut0ut.ic include/ut0vec.h include/ut0vec.ic include/ha_prototypes.h \
CMakeLists.txt CMakeLists.txt
noinst_LIBRARIES = libinnobase.a noinst_LIBRARIES = libinnobase.a

View File

@@ -190,6 +190,10 @@ btr_get_prev_user_rec(
|| (mtr_memo_contains(mtr, buf_block_align(prev_page), || (mtr_memo_contains(mtr, buf_block_align(prev_page),
MTR_MEMO_PAGE_X_FIX))); MTR_MEMO_PAGE_X_FIX)));
ut_a(page_is_comp(prev_page) == page_is_comp(page)); ut_a(page_is_comp(prev_page) == page_is_comp(page));
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_next(prev_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
return(page_rec_get_prev(page_get_supremum_rec(prev_page))); return(page_rec_get_prev(page_get_supremum_rec(prev_page)));
} }
@@ -237,6 +241,10 @@ btr_get_next_user_rec(
MTR_MEMO_PAGE_S_FIX)) MTR_MEMO_PAGE_S_FIX))
|| (mtr_memo_contains(mtr, buf_block_align(next_page), || (mtr_memo_contains(mtr, buf_block_align(next_page),
MTR_MEMO_PAGE_X_FIX))); MTR_MEMO_PAGE_X_FIX)));
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_prev(next_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
ut_a(page_is_comp(next_page) == page_is_comp(page)); ut_a(page_is_comp(next_page) == page_is_comp(page));
return(page_rec_get_next(page_get_infimum_rec(next_page))); return(page_rec_get_next(page_get_infimum_rec(next_page)));
@@ -597,9 +605,9 @@ btr_page_get_father_for_rec(
buf_page_print(buf_frame_align(node_ptr)); buf_page_print(buf_frame_align(node_ptr));
fputs("InnoDB: Corruption of an index tree: table ", stderr); fputs("InnoDB: Corruption of an index tree: table ", stderr);
ut_print_name(stderr, NULL, index->table_name); ut_print_name(stderr, NULL, TRUE, index->table_name);
fputs(", index ", stderr); fputs(", index ", stderr);
ut_print_name(stderr, NULL, index->name); ut_print_name(stderr, NULL, FALSE, index->name);
fprintf(stderr, ",\n" fprintf(stderr, ",\n"
"InnoDB: father ptr page no %lu, child page no %lu\n", "InnoDB: father ptr page no %lu, child page no %lu\n",
(ulong) (ulong)
@@ -1518,6 +1526,10 @@ btr_attach_half_pages(
prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr); prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr);
ut_a(page_is_comp(prev_page) == page_is_comp(page)); ut_a(page_is_comp(prev_page) == page_is_comp(page));
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_next(prev_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
btr_page_set_next(prev_page, lower_page_no, mtr); btr_page_set_next(prev_page, lower_page_no, mtr);
} }
@@ -1805,6 +1817,10 @@ btr_level_list_remove(
prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr); prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr);
ut_a(page_is_comp(prev_page) == page_is_comp(page)); ut_a(page_is_comp(prev_page) == page_is_comp(page));
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_next(prev_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
btr_page_set_next(prev_page, next_page_no, mtr); btr_page_set_next(prev_page, next_page_no, mtr);
} }
@@ -1813,6 +1829,10 @@ btr_level_list_remove(
next_page = btr_page_get(space, next_page_no, RW_X_LATCH, mtr); next_page = btr_page_get(space, next_page_no, RW_X_LATCH, mtr);
ut_a(page_is_comp(next_page) == page_is_comp(page)); ut_a(page_is_comp(next_page) == page_is_comp(page));
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_prev(next_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
btr_page_set_prev(next_page, prev_page_no, mtr); btr_page_set_prev(next_page, prev_page_no, mtr);
} }
@@ -2032,16 +2052,24 @@ btr_compress(
/* Decide the page to which we try to merge and which will inherit /* Decide the page to which we try to merge and which will inherit
the locks */ the locks */
if (left_page_no != FIL_NULL) { is_left = left_page_no != FIL_NULL;
if (is_left) {
is_left = TRUE;
merge_page = btr_page_get(space, left_page_no, RW_X_LATCH, merge_page = btr_page_get(space, left_page_no, RW_X_LATCH,
mtr); mtr);
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_next(merge_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
} else if (right_page_no != FIL_NULL) { } else if (right_page_no != FIL_NULL) {
is_left = FALSE;
merge_page = btr_page_get(space, right_page_no, RW_X_LATCH, merge_page = btr_page_get(space, right_page_no, RW_X_LATCH,
mtr); mtr);
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_prev(merge_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
} else { } else {
/* The page is the only one on the level, lift the records /* The page is the only one on the level, lift the records
to the father */ to the father */
@@ -2203,7 +2231,6 @@ btr_discard_page(
ulint left_page_no; ulint left_page_no;
ulint right_page_no; ulint right_page_no;
page_t* merge_page; page_t* merge_page;
ibool is_left;
page_t* page; page_t* page;
rec_t* node_ptr; rec_t* node_ptr;
@@ -2223,13 +2250,19 @@ btr_discard_page(
right_page_no = btr_page_get_next(page, mtr); right_page_no = btr_page_get_next(page, mtr);
if (left_page_no != FIL_NULL) { if (left_page_no != FIL_NULL) {
is_left = TRUE;
merge_page = btr_page_get(space, left_page_no, RW_X_LATCH, merge_page = btr_page_get(space, left_page_no, RW_X_LATCH,
mtr); mtr);
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_next(merge_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
} else if (right_page_no != FIL_NULL) { } else if (right_page_no != FIL_NULL) {
is_left = FALSE;
merge_page = btr_page_get(space, right_page_no, RW_X_LATCH, merge_page = btr_page_get(space, right_page_no, RW_X_LATCH,
mtr); mtr);
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_prev(merge_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
} else { } else {
btr_discard_only_page_on_level(tree, page, mtr); btr_discard_only_page_on_level(tree, page, mtr);
@@ -2256,11 +2289,11 @@ btr_discard_page(
/* Remove the page from the level list */ /* Remove the page from the level list */
btr_level_list_remove(tree, page, mtr); btr_level_list_remove(tree, page, mtr);
if (is_left) { if (left_page_no != FIL_NULL) {
lock_update_discard(page_get_supremum_rec(merge_page), page); lock_update_discard(page_get_supremum_rec(merge_page), page);
} else { } else {
lock_update_discard(page_rec_get_next( lock_update_discard(page_rec_get_next(
page_get_infimum_rec(merge_page)), page); page_get_infimum_rec(merge_page)), page);
} }
/* Free the file page */ /* Free the file page */
@@ -2745,7 +2778,29 @@ loop:
rec_t* right_rec; rec_t* right_rec;
right_page = btr_page_get(space, right_page_no, RW_X_LATCH, right_page = btr_page_get(space, right_page_no, RW_X_LATCH,
&mtr); &mtr);
ut_a(page_is_comp(right_page) == page_is_comp(page)); if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr)
!= buf_frame_get_page_no(page))) {
btr_validate_report2(index, level, page, right_page);
fputs("InnoDB: broken FIL_PAGE_NEXT"
" or FIL_PAGE_PREV links\n", stderr);
buf_page_print(page);
buf_page_print(right_page);
ret = FALSE;
}
if (UNIV_UNLIKELY(page_is_comp(right_page)
!= page_is_comp(page))) {
btr_validate_report2(index, level, page, right_page);
fputs("InnoDB: 'compact' flag mismatch\n", stderr);
buf_page_print(page);
buf_page_print(right_page);
ret = FALSE;
goto node_ptr_fails;
}
rec = page_rec_get_prev(page_get_supremum_rec(page)); rec = page_rec_get_prev(page_get_supremum_rec(page));
right_rec = page_rec_get_next( right_rec = page_rec_get_next(
page_get_infimum_rec(right_page)); page_get_infimum_rec(right_page));
@@ -2753,8 +2808,8 @@ loop:
offsets, ULINT_UNDEFINED, &heap); offsets, ULINT_UNDEFINED, &heap);
offsets2 = rec_get_offsets(right_rec, index, offsets2 = rec_get_offsets(right_rec, index,
offsets2, ULINT_UNDEFINED, &heap); offsets2, ULINT_UNDEFINED, &heap);
if (cmp_rec_rec(rec, right_rec, offsets, offsets2, index) if (UNIV_UNLIKELY(cmp_rec_rec(rec, right_rec,
>= 0) { offsets, offsets2, index) >= 0)) {
btr_validate_report2(index, level, page, right_page); btr_validate_report2(index, level, page, right_page);
@@ -2869,10 +2924,7 @@ loop:
ut_a(node_ptr == page_rec_get_prev( ut_a(node_ptr == page_rec_get_prev(
page_get_supremum_rec(father_page))); page_get_supremum_rec(father_page)));
ut_a(btr_page_get_next(father_page, &mtr) == FIL_NULL); ut_a(btr_page_get_next(father_page, &mtr) == FIL_NULL);
} } else {
if (right_page_no != FIL_NULL) {
right_node_ptr = btr_page_get_father_node_ptr(tree, right_node_ptr = btr_page_get_father_node_ptr(tree,
right_page, &mtr); right_page, &mtr);
if (page_rec_get_next(node_ptr) != if (page_rec_get_next(node_ptr) !=
@@ -2934,14 +2986,15 @@ loop:
} }
node_ptr_fails: node_ptr_fails:
/* Commit the mini-transaction to release the latch on 'page'.
Re-acquire the latch on right_page, which will become 'page'
on the next loop. The page has already been checked. */
mtr_commit(&mtr); mtr_commit(&mtr);
if (right_page_no != FIL_NULL) { if (right_page_no != FIL_NULL) {
ulint comp = page_is_comp(page);
mtr_start(&mtr); mtr_start(&mtr);
page = btr_page_get(space, right_page_no, RW_X_LATCH, &mtr); page = btr_page_get(space, right_page_no, RW_X_LATCH, &mtr);
ut_a(page_is_comp(page) == comp);
goto loop; goto loop;
} }

View File

@@ -157,6 +157,10 @@ btr_cur_latch_leaves(
if (left_page_no != FIL_NULL) { if (left_page_no != FIL_NULL) {
get_page = btr_page_get(space, left_page_no, get_page = btr_page_get(space, left_page_no,
RW_X_LATCH, mtr); RW_X_LATCH, mtr);
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_next(get_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
ut_a(page_is_comp(get_page) == page_is_comp(page)); ut_a(page_is_comp(get_page) == page_is_comp(page));
buf_block_align(get_page)->check_index_page_at_flush = buf_block_align(get_page)->check_index_page_at_flush =
TRUE; TRUE;
@@ -171,6 +175,10 @@ btr_cur_latch_leaves(
if (right_page_no != FIL_NULL) { if (right_page_no != FIL_NULL) {
get_page = btr_page_get(space, right_page_no, get_page = btr_page_get(space, right_page_no,
RW_X_LATCH, mtr); RW_X_LATCH, mtr);
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_prev(get_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
buf_block_align(get_page)->check_index_page_at_flush = buf_block_align(get_page)->check_index_page_at_flush =
TRUE; TRUE;
} }
@@ -183,6 +191,10 @@ btr_cur_latch_leaves(
if (left_page_no != FIL_NULL) { if (left_page_no != FIL_NULL) {
cursor->left_page = btr_page_get(space, left_page_no, cursor->left_page = btr_page_get(space, left_page_no,
RW_S_LATCH, mtr); RW_S_LATCH, mtr);
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_next(cursor->left_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
ut_a(page_is_comp(cursor->left_page) == ut_a(page_is_comp(cursor->left_page) ==
page_is_comp(page)); page_is_comp(page));
buf_block_align( buf_block_align(
@@ -201,6 +213,10 @@ btr_cur_latch_leaves(
if (left_page_no != FIL_NULL) { if (left_page_no != FIL_NULL) {
cursor->left_page = btr_page_get(space, left_page_no, cursor->left_page = btr_page_get(space, left_page_no,
RW_X_LATCH, mtr); RW_X_LATCH, mtr);
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_next(cursor->left_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
ut_a(page_is_comp(cursor->left_page) == ut_a(page_is_comp(cursor->left_page) ==
page_is_comp(page)); page_is_comp(page));
buf_block_align( buf_block_align(
@@ -1731,6 +1747,10 @@ btr_cur_pess_upd_restore_supremum(
ut_ad(prev_page_no != FIL_NULL); ut_ad(prev_page_no != FIL_NULL);
prev_page = buf_page_get_with_no_latch(space, prev_page_no, mtr); prev_page = buf_page_get_with_no_latch(space, prev_page_no, mtr);
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_next(prev_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
/* We must already have an x-latch to prev_page! */ /* We must already have an x-latch to prev_page! */
ut_ad(mtr_memo_contains(mtr, buf_block_align(prev_page), ut_ad(mtr_memo_contains(mtr, buf_block_align(prev_page),
@@ -3771,11 +3791,6 @@ btr_copy_externally_stored_field(
page_no = btr_blob_get_next_page_no(blob_header); page_no = btr_blob_get_next_page_no(blob_header);
/* On other BLOB pages except the first the BLOB header
always is at the page data start: */
offset = FIL_PAGE_DATA;
mtr_commit(&mtr); mtr_commit(&mtr);
if (page_no == FIL_NULL) { if (page_no == FIL_NULL) {
@@ -3786,6 +3801,11 @@ btr_copy_externally_stored_field(
return(buf); return(buf);
} }
/* On other BLOB pages except the first the BLOB header
always is at the page data start: */
offset = FIL_PAGE_DATA;
ut_a(copied_len < local_len + extern_len); ut_a(copied_len < local_len + extern_len);
} }
} }

View File

@@ -397,6 +397,9 @@ btr_pcur_move_to_next_page(
ut_ad(next_page_no != FIL_NULL); ut_ad(next_page_no != FIL_NULL);
next_page = btr_page_get(space, next_page_no, cursor->latch_mode, mtr); next_page = btr_page_get(space, next_page_no, cursor->latch_mode, mtr);
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_prev(next_page, mtr) == buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
ut_a(page_is_comp(next_page) == page_is_comp(page)); ut_a(page_is_comp(next_page) == page_is_comp(page));
buf_block_align(next_page)->check_index_page_at_flush = TRUE; buf_block_align(next_page)->check_index_page_at_flush = TRUE;

View File

@@ -136,13 +136,12 @@ btr_search_sys_create(
btr_search_latch_temp = mem_alloc(sizeof(rw_lock_t)); btr_search_latch_temp = mem_alloc(sizeof(rw_lock_t));
rw_lock_create(&btr_search_latch); rw_lock_create(&btr_search_latch, SYNC_SEARCH_SYS);
btr_search_sys = mem_alloc(sizeof(btr_search_sys_t)); btr_search_sys = mem_alloc(sizeof(btr_search_sys_t));
btr_search_sys->hash_index = ha_create(TRUE, hash_size, 0, 0); btr_search_sys->hash_index = ha_create(TRUE, hash_size, 0, 0);
rw_lock_set_level(&btr_search_latch, SYNC_SEARCH_SYS);
} }
/********************************************************************* /*********************************************************************

View File

@@ -524,12 +524,11 @@ buf_block_init(
block->n_pointers = 0; block->n_pointers = 0;
rw_lock_create(&(block->lock)); rw_lock_create(&block->lock, SYNC_LEVEL_VARYING);
ut_ad(rw_lock_validate(&(block->lock))); ut_ad(rw_lock_validate(&(block->lock)));
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
rw_lock_create(&(block->debug_latch)); rw_lock_create(&block->debug_latch, SYNC_NO_ORDER_CHECK);
rw_lock_set_level(&(block->debug_latch), SYNC_NO_ORDER_CHECK);
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
} }
@@ -572,8 +571,7 @@ buf_pool_init(
/* 1. Initialize general fields /* 1. Initialize general fields
---------------------------- */ ---------------------------- */
mutex_create(&(buf_pool->mutex)); mutex_create(&buf_pool->mutex, SYNC_BUF_POOL);
mutex_set_level(&(buf_pool->mutex), SYNC_BUF_POOL);
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
@@ -1856,7 +1854,6 @@ buf_page_io_complete(
buf_block_t* block) /* in: pointer to the block in question */ buf_block_t* block) /* in: pointer to the block in question */
{ {
ulint io_type; ulint io_type;
ulint read_page_no;
ut_ad(block); ut_ad(block);
@@ -1866,18 +1863,36 @@ buf_page_io_complete(
if (io_type == BUF_IO_READ) { if (io_type == BUF_IO_READ) {
/* If this page is not uninitialized and not in the /* If this page is not uninitialized and not in the
doublewrite buffer, then the page number should be the doublewrite buffer, then the page number and space id
same as in block */ should be the same as in block. */
ulint read_page_no = mach_read_from_4((block->frame)
read_page_no = mach_read_from_4((block->frame)
+ FIL_PAGE_OFFSET); + FIL_PAGE_OFFSET);
if (read_page_no != 0 ulint read_space_id = mach_read_from_4((block->frame)
&& !trx_doublewrite_page_inside(read_page_no) + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
&& read_page_no != block->offset) {
if (!block->space && trx_doublewrite_page_inside(
block->offset)) {
ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: page n:o stored in the page read in is %lu, should be %lu!\n", " InnoDB: Error: reading page %lu\n"
(ulong) read_page_no, (ulong) block->offset); "InnoDB: which is in the doublewrite buffer!\n",
(ulong) block->offset);
} else if (!read_space_id && !read_page_no) {
/* This is likely an uninitialized page. */
} else if ((block->space && block->space != read_space_id)
|| block->offset != read_page_no) {
/* We did not compare space_id to read_space_id
if block->space == 0, because the field on the
page may contain garbage in MySQL < 4.1.1,
which only supported block->space == 0. */
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: space id and page n:o stored in the page\n"
"InnoDB: read in are %lu:%lu, should be %lu:%lu!\n",
(ulong) read_space_id, (ulong) read_page_no,
(ulong) block->space, (ulong) block->offset);
} }
/* From version 3.23.38 up we store the page checksum /* From version 3.23.38 up we store the page checksum
to the 4 first bytes of the page end lsn field */ to the 4 first bytes of the page end lsn field */
@@ -2233,7 +2248,8 @@ buf_get_latched_pages_number(void)
} }
mutex_exit(&(buf_pool->mutex)); mutex_exit(&(buf_pool->mutex));
return fixed_pages_number;
return(fixed_pages_number);
} }
/************************************************************************* /*************************************************************************

View File

@@ -26,7 +26,7 @@ Created 11/11/1995 Heikki Tuuri
#include "trx0sys.h" #include "trx0sys.h"
#include "srv0srv.h" #include "srv0srv.h"
/* When flushed, dirty blocks are searched in neigborhoods of this size, and /* When flushed, dirty blocks are searched in neighborhoods of this size, and
flushed along with the original page. */ flushed along with the original page. */
#define BUF_FLUSH_AREA ut_min(BUF_READ_AHEAD_AREA,\ #define BUF_FLUSH_AREA ut_min(BUF_READ_AHEAD_AREA,\

View File

@@ -293,3 +293,36 @@ dtype_print(
fprintf(stderr, " len %lu prec %lu", (ulong) len, (ulong) type->prec); fprintf(stderr, " len %lu prec %lu", (ulong) len, (ulong) type->prec);
} }
/***************************************************************************
Returns the maximum size of a data type. Note: types in system tables may be
incomplete and return incorrect information. */
UNIV_INLINE
ulint
dtype_get_max_size(
/*===============*/
/* out: maximum size (ULINT_MAX for
unbounded types) */
const dtype_t* type) /* in: type */
{
switch (type->mtype) {
case DATA_SYS:
case DATA_CHAR:
case DATA_FIXBINARY:
case DATA_INT:
case DATA_FLOAT:
case DATA_DOUBLE:
case DATA_MYSQL:
case DATA_VARCHAR:
case DATA_BINARY:
case DATA_DECIMAL:
case DATA_VARMYSQL:
return(type->len);
case DATA_BLOB:
return(ULINT_MAX);
default:
ut_error;
}
return(ULINT_MAX);
}

View File

@@ -1250,9 +1250,9 @@ dict_foreign_eval_sql(
ut_print_timestamp(ef); ut_print_timestamp(ef);
fputs(" Error in foreign key constraint creation for table ", fputs(" Error in foreign key constraint creation for table ",
ef); ef);
ut_print_name(ef, trx, table->name); ut_print_name(ef, trx, TRUE, table->name);
fputs(".\nA foreign key constraint of name ", ef); fputs(".\nA foreign key constraint of name ", ef);
ut_print_name(ef, trx, foreign->id); ut_print_name(ef, trx, FALSE, foreign->id);
fputs("\nalready exists." fputs("\nalready exists."
" (Note that internally InnoDB adds 'databasename/'\n" " (Note that internally InnoDB adds 'databasename/'\n"
"in front of the user-defined constraint name).\n", "in front of the user-defined constraint name).\n",
@@ -1280,7 +1280,7 @@ dict_foreign_eval_sql(
ut_print_timestamp(ef); ut_print_timestamp(ef);
fputs(" Internal error in foreign key constraint creation" fputs(" Internal error in foreign key constraint creation"
" for table ", ef); " for table ", ef);
ut_print_name(ef, trx, table->name); ut_print_name(ef, trx, TRUE, table->name);
fputs(".\n" fputs(".\n"
"See the MySQL .err log in the datadir for more information.\n", ef); "See the MySQL .err log in the datadir for more information.\n", ef);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);

View File

@@ -26,6 +26,9 @@ Created 1/8/1996 Heikki Tuuri
#include "pars0sym.h" #include "pars0sym.h"
#include "que0que.h" #include "que0que.h"
#include "rem0cmp.h" #include "rem0cmp.h"
#ifndef UNIV_HOTBACKUP
# include "m_ctype.h" /* my_isspace() */
#endif /* !UNIV_HOTBACKUP */
dict_sys_t* dict_sys = NULL; /* the dictionary system */ dict_sys_t* dict_sys = NULL; /* the dictionary system */
@@ -55,6 +58,42 @@ static char dict_ibfk[] = "_ibfk_";
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
/********************************************************************** /**********************************************************************
Converts an identifier to a table name.
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
this function, you MUST change also the prototype here! */
extern
void
innobase_convert_from_table_id(
/*===========================*/
char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */
ulint len); /* in: length of 'to', in bytes;
should be at least 5 * strlen(to) + 1 */
/**********************************************************************
Converts an identifier to UTF-8.
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
this function, you MUST change also the prototype here! */
extern
void
innobase_convert_from_id(
/*=====================*/
char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */
ulint len); /* in: length of 'to', in bytes;
should be at least 3 * strlen(to) + 1 */
/**********************************************************************
Removes the filename encoding of a table or database name.
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
this function, you MUST change also the prototype here! */
extern
void
innobase_convert_from_filename(
/*===========================*/
char* s); /* in: identifier; out: decoded identifier */
/**********************************************************************
Compares NUL-terminated UTF-8 strings case insensitively. Compares NUL-terminated UTF-8 strings case insensitively.
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
@@ -77,6 +116,17 @@ void
innobase_casedn_str( innobase_casedn_str(
/*================*/ /*================*/
char* a); /* in/out: string to put in lower case */ char* a); /* in/out: string to put in lower case */
/**************************************************************************
Determines the connection character set.
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
this function, you MUST change also the prototype here! */
struct charset_info_st*
innobase_get_charset(
/*=================*/
/* out: connection character set */
void* mysql_thd); /* in: MySQL thread handle */
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
/************************************************************************** /**************************************************************************
@@ -607,7 +657,7 @@ dict_index_get_nth_field_pos(
} }
/************************************************************************** /**************************************************************************
Returns a table object, based on table id, and memoryfixes it. */ Returns a table object based on table id. */
dict_table_t* dict_table_t*
dict_table_get_on_id( dict_table_get_on_id(
@@ -629,12 +679,12 @@ dict_table_get_on_id(
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
return(dict_table_get_on_id_low(table_id, trx)); return(dict_table_get_on_id_low(table_id));
} }
mutex_enter(&(dict_sys->mutex)); mutex_enter(&(dict_sys->mutex));
table = dict_table_get_on_id_low(table_id, trx); table = dict_table_get_on_id_low(table_id);
mutex_exit(&(dict_sys->mutex)); mutex_exit(&(dict_sys->mutex));
@@ -716,8 +766,7 @@ dict_init(void)
{ {
dict_sys = mem_alloc(sizeof(dict_sys_t)); dict_sys = mem_alloc(sizeof(dict_sys_t));
mutex_create(&(dict_sys->mutex)); mutex_create(&dict_sys->mutex, SYNC_DICT);
mutex_set_level(&(dict_sys->mutex), SYNC_DICT);
dict_sys->table_hash = hash_create(buf_pool_get_max_size() / dict_sys->table_hash = hash_create(buf_pool_get_max_size() /
(DICT_POOL_PER_TABLE_HASH * (DICT_POOL_PER_TABLE_HASH *
@@ -732,32 +781,28 @@ dict_init(void)
UT_LIST_INIT(dict_sys->table_LRU); UT_LIST_INIT(dict_sys->table_LRU);
rw_lock_create(&dict_operation_lock); rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION);
rw_lock_set_level(&dict_operation_lock, SYNC_DICT_OPERATION);
dict_foreign_err_file = os_file_create_tmpfile(); dict_foreign_err_file = os_file_create_tmpfile();
ut_a(dict_foreign_err_file); ut_a(dict_foreign_err_file);
mutex_create(&dict_foreign_err_mutex);
mutex_set_level(&dict_foreign_err_mutex, SYNC_ANY_LATCH); mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
} }
/************************************************************************** /**************************************************************************
Returns a table object and memoryfixes it. NOTE! This is a high-level Returns a table object. NOTE! This is a high-level function to be used
function to be used mainly from outside the 'dict' directory. Inside this mainly from outside the 'dict' directory. Inside this directory
directory dict_table_get_low is usually the appropriate function. */ dict_table_get_low is usually the appropriate function. */
dict_table_t* dict_table_t*
dict_table_get( dict_table_get(
/*===========*/ /*===========*/
/* out: table, NULL if /* out: table, NULL if
does not exist */ does not exist */
const char* table_name, /* in: table name */ const char* table_name) /* in: table name */
trx_t* trx) /* in: transaction handle or NULL */
{ {
dict_table_t* table; dict_table_t* table;
UT_NOT_USED(trx);
mutex_enter(&(dict_sys->mutex)); mutex_enter(&(dict_sys->mutex));
table = dict_table_get_low(table_name); table = dict_table_get_low(table_name);
@@ -781,13 +826,10 @@ dict_table_get_and_increment_handle_count(
/*======================================*/ /*======================================*/
/* out: table, NULL if /* out: table, NULL if
does not exist */ does not exist */
const char* table_name, /* in: table name */ const char* table_name) /* in: table name */
trx_t* trx) /* in: transaction handle or NULL */
{ {
dict_table_t* table; dict_table_t* table;
UT_NOT_USED(trx);
mutex_enter(&(dict_sys->mutex)); mutex_enter(&(dict_sys->mutex));
table = dict_table_get_low(table_name); table = dict_table_get_low(table_name);
@@ -819,6 +861,7 @@ dict_table_add_to_cache(
ulint fold; ulint fold;
ulint id_fold; ulint id_fold;
ulint i; ulint i;
ulint row_len;
ut_ad(table); ut_ad(table);
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
@@ -866,6 +909,24 @@ dict_table_add_to_cache(
#error "DATA_N_SYS_COLS != 4" #error "DATA_N_SYS_COLS != 4"
#endif #endif
row_len = 0;
for (i = 0; i < table->n_def; i++) {
ulint col_len = dtype_get_max_size(
dict_col_get_type(dict_table_get_nth_col(table, i)));
/* If we have a single unbounded field, or several gigantic
fields, mark the maximum row size as ULINT_MAX. */
if (ut_max(col_len, row_len) >= (ULINT_MAX / 2)) {
row_len = ULINT_MAX;
break;
}
row_len += col_len;
}
table->max_row_size = row_len;
/* Look for a table with the same name: error if such exists */ /* Look for a table with the same name: error if such exists */
{ {
dict_table_t* table2; dict_table_t* table2;
@@ -897,10 +958,7 @@ dict_table_add_to_cache(
/* Add table to LRU list of tables */ /* Add table to LRU list of tables */
UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table); UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
/* If the dictionary cache grows too big, trim the table LRU list */
dict_sys->size += mem_heap_get_size(table->heap); dict_sys->size += mem_heap_get_size(table->heap);
/* dict_table_LRU_trim(); */
} }
/************************************************************************** /**************************************************************************
@@ -1265,38 +1323,6 @@ dict_table_remove_from_cache(
dict_mem_table_free(table); dict_mem_table_free(table);
} }
/**************************************************************************
Frees tables from the end of table_LRU if the dictionary cache occupies
too much space. Currently not used! */
void
dict_table_LRU_trim(void)
/*=====================*/
{
dict_table_t* table;
dict_table_t* prev_table;
ut_error;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&(dict_sys->mutex)));
#endif /* UNIV_SYNC_DEBUG */
table = UT_LIST_GET_LAST(dict_sys->table_LRU);
while (table && (dict_sys->size >
buf_pool_get_max_size() / DICT_POOL_PER_VARYING)) {
prev_table = UT_LIST_GET_PREV(table_LRU, table);
if (table->mem_fix == 0) {
dict_table_remove_from_cache(table);
}
table = prev_table;
}
}
/************************************************************************** /**************************************************************************
Adds a column to the data dictionary hash table. */ Adds a column to the data dictionary hash table. */
static static
@@ -1443,6 +1469,7 @@ dict_index_add_to_cache(
ut_ad(mem_heap_validate(index->heap)); ut_ad(mem_heap_validate(index->heap));
#ifdef UNIV_DEBUG
{ {
dict_index_t* index2; dict_index_t* index2;
index2 = UT_LIST_GET_FIRST(table->indexes); index2 = UT_LIST_GET_FIRST(table->indexes);
@@ -1452,10 +1479,11 @@ dict_index_add_to_cache(
index2 = UT_LIST_GET_NEXT(indexes, index2); index2 = UT_LIST_GET_NEXT(indexes, index2);
} }
ut_a(UT_LIST_GET_LEN(table->indexes) == 0
|| (index->type & DICT_CLUSTERED) == 0);
} }
#endif /* UNIV_DEBUG */
ut_a(!(index->type & DICT_CLUSTERED)
|| UT_LIST_GET_LEN(table->indexes) == 0);
success = dict_index_find_cols(table, index); success = dict_index_find_cols(table, index);
@@ -1526,10 +1554,7 @@ dict_index_add_to_cache(
/* Add the index to the list of indexes stored in the tree */ /* Add the index to the list of indexes stored in the tree */
tree->tree_index = new_index; tree->tree_index = new_index;
/* If the dictionary cache grows too big, trim the table LRU list */
dict_sys->size += mem_heap_get_size(new_index->heap); dict_sys->size += mem_heap_get_size(new_index->heap);
/* dict_table_LRU_trim(); */
dict_mem_index_free(index); dict_mem_index_free(index);
@@ -2091,6 +2116,7 @@ dict_foreign_find(
return(NULL); return(NULL);
} }
#ifndef UNIV_HOTBACKUP
/************************************************************************* /*************************************************************************
Tries to find an index whose first fields are the columns in the array, Tries to find an index whose first fields are the columns in the array,
in the same order. */ in the same order. */
@@ -2108,7 +2134,6 @@ dict_foreign_find_index(
only has an effect if types_idx != only has an effect if types_idx !=
NULL. */ NULL. */
{ {
#ifndef UNIV_HOTBACKUP
dict_index_t* index; dict_index_t* index;
const char* col_name; const char* col_name;
ulint i; ulint i;
@@ -2154,13 +2179,6 @@ dict_foreign_find_index(
} }
return(NULL); return(NULL);
#else /* UNIV_HOTBACKUP */
/* This function depends on MySQL code that is not included in
InnoDB Hot Backup builds. Besides, this function should never
be called in InnoDB Hot Backup. */
ut_error;
return(NULL);
#endif /* UNIV_HOTBACKUP */
} }
/************************************************************************** /**************************************************************************
@@ -2196,7 +2214,7 @@ dict_foreign_error_report(
putc('\n', file); putc('\n', file);
if (fk->foreign_index) { if (fk->foreign_index) {
fputs("The index in the foreign key in table is ", file); fputs("The index in the foreign key in table is ", file);
ut_print_name(file, NULL, fk->foreign_index->name); ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
fputs( fputs(
"\nSee http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" "\nSee http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n"
"for correct foreign key definition.\n", "for correct foreign key definition.\n",
@@ -2359,12 +2377,13 @@ dict_scan_to(
/************************************************************************* /*************************************************************************
Accepts a specified string. Comparisons are case-insensitive. */ Accepts a specified string. Comparisons are case-insensitive. */
static
const char* const char*
dict_accept( dict_accept(
/*========*/ /*========*/
/* out: if string was accepted, the pointer /* out: if string was accepted, the pointer
is moved after that, else ptr is returned */ is moved after that, else ptr is returned */
struct charset_info_st* cs,/* in: the character set of ptr */
const char* ptr, /* in: scan from this */ const char* ptr, /* in: scan from this */
const char* string, /* in: accept only this string as the next const char* string, /* in: accept only this string as the next
non-whitespace string */ non-whitespace string */
@@ -2375,7 +2394,7 @@ dict_accept(
*success = FALSE; *success = FALSE;
while (isspace(*ptr)) { while (my_isspace(cs, *ptr)) {
ptr++; ptr++;
} }
@@ -2400,12 +2419,15 @@ const char*
dict_scan_id( dict_scan_id(
/*=========*/ /*=========*/
/* out: scanned to */ /* out: scanned to */
struct charset_info_st* cs,/* in: the character set of ptr */
const char* ptr, /* in: scanned to */ const char* ptr, /* in: scanned to */
mem_heap_t* heap, /* in: heap where to allocate the id mem_heap_t* heap, /* in: heap where to allocate the id
(NULL=id will not be allocated, but it (NULL=id will not be allocated, but it
will point to string near ptr) */ will point to string near ptr) */
const char** id, /* out,own: the id; NULL if no id was const char** id, /* out,own: the id; NULL if no id was
scannable */ scannable */
ibool table_id,/* in: TRUE=convert the allocated id
as a table name; FALSE=convert to UTF-8 */
ibool accept_also_dot) ibool accept_also_dot)
/* in: TRUE if also a dot can appear in a /* in: TRUE if also a dot can appear in a
non-quoted id; in a quoted id it can appear non-quoted id; in a quoted id it can appear
@@ -2414,13 +2436,12 @@ dict_scan_id(
char quote = '\0'; char quote = '\0';
ulint len = 0; ulint len = 0;
const char* s; const char* s;
char* d; char* str;
ulint id_len; char* dst;
byte* b;
*id = NULL; *id = NULL;
while (isspace(*ptr)) { while (my_isspace(cs, *ptr)) {
ptr++; ptr++;
} }
@@ -2451,7 +2472,7 @@ dict_scan_id(
len++; len++;
} }
} else { } else {
while (!isspace(*ptr) && *ptr != '(' && *ptr != ')' while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
&& (accept_also_dot || *ptr != '.') && (accept_also_dot || *ptr != '.')
&& *ptr != ',' && *ptr != '\0') { && *ptr != ',' && *ptr != '\0') {
@@ -2461,43 +2482,50 @@ dict_scan_id(
len = ptr - s; len = ptr - s;
} }
if (quote && heap) { if (UNIV_UNLIKELY(!heap)) {
*id = d = mem_heap_alloc(heap, len + 1); /* no heap given: id will point to source string */
*id = s;
return(ptr);
}
if (quote) {
char* d;
str = d = mem_heap_alloc(heap, len + 1);
while (len--) { while (len--) {
if ((*d++ = *s++) == quote) { if ((*d++ = *s++) == quote) {
s++; s++;
} }
} }
*d++ = 0; *d++ = 0;
ut_a(*s == quote); len = d - str;
ut_a(s + 1 == ptr); ut_ad(*s == quote);
} else if (heap) { ut_ad(s + 1 == ptr);
*id = mem_heap_strdupl(heap, s, len);
} else { } else {
/* no heap given: id will point to source string */ str = mem_heap_strdupl(heap, s, len);
*id = s;
} }
if (heap && !quote) { if (!table_id) {
/* EMS MySQL Manager sometimes adds characters 0xA0 (in convert_id:
latin1, a 'non-breakable space') to the end of a table name. /* Convert the identifier from connection character set
But isspace(0xA0) is not true, which confuses our foreign key to UTF-8. */
parser. After the UTF-8 conversion in ha_innodb.cc, bytes 0xC2 len = 3 * len + 1;
and 0xA0 are at the end of the string. *id = dst = mem_heap_alloc(heap, len);
TODO: we should lex the string using thd->charset_info, and innobase_convert_from_id(dst, str, len);
my_isspace(). Only after that, convert id names to UTF-8. */ } else if (!strncmp(str, srv_mysql50_table_name_prefix,
sizeof srv_mysql50_table_name_prefix)) {
/* This is a pre-5.1 table name
containing chars other than [A-Za-z0-9].
Discard the prefix and use raw UTF-8 encoding. */
str += sizeof srv_mysql50_table_name_prefix;
len -= sizeof srv_mysql50_table_name_prefix;
goto convert_id;
} else {
/* Encode using filename-safe characters. */
len = 5 * len + 1;
*id = dst = mem_heap_alloc(heap, len);
b = (byte*)(*id); innobase_convert_from_table_id(dst, str, len);
id_len = strlen((char*) b);
if (id_len >= 3 && b[id_len - 1] == 0xA0
&& b[id_len - 2] == 0xC2) {
/* Strip the 2 last bytes */
b[id_len - 2] = '\0';
}
} }
return(ptr); return(ptr);
@@ -2510,6 +2538,7 @@ const char*
dict_scan_col( dict_scan_col(
/*==========*/ /*==========*/
/* out: scanned to */ /* out: scanned to */
struct charset_info_st* cs,/* in: the character set of ptr */
const char* ptr, /* in: scanned to */ const char* ptr, /* in: scanned to */
ibool* success,/* out: TRUE if success */ ibool* success,/* out: TRUE if success */
dict_table_t* table, /* in: table in which the column is */ dict_table_t* table, /* in: table in which the column is */
@@ -2518,13 +2547,12 @@ dict_scan_col(
const char** name) /* out,own: the column name; NULL if no name const char** name) /* out,own: the column name; NULL if no name
was scannable */ was scannable */
{ {
#ifndef UNIV_HOTBACKUP
dict_col_t* col; dict_col_t* col;
ulint i; ulint i;
*success = FALSE; *success = FALSE;
ptr = dict_scan_id(ptr, heap, name, TRUE); ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
if (*name == NULL) { if (*name == NULL) {
@@ -2552,13 +2580,6 @@ dict_scan_col(
} }
return(ptr); return(ptr);
#else /* UNIV_HOTBACKUP */
/* This function depends on MySQL code that is not included in
InnoDB Hot Backup builds. Besides, this function should never
be called in InnoDB Hot Backup. */
ut_error;
return(NULL);
#endif /* UNIV_HOTBACKUP */
} }
/************************************************************************* /*************************************************************************
@@ -2568,6 +2589,7 @@ const char*
dict_scan_table_name( dict_scan_table_name(
/*=================*/ /*=================*/
/* out: scanned to */ /* out: scanned to */
struct charset_info_st* cs,/* in: the character set of ptr */
const char* ptr, /* in: scanned to */ const char* ptr, /* in: scanned to */
dict_table_t** table, /* out: table object or NULL */ dict_table_t** table, /* out: table object or NULL */
const char* name, /* in: foreign key table name */ const char* name, /* in: foreign key table name */
@@ -2576,7 +2598,6 @@ dict_scan_table_name(
const char** ref_name)/* out,own: the table name; const char** ref_name)/* out,own: the table name;
NULL if no name was scannable */ NULL if no name was scannable */
{ {
#ifndef UNIV_HOTBACKUP
const char* database_name = NULL; const char* database_name = NULL;
ulint database_name_len = 0; ulint database_name_len = 0;
const char* table_name = NULL; const char* table_name = NULL;
@@ -2587,7 +2608,7 @@ dict_scan_table_name(
*success = FALSE; *success = FALSE;
*table = NULL; *table = NULL;
ptr = dict_scan_id(ptr, heap, &scan_name, FALSE); ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
if (scan_name == NULL) { if (scan_name == NULL) {
@@ -2602,7 +2623,7 @@ dict_scan_table_name(
database_name = scan_name; database_name = scan_name;
database_name_len = strlen(database_name); database_name_len = strlen(database_name);
ptr = dict_scan_id(ptr, heap, &table_name, FALSE); ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
if (table_name == NULL) { if (table_name == NULL) {
@@ -2658,13 +2679,6 @@ dict_scan_table_name(
*table = dict_table_get_low(ref); *table = dict_table_get_low(ref);
return(ptr); return(ptr);
#else /* UNIV_HOTBACKUP */
/* This function depends on MySQL code that is not included in
InnoDB Hot Backup builds. Besides, this function should never
be called in InnoDB Hot Backup. */
ut_error;
return(NULL);
#endif /* UNIV_HOTBACKUP */
} }
/************************************************************************* /*************************************************************************
@@ -2674,6 +2688,7 @@ const char*
dict_skip_word( dict_skip_word(
/*===========*/ /*===========*/
/* out: scanned to */ /* out: scanned to */
struct charset_info_st* cs,/* in: the character set of ptr */
const char* ptr, /* in: scanned to */ const char* ptr, /* in: scanned to */
ibool* success)/* out: TRUE if success, FALSE if just spaces ibool* success)/* out: TRUE if success, FALSE if just spaces
left in string or a syntax error */ left in string or a syntax error */
@@ -2682,7 +2697,7 @@ dict_skip_word(
*success = FALSE; *success = FALSE;
ptr = dict_scan_id(ptr, NULL, &start, TRUE); ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
if (start) { if (start) {
*success = TRUE; *success = TRUE;
@@ -2860,6 +2875,7 @@ dict_create_foreign_constraints_low(
/* out: error code or DB_SUCCESS */ /* out: error code or DB_SUCCESS */
trx_t* trx, /* in: transaction */ trx_t* trx, /* in: transaction */
mem_heap_t* heap, /* in: memory heap */ mem_heap_t* heap, /* in: memory heap */
struct charset_info_st* cs,/* in: the character set of sql_string */
const char* sql_string, const char* sql_string,
/* in: CREATE TABLE or ALTER TABLE statement /* in: CREATE TABLE or ALTER TABLE statement
where foreign keys are declared like: where foreign keys are declared like:
@@ -2917,14 +2933,14 @@ dict_create_foreign_constraints_low(
/* First check if we are actually doing an ALTER TABLE, and in that /* First check if we are actually doing an ALTER TABLE, and in that
case look for the table being altered */ case look for the table being altered */
ptr = dict_accept(ptr, "ALTER", &success); ptr = dict_accept(cs, ptr, "ALTER", &success);
if (!success) { if (!success) {
goto loop; goto loop;
} }
ptr = dict_accept(ptr, "TABLE", &success); ptr = dict_accept(cs, ptr, "TABLE", &success);
if (!success) { if (!success) {
@@ -2933,7 +2949,7 @@ dict_create_foreign_constraints_low(
/* We are doing an ALTER TABLE: scan the table name we are altering */ /* We are doing an ALTER TABLE: scan the table name we are altering */
ptr = dict_scan_table_name(ptr, &table_to_alter, name, ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
&success, heap, &referenced_table_name); &success, heap, &referenced_table_name);
if (!success) { if (!success) {
fprintf(stderr, fprintf(stderr,
@@ -2973,21 +2989,22 @@ loop:
of the constraint to system tables. */ of the constraint to system tables. */
ptr = ptr1; ptr = ptr1;
ptr = dict_accept(ptr, "CONSTRAINT", &success); ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
ut_a(success); ut_a(success);
if (!isspace(*ptr) && *ptr != '"' && *ptr != '`') { if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
goto loop; goto loop;
} }
while (isspace(*ptr)) { while (my_isspace(cs, *ptr)) {
ptr++; ptr++;
} }
/* read constraint name unless got "CONSTRAINT FOREIGN" */ /* read constraint name unless got "CONSTRAINT FOREIGN" */
if (ptr != ptr2) { if (ptr != ptr2) {
ptr = dict_scan_id(ptr, heap, &constraint_name, FALSE); ptr = dict_scan_id(cs, ptr, heap,
&constraint_name, FALSE, FALSE);
} }
} else { } else {
ptr = ptr2; ptr = ptr2;
@@ -3002,7 +3019,8 @@ loop:
if so, immediately reject the command if the table is a if so, immediately reject the command if the table is a
temporary one. For now, this kludge will work. */ temporary one. For now, this kludge will work. */
if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) { if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
return DB_CANNOT_ADD_CONSTRAINT;
return(DB_CANNOT_ADD_CONSTRAINT);
} }
/**********************************************************/ /**********************************************************/
@@ -3016,28 +3034,28 @@ loop:
start_of_latest_foreign = ptr; start_of_latest_foreign = ptr;
ptr = dict_accept(ptr, "FOREIGN", &success); ptr = dict_accept(cs, ptr, "FOREIGN", &success);
if (!success) { if (!success) {
goto loop; goto loop;
} }
if (!isspace(*ptr)) { if (!my_isspace(cs, *ptr)) {
goto loop; goto loop;
} }
ptr = dict_accept(ptr, "KEY", &success); ptr = dict_accept(cs, ptr, "KEY", &success);
if (!success) { if (!success) {
goto loop; goto loop;
} }
ptr = dict_accept(ptr, "(", &success); ptr = dict_accept(cs, ptr, "(", &success);
if (!success) { if (!success) {
/* MySQL allows also an index id before the '('; we /* MySQL allows also an index id before the '('; we
skip it */ skip it */
ptr = dict_skip_word(ptr, &success); ptr = dict_skip_word(cs, ptr, &success);
if (!success) { if (!success) {
dict_foreign_report_syntax_err(name, dict_foreign_report_syntax_err(name,
@@ -3046,7 +3064,7 @@ loop:
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
ptr = dict_accept(ptr, "(", &success); ptr = dict_accept(cs, ptr, "(", &success);
if (!success) { if (!success) {
/* We do not flag a syntax error here because in an /* We do not flag a syntax error here because in an
@@ -3061,7 +3079,7 @@ loop:
/* Scan the columns in the first list */ /* Scan the columns in the first list */
col_loop1: col_loop1:
ut_a(i < (sizeof column_names) / sizeof *column_names); ut_a(i < (sizeof column_names) / sizeof *column_names);
ptr = dict_scan_col(ptr, &success, table, columns + i, ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
heap, column_names + i); heap, column_names + i);
if (!success) { if (!success) {
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
@@ -3075,13 +3093,13 @@ col_loop1:
i++; i++;
ptr = dict_accept(ptr, ",", &success); ptr = dict_accept(cs, ptr, ",", &success);
if (success) { if (success) {
goto col_loop1; goto col_loop1;
} }
ptr = dict_accept(ptr, ")", &success); ptr = dict_accept(cs, ptr, ")", &success);
if (!success) { if (!success) {
dict_foreign_report_syntax_err(name, start_of_latest_foreign, dict_foreign_report_syntax_err(name, start_of_latest_foreign,
@@ -3098,7 +3116,7 @@ col_loop1:
mutex_enter(&dict_foreign_err_mutex); mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name); dict_foreign_error_report_low(ef, name);
fputs("There is no index in table ", ef); fputs("There is no index in table ", ef);
ut_print_name(ef, NULL, name); ut_print_name(ef, NULL, TRUE, name);
fprintf(ef, " where the columns appear\n" fprintf(ef, " where the columns appear\n"
"as the first columns. Constraint:\n%s\n" "as the first columns. Constraint:\n%s\n"
"See http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n" "See http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n"
@@ -3108,9 +3126,9 @@ col_loop1:
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
ptr = dict_accept(ptr, "REFERENCES", &success); ptr = dict_accept(cs, ptr, "REFERENCES", &success);
if (!success || !isspace(*ptr)) { if (!success || !my_isspace(cs, *ptr)) {
dict_foreign_report_syntax_err(name, start_of_latest_foreign, dict_foreign_report_syntax_err(name, start_of_latest_foreign,
ptr); ptr);
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
@@ -3150,7 +3168,7 @@ col_loop1:
mem_heap_strdup(foreign->heap, columns[i]->name); mem_heap_strdup(foreign->heap, columns[i]->name);
} }
ptr = dict_scan_table_name(ptr, &referenced_table, name, ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
&success, heap, &referenced_table_name); &success, heap, &referenced_table_name);
/* Note that referenced_table can be NULL if the user has suppressed /* Note that referenced_table can be NULL if the user has suppressed
@@ -3169,7 +3187,7 @@ col_loop1:
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
ptr = dict_accept(ptr, "(", &success); ptr = dict_accept(cs, ptr, "(", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
@@ -3182,7 +3200,7 @@ col_loop1:
i = 0; i = 0;
col_loop2: col_loop2:
ptr = dict_scan_col(ptr, &success, referenced_table, columns + i, ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
heap, column_names + i); heap, column_names + i);
i++; i++;
@@ -3199,13 +3217,13 @@ col_loop2:
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
ptr = dict_accept(ptr, ",", &success); ptr = dict_accept(cs, ptr, ",", &success);
if (success) { if (success) {
goto col_loop2; goto col_loop2;
} }
ptr = dict_accept(ptr, ")", &success); ptr = dict_accept(cs, ptr, ")", &success);
if (!success || foreign->n_fields != i) { if (!success || foreign->n_fields != i) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
@@ -3221,17 +3239,17 @@ col_loop2:
scan_on_conditions: scan_on_conditions:
/* Loop here as long as we can find ON ... conditions */ /* Loop here as long as we can find ON ... conditions */
ptr = dict_accept(ptr, "ON", &success); ptr = dict_accept(cs, ptr, "ON", &success);
if (!success) { if (!success) {
goto try_find_index; goto try_find_index;
} }
ptr = dict_accept(ptr, "DELETE", &success); ptr = dict_accept(cs, ptr, "DELETE", &success);
if (!success) { if (!success) {
ptr = dict_accept(ptr, "UPDATE", &success); ptr = dict_accept(cs, ptr, "UPDATE", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
@@ -3248,13 +3266,13 @@ scan_on_conditions:
n_on_deletes++; n_on_deletes++;
} }
ptr = dict_accept(ptr, "RESTRICT", &success); ptr = dict_accept(cs, ptr, "RESTRICT", &success);
if (success) { if (success) {
goto scan_on_conditions; goto scan_on_conditions;
} }
ptr = dict_accept(ptr, "CASCADE", &success); ptr = dict_accept(cs, ptr, "CASCADE", &success);
if (success) { if (success) {
if (is_on_delete) { if (is_on_delete) {
@@ -3266,10 +3284,10 @@ scan_on_conditions:
goto scan_on_conditions; goto scan_on_conditions;
} }
ptr = dict_accept(ptr, "NO", &success); ptr = dict_accept(cs, ptr, "NO", &success);
if (success) { if (success) {
ptr = dict_accept(ptr, "ACTION", &success); ptr = dict_accept(cs, ptr, "ACTION", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
@@ -3288,7 +3306,7 @@ scan_on_conditions:
goto scan_on_conditions; goto scan_on_conditions;
} }
ptr = dict_accept(ptr, "SET", &success); ptr = dict_accept(cs, ptr, "SET", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
@@ -3297,7 +3315,7 @@ scan_on_conditions:
return(DB_CANNOT_ADD_CONSTRAINT); return(DB_CANNOT_ADD_CONSTRAINT);
} }
ptr = dict_accept(ptr, "NULL", &success); ptr = dict_accept(cs, ptr, "NULL", &success);
if (!success) { if (!success) {
dict_foreign_free(foreign); dict_foreign_free(foreign);
@@ -3407,6 +3425,25 @@ try_find_index:
goto loop; goto loop;
} }
/**************************************************************************
Determines whether a string starts with the specified keyword. */
ibool
dict_str_starts_with_keyword(
/*=========================*/
/* out: TRUE if str starts
with keyword */
void* mysql_thd, /* in: MySQL thread handle */
const char* str, /* in: string to scan for keyword */
const char* keyword) /* in: keyword to look for */
{
struct charset_info_st* cs = innobase_get_charset(mysql_thd);
ibool success;
dict_accept(cs, str, keyword, &success);
return(success);
}
/************************************************************************* /*************************************************************************
Scans a table create SQL string and adds to the data dictionary the foreign Scans a table create SQL string and adds to the data dictionary the foreign
key constraints declared in the string. This function should be called after key constraints declared in the string. This function should be called after
@@ -3434,15 +3471,18 @@ dict_create_foreign_constraints(
code DB_CANNOT_ADD_CONSTRAINT if code DB_CANNOT_ADD_CONSTRAINT if
any foreign keys are found. */ any foreign keys are found. */
{ {
char* str; char* str;
ulint err; ulint err;
mem_heap_t* heap; mem_heap_t* heap;
ut_a(trx && trx->mysql_thd);
str = dict_strip_comments(sql_string); str = dict_strip_comments(sql_string);
heap = mem_heap_create(10000); heap = mem_heap_create(10000);
err = dict_create_foreign_constraints_low(trx, heap, str, name, err = dict_create_foreign_constraints_low(trx, heap,
reject_fks); innobase_get_charset(trx->mysql_thd),
str, name, reject_fks);
mem_heap_free(heap); mem_heap_free(heap);
mem_free(str); mem_free(str);
@@ -3469,12 +3509,17 @@ dict_foreign_parse_drop_constraints(
const char*** constraints_to_drop) /* out: id's of the const char*** constraints_to_drop) /* out: id's of the
constraints to drop */ constraints to drop */
{ {
dict_foreign_t* foreign; dict_foreign_t* foreign;
ibool success; ibool success;
char* str; char* str;
const char* ptr; const char* ptr;
const char* id; const char* id;
FILE* ef = dict_foreign_err_file; FILE* ef = dict_foreign_err_file;
struct charset_info_st* cs;
ut_a(trx && trx->mysql_thd);
cs = innobase_get_charset(trx->mysql_thd);
*n = 0; *n = 0;
@@ -3495,28 +3540,28 @@ loop:
return(DB_SUCCESS); return(DB_SUCCESS);
} }
ptr = dict_accept(ptr, "DROP", &success); ptr = dict_accept(cs, ptr, "DROP", &success);
if (!isspace(*ptr)) { if (!my_isspace(cs, *ptr)) {
goto loop; goto loop;
} }
ptr = dict_accept(ptr, "FOREIGN", &success); ptr = dict_accept(cs, ptr, "FOREIGN", &success);
if (!success) { if (!success) {
goto loop; goto loop;
} }
ptr = dict_accept(ptr, "KEY", &success); ptr = dict_accept(cs, ptr, "KEY", &success);
if (!success) { if (!success) {
goto syntax_error; goto syntax_error;
} }
ptr = dict_scan_id(ptr, heap, &id, TRUE); ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
if (id == NULL) { if (id == NULL) {
@@ -3549,12 +3594,12 @@ loop:
ut_print_timestamp(ef); ut_print_timestamp(ef);
fputs( fputs(
" Error in dropping of a foreign key constraint of table ", ef); " Error in dropping of a foreign key constraint of table ", ef);
ut_print_name(ef, NULL, table->name); ut_print_name(ef, NULL, TRUE, table->name);
fputs(",\n" fputs(",\n"
"in SQL command\n", ef); "in SQL command\n", ef);
fputs(str, ef); fputs(str, ef);
fputs("\nCannot find a constraint with the given id ", ef); fputs("\nCannot find a constraint with the given id ", ef);
ut_print_name(ef, NULL, id); ut_print_name(ef, NULL, FALSE, id);
fputs(".\n", ef); fputs(".\n", ef);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
@@ -3571,7 +3616,7 @@ syntax_error:
ut_print_timestamp(ef); ut_print_timestamp(ef);
fputs( fputs(
" Syntax error in dropping of a foreign key constraint of table ", ef); " Syntax error in dropping of a foreign key constraint of table ", ef);
ut_print_name(ef, NULL, table->name); ut_print_name(ef, NULL, TRUE, table->name);
fprintf(ef, ",\n" fprintf(ef, ",\n"
"close to:\n%s\n in SQL command\n%s\n", ptr, str); "close to:\n%s\n in SQL command\n%s\n", ptr, str);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
@@ -3580,6 +3625,7 @@ syntax_error:
return(DB_CANNOT_DROP_CONSTRAINT); return(DB_CANNOT_DROP_CONSTRAINT);
} }
#endif /* UNIV_HOTBACKUP */
/*==================== END OF FOREIGN KEY PROCESSING ====================*/ /*==================== END OF FOREIGN KEY PROCESSING ====================*/
@@ -3653,9 +3699,7 @@ dict_tree_create(
tree->magic_n = DICT_TREE_MAGIC_N; tree->magic_n = DICT_TREE_MAGIC_N;
rw_lock_create(&(tree->lock)); rw_lock_create(&tree->lock, SYNC_INDEX_TREE);
rw_lock_set_level(&(tree->lock), SYNC_INDEX_TREE);
return(tree); return(tree);
} }
@@ -4232,11 +4276,11 @@ dict_print_info_on_foreign_key_in_create_format(
} }
fputs(" CONSTRAINT ", file); fputs(" CONSTRAINT ", file);
ut_print_name(file, trx, stripped_id); ut_print_name(file, trx, FALSE, stripped_id);
fputs(" FOREIGN KEY (", file); fputs(" FOREIGN KEY (", file);
for (i = 0;;) { for (i = 0;;) {
ut_print_name(file, trx, foreign->foreign_col_names[i]); ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
if (++i < foreign->n_fields) { if (++i < foreign->n_fields) {
fputs(", ", file); fputs(", ", file);
} else { } else {
@@ -4249,7 +4293,7 @@ dict_print_info_on_foreign_key_in_create_format(
if (dict_tables_have_same_db(foreign->foreign_table_name, if (dict_tables_have_same_db(foreign->foreign_table_name,
foreign->referenced_table_name)) { foreign->referenced_table_name)) {
/* Do not print the database name of the referenced table */ /* Do not print the database name of the referenced table */
ut_print_name(file, trx, dict_remove_db_name( ut_print_name(file, trx, TRUE, dict_remove_db_name(
foreign->referenced_table_name)); foreign->referenced_table_name));
} else { } else {
/* Look for the '/' in the table name */ /* Look for the '/' in the table name */
@@ -4259,9 +4303,10 @@ dict_print_info_on_foreign_key_in_create_format(
i++; i++;
} }
ut_print_namel(file, trx, foreign->referenced_table_name, i); ut_print_namel(file, trx, TRUE,
foreign->referenced_table_name, i);
putc('.', file); putc('.', file);
ut_print_name(file, trx, ut_print_name(file, trx, TRUE,
foreign->referenced_table_name + i + 1); foreign->referenced_table_name + i + 1);
} }
@@ -4269,7 +4314,8 @@ dict_print_info_on_foreign_key_in_create_format(
putc('(', file); putc('(', file);
for (i = 0;;) { for (i = 0;;) {
ut_print_name(file, trx, foreign->referenced_col_names[i]); ut_print_name(file, trx, FALSE,
foreign->referenced_col_names[i]);
if (++i < foreign->n_fields) { if (++i < foreign->n_fields) {
fputs(", ", file); fputs(", ", file);
} else { } else {
@@ -4343,12 +4389,12 @@ dict_print_info_on_foreign_keys(
putc(' ', file); putc(' ', file);
} }
ut_print_name(file, trx, ut_print_name(file, trx, FALSE,
foreign->foreign_col_names[i]); foreign->foreign_col_names[i]);
} }
fputs(") REFER ", file); fputs(") REFER ", file);
ut_print_name(file, trx, ut_print_name(file, trx, TRUE,
foreign->referenced_table_name); foreign->referenced_table_name);
putc('(', file); putc('(', file);
@@ -4356,7 +4402,7 @@ dict_print_info_on_foreign_keys(
if (i) { if (i) {
putc(' ', file); putc(' ', file);
} }
ut_print_name(file, trx, ut_print_name(file, trx, FALSE,
foreign->referenced_col_names[i]); foreign->referenced_col_names[i]);
} }
@@ -4403,7 +4449,7 @@ dict_index_name_print(
const dict_index_t* index) /* in: index to print */ const dict_index_t* index) /* in: index to print */
{ {
fputs("index ", file); fputs("index ", file);
ut_print_name(file, trx, index->name); ut_print_name(file, trx, FALSE, index->name);
fputs(" of table ", file); fputs(" of table ", file);
ut_print_name(file, trx, index->table_name); ut_print_name(file, trx, TRUE, index->table_name);
} }

View File

@@ -184,7 +184,7 @@ loop:
if (table == NULL) { if (table == NULL) {
fputs("InnoDB: Failed to load table ", stderr); fputs("InnoDB: Failed to load table ", stderr);
ut_print_namel(stderr, NULL, (char*) field, len); ut_print_namel(stderr, NULL, TRUE, (char*) field, len);
putc('\n', stderr); putc('\n', stderr);
} else { } else {
/* The table definition was corrupt if there /* The table definition was corrupt if there

View File

@@ -58,7 +58,6 @@ dict_mem_table_create(
table->tablespace_discarded = FALSE; table->tablespace_discarded = FALSE;
table->n_def = 0; table->n_def = 0;
table->n_cols = n_cols + DATA_N_SYS_COLS; table->n_cols = n_cols + DATA_N_SYS_COLS;
table->mem_fix = 0;
table->n_mysql_handles_opened = 0; table->n_mysql_handles_opened = 0;
table->n_foreign_key_checks_running = 0; table->n_foreign_key_checks_running = 0;
@@ -83,8 +82,9 @@ dict_mem_table_create(
table->stat_modified_counter = 0; table->stat_modified_counter = 0;
mutex_create(&(table->autoinc_mutex)); table->max_row_size = 0;
mutex_set_level(&(table->autoinc_mutex), SYNC_DICT_AUTOINC_MUTEX);
mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
table->autoinc_inited = FALSE; table->autoinc_inited = FALSE;

View File

@@ -1050,8 +1050,7 @@ try_again:
space->ibuf_data = NULL; space->ibuf_data = NULL;
rw_lock_create(&(space->latch)); rw_lock_create(&space->latch, SYNC_FSP);
rw_lock_set_level(&(space->latch), SYNC_FSP);
HASH_INSERT(fil_space_t, hash, system->spaces, id, space); HASH_INSERT(fil_space_t, hash, system->spaces, id, space);
@@ -1295,9 +1294,7 @@ fil_system_create(
system = mem_alloc(sizeof(fil_system_t)); system = mem_alloc(sizeof(fil_system_t));
mutex_create(&(system->mutex)); mutex_create(&system->mutex, SYNC_ANY_LATCH);
mutex_set_level(&(system->mutex), SYNC_ANY_LATCH);
system->spaces = hash_create(hash_size); system->spaces = hash_create(hash_size);
system->name_hash = hash_create(hash_size); system->name_hash = hash_create(hash_size);

View File

@@ -144,9 +144,7 @@ hash_create_mutexes(
table->mutexes = mem_alloc(n_mutexes * sizeof(mutex_t)); table->mutexes = mem_alloc(n_mutexes * sizeof(mutex_t));
for (i = 0; i < n_mutexes; i++) { for (i = 0; i < n_mutexes; i++) {
mutex_create(table->mutexes + i); mutex_create(table->mutexes + i, sync_level);
mutex_set_level(table->mutexes + i, sync_level);
} }
table->n_mutexes = n_mutexes; table->n_mutexes = n_mutexes;

View File

@@ -144,6 +144,7 @@ static ulint ibuf_rnd = 986058871;
ulint ibuf_flush_count = 0; ulint ibuf_flush_count = 0;
#ifdef UNIV_IBUF_DEBUG
/* Dimensions for the ibuf_count array */ /* Dimensions for the ibuf_count array */
#define IBUF_COUNT_N_SPACES 500 #define IBUF_COUNT_N_SPACES 500
#define IBUF_COUNT_N_PAGES 2000 #define IBUF_COUNT_N_PAGES 2000
@@ -152,6 +153,7 @@ ulint ibuf_flush_count = 0;
static ulint* ibuf_counts[IBUF_COUNT_N_SPACES]; static ulint* ibuf_counts[IBUF_COUNT_N_SPACES];
static ibool ibuf_counts_inited = FALSE; static ibool ibuf_counts_inited = FALSE;
#endif
/* The start address for an insert buffer bitmap page bitmap */ /* The start address for an insert buffer bitmap page bitmap */
#define IBUF_BITMAP PAGE_DATA #define IBUF_BITMAP PAGE_DATA
@@ -314,6 +316,7 @@ ibuf_tree_root_get(
return(page); return(page);
} }
#ifdef UNIV_IBUF_DEBUG
/********************************************************************** /**********************************************************************
Gets the ibuf count for a given page. */ Gets the ibuf count for a given page. */
@@ -338,7 +341,6 @@ ibuf_count_get(
/********************************************************************** /**********************************************************************
Sets the ibuf count for a given page. */ Sets the ibuf count for a given page. */
#ifdef UNIV_IBUF_DEBUG
static static
void void
ibuf_count_set( ibuf_count_set(
@@ -389,23 +391,18 @@ ibuf_init_at_db_start(void)
ibuf_count_set(i, j, 0); ibuf_count_set(i, j, 0);
} }
} }
ibuf_counts_inited = TRUE;
} }
#endif #endif
mutex_create(&ibuf_pessimistic_insert_mutex); mutex_create(&ibuf_pessimistic_insert_mutex,
SYNC_IBUF_PESS_INSERT_MUTEX);
mutex_set_level(&ibuf_pessimistic_insert_mutex, mutex_create(&ibuf_mutex, SYNC_IBUF_MUTEX);
SYNC_IBUF_PESS_INSERT_MUTEX);
mutex_create(&ibuf_mutex);
mutex_set_level(&ibuf_mutex, SYNC_IBUF_MUTEX); mutex_create(&ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
mutex_create(&ibuf_bitmap_mutex);
mutex_set_level(&ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX);
fil_ibuf_init_at_db_start(); fil_ibuf_init_at_db_start();
ibuf_counts_inited = TRUE;
} }
/********************************************************************** /**********************************************************************
@@ -2348,6 +2345,10 @@ ibuf_get_volume_buffered(
} }
prev_page = buf_page_get(0, prev_page_no, RW_X_LATCH, mtr); prev_page = buf_page_get(0, prev_page_no, RW_X_LATCH, mtr);
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_next(prev_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
buf_page_dbg_add_level(prev_page, SYNC_TREE_NODE); buf_page_dbg_add_level(prev_page, SYNC_TREE_NODE);
@@ -2411,6 +2412,10 @@ count_later:
} }
next_page = buf_page_get(0, next_page_no, RW_X_LATCH, mtr); next_page = buf_page_get(0, next_page_no, RW_X_LATCH, mtr);
#ifdef UNIV_BTR_DEBUG
ut_a(btr_page_get_prev(next_page, mtr)
== buf_frame_get_page_no(page));
#endif /* UNIV_BTR_DEBUG */
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
buf_page_dbg_add_level(next_page, SYNC_TREE_NODE); buf_page_dbg_add_level(next_page, SYNC_TREE_NODE);

View File

@@ -330,6 +330,16 @@ dtype_get_min_size(
/* out: minimum size */ /* out: minimum size */
const dtype_t* type); /* in: type */ const dtype_t* type); /* in: type */
/*************************************************************************** /***************************************************************************
Returns the maximum size of a data type. Note: types in system tables may be
incomplete and return incorrect information. */
UNIV_INLINE
ulint
dtype_get_max_size(
/*===============*/
/* out: maximum size (ULINT_MAX for
unbounded types) */
const dtype_t* type); /* in: type */
/***************************************************************************
Returns a stored SQL NULL size for a type. For fixed length types it is Returns a stored SQL NULL size for a type. For fixed length types it is
the fixed length of the type, otherwise 0. */ the fixed length of the type, otherwise 0. */
UNIV_INLINE UNIV_INLINE

View File

@@ -44,18 +44,6 @@ dict_get_db_name_len(
/* out: database name length */ /* out: database name length */
const char* name); /* in: table name in the form const char* name); /* in: table name in the form
dbname '/' tablename */ dbname '/' tablename */
/*************************************************************************
Accepts a specified string. Comparisons are case-insensitive. */
const char*
dict_accept(
/*========*/
/* out: if string was accepted, the pointer
is moved after that, else ptr is returned */
const char* ptr, /* in: scan from this */
const char* string, /* in: accept only this string as the next
non-whitespace string */
ibool* success);/* out: TRUE if accepted */
/************************************************************************ /************************************************************************
Decrements the count of open MySQL handles to a table. */ Decrements the count of open MySQL handles to a table. */
@@ -219,6 +207,17 @@ dict_table_referenced_by_foreign_key(
/* out: TRUE if table is referenced by a /* out: TRUE if table is referenced by a
foreign key */ foreign key */
dict_table_t* table); /* in: InnoDB table */ dict_table_t* table); /* in: InnoDB table */
/**************************************************************************
Determines whether a string starts with the specified keyword. */
ibool
dict_str_starts_with_keyword(
/*=========================*/
/* out: TRUE if str starts
with keyword */
void* mysql_thd, /* in: MySQL thread handle */
const char* str, /* in: string to scan for keyword */
const char* keyword); /* in: keyword to look for */
/************************************************************************* /*************************************************************************
Scans a table create SQL string and adds to the data dictionary Scans a table create SQL string and adds to the data dictionary
the foreign key constraints declared in the string. This function the foreign key constraints declared in the string. This function
@@ -265,17 +264,16 @@ dict_foreign_parse_drop_constraints(
const char*** constraints_to_drop); /* out: id's of the const char*** constraints_to_drop); /* out: id's of the
constraints to drop */ constraints to drop */
/************************************************************************** /**************************************************************************
Returns a table object and memoryfixes it. NOTE! This is a high-level Returns a table object. NOTE! This is a high-level function to be used
function to be used mainly from outside the 'dict' directory. Inside this mainly from outside the 'dict' directory. Inside this directory
directory dict_table_get_low is usually the appropriate function. */ dict_table_get_low is usually the appropriate function. */
dict_table_t* dict_table_t*
dict_table_get( dict_table_get(
/*===========*/ /*===========*/
/* out: table, NULL if /* out: table, NULL if
does not exist */ does not exist */
const char* table_name, /* in: table name */ const char* table_name); /* in: table name */
trx_t* trx); /* in: transaction handle */
/************************************************************************** /**************************************************************************
Returns a table object and increments MySQL open handle count on the table. Returns a table object and increments MySQL open handle count on the table.
*/ */
@@ -285,10 +283,9 @@ dict_table_get_and_increment_handle_count(
/*======================================*/ /*======================================*/
/* out: table, NULL if /* out: table, NULL if
does not exist */ does not exist */
const char* table_name, /* in: table name */ const char* table_name); /* in: table name */
trx_t* trx); /* in: transaction handle or NULL */
/************************************************************************** /**************************************************************************
Returns a table object, based on table id, and memoryfixes it. */ Returns a table object based on table id. */
dict_table_t* dict_table_t*
dict_table_get_on_id( dict_table_get_on_id(
@@ -297,21 +294,13 @@ dict_table_get_on_id(
dulint table_id, /* in: table id */ dulint table_id, /* in: table id */
trx_t* trx); /* in: transaction handle */ trx_t* trx); /* in: transaction handle */
/************************************************************************** /**************************************************************************
Returns a table object, based on table id, and memoryfixes it. */ Returns a table object based on table id. */
UNIV_INLINE UNIV_INLINE
dict_table_t* dict_table_t*
dict_table_get_on_id_low( dict_table_get_on_id_low(
/*=====================*/ /*=====================*/
/* out: table, NULL if does not exist */ /* out: table, NULL if does not exist */
dulint table_id, /* in: table id */ dulint table_id); /* in: table id */
trx_t* trx); /* in: transaction handle */
/**************************************************************************
Releases a table from being memoryfixed. Currently this has no relevance. */
UNIV_INLINE
void
dict_table_release(
/*===============*/
dict_table_t* table); /* in: table to be released */
/************************************************************************** /**************************************************************************
Checks if a table is in the dictionary cache. */ Checks if a table is in the dictionary cache. */
UNIV_INLINE UNIV_INLINE

View File

@@ -545,14 +545,13 @@ dict_table_get_low(
} }
/************************************************************************** /**************************************************************************
Returns a table object, based on table id, and memoryfixes it. */ Returns a table object based on table id. */
UNIV_INLINE UNIV_INLINE
dict_table_t* dict_table_t*
dict_table_get_on_id_low( dict_table_get_on_id_low(
/*=====================*/ /*=====================*/
/* out: table, NULL if does not exist */ /* out: table, NULL if does not exist */
dulint table_id, /* in: table id */ dulint table_id) /* in: table id */
trx_t* trx) /* in: transaction handle */
{ {
dict_table_t* table; dict_table_t* table;
ulint fold; ulint fold;
@@ -560,7 +559,6 @@ dict_table_get_on_id_low(
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
UT_NOT_USED(trx);
/* Look for the table name in the hash table */ /* Look for the table name in the hash table */
fold = ut_fold_dulint(table_id); fold = ut_fold_dulint(table_id);
@@ -571,32 +569,11 @@ dict_table_get_on_id_low(
table = dict_load_table_on_id(table_id); table = dict_load_table_on_id(table_id);
} }
if (table != NULL) {
table->mem_fix++;
/* lock_push(trx, table, LOCK_DICT_MEM_FIX) */
}
/* TODO: should get the type information from MySQL */ /* TODO: should get the type information from MySQL */
return(table); return(table);
} }
/**************************************************************************
Releases a table from being memoryfixed. Currently this has no relevance. */
UNIV_INLINE
void
dict_table_release(
/*===============*/
dict_table_t* table) /* in: table to be released */
{
mutex_enter(&(dict_sys->mutex));
table->mem_fix--;
mutex_exit(&(dict_sys->mutex));
}
/************************************************************************** /**************************************************************************
Returns an index object. */ Returns an index object. */
UNIV_INLINE UNIV_INLINE

View File

@@ -169,10 +169,6 @@ struct dict_tree_struct{
the same memory cache line */ the same memory cache line */
rw_lock_t lock; /* read-write lock protecting the upper levels rw_lock_t lock; /* read-write lock protecting the upper levels
of the index tree */ of the index tree */
ulint mem_fix;/* count of how many times this tree
struct has been memoryfixed (by mini-
transactions wanting to access the index
tree) */
dict_index_t* tree_index; /* the index stored in the dict_index_t* tree_index; /* the index stored in the
index tree */ index tree */
ulint magic_n;/* magic number */ ulint magic_n;/* magic number */
@@ -315,9 +311,6 @@ struct dict_table_struct{
which refer to this table */ which refer to this table */
UT_LIST_NODE_T(dict_table_t) UT_LIST_NODE_T(dict_table_t)
table_LRU; /* node of the LRU list of tables */ table_LRU; /* node of the LRU list of tables */
ulint mem_fix;/* count of how many times the table
and its indexes has been fixed in memory;
currently NOT used */
ulint n_mysql_handles_opened; ulint n_mysql_handles_opened;
/* count of how many handles MySQL has opened /* count of how many handles MySQL has opened
to this table; dropping of the table is to this table; dropping of the table is
@@ -348,6 +341,12 @@ struct dict_table_struct{
had an IX lock on */ had an IX lock on */
UT_LIST_BASE_NODE_T(lock_t) UT_LIST_BASE_NODE_T(lock_t)
locks; /* list of locks on the table */ locks; /* list of locks on the table */
ulint max_row_size;
/* maximum size of a single row in the
table, not guaranteed to be especially
accurate. it's ULINT_MAX if there are
unbounded variable-width fields. initialized
in dict_table_add_to_cache. */
/*----------------------*/ /*----------------------*/
ibool does_not_fit_in_memory; ibool does_not_fit_in_memory;
/* this field is used to specify in simulations /* this field is used to specify in simulations

View File

@@ -57,9 +57,21 @@ extern fil_addr_t fil_addr_null;
page */ page */
#define FIL_PAGE_OFFSET 4 /* page offset inside space */ #define FIL_PAGE_OFFSET 4 /* page offset inside space */
#define FIL_PAGE_PREV 8 /* if there is a 'natural' predecessor #define FIL_PAGE_PREV 8 /* if there is a 'natural' predecessor
of the page, its offset */ of the page, its offset.
Otherwise FIL_NULL.
This field is not set on BLOB pages,
which are stored as a singly-linked
list. See also FIL_PAGE_NEXT. */
#define FIL_PAGE_NEXT 12 /* if there is a 'natural' successor #define FIL_PAGE_NEXT 12 /* if there is a 'natural' successor
of the page, its offset */ of the page, its offset.
Otherwise FIL_NULL.
B-tree index pages
(FIL_PAGE_TYPE contains FIL_PAGE_INDEX)
on the same PAGE_LEVEL are maintained
as a doubly linked list via
FIL_PAGE_PREV and FIL_PAGE_NEXT
in the collation order of the
smallest user record on each page. */
#define FIL_PAGE_LSN 16 /* lsn of the end of the newest #define FIL_PAGE_LSN 16 /* lsn of the end of the newest
modification log record to the page */ modification log record to the page */
#define FIL_PAGE_TYPE 24 /* file page type: FIL_PAGE_INDEX,..., #define FIL_PAGE_TYPE 24 /* file page type: FIL_PAGE_INDEX,...,

View File

@@ -360,24 +360,28 @@ description takes less than 1 byte; a descriptor page is repeated every
this many file pages */ this many file pages */
#define XDES_DESCRIBED_PER_PAGE UNIV_PAGE_SIZE #define XDES_DESCRIBED_PER_PAGE UNIV_PAGE_SIZE
/* The space low address page map, and also offsets for extent descriptor and /* The space low address page map */
bitmap pages which are repeated always after XDES_DESCRIBED_PER_PAGE more
pages: */
/*--------------------------------------*/ /*--------------------------------------*/
#define FSP_XDES_OFFSET 0 /* The following two pages are repeated
#define FSP_IBUF_BITMAP_OFFSET 1 every XDES_DESCRIBED_PER_PAGE pages in
every tablespace. */
#define FSP_XDES_OFFSET 0 /* extent descriptor */
#define FSP_IBUF_BITMAP_OFFSET 1 /* insert buffer bitmap */
/* The ibuf bitmap pages are the ones whose /* The ibuf bitmap pages are the ones whose
page number is the number above plus a page number is the number above plus a
multiple of XDES_DESCRIBED_PER_PAGE */ multiple of XDES_DESCRIBED_PER_PAGE */
#define FSP_FIRST_INODE_PAGE_NO 2
#define FSP_IBUF_HEADER_PAGE_NO 3 #define FSP_FIRST_INODE_PAGE_NO 2 /* in every tablespace */
#define FSP_IBUF_TREE_ROOT_PAGE_NO 4 /* The following pages exist
in the system tablespace (space 0). */
#define FSP_IBUF_HEADER_PAGE_NO 3 /* in tablespace 0 */
#define FSP_IBUF_TREE_ROOT_PAGE_NO 4 /* in tablespace 0 */
/* The ibuf tree root page number in /* The ibuf tree root page number in
tablespace 0; its fseg inode is on the page tablespace 0; its fseg inode is on the page
number FSP_FIRST_INODE_PAGE_NO */ number FSP_FIRST_INODE_PAGE_NO */
#define FSP_TRX_SYS_PAGE_NO 5 #define FSP_TRX_SYS_PAGE_NO 5 /* in tablespace 0 */
#define FSP_FIRST_RSEG_PAGE_NO 6 #define FSP_FIRST_RSEG_PAGE_NO 6 /* in tablespace 0 */
#define FSP_DICT_HDR_PAGE_NO 7 #define FSP_DICT_HDR_PAGE_NO 7 /* in tablespace 0 */
/*--------------------------------------*/ /*--------------------------------------*/
#ifndef UNIV_NONINL #ifndef UNIV_NONINL

View File

@@ -0,0 +1,22 @@
#ifndef HA_INNODB_PROTOTYPES_H
#define HA_INNODB_PROTOTYPES_H
/* Prototypes for global functions in ha_innodb.cc that are called by
InnoDB's C-code. */
/*************************************************************************
Wrapper around MySQL's copy_and_convert function, see it for
documentation. */
ulint
innobase_convert_string(
/*====================*/
void* to,
ulint to_length,
CHARSET_INFO* to_cs,
const void* from,
ulint from_length,
CHARSET_INFO* from_cs,
uint* errors);
#endif

View File

@@ -267,6 +267,7 @@ ibuf_parse_bitmap_init(
byte* end_ptr,/* in: buffer end */ byte* end_ptr,/* in: buffer end */
page_t* page, /* in: page or NULL */ page_t* page, /* in: page or NULL */
mtr_t* mtr); /* in: mtr or NULL */ mtr_t* mtr); /* in: mtr or NULL */
#ifdef UNIV_IBUF_DEBUG
/********************************************************************** /**********************************************************************
Gets the ibuf count for a given page. */ Gets the ibuf count for a given page. */
@@ -277,6 +278,7 @@ ibuf_count_get(
currently buffered for this page */ currently buffered for this page */
ulint space, /* in: space id */ ulint space, /* in: space id */
ulint page_no);/* in: page number */ ulint page_no);/* in: page number */
#endif
/********************************************************************** /**********************************************************************
Looks if the insert buffer is empty. */ Looks if the insert buffer is empty. */

View File

@@ -297,8 +297,8 @@ char*
mem_heap_strdup( mem_heap_strdup(
/*============*/ /*============*/
/* out, own: a copy of the string */ /* out, own: a copy of the string */
mem_heap_t* heap, /* in: memory heap where string is allocated */ mem_heap_t* heap, /* in: memory heap where string is allocated */
const char* str); /* in: string to be copied */ const char* str); /* in: string to be copied */
/************************************************************************** /**************************************************************************
Makes a NUL-terminated copy of a nonterminated string, Makes a NUL-terminated copy of a nonterminated string,
allocated from a memory heap. */ allocated from a memory heap. */
@@ -322,6 +322,44 @@ mem_heap_strcat(
const char* s1, /* in: string 1 */ const char* s1, /* in: string 1 */
const char* s2); /* in: string 2 */ const char* s2); /* in: string 2 */
/**************************************************************************
Duplicate a block of data, allocated from a memory heap. */
void*
mem_heap_dup(
/*=========*/
/* out, own: a copy of the data */
mem_heap_t* heap, /* in: memory heap where copy is allocated */
const void* data, /* in: data to be copied */
ulint len); /* in: length of data, in bytes */
/**************************************************************************
Concatenate two memory blocks and return the result, using a memory heap. */
void*
mem_heap_cat(
/*=========*/
/* out, own: the result */
mem_heap_t* heap, /* in: memory heap where result is allocated */
const void* b1, /* in: block 1 */
ulint len1, /* in: length of b1, in bytes */
const void* b2, /* in: block 2 */
ulint len2); /* in: length of b2, in bytes */
/********************************************************************
A simple (s)printf replacement that dynamically allocates the space for the
formatted string from the given heap. This supports a very limited set of
the printf syntax: types 's' and 'u' and length modifier 'l' (which is
required for the 'u' type). */
char*
mem_heap_printf(
/*============*/
/* out: heap-allocated formatted string */
mem_heap_t* heap, /* in: memory heap */
const char* format, /* in: format string */
...) __attribute__ ((format (printf, 2, 3)));
#ifdef MEM_PERIODIC_CHECK #ifdef MEM_PERIODIC_CHECK
/********************************************************************** /**********************************************************************
Goes through the list of all allocated mem blocks, checks their magic Goes through the list of all allocated mem blocks, checks their magic

View File

@@ -531,6 +531,16 @@ pars_info_add_function(
pars_user_func_cb_t func, /* in: function address */ pars_user_func_cb_t func, /* in: function address */
void* arg); /* in: user-supplied argument */ void* arg); /* in: user-supplied argument */
/********************************************************************
Add bound id. */
void
pars_info_add_id(
/*=============*/
pars_info_t* info, /* in: info struct */
const char* name, /* in: name */
const char* id); /* in: id */
/******************************************************************** /********************************************************************
Get user function with the given name.*/ Get user function with the given name.*/
@@ -553,6 +563,17 @@ pars_info_get_bound_lit(
pars_info_t* info, /* in: info struct */ pars_info_t* info, /* in: info struct */
const char* name); /* in: bound literal name to find */ const char* name); /* in: bound literal name to find */
/********************************************************************
Get bound id with the given name.*/
pars_bound_id_t*
pars_info_get_bound_id(
/*===================*/
/* out: bound id, or NULL if not
found */
pars_info_t* info, /* in: info struct */
const char* name); /* in: bound id name to find */
/* Extra information supplied for pars_sql(). */ /* Extra information supplied for pars_sql(). */
struct pars_info_struct { struct pars_info_struct {
@@ -562,6 +583,8 @@ struct pars_info_struct {
(pars_user_func_t*) */ (pars_user_func_t*) */
ib_vector_t* bound_lits; /* bound literals, or NULL ib_vector_t* bound_lits; /* bound literals, or NULL
(pars_bound_lit_t*) */ (pars_bound_lit_t*) */
ib_vector_t* bound_ids; /* bound ids, or NULL
(pars_bound_id_t*) */
ibool graph_owns_us; /* if TRUE (which is the default), ibool graph_owns_us; /* if TRUE (which is the default),
que_graph_free() will free us */ que_graph_free() will free us */
@@ -583,6 +606,12 @@ struct pars_bound_lit_struct {
ulint prtype; /* precise type, e.g. DATA_UNSIGNED */ ulint prtype; /* precise type, e.g. DATA_UNSIGNED */
}; };
/* Bound id. */
struct pars_bound_id_struct {
const char* name; /* name */
const char* id; /* id */
};
/* Struct used to denote a reserved word in a parsing tree */ /* Struct used to denote a reserved word in a parsing tree */
struct pars_res_word_struct{ struct pars_res_word_struct{
int code; /* the token code for the reserved word from int code; /* the token code for the reserved word from

View File

@@ -82,6 +82,16 @@ sym_tab_add_id(
byte* name, /* in: identifier name */ byte* name, /* in: identifier name */
ulint len); /* in: identifier length */ ulint len); /* in: identifier length */
/**********************************************************************
Add a bound identifier to a symbol table. */
sym_node_t*
sym_tab_add_bound_id(
/*===========*/
/* out: symbol table node */
sym_tab_t* sym_tab, /* in: symbol table */
const char* name); /* in: name of bound id */
#define SYM_CLUST_FIELD_NO 0 #define SYM_CLUST_FIELD_NO 0
#define SYM_SEC_FIELD_NO 1 #define SYM_SEC_FIELD_NO 1

View File

@@ -12,6 +12,7 @@ Created 1/11/1998 Heikki Tuuri
typedef struct pars_info_struct pars_info_t; typedef struct pars_info_struct pars_info_t;
typedef struct pars_user_func_struct pars_user_func_t; typedef struct pars_user_func_struct pars_user_func_t;
typedef struct pars_bound_lit_struct pars_bound_lit_t; typedef struct pars_bound_lit_struct pars_bound_lit_t;
typedef struct pars_bound_id_struct pars_bound_id_t;
typedef struct sym_node_struct sym_node_t; typedef struct sym_node_struct sym_node_t;
typedef struct sym_tab_struct sym_tab_t; typedef struct sym_tab_struct sym_tab_t;
typedef struct pars_res_word_struct pars_res_word_t; typedef struct pars_res_word_struct pars_res_word_t;

View File

@@ -19,8 +19,10 @@ Created 5/30/1994 Heikki Tuuri
#define REC_MAX_HEAP_NO (2 * 8192 - 1) #define REC_MAX_HEAP_NO (2 * 8192 - 1)
#define REC_MAX_N_OWNED (16 - 1) #define REC_MAX_N_OWNED (16 - 1)
/* Flag denoting the predefined minimum record: this bit is ORed in the 4 /* Info bit denoting the predefined minimum record: this bit is set
info bits of a record */ if and only if the record is the first user record on a non-leaf
B-tree page that is the leftmost page on its level
(PAGE_LEVEL is nonzero and FIL_PAGE_PREV is FIL_NULL). */
#define REC_INFO_MIN_REC_FLAG 0x10UL #define REC_INFO_MIN_REC_FLAG 0x10UL
/* Number of extra bytes in an old-style record, /* Number of extra bytes in an old-style record,

View File

@@ -56,9 +56,7 @@ struct purge_node_struct{
determined by ref was found in the clustered determined by ref was found in the clustered
index, and we were able to position pcur on index, and we were able to position pcur on
it */ it */
dict_table_t* table; /* table where purge is done; NOTE that the dict_table_t* table; /* table where purge is done */
table has to be released explicitly with
dict_table_release */
ulint cmpl_info;/* compiler analysis info of an update */ ulint cmpl_info;/* compiler analysis info of an update */
upd_t* update; /* update vector for a clustered index record */ upd_t* update; /* update vector for a clustered index record */
dtuple_t* ref; /* NULL, or row reference to the next row to dtuple_t* ref; /* NULL, or row reference to the next row to

View File

@@ -84,9 +84,7 @@ struct undo_node_struct{
record */ record */
btr_pcur_t pcur; /* persistent cursor used in searching the btr_pcur_t pcur; /* persistent cursor used in searching the
clustered index record */ clustered index record */
dict_table_t* table; /* table where undo is done; NOTE that the dict_table_t* table; /* table where undo is done */
table has to be released explicitly with
dict_table_release */
ulint cmpl_info;/* compiler analysis of an update */ ulint cmpl_info;/* compiler analysis of an update */
upd_t* update; /* update vector for a clustered index record */ upd_t* update; /* update vector for a clustered index record */
dtuple_t* ref; /* row reference to the next row to handle */ dtuple_t* ref; /* row reference to the next row to handle */

View File

@@ -18,6 +18,9 @@ Created 10/10/1995 Heikki Tuuri
extern const char* srv_main_thread_op_info; extern const char* srv_main_thread_op_info;
/* Prefix used by MySQL to indicate pre-5.1 table name encoding */
extern const char srv_mysql50_table_name_prefix[9];
/* When this event is set the lock timeout and InnoDB monitor /* When this event is set the lock timeout and InnoDB monitor
thread starts running */ thread starts running */
extern os_event_t srv_lock_timeout_thread_event; extern os_event_t srv_lock_timeout_thread_event;

View File

@@ -61,7 +61,7 @@ Creates, or rather, initializes an rw-lock object in a specified memory
location (which must be appropriately aligned). The rw-lock is initialized location (which must be appropriately aligned). The rw-lock is initialized
to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
is necessary only if the memory block containing it is freed. */ is necessary only if the memory block containing it is freed. */
#define rw_lock_create(L) rw_lock_create_func((L), __FILE__, __LINE__, #L) #define rw_lock_create(L, level) rw_lock_create_func((L), (level), __FILE__, __LINE__, #L)
/*=====================*/ /*=====================*/
/********************************************************************** /**********************************************************************
@@ -74,9 +74,10 @@ void
rw_lock_create_func( rw_lock_create_func(
/*================*/ /*================*/
rw_lock_t* lock, /* in: pointer to memory */ rw_lock_t* lock, /* in: pointer to memory */
ulint level, /* in: level */
const char* cfile_name, /* in: file name where created */ const char* cfile_name, /* in: file name where created */
ulint cline, /* in: file line where created */ ulint cline, /* in: file line where created */
const char* cmutex_name); /* in: mutex name */ const char* cmutex_name); /* in: mutex name */
/********************************************************************** /**********************************************************************
Calling this function is obligatory only if the memory buffer containing Calling this function is obligatory only if the memory buffer containing
the rw-lock is freed. Removes an rw-lock object from the global list. The the rw-lock is freed. Removes an rw-lock object from the global list. The
@@ -299,14 +300,6 @@ rw_lock_x_unlock_direct(
/*====================*/ /*====================*/
rw_lock_t* lock); /* in: rw-lock */ rw_lock_t* lock); /* in: rw-lock */
/********************************************************************** /**********************************************************************
Sets the rw-lock latching level field. */
void
rw_lock_set_level(
/*==============*/
rw_lock_t* lock, /* in: rw-lock */
ulint level); /* in: level */
/**********************************************************************
Returns the value of writer_count for the lock. Does not reserve the lock Returns the value of writer_count for the lock. Does not reserve the lock
mutex, so the caller must be sure it is not changed during the call. */ mutex, so the caller must be sure it is not changed during the call. */
UNIV_INLINE UNIV_INLINE
@@ -448,8 +441,8 @@ struct rw_lock_struct {
/* In the debug version: pointer to the debug /* In the debug version: pointer to the debug
info list of the lock */ info list of the lock */
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
ulint level; /* Level in the global latching
order; default SYNC_LEVEL_NONE */ ulint level; /* Level in the global latching order. */
const char* cfile_name;/* File name where lock created */ const char* cfile_name;/* File name where lock created */
ulint cline; /* Line where created */ ulint cline; /* Line where created */
const char* last_s_file_name;/* File name where last s-locked */ const char* last_s_file_name;/* File name where last s-locked */

View File

@@ -39,7 +39,7 @@ location (which must be appropriately aligned). The mutex is initialized
in the reset state. Explicit freeing of the mutex with mutex_free is in the reset state. Explicit freeing of the mutex with mutex_free is
necessary only if the memory block containing it is freed. */ necessary only if the memory block containing it is freed. */
#define mutex_create(M) mutex_create_func((M), __FILE__, __LINE__, #M) #define mutex_create(M, level) mutex_create_func((M), (level), __FILE__, __LINE__, #M)
/*===================*/ /*===================*/
/********************************************************************** /**********************************************************************
Creates, or rather, initializes a mutex object in a specified memory Creates, or rather, initializes a mutex object in a specified memory
@@ -51,6 +51,7 @@ void
mutex_create_func( mutex_create_func(
/*==============*/ /*==============*/
mutex_t* mutex, /* in: pointer to memory */ mutex_t* mutex, /* in: pointer to memory */
ulint level, /* in: level */
const char* cfile_name, /* in: file name where created */ const char* cfile_name, /* in: file name where created */
ulint cline, /* in: file line where created */ ulint cline, /* in: file line where created */
const char* cmutex_name); /* in: mutex name */ const char* cmutex_name); /* in: mutex name */
@@ -155,14 +156,6 @@ mutex_validate(
/*===========*/ /*===========*/
mutex_t* mutex); mutex_t* mutex);
/********************************************************************** /**********************************************************************
Sets the mutex latching level field. */
void
mutex_set_level(
/*============*/
mutex_t* mutex, /* in: mutex */
ulint level); /* in: level */
/**********************************************************************
Adds a latch and its level in the thread level array. Allocates the memory Adds a latch and its level in the thread level array. Allocates the memory
for the array if called first time for this OS thread. Makes the checks for the array if called first time for this OS thread. Makes the checks
against other latch levels stored in the array for this thread. */ against other latch levels stored in the array for this thread. */
@@ -171,8 +164,8 @@ void
sync_thread_add_level( sync_thread_add_level(
/*==================*/ /*==================*/
void* latch, /* in: pointer to a mutex or an rw-lock */ void* latch, /* in: pointer to a mutex or an rw-lock */
ulint level); /* in: level in the latching order; if SYNC_LEVEL_NONE, ulint level); /* in: level in the latching order; if
nothing is done */ SYNC_LEVEL_VARYING, nothing is done */
/********************************************************************** /**********************************************************************
Removes a latch from the thread level array if it is found there. */ Removes a latch from the thread level array if it is found there. */
@@ -383,7 +376,12 @@ or row lock! */
#define SYNC_USER_TRX_LOCK 9999 #define SYNC_USER_TRX_LOCK 9999
#define SYNC_NO_ORDER_CHECK 3000 /* this can be used to suppress #define SYNC_NO_ORDER_CHECK 3000 /* this can be used to suppress
latching order checking */ latching order checking */
#define SYNC_LEVEL_NONE 2000 /* default: level not defined */ #define SYNC_LEVEL_VARYING 2000 /* Level is varying. Only used with
buffer pool page locks, which do not
have a fixed level, but instead have
their level set after the page is
locked; see e.g.
ibuf_bitmap_get_map_page(). */
#define SYNC_DICT_OPERATION 1001 /* table create, drop, etc. reserve #define SYNC_DICT_OPERATION 1001 /* table create, drop, etc. reserve
this in X-mode, implicit or backround this in X-mode, implicit or backround
operations purge, rollback, foreign operations purge, rollback, foreign
@@ -426,6 +424,7 @@ or row lock! */
#define SYNC_TRX_SYS_HEADER 290 #define SYNC_TRX_SYS_HEADER 290
#define SYNC_LOG 170 #define SYNC_LOG 170
#define SYNC_RECV 168 #define SYNC_RECV 168
#define SYNC_WORK_QUEUE 161
#define SYNC_SEARCH_SYS 160 /* NOTE that if we have a memory #define SYNC_SEARCH_SYS 160 /* NOTE that if we have a memory
heap that can be extended to the heap that can be extended to the
buffer pool, its logical level is buffer pool, its logical level is
@@ -472,8 +471,7 @@ struct mutex_struct {
os_thread_id_t thread_id; /* Debug version: The thread id of the os_thread_id_t thread_id; /* Debug version: The thread id of the
thread which locked the mutex. */ thread which locked the mutex. */
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
ulint level; /* Level in the global latching ulint level; /* Level in the global latching order */
order; default SYNC_LEVEL_NONE */
const char* cfile_name;/* File name where mutex created */ const char* cfile_name;/* File name where mutex created */
ulint cline; /* Line where created */ ulint cline; /* Line where created */
ulint magic_n; ulint magic_n;

View File

@@ -82,7 +82,7 @@ memory is read outside the allocated blocks. */
/* Make a non-inline debug version */ /* Make a non-inline debug version */
/* #if 0
#define UNIV_DEBUG #define UNIV_DEBUG
#define UNIV_MEM_DEBUG #define UNIV_MEM_DEBUG
#define UNIV_IBUF_DEBUG #define UNIV_IBUF_DEBUG
@@ -90,8 +90,10 @@ memory is read outside the allocated blocks. */
#define UNIV_SEARCH_DEBUG #define UNIV_SEARCH_DEBUG
#define UNIV_SYNC_PERF_STAT #define UNIV_SYNC_PERF_STAT
#define UNIV_SEARCH_PERF_STAT #define UNIV_SEARCH_PERF_STAT
#define UNIV_SRV_PRINT_LATCH_WAITS; #define UNIV_SRV_PRINT_LATCH_WAITS
*/ #endif
#define UNIV_BTR_DEBUG
#define UNIV_LIGHT_MEM_DEBUG #define UNIV_LIGHT_MEM_DEBUG
#define YYDEBUG 1 #define YYDEBUG 1

View File

@@ -41,13 +41,22 @@ void ut_dbg_panic(void);
/* Stop threads in ut_a(). */ /* Stop threads in ut_a(). */
# define UT_DBG_STOP while (0) /* We do not do this on NetWare */ # define UT_DBG_STOP while (0) /* We do not do this on NetWare */
#else /* __NETWARE__ */ #else /* __NETWARE__ */
# if defined(__WIN__) || defined(__INTEL_COMPILER)
# undef UT_DBG_USE_ABORT
# elif defined(__GNUC__) && (__GNUC__ > 2)
# define UT_DBG_USE_ABORT
# endif
# ifndef UT_DBG_USE_ABORT
/* A null pointer that will be dereferenced to trigger a memory trap */
extern ulint* ut_dbg_null_ptr;
# endif
# if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
/* Flag for indicating that all threads should stop. This will be set /* Flag for indicating that all threads should stop. This will be set
by ut_dbg_assertion_failed(). */ by ut_dbg_assertion_failed(). */
extern ibool ut_dbg_stop_threads; extern ibool ut_dbg_stop_threads;
/* A null pointer that will be dereferenced to trigger a memory trap */
extern ulint* ut_dbg_null_ptr;
/***************************************************************** /*****************************************************************
Stop a thread after assertion failure. */ Stop a thread after assertion failure. */
@@ -56,15 +65,23 @@ ut_dbg_stop_thread(
/*===============*/ /*===============*/
const char* file, const char* file,
ulint line); ulint line);
# endif
# ifdef UT_DBG_USE_ABORT
/* Abort the execution. */ /* Abort the execution. */
# define UT_DBG_PANIC \ # define UT_DBG_PANIC abort()
/* Stop threads (null operation) */
# define UT_DBG_STOP while (0)
# else /* UT_DBG_USE_ABORT */
/* Abort the execution. */
# define UT_DBG_PANIC \
if (*(ut_dbg_null_ptr)) ut_dbg_null_ptr = NULL if (*(ut_dbg_null_ptr)) ut_dbg_null_ptr = NULL
/* Stop threads in ut_a(). */ /* Stop threads in ut_a(). */
# define UT_DBG_STOP do \ # define UT_DBG_STOP do \
if (UNIV_UNLIKELY(ut_dbg_stop_threads)) { \ if (UNIV_UNLIKELY(ut_dbg_stop_threads)) { \
ut_dbg_stop_thread(__FILE__, (ulint) __LINE__); \ ut_dbg_stop_thread(__FILE__, (ulint) __LINE__); \
} while (0) } while (0)
# endif /* UT_DBG_USE_ABORT */
#endif /* __NETWARE__ */ #endif /* __NETWARE__ */
/* Abort execution if EXPR does not evaluate to nonzero. */ /* Abort execution if EXPR does not evaluate to nonzero. */

View File

@@ -0,0 +1,148 @@
/***********************************************************************
A double-linked list. This differs from the one in ut0lst.h in that in this
one, each list node contains a pointer to the data, whereas the one in
ut0lst.h uses a strategy where the list pointers are embedded in the data
items themselves.
Use this one when you need to store arbitrary data in the list where you
can't embed the list pointers in the data, if a data item needs to be
stored in multiple lists, etc.
Note about the memory management: ib_list_t is a fixed-size struct whose
allocation/deallocation is done through ib_list_create/ib_list_free, but the
memory for the list nodes is allocated through a user-given memory heap,
which can either be the same for all nodes or vary per node. Most users will
probably want to create a memory heap to store the item-specific data, and
pass in this same heap to the list node creation functions, thus
automatically freeing the list node when the item's heap is freed.
************************************************************************/
#ifndef IB_LIST_H
#define IB_LIST_H
#include "mem0mem.h"
typedef struct ib_list_struct ib_list_t;
typedef struct ib_list_node_struct ib_list_node_t;
typedef struct ib_list_helper_struct ib_list_helper_t;
/********************************************************************
Create a new list using mem_alloc. Lists created with this function must be
freed with ib_list_free. */
ib_list_t*
ib_list_create(void);
/*=================*/
/* out: list */
/********************************************************************
Create a new list using the given heap. ib_list_free MUST NOT BE CALLED for
lists created with this function. */
ib_list_t*
ib_list_create_heap(
/*================*/
/* out: list */
mem_heap_t* heap); /* in: memory heap to use */
/********************************************************************
Free a list. */
void
ib_list_free(
/*=========*/
ib_list_t* list); /* in: list */
/********************************************************************
Add the data to the start of the list. */
ib_list_node_t*
ib_list_add_first(
/*==============*/
/* out: new list node*/
ib_list_t* list, /* in: list */
void* data, /* in: data */
mem_heap_t* heap); /* in: memory heap to use */
/********************************************************************
Add the data to the end of the list. */
ib_list_node_t*
ib_list_add_last(
/*=============*/
/* out: new list node*/
ib_list_t* list, /* in: list */
void* data, /* in: data */
mem_heap_t* heap); /* in: memory heap to use */
/********************************************************************
Add the data after the indicated node. */
ib_list_node_t*
ib_list_add_after(
/*==============*/
/* out: new list node*/
ib_list_t* list, /* in: list */
ib_list_node_t* prev_node, /* in: node preceding new node (can
be NULL) */
void* data, /* in: data */
mem_heap_t* heap); /* in: memory heap to use */
/********************************************************************
Remove the node from the list. */
void
ib_list_remove(
/*===========*/
ib_list_t* list, /* in: list */
ib_list_node_t* node); /* in: node to remove */
/********************************************************************
Get the first node in the list. */
UNIV_INLINE
ib_list_node_t*
ib_list_get_first(
/*==============*/
/* out: first node, or NULL */
ib_list_t* list); /* in: list */
/********************************************************************
Get the last node in the list. */
UNIV_INLINE
ib_list_node_t*
ib_list_get_last(
/*=============*/
/* out: last node, or NULL */
ib_list_t* list); /* in: list */
/* List. */
struct ib_list_struct {
ib_list_node_t* first; /* first node */
ib_list_node_t* last; /* last node */
ibool is_heap_list; /* TRUE if this list was
allocated through a heap */
};
/* A list node. */
struct ib_list_node_struct {
ib_list_node_t* prev; /* previous node */
ib_list_node_t* next; /* next node */
void* data; /* user data */
};
/* Quite often, the only additional piece of data you need is the per-item
memory heap, so we have this generic struct available to use in those
cases. */
struct ib_list_helper_struct {
mem_heap_t* heap; /* memory heap */
void* data; /* user data */
};
#ifndef UNIV_NONINL
#include "ut0list.ic"
#endif
#endif

View File

@@ -0,0 +1,23 @@
/********************************************************************
Get the first node in the list. */
UNIV_INLINE
ib_list_node_t*
ib_list_get_first(
/*==============*/
/* out: first node, or NULL */
ib_list_t* list) /* in: list */
{
return(list->first);
}
/********************************************************************
Get the last node in the list. */
UNIV_INLINE
ib_list_node_t*
ib_list_get_last(
/*=============*/
/* out: last node, or NULL */
ib_list_t* list) /* in: list */
{
return(list->last);
}

View File

@@ -224,6 +224,7 @@ ut_print_name(
/*==========*/ /*==========*/
FILE* f, /* in: output stream */ FILE* f, /* in: output stream */
struct trx_struct*trx, /* in: transaction */ struct trx_struct*trx, /* in: transaction */
ibool table_id,/* in: TRUE=decode table name */
const char* name); /* in: name to print */ const char* name); /* in: name to print */
/************************************************************************** /**************************************************************************
@@ -234,6 +235,7 @@ ut_print_namel(
/*===========*/ /*===========*/
FILE* f, /* in: output stream */ FILE* f, /* in: output stream */
struct trx_struct*trx, /* in: transaction (NULL=no quotes) */ struct trx_struct*trx, /* in: transaction (NULL=no quotes) */
ibool table_id,/* in: TRUE=decode table name */
const char* name, /* in: name to print */ const char* name, /* in: name to print */
ulint namelen);/* in: length of name */ ulint namelen);/* in: length of name */

View File

@@ -0,0 +1,60 @@
/***********************************************************************
A Work queue. Threads can add work items to the queue and other threads can
wait for work items to be available and take them off the queue for
processing.
************************************************************************/
#ifndef IB_WORK_QUEUE_H
#define IB_WORK_QUEUE_H
#include "ut0list.h"
#include "mem0mem.h"
#include "os0sync.h"
#include "sync0types.h"
typedef struct ib_wqueue_struct ib_wqueue_t;
/********************************************************************
Create a new work queue. */
ib_wqueue_t*
ib_wqueue_create(void);
/*===================*/
/* out: work queue */
/********************************************************************
Free a work queue. */
void
ib_wqueue_free(
/*===========*/
ib_wqueue_t* wq); /* in: work queue */
/********************************************************************
Add a work item to the queue. */
void
ib_wqueue_add(
/*==========*/
ib_wqueue_t* wq, /* in: work queue */
void* item, /* in: work item */
mem_heap_t* heap); /* in: memory heap to use for allocating the
list node */
/********************************************************************
Wait for a work item to appear in the queue. */
void*
ib_wqueue_wait(
/* out: work item */
ib_wqueue_t* wq); /* in: work queue */
/* Work queue. */
struct ib_wqueue_struct {
mutex_t mutex; /* mutex protecting everything */
ib_list_t* items; /* work item list */
os_event_t event; /* event we use to signal additions to list */
};
#endif

View File

@@ -1860,7 +1860,7 @@ lock_rec_enqueue_waiting(
fputs( fputs(
" InnoDB: Error: a record lock wait happens in a dictionary operation!\n" " InnoDB: Error: a record lock wait happens in a dictionary operation!\n"
"InnoDB: Table name ", stderr); "InnoDB: Table name ", stderr);
ut_print_name(stderr, trx, index->table_name); ut_print_name(stderr, trx, TRUE, index->table_name);
fputs(".\n" fputs(".\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", "InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n",
stderr); stderr);
@@ -1899,7 +1899,7 @@ lock_rec_enqueue_waiting(
if (lock_print_waits) { if (lock_print_waits) {
fprintf(stderr, "Lock wait for trx %lu in index ", fprintf(stderr, "Lock wait for trx %lu in index ",
(ulong) ut_dulint_get_low(trx->id)); (ulong) ut_dulint_get_low(trx->id));
ut_print_name(stderr, trx, index->name); ut_print_name(stderr, trx, FALSE, index->name);
} }
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
@@ -3555,7 +3555,7 @@ lock_table_enqueue_waiting(
fputs( fputs(
" InnoDB: Error: a table lock wait happens in a dictionary operation!\n" " InnoDB: Error: a table lock wait happens in a dictionary operation!\n"
"InnoDB: Table name ", stderr); "InnoDB: Table name ", stderr);
ut_print_name(stderr, trx, table->name); ut_print_name(stderr, trx, TRUE, table->name);
fputs(".\n" fputs(".\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", "InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n",
stderr); stderr);
@@ -4074,7 +4074,8 @@ lock_table_print(
ut_a(lock_get_type(lock) == LOCK_TABLE); ut_a(lock_get_type(lock) == LOCK_TABLE);
fputs("TABLE LOCK table ", file); fputs("TABLE LOCK table ", file);
ut_print_name(file, lock->trx, lock->un_member.tab_lock.table->name); ut_print_name(file, lock->trx, TRUE,
lock->un_member.tab_lock.table->name);
fprintf(file, " trx id %lu %lu", fprintf(file, " trx id %lu %lu",
(ulong) (lock->trx)->id.high, (ulong) (lock->trx)->id.low); (ulong) (lock->trx)->id.high, (ulong) (lock->trx)->id.low);

View File

@@ -741,8 +741,7 @@ log_init(void)
log_sys = mem_alloc(sizeof(log_t)); log_sys = mem_alloc(sizeof(log_t));
mutex_create(&(log_sys->mutex)); mutex_create(&log_sys->mutex, SYNC_LOG);
mutex_set_level(&(log_sys->mutex), SYNC_LOG);
mutex_enter(&(log_sys->mutex)); mutex_enter(&(log_sys->mutex));
@@ -798,8 +797,7 @@ log_init(void)
log_sys->last_checkpoint_lsn = log_sys->lsn; log_sys->last_checkpoint_lsn = log_sys->lsn;
log_sys->n_pending_checkpoint_writes = 0; log_sys->n_pending_checkpoint_writes = 0;
rw_lock_create(&(log_sys->checkpoint_lock)); rw_lock_create(&log_sys->checkpoint_lock, SYNC_NO_ORDER_CHECK);
rw_lock_set_level(&(log_sys->checkpoint_lock), SYNC_NO_ORDER_CHECK);
log_sys->checkpoint_buf = ut_align( log_sys->checkpoint_buf = ut_align(
mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE), mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE),
@@ -815,8 +813,7 @@ log_init(void)
log_sys->n_pending_archive_ios = 0; log_sys->n_pending_archive_ios = 0;
rw_lock_create(&(log_sys->archive_lock)); rw_lock_create(&log_sys->archive_lock, SYNC_NO_ORDER_CHECK);
rw_lock_set_level(&(log_sys->archive_lock), SYNC_NO_ORDER_CHECK);
log_sys->archive_buf = NULL; log_sys->archive_buf = NULL;

View File

@@ -112,8 +112,7 @@ recv_sys_create(void)
recv_sys = mem_alloc(sizeof(recv_sys_t)); recv_sys = mem_alloc(sizeof(recv_sys_t));
mutex_create(&(recv_sys->mutex)); mutex_create(&recv_sys->mutex, SYNC_RECV);
mutex_set_level(&(recv_sys->mutex), SYNC_RECV);
recv_sys->heap = NULL; recv_sys->heap = NULL;
recv_sys->addr_hash = NULL; recv_sys->addr_hash = NULL;
@@ -894,7 +893,6 @@ recv_parse_or_apply_log_rec_body(
recv_sys->found_corrupt_log = TRUE; recv_sys->found_corrupt_log = TRUE;
} }
ut_ad(!page || ptr);
if (index) { if (index) {
dict_table_t* table = index->table; dict_table_t* table = index->table;

View File

@@ -122,8 +122,7 @@ mem_init(
/* Initialize the hash table */ /* Initialize the hash table */
ut_a(FALSE == mem_hash_initialized); ut_a(FALSE == mem_hash_initialized);
mutex_create(&mem_hash_mutex); mutex_create(&mem_hash_mutex, SYNC_MEM_HASH);
mutex_set_level(&mem_hash_mutex, SYNC_MEM_HASH);
for (i = 0; i < MEM_HASH_SIZE; i++) { for (i = 0; i < MEM_HASH_SIZE; i++) {
UT_LIST_INIT(*mem_hash_get_nth_cell(i)); UT_LIST_INIT(*mem_hash_get_nth_cell(i));

View File

@@ -17,6 +17,7 @@ Created 6/9/1994 Heikki Tuuri
#include "btr0sea.h" #include "btr0sea.h"
#include "srv0srv.h" #include "srv0srv.h"
#include "mem0dbg.c" #include "mem0dbg.c"
#include <stdarg.h>
/* /*
THE MEMORY MANAGEMENT THE MEMORY MANAGEMENT
@@ -107,11 +108,45 @@ char*
mem_heap_strdup( mem_heap_strdup(
/*============*/ /*============*/
/* out, own: a copy of the string */ /* out, own: a copy of the string */
mem_heap_t* heap, /* in: memory heap where string is allocated */ mem_heap_t* heap, /* in: memory heap where string is allocated */
const char* str) /* in: string to be copied */ const char* str) /* in: string to be copied */
{ {
ulint len = strlen(str) + 1; return(mem_heap_dup(heap, str, strlen(str) + 1));
return(memcpy(mem_heap_alloc(heap, len), str, len)); }
/**************************************************************************
Duplicate a block of data, allocated from a memory heap. */
void*
mem_heap_dup(
/*=========*/
/* out, own: a copy of the data */
mem_heap_t* heap, /* in: memory heap where copy is allocated */
const void* data, /* in: data to be copied */
ulint len) /* in: length of data, in bytes */
{
return(memcpy(mem_heap_alloc(heap, len), data, len));
}
/**************************************************************************
Concatenate two memory blocks and return the result, using a memory heap. */
void*
mem_heap_cat(
/*=========*/
/* out, own: the result */
mem_heap_t* heap, /* in: memory heap where result is allocated */
const void* b1, /* in: block 1 */
ulint len1, /* in: length of b1, in bytes */
const void* b2, /* in: block 2 */
ulint len2) /* in: length of b2, in bytes */
{
void* res = mem_heap_alloc(heap, len1 + len2);
memcpy(res, b1, len1);
memcpy(res + len1, b2, len2);
return(res);
} }
/************************************************************************** /**************************************************************************
@@ -139,6 +174,150 @@ mem_heap_strcat(
return(s); return(s);
} }
/********************************************************************
Helper function for mem_heap_printf. */
static
ulint
mem_heap_printf_low(
/*================*/
/* out: length of formatted string,
including terminating NUL */
char* buf, /* in/out: buffer to store formatted string
in, or NULL to just calculate length */
const char* format, /* in: format string */
va_list ap) /* in: arguments */
{
ulint len = 0;
while (*format) {
/* Does this format specifier have the 'l' length modifier. */
ibool is_long = FALSE;
/* Length of one parameter. */
size_t plen;
if (*format++ != '%') {
/* Non-format character. */
len++;
if (buf) {
*buf++ = *(format - 1);
}
continue;
}
if (*format == 'l') {
is_long = TRUE;
format++;
}
switch (*format++) {
case 's':
/* string */
{
char* s = va_arg(ap, char*);
/* "%ls" is a non-sensical format specifier. */
ut_a(!is_long);
plen = strlen(s);
len += plen;
if (buf) {
memcpy(buf, s, plen);
buf += plen;
}
}
break;
case 'u':
/* unsigned int */
{
char tmp[32];
unsigned long val;
/* We only support 'long' values for now. */
ut_a(is_long);
val = va_arg(ap, unsigned long);
plen = sprintf(tmp, "%lu", val);
len += plen;
if (buf) {
memcpy(buf, tmp, plen);
buf += plen;
}
}
break;
case '%':
/* "%l%" is a non-sensical format specifier. */
ut_a(!is_long);
len++;
if (buf) {
*buf++ = '%';
}
break;
default:
ut_error;
}
}
/* For the NUL character. */
len++;
if (buf) {
*buf = '\0';
}
return(len);
}
/********************************************************************
A simple (s)printf replacement that dynamically allocates the space for the
formatted string from the given heap. This supports a very limited set of
the printf syntax: types 's' and 'u' and length modifier 'l' (which is
required for the 'u' type). */
char*
mem_heap_printf(
/*============*/
/* out: heap-allocated formatted string */
mem_heap_t* heap, /* in: memory heap */
const char* format, /* in: format string */
...)
{
va_list ap;
char* str;
ulint len;
/* Calculate length of string */
len = 0;
va_start(ap, format);
len = mem_heap_printf_low(NULL, format, ap);
va_end(ap);
/* Now create it for real. */
str = mem_heap_alloc(heap, len);
va_start(ap, format);
mem_heap_printf_low(str, format, ap);
va_end(ap);
return(str);
}
/******************************************************************* /*******************************************************************
Creates a memory heap block where data can be allocated. */ Creates a memory heap block where data can be allocated. */

View File

@@ -204,8 +204,7 @@ mem_pool_create(
pool->buf = ut_malloc_low(size, FALSE, TRUE); pool->buf = ut_malloc_low(size, FALSE, TRUE);
pool->size = size; pool->size = size;
mutex_create(&(pool->mutex)); mutex_create(&pool->mutex, SYNC_MEM_POOL);
mutex_set_level(&(pool->mutex), SYNC_MEM_POOL);
/* Initialize the free lists */ /* Initialize the free lists */

View File

@@ -3679,6 +3679,37 @@ os_aio_posix_handle(
} }
#endif #endif
/**************************************************************************
Do a 'last millisecond' check that the page end is sensible;
reported page checksum errors from Linux seem to wipe over the page end. */
static
void
os_file_check_page_trailers(
/*========================*/
byte* combined_buf, /* in: combined write buffer */
ulint total_len) /* in: size of combined_buf, in bytes
(a multiple of UNIV_PAGE_SIZE) */
{
ulint len;
for (len = 0; len + UNIV_PAGE_SIZE <= total_len;
len += UNIV_PAGE_SIZE) {
byte* buf = combined_buf + len;
if (memcmp(buf + (FIL_PAGE_LSN + 4), buf + (UNIV_PAGE_SIZE
- FIL_PAGE_END_LSN_OLD_CHKSUM + 4), 4)) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: ERROR: The page to be written seems corrupt!\n"
"InnoDB: Writing a block of %lu bytes, currently at offset %lu\n",
(ulong)total_len, (ulong)len);
buf_page_print(buf);
fprintf(stderr,
"InnoDB: ERROR: The page to be written seems corrupt!\n");
}
}
}
/************************************************************************** /**************************************************************************
Does simulated aio. This function should be called by an i/o-handler Does simulated aio. This function should be called by an i/o-handler
thread. */ thread. */
@@ -3716,7 +3747,6 @@ os_aio_simulated_handle(
ibool ret; ibool ret;
ulint n; ulint n;
ulint i; ulint i;
ulint len2;
segment = os_aio_get_array_and_local_segment(&array, global_segment); segment = os_aio_get_array_and_local_segment(&array, global_segment);
@@ -3924,32 +3954,15 @@ consecutive_loop:
ut_error; ut_error;
} }
/* Do a 'last millisecond' check that the page end os_file_check_page_trailers(combined_buf, total_len);
is sensible; reported page checksum errors from
Linux seem to wipe over the page end */
for (len2 = 0; len2 + UNIV_PAGE_SIZE <= total_len;
len2 += UNIV_PAGE_SIZE) {
if (mach_read_from_4(combined_buf + len2
+ FIL_PAGE_LSN + 4)
!= mach_read_from_4(combined_buf + len2
+ UNIV_PAGE_SIZE
- FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: ERROR: The page to be written seems corrupt!\n");
fprintf(stderr,
"InnoDB: Writing a block of %lu bytes, currently writing at offset %lu\n",
(ulong)total_len, (ulong)len2);
buf_page_print(combined_buf + len2);
fprintf(stderr,
"InnoDB: ERROR: The page to be written seems corrupt!\n");
}
}
} }
ret = os_file_write(slot->name, slot->file, combined_buf, ret = os_file_write(slot->name, slot->file, combined_buf,
slot->offset, slot->offset_high, total_len); slot->offset, slot->offset_high, total_len);
if (array == os_aio_write_array) {
os_file_check_page_trailers(combined_buf, total_len);
}
} else { } else {
ret = os_file_read(slot->file, combined_buf, ret = os_file_read(slot->file, combined_buf,
slot->offset, slot->offset_high, total_len); slot->offset, slot->offset_high, total_len);

View File

@@ -220,7 +220,7 @@ os_thread_join(
/*===========*/ /*===========*/
os_thread_id_t thread_id) /* in: id of the thread to join */ os_thread_id_t thread_id) /* in: id of the thread to join */
{ {
return pthread_join(thread_id, NULL); return(pthread_join(thread_id, NULL));
} }
#endif #endif
/********************************************************************* /*********************************************************************

File diff suppressed because it is too large Load Diff

View File

@@ -84,6 +84,7 @@ string_append(
DIGIT [0-9] DIGIT [0-9]
ID [a-z_A-Z][a-z_A-Z0-9]* ID [a-z_A-Z][a-z_A-Z0-9]*
BOUND_LIT \:[a-z_A-Z0-9]+ BOUND_LIT \:[a-z_A-Z0-9]+
BOUND_ID \$[a-z_A-Z0-9]+
%x comment %x comment
%x quoted %x quoted
@@ -111,6 +112,13 @@ BOUND_LIT \:[a-z_A-Z0-9]+
return(type); return(type);
} }
{BOUND_ID} {
yylval = sym_tab_add_bound_id(pars_sym_tab_global,
yytext + 1);
return(PARS_ID_TOKEN);
}
"'" { "'" {
/* Quoted character string literals are handled in an explicit /* Quoted character string literals are handled in an explicit
start state 'quoted'. This state is entered and the buffer for start state 'quoted'. This state is entered and the buffer for

View File

@@ -1931,6 +1931,7 @@ pars_info_create(void)
info->heap = heap; info->heap = heap;
info->funcs = NULL; info->funcs = NULL;
info->bound_lits = NULL; info->bound_lits = NULL;
info->bound_ids = NULL;
info->graph_owns_us = TRUE; info->graph_owns_us = TRUE;
return(info); return(info);
@@ -2070,6 +2071,32 @@ pars_info_add_function(
ib_vector_push(info->funcs, puf); ib_vector_push(info->funcs, puf);
} }
/********************************************************************
Add bound id. */
void
pars_info_add_id(
/*=============*/
pars_info_t* info, /* in: info struct */
const char* name, /* in: name */
const char* id) /* in: id */
{
pars_bound_id_t* bid;
ut_ad(!pars_info_get_bound_id(info, name));
bid = mem_heap_alloc(info->heap, sizeof(*bid));
bid->name = name;
bid->id = id;
if (!info->bound_ids) {
info->bound_ids = ib_vector_create(info->heap, 8);
}
ib_vector_push(info->bound_ids, bid);
}
/******************************************************************** /********************************************************************
Get user function with the given name.*/ Get user function with the given name.*/
@@ -2131,3 +2158,34 @@ pars_info_get_bound_lit(
return(NULL); return(NULL);
} }
/********************************************************************
Get bound id with the given name.*/
pars_bound_id_t*
pars_info_get_bound_id(
/*===================*/
/* out: bound id, or NULL if not
found */
pars_info_t* info, /* in: info struct */
const char* name) /* in: bound id name to find */
{
ulint i;
ib_vector_t* vec;
if (!info || !info->bound_ids) {
return(NULL);
}
vec = info->bound_ids;
for (i = 0; i < ib_vector_size(vec); i++) {
pars_bound_id_t* bid = ib_vector_get(vec, i);
if (strcmp(bid->name, name) == 0) {
return(bid);
}
}
return(NULL);
}

View File

@@ -207,6 +207,13 @@ sym_tab_add_bound_lit(
*lit_type = PARS_STR_LIT; *lit_type = PARS_STR_LIT;
break; break;
case DATA_CHAR:
ut_a(blit->length > 0);
len = blit->length;
*lit_type = PARS_STR_LIT;
break;
case DATA_INT: case DATA_INT:
ut_a(blit->length > 0); ut_a(blit->length > 0);
ut_a(blit->length <= 8); ut_a(blit->length <= 8);
@@ -304,3 +311,42 @@ sym_tab_add_id(
return(node); return(node);
} }
/**********************************************************************
Add a bound identifier to a symbol table. */
sym_node_t*
sym_tab_add_bound_id(
/*===========*/
/* out: symbol table node */
sym_tab_t* sym_tab, /* in: symbol table */
const char* name) /* in: name of bound id */
{
sym_node_t* node;
pars_bound_id_t* bid;
bid = pars_info_get_bound_id(sym_tab->info, name);
ut_a(bid);
node = mem_heap_alloc(sym_tab->heap, sizeof(sym_node_t));
node->common.type = QUE_NODE_SYMBOL;
node->resolved = FALSE;
node->indirection = NULL;
node->name = mem_heap_strdup(sym_tab->heap, bid->id);
node->name_len = strlen(node->name);
UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node);
dfield_set_data(&(node->common.val), NULL, UNIV_SQL_NULL);
node->common.val_buf_size = 0;
node->prefetch_buf = NULL;
node->cursor_def = NULL;
node->sym_table = sym_tab;
return(node);
}

View File

@@ -601,7 +601,7 @@ row_ins_set_detailed(
rewind(srv_misc_tmpfile); rewind(srv_misc_tmpfile);
if (os_file_set_eof(srv_misc_tmpfile)) { if (os_file_set_eof(srv_misc_tmpfile)) {
ut_print_name(srv_misc_tmpfile, trx, ut_print_name(srv_misc_tmpfile, trx, TRUE,
foreign->foreign_table_name); foreign->foreign_table_name);
dict_print_info_on_foreign_key_in_create_format( dict_print_info_on_foreign_key_in_create_format(
srv_misc_tmpfile, srv_misc_tmpfile,
@@ -643,22 +643,22 @@ row_ins_foreign_report_err(
trx_print(ef, trx, 600); trx_print(ef, trx, 600);
fputs("Foreign key constraint fails for table ", ef); fputs("Foreign key constraint fails for table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name); ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
fputs(":\n", ef); fputs(":\n", ef);
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign, dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
TRUE); TRUE);
putc('\n', ef); putc('\n', ef);
fputs(errstr, ef); fputs(errstr, ef);
fputs(" in parent table, in index ", ef); fputs(" in parent table, in index ", ef);
ut_print_name(ef, trx, foreign->referenced_index->name); ut_print_name(ef, trx, FALSE, foreign->referenced_index->name);
if (entry) { if (entry) {
fputs(" tuple:\n", ef); fputs(" tuple:\n", ef);
dtuple_print(ef, entry); dtuple_print(ef, entry);
} }
fputs("\nBut in child table ", ef); fputs("\nBut in child table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name); ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
fputs(", in index ", ef); fputs(", in index ", ef);
ut_print_name(ef, trx, foreign->foreign_index->name); ut_print_name(ef, trx, FALSE, foreign->foreign_index->name);
if (rec) { if (rec) {
fputs(", there is a record:\n", ef); fputs(", there is a record:\n", ef);
rec_print(ef, rec, foreign->foreign_index); rec_print(ef, rec, foreign->foreign_index);
@@ -696,20 +696,20 @@ row_ins_foreign_report_add_err(
fputs(" Transaction:\n", ef); fputs(" Transaction:\n", ef);
trx_print(ef, trx, 600); trx_print(ef, trx, 600);
fputs("Foreign key constraint fails for table ", ef); fputs("Foreign key constraint fails for table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name); ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
fputs(":\n", ef); fputs(":\n", ef);
dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign, dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
TRUE); TRUE);
fputs("\nTrying to add in child table, in index ", ef); fputs("\nTrying to add in child table, in index ", ef);
ut_print_name(ef, trx, foreign->foreign_index->name); ut_print_name(ef, trx, FALSE, foreign->foreign_index->name);
if (entry) { if (entry) {
fputs(" tuple:\n", ef); fputs(" tuple:\n", ef);
dtuple_print(ef, entry); dtuple_print(ef, entry);
} }
fputs("\nBut in parent table ", ef); fputs("\nBut in parent table ", ef);
ut_print_name(ef, trx, foreign->referenced_table_name); ut_print_name(ef, trx, TRUE, foreign->referenced_table_name);
fputs(", in index ", ef); fputs(", in index ", ef);
ut_print_name(ef, trx, foreign->referenced_index->name); ut_print_name(ef, trx, FALSE, foreign->referenced_index->name);
fputs(",\nthe closest match we can find is record:\n", ef); fputs(",\nthe closest match we can find is record:\n", ef);
if (rec && page_rec_is_supremum(rec)) { if (rec && page_rec_is_supremum(rec)) {
/* If the cursor ended on a supremum record, it is better /* If the cursor ended on a supremum record, it is better
@@ -1277,16 +1277,19 @@ run_again:
fputs(" Transaction:\n", ef); fputs(" Transaction:\n", ef);
trx_print(ef, trx, 600); trx_print(ef, trx, 600);
fputs("Foreign key constraint fails for table ", ef); fputs("Foreign key constraint fails for table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name); ut_print_name(ef, trx, TRUE,
foreign->foreign_table_name);
fputs(":\n", ef); fputs(":\n", ef);
dict_print_info_on_foreign_key_in_create_format(ef, dict_print_info_on_foreign_key_in_create_format(ef,
trx, foreign, TRUE); trx, foreign, TRUE);
fputs("\nTrying to add to index ", ef); fputs("\nTrying to add to index ", ef);
ut_print_name(ef, trx, foreign->foreign_index->name); ut_print_name(ef, trx, FALSE,
foreign->foreign_index->name);
fputs(" tuple:\n", ef); fputs(" tuple:\n", ef);
dtuple_print(ef, entry); dtuple_print(ef, entry);
fputs("\nBut the parent table ", ef); fputs("\nBut the parent table ", ef);
ut_print_name(ef, trx, foreign->referenced_table_name); ut_print_name(ef, trx, TRUE,
foreign->referenced_table_name);
fputs("\nor its .ibd file does not currently exist!\n", ef); fputs("\nor its .ibd file does not currently exist!\n", ef);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
@@ -1513,8 +1516,7 @@ row_ins_check_foreign_constraints(
if (foreign->foreign_index == index) { if (foreign->foreign_index == index) {
if (foreign->referenced_table == NULL) { if (foreign->referenced_table == NULL) {
dict_table_get(foreign->referenced_table_name, dict_table_get(foreign->referenced_table_name);
trx);
} }
if (0 == trx->dict_operation_lock_mode) { if (0 == trx->dict_operation_lock_mode) {

View File

@@ -680,7 +680,7 @@ row_prebuilt_free(
"InnoDB: table handle. Magic n %lu, magic n2 %lu, table name", "InnoDB: table handle. Magic n %lu, magic n2 %lu, table name",
(ulong) prebuilt->magic_n, (ulong) prebuilt->magic_n,
(ulong) prebuilt->magic_n2); (ulong) prebuilt->magic_n2);
ut_print_name(stderr, NULL, prebuilt->table->name); ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
putc('\n', stderr); putc('\n', stderr);
mem_analyze_corruption(prebuilt); mem_analyze_corruption(prebuilt);
@@ -773,7 +773,7 @@ row_update_prebuilt_trx(
"InnoDB: Error: trying to use a corrupt\n" "InnoDB: Error: trying to use a corrupt\n"
"InnoDB: table handle. Magic n %lu, table name", "InnoDB: table handle. Magic n %lu, table name",
(ulong) prebuilt->magic_n); (ulong) prebuilt->magic_n);
ut_print_name(stderr, NULL, prebuilt->table->name); ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
putc('\n', stderr); putc('\n', stderr);
mem_analyze_corruption(prebuilt); mem_analyze_corruption(prebuilt);
@@ -1094,7 +1094,8 @@ row_insert_for_mysql(
"InnoDB: Error: trying to free a corrupt\n" "InnoDB: Error: trying to free a corrupt\n"
"InnoDB: table handle. Magic n %lu, table name", "InnoDB: table handle. Magic n %lu, table name",
(ulong) prebuilt->magic_n); (ulong) prebuilt->magic_n);
ut_print_name(stderr, prebuilt->trx, prebuilt->table->name); ut_print_name(stderr, prebuilt->trx, TRUE,
prebuilt->table->name);
putc('\n', stderr); putc('\n', stderr);
mem_analyze_corruption(prebuilt); mem_analyze_corruption(prebuilt);
@@ -1329,7 +1330,8 @@ row_update_for_mysql(
"InnoDB: Error: trying to free a corrupt\n" "InnoDB: Error: trying to free a corrupt\n"
"InnoDB: table handle. Magic n %lu, table name", "InnoDB: table handle. Magic n %lu, table name",
(ulong) prebuilt->magic_n); (ulong) prebuilt->magic_n);
ut_print_name(stderr, prebuilt->trx, prebuilt->table->name); ut_print_name(stderr, prebuilt->trx, TRUE,
prebuilt->table->name);
putc('\n', stderr); putc('\n', stderr);
mem_analyze_corruption(prebuilt); mem_analyze_corruption(prebuilt);
@@ -1941,7 +1943,7 @@ row_create_table_for_mysql(
fputs(" InnoDB: Warning: cannot create table ", fputs(" InnoDB: Warning: cannot create table ",
stderr); stderr);
ut_print_name(stderr, trx, table->name); ut_print_name(stderr, trx, TRUE, table->name);
fputs(" because tablespace full\n", stderr); fputs(" because tablespace full\n", stderr);
if (dict_table_get_low(table->name)) { if (dict_table_get_low(table->name)) {
@@ -1954,7 +1956,7 @@ row_create_table_for_mysql(
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr); fputs(" InnoDB: Error: table ", stderr);
ut_print_name(stderr, trx, table->name); ut_print_name(stderr, trx, TRUE, table->name);
fputs(" already exists in InnoDB internal\n" fputs(" already exists in InnoDB internal\n"
"InnoDB: data dictionary. Have you deleted the .frm file\n" "InnoDB: data dictionary. Have you deleted the .frm file\n"
"InnoDB: and not used DROP TABLE? Have you used DROP DATABASE\n" "InnoDB: and not used DROP TABLE? Have you used DROP DATABASE\n"
@@ -2031,7 +2033,7 @@ row_create_index_for_mysql(
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: column ", stderr); fputs(" InnoDB: Error: column ", stderr);
ut_print_name(stderr, trx, ut_print_name(stderr, trx, FALSE,
dict_index_get_nth_field(index, i)->name); dict_index_get_nth_field(index, i)->name);
fputs(" appears twice in ", stderr); fputs(" appears twice in ", stderr);
dict_index_name_print(stderr, trx, index); dict_index_name_print(stderr, trx, index);
@@ -2196,7 +2198,7 @@ row_drop_table_for_mysql_in_background(
trx->check_foreigns = FALSE; trx->check_foreigns = FALSE;
/* fputs("InnoDB: Error: Dropping table ", stderr); /* fputs("InnoDB: Error: Dropping table ", stderr);
ut_print_name(stderr, name); ut_print_name(stderr, trx, TRUE, name);
fputs(" in background drop list\n", stderr); */ fputs(" in background drop list\n", stderr); */
/* Try to drop the table in InnoDB */ /* Try to drop the table in InnoDB */
@@ -2360,7 +2362,7 @@ row_add_table_to_background_drop_list(
UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop); UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
/* fputs("InnoDB: Adding table ", stderr); /* fputs("InnoDB: Adding table ", stderr);
ut_print_name(stderr, drop->table_name); ut_print_name(stderr, trx, TRUE, drop->table_name);
fputs(" to background drop list\n", stderr); */ fputs(" to background drop list\n", stderr); */
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
@@ -2429,7 +2431,7 @@ do not allow the discard. We also reserve the data dictionary latch. */
if (table->space == 0) { if (table->space == 0) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr); fputs(" InnoDB: Error: table ", stderr);
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fputs("\n" fputs("\n"
"InnoDB: is in the system tablespace 0 which cannot be discarded\n", stderr); "InnoDB: is in the system tablespace 0 which cannot be discarded\n", stderr);
err = DB_ERROR; err = DB_ERROR;
@@ -2441,7 +2443,7 @@ do not allow the discard. We also reserve the data dictionary latch. */
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: You are trying to DISCARD table ", stderr); fputs(" InnoDB: You are trying to DISCARD table ", stderr);
ut_print_name(stderr, trx, table->name); ut_print_name(stderr, trx, TRUE, table->name);
fputs("\n" fputs("\n"
"InnoDB: though there is a foreign key check running on it.\n" "InnoDB: though there is a foreign key check running on it.\n"
"InnoDB: Cannot discard the table.\n", "InnoDB: Cannot discard the table.\n",
@@ -2475,10 +2477,10 @@ do not allow the discard. We also reserve the data dictionary latch. */
ut_print_timestamp(ef); ut_print_timestamp(ef);
fputs(" Cannot DISCARD table ", ef); fputs(" Cannot DISCARD table ", ef);
ut_print_name(ef, trx, name); ut_print_name(ef, trx, TRUE, name);
fputs("\n" fputs("\n"
"because it is referenced by ", ef); "because it is referenced by ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name); ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
putc('\n', ef); putc('\n', ef);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
@@ -2540,10 +2542,10 @@ do not allow the discard. We also reserve the data dictionary latch. */
} }
funct_exit: funct_exit:
row_mysql_unlock_data_dictionary(trx);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
row_mysql_unlock_data_dictionary(trx);
trx->op_info = ""; trx->op_info = "";
return((int) err); return((int) err);
@@ -2590,7 +2592,7 @@ row_import_tablespace_for_mysql(
if (!success) { if (!success) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: cannot reset lsn's in table ", stderr); fputs(" InnoDB: Error: cannot reset lsn's in table ", stderr);
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fputs("\n" fputs("\n"
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n", stderr); "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n", stderr);
@@ -2611,7 +2613,7 @@ row_import_tablespace_for_mysql(
if (!table) { if (!table) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: table ", stderr); fputs(" InnoDB: table ", stderr);
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fputs("\n" fputs("\n"
"InnoDB: does not exist in the InnoDB data dictionary\n" "InnoDB: does not exist in the InnoDB data dictionary\n"
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n", "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
@@ -2625,7 +2627,7 @@ row_import_tablespace_for_mysql(
if (table->space == 0) { if (table->space == 0) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr); fputs(" InnoDB: Error: table ", stderr);
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fputs("\n" fputs("\n"
"InnoDB: is in the system tablespace 0 which cannot be imported\n", stderr); "InnoDB: is in the system tablespace 0 which cannot be imported\n", stderr);
err = DB_ERROR; err = DB_ERROR;
@@ -2638,7 +2640,7 @@ row_import_tablespace_for_mysql(
fputs( fputs(
" InnoDB: Error: you are trying to IMPORT a tablespace\n" " InnoDB: Error: you are trying to IMPORT a tablespace\n"
"InnoDB: ", stderr); "InnoDB: ", stderr);
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fputs(", though you have not called DISCARD on it yet\n" fputs(", though you have not called DISCARD on it yet\n"
"InnoDB: during the lifetime of the mysqld process!\n", stderr); "InnoDB: during the lifetime of the mysqld process!\n", stderr);
@@ -2663,7 +2665,7 @@ row_import_tablespace_for_mysql(
fputs( fputs(
" InnoDB: cannot find or open in the database directory the .ibd file of\n" " InnoDB: cannot find or open in the database directory the .ibd file of\n"
"InnoDB: table ", stderr); "InnoDB: table ", stderr);
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fputs("\n" fputs("\n"
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n", "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
stderr); stderr);
@@ -2673,10 +2675,10 @@ row_import_tablespace_for_mysql(
} }
funct_exit: funct_exit:
row_mysql_unlock_data_dictionary(trx);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
row_mysql_unlock_data_dictionary(trx);
trx->op_info = ""; trx->op_info = "";
return((int) err); return((int) err);
@@ -2783,10 +2785,10 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */
ut_print_timestamp(ef); ut_print_timestamp(ef);
fputs(" Cannot truncate table ", ef); fputs(" Cannot truncate table ", ef);
ut_print_name(ef, trx, table->name); ut_print_name(ef, trx, TRUE, table->name);
fputs(" by DROP+CREATE\n" fputs(" by DROP+CREATE\n"
"InnoDB: because it is referenced by ", ef); "InnoDB: because it is referenced by ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name); ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
putc('\n', ef); putc('\n', ef);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
@@ -2803,7 +2805,7 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */
if (table->n_foreign_key_checks_running > 0) { if (table->n_foreign_key_checks_running > 0) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Cannot truncate table ", stderr); fputs(" InnoDB: Cannot truncate table ", stderr);
ut_print_name(stderr, trx, table->name); ut_print_name(stderr, trx, TRUE, table->name);
fputs(" by DROP+CREATE\n" fputs(" by DROP+CREATE\n"
"InnoDB: because there is a foreign key check running on it.\n", "InnoDB: because there is a foreign key check running on it.\n",
stderr); stderr);
@@ -2918,7 +2920,7 @@ do not allow the TRUNCATE. We also reserve the data dictionary latch. */
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Unable to assign a new identifier to table ", stderr); fputs(" InnoDB: Unable to assign a new identifier to table ", stderr);
ut_print_name(stderr, trx, table->name); ut_print_name(stderr, trx, TRUE, table->name);
fputs("\n" fputs("\n"
"InnoDB: after truncating it. Background processes may corrupt the table!\n", "InnoDB: after truncating it. Background processes may corrupt the table!\n",
stderr); stderr);
@@ -3045,7 +3047,7 @@ row_drop_table_for_mysql(
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr); fputs(" InnoDB: Error: table ", stderr);
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fputs(" does not exist in the InnoDB internal\n" fputs(" does not exist in the InnoDB internal\n"
"InnoDB: data dictionary though MySQL is trying to drop it.\n" "InnoDB: data dictionary though MySQL is trying to drop it.\n"
"InnoDB: Have you copied the .frm file of the table to the\n" "InnoDB: Have you copied the .frm file of the table to the\n"
@@ -3081,10 +3083,10 @@ row_drop_table_for_mysql(
ut_print_timestamp(ef); ut_print_timestamp(ef);
fputs(" Cannot drop table ", ef); fputs(" Cannot drop table ", ef);
ut_print_name(ef, trx, name); ut_print_name(ef, trx, TRUE, name);
fputs("\n" fputs("\n"
"because it is referenced by ", ef); "because it is referenced by ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name); ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
putc('\n', ef); putc('\n', ef);
mutex_exit(&dict_foreign_err_mutex); mutex_exit(&dict_foreign_err_mutex);
@@ -3103,7 +3105,7 @@ row_drop_table_for_mysql(
if (added) { if (added) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Warning: MySQL is trying to drop table ", stderr); fputs(" InnoDB: Warning: MySQL is trying to drop table ", stderr);
ut_print_name(stderr, trx, table->name); ut_print_name(stderr, trx, TRUE, table->name);
fputs("\n" fputs("\n"
"InnoDB: though there are still open handles to it.\n" "InnoDB: though there are still open handles to it.\n"
"InnoDB: Adding the table to the background drop queue.\n", "InnoDB: Adding the table to the background drop queue.\n",
@@ -3136,7 +3138,7 @@ fputs(" InnoDB: Warning: MySQL is trying to drop table ", stderr);
if (added) { if (added) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: You are trying to drop table ", stderr); fputs(" InnoDB: You are trying to drop table ", stderr);
ut_print_name(stderr, trx, table->name); ut_print_name(stderr, trx, TRUE, table->name);
fputs("\n" fputs("\n"
"InnoDB: though there is a foreign key check running on it.\n" "InnoDB: though there is a foreign key check running on it.\n"
"InnoDB: Adding the table to the background drop queue.\n", "InnoDB: Adding the table to the background drop queue.\n",
@@ -3259,7 +3261,7 @@ fputs(" InnoDB: You are trying to drop table ", stderr);
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: not able to remove table ", fputs(" InnoDB: Error: not able to remove table ",
stderr); stderr);
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fputs(" from the dictionary cache!\n", stderr); fputs(" from the dictionary cache!\n", stderr);
err = DB_ERROR; err = DB_ERROR;
} }
@@ -3277,7 +3279,7 @@ fputs(" InnoDB: You are trying to drop table ", stderr);
fprintf(stderr, fprintf(stderr,
"InnoDB: We removed now the InnoDB internal data dictionary entry\n" "InnoDB: We removed now the InnoDB internal data dictionary entry\n"
"InnoDB: of table "); "InnoDB: of table ");
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fprintf(stderr, ".\n"); fprintf(stderr, ".\n");
goto funct_exit; goto funct_exit;
@@ -3289,14 +3291,14 @@ fputs(" InnoDB: You are trying to drop table ", stderr);
fprintf(stderr, fprintf(stderr,
"InnoDB: We removed now the InnoDB internal data dictionary entry\n" "InnoDB: We removed now the InnoDB internal data dictionary entry\n"
"InnoDB: of table "); "InnoDB: of table ");
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fprintf(stderr, ".\n"); fprintf(stderr, ".\n");
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
" InnoDB: Error: not able to delete tablespace %lu of table ", " InnoDB: Error: not able to delete tablespace %lu of table ",
(ulong) space_id); (ulong) space_id);
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fputs("!\n", stderr); fputs("!\n", stderr);
err = DB_ERROR; err = DB_ERROR;
} }
@@ -3304,6 +3306,8 @@ fputs(" InnoDB: You are trying to drop table ", stderr);
} }
funct_exit: funct_exit:
trx_commit_for_mysql(trx);
if (locked_dictionary) { if (locked_dictionary) {
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
} }
@@ -3312,8 +3316,6 @@ funct_exit:
mem_free(dir_path_of_temp_table); mem_free(dir_path_of_temp_table);
} }
trx_commit_for_mysql(trx);
trx->op_info = ""; trx->op_info = "";
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
@@ -3364,10 +3366,10 @@ loop:
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs( fputs(
" InnoDB: Warning: MySQL is trying to drop database ", stderr); " InnoDB: Warning: MySQL is trying to drop database ", stderr);
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fputs("\n" fputs("\n"
"InnoDB: though there are still open handles to table ", stderr); "InnoDB: though there are still open handles to table ", stderr);
ut_print_name(stderr, trx, table_name); ut_print_name(stderr, trx, TRUE, table_name);
fputs(".\n", stderr); fputs(".\n", stderr);
os_thread_sleep(1000000); os_thread_sleep(1000000);
@@ -3383,19 +3385,19 @@ loop:
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
fputs("InnoDB: DROP DATABASE ", stderr); fputs("InnoDB: DROP DATABASE ", stderr);
ut_print_name(stderr, trx, name); ut_print_name(stderr, trx, TRUE, name);
fprintf(stderr, " failed with error %lu for table ", fprintf(stderr, " failed with error %lu for table ",
(ulint) err); (ulint) err);
ut_print_name(stderr, trx, table_name); ut_print_name(stderr, trx, TRUE, table_name);
putc('\n', stderr); putc('\n', stderr);
break; break;
} }
} }
row_mysql_unlock_data_dictionary(trx);
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
row_mysql_unlock_data_dictionary(trx);
trx->op_info = ""; trx->op_info = "";
return(err); return(err);
@@ -3543,7 +3545,7 @@ row_rename_table_for_mysql(
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr); fputs(" InnoDB: Error: table ", stderr);
ut_print_name(stderr, trx, old_name); ut_print_name(stderr, trx, TRUE, old_name);
fputs(" does not exist in the InnoDB internal\n" fputs(" does not exist in the InnoDB internal\n"
"InnoDB: data dictionary though MySQL is trying to rename the table.\n" "InnoDB: data dictionary though MySQL is trying to rename the table.\n"
"InnoDB: Have you copied the .frm file of the table to the\n" "InnoDB: Have you copied the .frm file of the table to the\n"
@@ -3559,7 +3561,7 @@ row_rename_table_for_mysql(
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr); fputs(" InnoDB: Error: table ", stderr);
ut_print_name(stderr, trx, old_name); ut_print_name(stderr, trx, TRUE, old_name);
fputs( fputs(
" does not have an .ibd file in the database directory.\n" " does not have an .ibd file in the database directory.\n"
"InnoDB: You can look for further help from\n" "InnoDB: You can look for further help from\n"
@@ -3704,17 +3706,17 @@ end:
"InnoDB: 1) Table rename would cause two FOREIGN KEY constraints\n" "InnoDB: 1) Table rename would cause two FOREIGN KEY constraints\n"
"InnoDB: to have the same internal name in case-insensitive comparison.\n" "InnoDB: to have the same internal name in case-insensitive comparison.\n"
"InnoDB: 2) table ", stderr); "InnoDB: 2) table ", stderr);
ut_print_name(stderr, trx, new_name); ut_print_name(stderr, trx, TRUE, new_name);
fputs(" exists in the InnoDB internal data\n" fputs(" exists in the InnoDB internal data\n"
"InnoDB: dictionary though MySQL is trying rename table ", stderr); "InnoDB: dictionary though MySQL is trying rename table ", stderr);
ut_print_name(stderr, trx, old_name); ut_print_name(stderr, trx, TRUE, old_name);
fputs(" to it.\n" fputs(" to it.\n"
"InnoDB: Have you deleted the .frm file and not used DROP TABLE?\n" "InnoDB: Have you deleted the .frm file and not used DROP TABLE?\n"
"InnoDB: You can look for further help from\n" "InnoDB: You can look for further help from\n"
"InnoDB: http://dev.mysql.com/doc/mysql/en/" "InnoDB: http://dev.mysql.com/doc/mysql/en/"
"InnoDB_troubleshooting_datadict.html\n" "InnoDB_troubleshooting_datadict.html\n"
"InnoDB: If table ", stderr); "InnoDB: If table ", stderr);
ut_print_name(stderr, trx, new_name); ut_print_name(stderr, trx, TRUE, new_name);
fputs( fputs(
" is a temporary table #sql..., then it can be that\n" " is a temporary table #sql..., then it can be that\n"
"InnoDB: there are still queries running on the table, and it will be\n" "InnoDB: there are still queries running on the table, and it will be\n"
@@ -3742,9 +3744,9 @@ end:
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error in table rename, cannot rename ", fputs(" InnoDB: Error in table rename, cannot rename ",
stderr); stderr);
ut_print_name(stderr, trx, old_name); ut_print_name(stderr, trx, TRUE, old_name);
fputs(" to ", stderr); fputs(" to ", stderr);
ut_print_name(stderr, trx, new_name); ut_print_name(stderr, trx, TRUE, new_name);
putc('\n', stderr); putc('\n', stderr);
err = DB_ERROR; err = DB_ERROR;
@@ -3763,7 +3765,7 @@ end:
if (old_is_tmp) { if (old_is_tmp) {
fputs(" InnoDB: Error: in ALTER TABLE ", fputs(" InnoDB: Error: in ALTER TABLE ",
stderr); stderr);
ut_print_name(stderr, trx, new_name); ut_print_name(stderr, trx, TRUE, new_name);
fputs("\n" fputs("\n"
"InnoDB: has or is referenced in foreign key constraints\n" "InnoDB: has or is referenced in foreign key constraints\n"
"InnoDB: which are not compatible with the new table definition.\n", "InnoDB: which are not compatible with the new table definition.\n",
@@ -3772,7 +3774,7 @@ end:
fputs( fputs(
" InnoDB: Error: in RENAME TABLE table ", " InnoDB: Error: in RENAME TABLE table ",
stderr); stderr);
ut_print_name(stderr, trx, new_name); ut_print_name(stderr, trx, TRUE, new_name);
fputs("\n" fputs("\n"
"InnoDB: is referenced in foreign key constraints\n" "InnoDB: is referenced in foreign key constraints\n"
"InnoDB: which are not compatible with the new table definition.\n", "InnoDB: which are not compatible with the new table definition.\n",
@@ -3788,6 +3790,8 @@ end:
} }
funct_exit: funct_exit:
trx_commit_for_mysql(trx);
if (!recovering_temp_table) { if (!recovering_temp_table) {
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
} }
@@ -3796,8 +3800,6 @@ funct_exit:
mem_heap_free(heap); mem_heap_free(heap);
} }
trx_commit_for_mysql(trx);
trx->op_info = ""; trx->op_info = "";
return((int) err); return((int) err);
@@ -3986,7 +3988,7 @@ row_check_table_for_mysql(
while (index != NULL) { while (index != NULL) {
/* fputs("Validating index ", stderr); /* fputs("Validating index ", stderr);
ut_print_name(stderr, index->name); ut_print_name(stderr, trx, FALSE, index->name);
putc('\n', stderr); */ putc('\n', stderr); */
if (!btr_validate_tree(index->tree, prebuilt->trx)) { if (!btr_validate_tree(index->tree, prebuilt->trx)) {

View File

@@ -520,7 +520,7 @@ row_purge_parse_undo_rec(
mutex_enter(&(dict_sys->mutex)); mutex_enter(&(dict_sys->mutex));
node->table = dict_table_get_on_id_low(table_id, trx); node->table = dict_table_get_on_id_low(table_id);
mutex_exit(&(dict_sys->mutex)); mutex_exit(&(dict_sys->mutex));

View File

@@ -480,12 +480,12 @@ row_build_row_ref_in_tuple(
ut_a(ref && index && rec); ut_a(ref && index && rec);
if (!index->table) { if (UNIV_UNLIKELY(!index->table)) {
fputs("InnoDB: table ", stderr); fputs("InnoDB: table ", stderr);
notfound: notfound:
ut_print_name(stderr, trx, index->table_name); ut_print_name(stderr, trx, TRUE, index->table_name);
fputs(" for index ", stderr); fputs(" for index ", stderr);
ut_print_name(stderr, trx, index->name); ut_print_name(stderr, trx, FALSE, index->name);
fputs(" not found\n", stderr); fputs(" not found\n", stderr);
ut_error; ut_error;
} }

View File

@@ -302,19 +302,45 @@ row_sel_fetch_columns(
} }
while (column) { while (column) {
mem_heap_t* heap = NULL;
ibool needs_copy;
field_no = column->field_nos[index_type]; field_no = column->field_nos[index_type];
if (field_no != ULINT_UNDEFINED) { if (field_no != ULINT_UNDEFINED) {
data = rec_get_nth_field(rec, offsets, field_no, &len); if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets,
field_no))) {
if (column->copy_val) { /* Copy an externally stored field to the
temporary heap */
heap = mem_heap_create(1);
data = btr_rec_copy_externally_stored_field(
rec, offsets, field_no, &len, heap);
ut_a(len != UNIV_SQL_NULL);
needs_copy = TRUE;
} else {
data = rec_get_nth_field(rec, offsets,
field_no, &len);
needs_copy = column->copy_val;
}
if (needs_copy) {
eval_node_copy_and_alloc_val(column, data, eval_node_copy_and_alloc_val(column, data,
len); len);
} else { } else {
val = que_node_get_val(column); val = que_node_get_val(column);
dfield_set_data(val, data, len); dfield_set_data(val, data, len);
} }
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
} }
column = UT_LIST_GET_NEXT(col_var_list, column); column = UT_LIST_GET_NEXT(col_var_list, column);
@@ -2036,8 +2062,13 @@ row_fetch_print(
dtype_print(type); dtype_print(type);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
ut_print_buf(stderr, dfield_get_data(dfield), if (dfield_get_len(dfield) != UNIV_SQL_NULL) {
dfield_get_len(dfield)); ut_print_buf(stderr, dfield_get_data(dfield),
dfield_get_len(dfield));
} else {
fprintf(stderr, " <NULL>;");
}
fprintf(stderr, "\n"); fprintf(stderr, "\n");
exp = que_node_get_next(exp); exp = que_node_get_next(exp);
@@ -2542,6 +2573,7 @@ row_sel_store_mysql_rec(
{ {
mysql_row_templ_t* templ; mysql_row_templ_t* templ;
mem_heap_t* extern_field_heap = NULL; mem_heap_t* extern_field_heap = NULL;
mem_heap_t* heap;
byte* data; byte* data;
ulint len; ulint len;
ulint i; ulint i;
@@ -2558,9 +2590,6 @@ row_sel_store_mysql_rec(
templ = prebuilt->mysql_template + i; templ = prebuilt->mysql_template + i;
data = rec_get_nth_field(rec, offsets,
templ->rec_field_no, &len);
if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets, if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets,
templ->rec_field_no))) { templ->rec_field_no))) {
@@ -2569,7 +2598,19 @@ row_sel_store_mysql_rec(
ut_a(!prebuilt->trx->has_search_latch); ut_a(!prebuilt->trx->has_search_latch);
extern_field_heap = mem_heap_create(UNIV_PAGE_SIZE); if (UNIV_UNLIKELY(templ->type == DATA_BLOB)) {
if (prebuilt->blob_heap == NULL) {
prebuilt->blob_heap =
mem_heap_create(UNIV_PAGE_SIZE);
}
heap = prebuilt->blob_heap;
} else {
extern_field_heap =
mem_heap_create(UNIV_PAGE_SIZE);
heap = extern_field_heap;
}
/* NOTE: if we are retrieving a big BLOB, we may /* NOTE: if we are retrieving a big BLOB, we may
already run out of memory in the next call, which already run out of memory in the next call, which
@@ -2577,54 +2618,17 @@ row_sel_store_mysql_rec(
data = btr_rec_copy_externally_stored_field(rec, data = btr_rec_copy_externally_stored_field(rec,
offsets, templ->rec_field_no, &len, offsets, templ->rec_field_no, &len,
extern_field_heap); heap);
ut_a(len != UNIV_SQL_NULL); ut_a(len != UNIV_SQL_NULL);
} else {
/* Field is stored in the row. */
data = rec_get_nth_field(rec, offsets,
templ->rec_field_no, &len);
} }
if (len != UNIV_SQL_NULL) { if (len != UNIV_SQL_NULL) {
if (UNIV_UNLIKELY(templ->type == DATA_BLOB)) {
ut_a(prebuilt->templ_contains_blob);
/* A heuristic test that we can allocate the
memory for a big BLOB. We have a safety margin
of 1000000 bytes. Since the test takes some
CPU time, we do not use it for small BLOBs. */
if (UNIV_UNLIKELY(len > 2000000)
&& UNIV_UNLIKELY(!ut_test_malloc(
len + 1000000))) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: could not allocate %lu + 1000000 bytes to retrieve\n"
"InnoDB: a big column. Table name ", (ulong) len);
ut_print_name(stderr,
prebuilt->trx,
prebuilt->table->name);
putc('\n', stderr);
if (extern_field_heap) {
mem_heap_free(
extern_field_heap);
}
return(FALSE);
}
/* Copy the BLOB data to the BLOB heap of
prebuilt */
if (prebuilt->blob_heap == NULL) {
prebuilt->blob_heap =
mem_heap_create(len);
}
data = memcpy(mem_heap_alloc(
prebuilt->blob_heap, len),
data, len);
}
row_sel_field_store_in_mysql_format( row_sel_field_store_in_mysql_format(
mysql_rec + templ->mysql_col_offset, mysql_rec + templ->mysql_col_offset,
templ, data, len); templ, data, len);
@@ -3244,7 +3248,7 @@ row_search_for_mysql(
"InnoDB: Error: trying to free a corrupt\n" "InnoDB: Error: trying to free a corrupt\n"
"InnoDB: table handle. Magic n %lu, table name ", "InnoDB: table handle. Magic n %lu, table name ",
(ulong) prebuilt->magic_n); (ulong) prebuilt->magic_n);
ut_print_name(stderr, trx, prebuilt->table->name); ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
putc('\n', stderr); putc('\n', stderr);
mem_analyze_corruption(prebuilt); mem_analyze_corruption(prebuilt);
@@ -3530,15 +3534,13 @@ shortcut_fails_too_big_rec:
if (trx->isolation_level <= TRX_ISO_READ_COMMITTED if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
&& prebuilt->select_lock_type != LOCK_NONE && prebuilt->select_lock_type != LOCK_NONE
&& trx->mysql_query_str) { && trx->mysql_query_str && trx->mysql_thd) {
/* Scan the MySQL query string; check if SELECT is the first /* Scan the MySQL query string; check if SELECT is the first
word there */ word there */
ibool success;
dict_accept(*trx->mysql_query_str, "SELECT", &success); if (dict_str_starts_with_keyword(trx->mysql_thd,
*trx->mysql_query_str, "SELECT")) {
if (success) {
/* It is a plain locking SELECT and the isolation /* It is a plain locking SELECT and the isolation
level is low: do not lock gaps */ level is low: do not lock gaps */
@@ -4402,7 +4404,7 @@ row_search_check_if_query_cache_permitted(
dict_table_t* table; dict_table_t* table;
ibool ret = FALSE; ibool ret = FALSE;
table = dict_table_get(norm_name, trx); table = dict_table_get(norm_name);
if (table == NULL) { if (table == NULL) {

View File

@@ -202,8 +202,7 @@ row_upd_check_references_constraints(
foreign->n_fields))) { foreign->n_fields))) {
if (foreign->foreign_table == NULL) { if (foreign->foreign_table == NULL) {
dict_table_get(foreign->foreign_table_name, dict_table_get(foreign->foreign_table_name);
trx);
} }
if (foreign->foreign_table) { if (foreign->foreign_table) {

View File

@@ -68,6 +68,9 @@ ibool srv_error_monitor_active = FALSE;
const char* srv_main_thread_op_info = ""; const char* srv_main_thread_op_info = "";
/* Prefix used by MySQL to indicate pre-5.1 table name encoding */
const char srv_mysql50_table_name_prefix[9] = "#mysql50#";
/* Server parameters which are read from the initfile */ /* Server parameters which are read from the initfile */
/* The following three are dir paths which are catenated before file /* The following three are dir paths which are catenated before file
@@ -849,11 +852,9 @@ srv_init(void)
srv_sys = mem_alloc(sizeof(srv_sys_t)); srv_sys = mem_alloc(sizeof(srv_sys_t));
kernel_mutex_temp = mem_alloc(sizeof(mutex_t)); kernel_mutex_temp = mem_alloc(sizeof(mutex_t));
mutex_create(&kernel_mutex); mutex_create(&kernel_mutex, SYNC_KERNEL);
mutex_set_level(&kernel_mutex, SYNC_KERNEL);
mutex_create(&srv_innodb_monitor_mutex); mutex_create(&srv_innodb_monitor_mutex, SYNC_NO_ORDER_CHECK);
mutex_set_level(&srv_innodb_monitor_mutex, SYNC_NO_ORDER_CHECK);
srv_sys->threads = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_slot_t)); srv_sys->threads = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_slot_t));
@@ -2559,18 +2560,9 @@ suspend_thread:
os_thread_exit(NULL); os_thread_exit(NULL);
} }
/* When there is user activity, InnoDB will set the event and the main /* When there is user activity, InnoDB will set the event and the
thread goes back to loop: */ main thread goes back to loop. */
goto loop; goto loop;
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit.
The thread actually never comes here because it is exited in an
os_event_wait(). */
os_thread_exit(NULL);
OS_THREAD_DUMMY_RETURN;
} }
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */

View File

@@ -108,12 +108,45 @@ static char* srv_monitor_file_name;
static int inno_bcmp(register const char *s1, register const char *s2, static int inno_bcmp(register const char *s1, register const char *s2,
register uint len) register uint len)
{ {
while (len-- != 0 && *s1++ == *s2++) ; while ((len-- != 0) && (*s1++ == *s2++))
return len+1; ;
return(len + 1);
} }
#define memcmp(A,B,C) inno_bcmp((A),(B),(C)) #define memcmp(A,B,C) inno_bcmp((A),(B),(C))
#endif #endif
static
char*
srv_parse_megabytes(
/*================*/
/* out: next character in string */
char* str, /* in: string containing a quantity in bytes */
ulint* megs) /* out: the number in megabytes */
{
char* endp;
ulint size;
size = strtoul(str, &endp, 10);
str = endp;
switch (*str) {
case 'G': case 'g':
size *= 1024;
/* fall through */
case 'M': case 'm':
str++;
break;
default:
size /= 1024 * 1024;
break;
}
*megs = size;
return(str);
}
/************************************************************************* /*************************************************************************
Reads the data files and their sizes from a character string given in Reads the data files and their sizes from a character string given in
the .cnf file. */ the .cnf file. */
@@ -138,7 +171,6 @@ srv_parse_data_file_paths_and_sizes(
last file if specified, 0 if not */ last file if specified, 0 if not */
{ {
char* input_str; char* input_str;
char* endp;
char* path; char* path;
ulint size; ulint size;
ulint i = 0; ulint i = 0;
@@ -168,18 +200,7 @@ srv_parse_data_file_paths_and_sizes(
str++; str++;
size = strtoul(str, &endp, 10); str = srv_parse_megabytes(str, &size);
str = endp;
if (*str != 'M' && *str != 'G') {
size = size / (1024 * 1024);
} else if (*str == 'G') {
size = size * 1024;
str++;
} else {
str++;
}
if (0 == memcmp(str, ":autoextend", (sizeof ":autoextend") - 1)) { if (0 == memcmp(str, ":autoextend", (sizeof ":autoextend") - 1)) {
@@ -189,18 +210,7 @@ srv_parse_data_file_paths_and_sizes(
str += (sizeof ":max:") - 1; str += (sizeof ":max:") - 1;
size = strtoul(str, &endp, 10); str = srv_parse_megabytes(str, &size);
str = endp;
if (*str != 'M' && *str != 'G') {
size = size / (1024 * 1024);
} else if (*str == 'G') {
size = size * 1024;
str++;
} else {
str++;
}
} }
if (*str != '\0') { if (*str != '\0') {
@@ -273,18 +283,7 @@ srv_parse_data_file_paths_and_sizes(
str++; str++;
} }
size = strtoul(str, &endp, 10); str = srv_parse_megabytes(str, &size);
str = endp;
if ((*str != 'M') && (*str != 'G')) {
size = size / (1024 * 1024);
} else if (*str == 'G') {
size = size * 1024;
str++;
} else {
str++;
}
(*data_file_names)[i] = path; (*data_file_names)[i] = path;
(*data_file_sizes)[i] = size; (*data_file_sizes)[i] = size;
@@ -299,20 +298,8 @@ srv_parse_data_file_paths_and_sizes(
str += (sizeof ":max:") - 1; str += (sizeof ":max:") - 1;
size = strtoul(str, &endp, 10); str = srv_parse_megabytes(str,
max_auto_extend_size);
str = endp;
if (*str != 'M' && *str != 'G') {
size = size / (1024 * 1024);
} else if (*str == 'G') {
size = size * 1024;
str++;
} else {
str++;
}
*max_auto_extend_size = size;
} }
if (*str != '\0') { if (*str != '\0') {
@@ -934,8 +921,7 @@ skip_size_check:
ios = 0; ios = 0;
mutex_create(&ios_mutex); mutex_create(&ios_mutex, SYNC_NO_ORDER_CHECK);
mutex_set_level(&ios_mutex, SYNC_NO_ORDER_CHECK);
return(DB_SUCCESS); return(DB_SUCCESS);
} }
@@ -1167,8 +1153,8 @@ NetWare. */
return((int) err); return((int) err);
} }
mutex_create(&srv_monitor_file_mutex); mutex_create(&srv_monitor_file_mutex, SYNC_NO_ORDER_CHECK);
mutex_set_level(&srv_monitor_file_mutex, SYNC_NO_ORDER_CHECK);
if (srv_innodb_status) { if (srv_innodb_status) {
srv_monitor_file_name = mem_alloc( srv_monitor_file_name = mem_alloc(
strlen(fil_path_to_mysql_datadir) + strlen(fil_path_to_mysql_datadir) +
@@ -1189,15 +1175,15 @@ NetWare. */
} }
} }
mutex_create(&srv_dict_tmpfile_mutex); mutex_create(&srv_dict_tmpfile_mutex, SYNC_DICT_OPERATION);
mutex_set_level(&srv_dict_tmpfile_mutex, SYNC_DICT_OPERATION);
srv_dict_tmpfile = os_file_create_tmpfile(); srv_dict_tmpfile = os_file_create_tmpfile();
if (!srv_dict_tmpfile) { if (!srv_dict_tmpfile) {
return(DB_ERROR); return(DB_ERROR);
} }
mutex_create(&srv_misc_tmpfile_mutex); mutex_create(&srv_misc_tmpfile_mutex, SYNC_ANY_LATCH);
mutex_set_level(&srv_misc_tmpfile_mutex, SYNC_ANY_LATCH);
srv_misc_tmpfile = os_file_create_tmpfile(); srv_misc_tmpfile = os_file_create_tmpfile();
if (!srv_misc_tmpfile) { if (!srv_misc_tmpfile) {
return(DB_ERROR); return(DB_ERROR);

View File

@@ -213,8 +213,7 @@ sync_array_create(
if (protection == SYNC_ARRAY_OS_MUTEX) { if (protection == SYNC_ARRAY_OS_MUTEX) {
arr->os_mutex = os_mutex_create(NULL); arr->os_mutex = os_mutex_create(NULL);
} else if (protection == SYNC_ARRAY_MUTEX) { } else if (protection == SYNC_ARRAY_MUTEX) {
mutex_create(&(arr->mutex)); mutex_create(&arr->mutex, SYNC_NO_ORDER_CHECK);
mutex_set_level(&(arr->mutex), SYNC_NO_ORDER_CHECK);
} else { } else {
ut_error; ut_error;
} }

View File

@@ -89,19 +89,19 @@ void
rw_lock_create_func( rw_lock_create_func(
/*================*/ /*================*/
rw_lock_t* lock, /* in: pointer to memory */ rw_lock_t* lock, /* in: pointer to memory */
ulint level, /* in: level */
const char* cfile_name, /* in: file name where created */ const char* cfile_name, /* in: file name where created */
ulint cline, /* in: file line where created */ ulint cline, /* in: file line where created */
const char* cmutex_name) /* in: mutex name */ const char* cmutex_name) /* in: mutex name */
{ {
/* If this is the very first time a synchronization /* If this is the very first time a synchronization object is
object is created, then the following call initializes created, then the following call initializes the sync system. */
the sync system. */
mutex_create(rw_lock_get_mutex(lock)); mutex_create(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK);
mutex_set_level(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK);
lock->mutex.cfile_name = cfile_name; lock->mutex.cfile_name = cfile_name;
lock->mutex.cline = cline; lock->mutex.cline = cline;
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
lock->mutex.cmutex_name = cmutex_name; lock->mutex.cmutex_name = cmutex_name;
lock->mutex.mutex_type = 1; lock->mutex.mutex_type = 1;
@@ -116,9 +116,10 @@ rw_lock_create_func(
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
UT_LIST_INIT(lock->debug_list); UT_LIST_INIT(lock->debug_list);
lock->level = SYNC_LEVEL_NONE;
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
lock->level = level;
lock->magic_n = RW_LOCK_MAGIC_N; lock->magic_n = RW_LOCK_MAGIC_N;
lock->cfile_name = cfile_name; lock->cfile_name = cfile_name;
@@ -669,18 +670,6 @@ rw_lock_remove_debug_info(
} }
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
/**********************************************************************
Sets the rw-lock latching level field. */
void
rw_lock_set_level(
/*==============*/
rw_lock_t* lock, /* in: rw-lock */
ulint level) /* in: level */
{
lock->level = level;
}
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
/********************************************************************** /**********************************************************************
Checks if the thread has locked the rw-lock in the specified mode, with Checks if the thread has locked the rw-lock in the specified mode, with

View File

@@ -202,6 +202,7 @@ void
mutex_create_func( mutex_create_func(
/*==============*/ /*==============*/
mutex_t* mutex, /* in: pointer to memory */ mutex_t* mutex, /* in: pointer to memory */
ulint level, /* in: level */
const char* cfile_name, /* in: file name where created */ const char* cfile_name, /* in: file name where created */
ulint cline, /* in: file line where created */ ulint cline, /* in: file line where created */
const char* cmutex_name) /* in: mutex name */ const char* cmutex_name) /* in: mutex name */
@@ -218,7 +219,7 @@ mutex_create_func(
mutex->line = 0; mutex->line = 0;
mutex->file_name = "not yet reserved"; mutex->file_name = "not yet reserved";
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
mutex->level = SYNC_LEVEL_NONE; mutex->level = level;
mutex->cfile_name = cfile_name; mutex->cfile_name = cfile_name;
mutex->cline = cline; mutex->cline = cline;
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
@@ -598,19 +599,6 @@ mutex_get_debug_info(
} }
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
/**********************************************************************
Sets the mutex latching level field. */
void
mutex_set_level(
/*============*/
mutex_t* mutex, /* in: mutex */
ulint level) /* in: level */
{
mutex->level = level;
}
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
/********************************************************************** /**********************************************************************
Checks that the current thread owns the mutex. Works only in the debug Checks that the current thread owns the mutex. Works only in the debug
@@ -979,8 +967,8 @@ void
sync_thread_add_level( sync_thread_add_level(
/*==================*/ /*==================*/
void* latch, /* in: pointer to a mutex or an rw-lock */ void* latch, /* in: pointer to a mutex or an rw-lock */
ulint level) /* in: level in the latching order; if SYNC_LEVEL_NONE, ulint level) /* in: level in the latching order; if
nothing is done */ SYNC_LEVEL_VARYING, nothing is done */
{ {
sync_level_t* array; sync_level_t* array;
sync_level_t* slot; sync_level_t* slot;
@@ -1002,7 +990,7 @@ sync_thread_add_level(
return; return;
} }
if (level == SYNC_LEVEL_NONE) { if (level == SYNC_LEVEL_VARYING) {
return; return;
} }
@@ -1050,6 +1038,9 @@ sync_thread_add_level(
case SYNC_RECV: case SYNC_RECV:
ut_a(sync_thread_levels_g(array, SYNC_RECV)); ut_a(sync_thread_levels_g(array, SYNC_RECV));
break; break;
case SYNC_WORK_QUEUE:
ut_a(sync_thread_levels_g(array, SYNC_WORK_QUEUE));
break;
case SYNC_LOG: case SYNC_LOG:
ut_a(sync_thread_levels_g(array, SYNC_LOG)); ut_a(sync_thread_levels_g(array, SYNC_LOG));
break; break;
@@ -1290,21 +1281,17 @@ sync_init(void)
/* Init the mutex list and create the mutex to protect it. */ /* Init the mutex list and create the mutex to protect it. */
UT_LIST_INIT(mutex_list); UT_LIST_INIT(mutex_list);
mutex_create(&mutex_list_mutex); mutex_create(&mutex_list_mutex, SYNC_NO_ORDER_CHECK);
mutex_set_level(&mutex_list_mutex, SYNC_NO_ORDER_CHECK);
mutex_create(&sync_thread_mutex); mutex_create(&sync_thread_mutex, SYNC_NO_ORDER_CHECK);
mutex_set_level(&sync_thread_mutex, SYNC_NO_ORDER_CHECK);
/* Init the rw-lock list and create the mutex to protect it. */ /* Init the rw-lock list and create the mutex to protect it. */
UT_LIST_INIT(rw_lock_list); UT_LIST_INIT(rw_lock_list);
mutex_create(&rw_lock_list_mutex); mutex_create(&rw_lock_list_mutex, SYNC_NO_ORDER_CHECK);
mutex_set_level(&rw_lock_list_mutex, SYNC_NO_ORDER_CHECK);
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
mutex_create(&rw_lock_debug_mutex); mutex_create(&rw_lock_debug_mutex, SYNC_NO_ORDER_CHECK);
mutex_set_level(&rw_lock_debug_mutex, SYNC_NO_ORDER_CHECK);
rw_lock_debug_event = os_event_create(NULL); rw_lock_debug_event = os_event_create(NULL);
rw_lock_debug_waiters = FALSE; rw_lock_debug_waiters = FALSE;

View File

@@ -226,6 +226,5 @@ thr_local_init(void)
thr_local_hash = hash_create(OS_THREAD_MAX_N + 100); thr_local_hash = hash_create(OS_THREAD_MAX_N + 100);
mutex_create(&thr_local_mutex); mutex_create(&thr_local_mutex, SYNC_THR_LOCAL);
mutex_set_level(&thr_local_mutex, SYNC_THR_LOCAL);
} }

View File

@@ -211,11 +211,9 @@ trx_purge_sys_create(void)
purge_sys->purge_undo_no = ut_dulint_zero; purge_sys->purge_undo_no = ut_dulint_zero;
purge_sys->next_stored = FALSE; purge_sys->next_stored = FALSE;
rw_lock_create(&(purge_sys->latch)); rw_lock_create(&purge_sys->latch, SYNC_PURGE_LATCH);
rw_lock_set_level(&(purge_sys->latch), SYNC_PURGE_LATCH);
mutex_create(&(purge_sys->mutex)); mutex_create(&purge_sys->mutex, SYNC_PURGE_SYS);
mutex_set_level(&(purge_sys->mutex), SYNC_PURGE_SYS);
purge_sys->heap = mem_heap_create(256); purge_sys->heap = mem_heap_create(256);

View File

@@ -843,7 +843,7 @@ trx_undo_update_rec_get_update(
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n" "InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n"
"InnoDB: Run also CHECK TABLE ", "InnoDB: Run also CHECK TABLE ",
(ulong) dict_index_get_n_fields(index)); (ulong) dict_index_get_n_fields(index));
ut_print_name(stderr, trx, index->table_name); ut_print_name(stderr, trx, TRUE, index->table_name);
fprintf(stderr, "\n" fprintf(stderr, "\n"
"InnoDB: n_fields = %lu, i = %lu, ptr %p\n", "InnoDB: n_fields = %lu, i = %lu, ptr %p\n",
(ulong) n_fields, (ulong) i, ptr); (ulong) n_fields, (ulong) i, ptr);

View File

@@ -241,7 +241,7 @@ trx_rollback_to_savepoint_for_mysql(
if (trx->conc_state == TRX_NOT_STARTED) { if (trx->conc_state == TRX_NOT_STARTED) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: transaction has a savepoint ", stderr); fputs(" InnoDB: Error: transaction has a savepoint ", stderr);
ut_print_name(stderr, trx, savep->name); ut_print_name(stderr, trx, FALSE, savep->name);
fputs(" though it is not started\n", stderr); fputs(" though it is not started\n", stderr);
return(DB_ERROR); return(DB_ERROR);
} }
@@ -540,11 +540,11 @@ loop:
(ulong) ut_dulint_get_high(trx->table_id), (ulong) ut_dulint_get_high(trx->table_id),
(ulong) ut_dulint_get_low(trx->table_id)); (ulong) ut_dulint_get_low(trx->table_id));
table = dict_table_get_on_id_low(trx->table_id, trx); table = dict_table_get_on_id_low(trx->table_id);
if (table) { if (table) {
fputs("InnoDB: Table found: dropping table ", stderr); fputs("InnoDB: Table found: dropping table ", stderr);
ut_print_name(stderr, trx, table->name); ut_print_name(stderr, trx, TRUE, table->name);
fputs(" in recovery\n", stderr); fputs(" in recovery\n", stderr);
err = row_drop_table_for_mysql(table->name, trx, TRUE); err = row_drop_table_for_mysql(table->name, trx, TRUE);

View File

@@ -147,8 +147,7 @@ trx_rseg_mem_create(
rseg->space = space; rseg->space = space;
rseg->page_no = page_no; rseg->page_no = page_no;
mutex_create(&(rseg->mutex)); mutex_create(&rseg->mutex, SYNC_RSEG);
mutex_set_level(&(rseg->mutex), SYNC_RSEG);
UT_LIST_ADD_LAST(rseg_list, trx_sys->rseg_list, rseg); UT_LIST_ADD_LAST(rseg_list, trx_sys->rseg_list, rseg);

View File

@@ -101,8 +101,7 @@ trx_doublewrite_init(
os_do_not_call_flush_at_each_write = TRUE; os_do_not_call_flush_at_each_write = TRUE;
#endif /* UNIV_DO_FLUSH */ #endif /* UNIV_DO_FLUSH */
mutex_create(&(trx_doublewrite->mutex)); mutex_create(&trx_doublewrite->mutex, SYNC_DOUBLEWRITE);
mutex_set_level(&(trx_doublewrite->mutex), SYNC_DOUBLEWRITE);
trx_doublewrite->first_free = 0; trx_doublewrite->first_free = 0;

View File

@@ -144,8 +144,7 @@ trx_create(
trx->repl_wait_binlog_name = NULL; trx->repl_wait_binlog_name = NULL;
trx->repl_wait_binlog_pos = 0; trx->repl_wait_binlog_pos = 0;
mutex_create(&(trx->undo_mutex)); mutex_create(&trx->undo_mutex, SYNC_TRX_UNDO);
mutex_set_level(&(trx->undo_mutex), SYNC_TRX_UNDO);
trx->rseg = NULL; trx->rseg = NULL;

View File

@@ -19,6 +19,6 @@ include ../include/Makefile.i
noinst_LIBRARIES = libut.a noinst_LIBRARIES = libut.a
libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c ut0vec.c libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c ut0vec.c ut0list.c ut0wqueue.c
EXTRA_PROGRAMS = EXTRA_PROGRAMS =

View File

@@ -14,19 +14,21 @@ Created 1/30/1994 Heikki Tuuri
ulint ut_dbg_zero = 0; ulint ut_dbg_zero = 0;
#endif #endif
#if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
/* If this is set to TRUE all threads will stop into the next assertion /* If this is set to TRUE all threads will stop into the next assertion
and assert */ and assert */
ibool ut_dbg_stop_threads = FALSE; ibool ut_dbg_stop_threads = FALSE;
#endif
#ifdef __NETWARE__ #ifdef __NETWARE__
ibool panic_shutdown = FALSE; /* This is set to TRUE when on NetWare there ibool panic_shutdown = FALSE; /* This is set to TRUE when on NetWare there
happens an InnoDB assertion failure or other happens an InnoDB assertion failure or other
fatal error condition that requires an fatal error condition that requires an
immediate shutdown. */ immediate shutdown. */
#else /* __NETWARE__ */ #elif !defined(UT_DBG_USE_ABORT)
/* Null pointer used to generate memory trap */ /* Null pointer used to generate memory trap */
ulint* ut_dbg_null_ptr = NULL; ulint* ut_dbg_null_ptr = NULL;
#endif /* __NETWARE__ */ #endif
/***************************************************************** /*****************************************************************
Report a failed assertion. */ Report a failed assertion. */
@@ -56,7 +58,9 @@ ut_dbg_assertion_failed(
"InnoDB: corruption in the InnoDB tablespace. Please refer to\n" "InnoDB: corruption in the InnoDB tablespace. Please refer to\n"
"InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n" "InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n"
"InnoDB: about forcing recovery.\n", stderr); "InnoDB: about forcing recovery.\n", stderr);
#if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
ut_dbg_stop_threads = TRUE; ut_dbg_stop_threads = TRUE;
#endif
} }
#ifdef __NETWARE__ #ifdef __NETWARE__
@@ -74,6 +78,7 @@ ut_dbg_panic(void)
exit(1); exit(1);
} }
#else /* __NETWARE__ */ #else /* __NETWARE__ */
# if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
/***************************************************************** /*****************************************************************
Stop a thread after assertion failure. */ Stop a thread after assertion failure. */
@@ -87,4 +92,5 @@ ut_dbg_stop_thread(
os_thread_pf(os_thread_get_curr_id()), file, line); os_thread_pf(os_thread_get_curr_id()), file, line);
os_thread_sleep(1000000000); os_thread_sleep(1000000000);
} }
# endif
#endif /* __NETWARE__ */ #endif /* __NETWARE__ */

View File

@@ -0,0 +1,169 @@
#include "ut0list.h"
#ifdef UNIV_NONINL
#include "ut0list.ic"
#endif
/********************************************************************
Create a new list. */
ib_list_t*
ib_list_create(void)
/*=================*/
/* out: list */
{
ib_list_t* list = mem_alloc(sizeof(ib_list_t));
list->first = NULL;
list->last = NULL;
list->is_heap_list = FALSE;
return(list);
}
/********************************************************************
Create a new list using the given heap. ib_list_free MUST NOT BE CALLED for
lists created with this function. */
ib_list_t*
ib_list_create_heap(
/*================*/
/* out: list */
mem_heap_t* heap) /* in: memory heap to use */
{
ib_list_t* list = mem_heap_alloc(heap, sizeof(ib_list_t));
list->first = NULL;
list->last = NULL;
list->is_heap_list = TRUE;
return(list);
}
/********************************************************************
Free a list. */
void
ib_list_free(
/*=========*/
ib_list_t* list) /* in: list */
{
ut_a(!list->is_heap_list);
/* We don't check that the list is empty because it's entirely valid
to e.g. have all the nodes allocated from a single heap that is then
freed after the list itself is freed. */
mem_free(list);
}
/********************************************************************
Add the data to the start of the list. */
ib_list_node_t*
ib_list_add_first(
/*==============*/
/* out: new list node*/
ib_list_t* list, /* in: list */
void* data, /* in: data */
mem_heap_t* heap) /* in: memory heap to use */
{
return(ib_list_add_after(list, ib_list_get_first(list), data, heap));
}
/********************************************************************
Add the data to the end of the list. */
ib_list_node_t*
ib_list_add_last(
/*=============*/
/* out: new list node*/
ib_list_t* list, /* in: list */
void* data, /* in: data */
mem_heap_t* heap) /* in: memory heap to use */
{
return(ib_list_add_after(list, ib_list_get_last(list), data, heap));
}
/********************************************************************
Add the data after the indicated node. */
ib_list_node_t*
ib_list_add_after(
/*==============*/
/* out: new list node*/
ib_list_t* list, /* in: list */
ib_list_node_t* prev_node, /* in: node preceding new node (can
be NULL) */
void* data, /* in: data */
mem_heap_t* heap) /* in: memory heap to use */
{
ib_list_node_t* node = mem_heap_alloc(heap, sizeof(ib_list_node_t));
node->data = data;
if (!list->first) {
/* Empty list. */
ut_a(!prev_node);
node->prev = NULL;
node->next = NULL;
list->first = node;
list->last = node;
} else if (!prev_node) {
/* Start of list. */
node->prev = NULL;
node->next = list->first;
list->first->prev = node;
list->first = node;
} else {
/* Middle or end of list. */
node->prev = prev_node;
node->next = prev_node->next;
prev_node->next = node;
if (node->next) {
node->next->prev = node;
} else {
list->last = node;
}
}
return(node);
}
/********************************************************************
Remove the node from the list. */
void
ib_list_remove(
/*===========*/
ib_list_t* list, /* in: list */
ib_list_node_t* node) /* in: node to remove */
{
if (node->prev) {
node->prev->next = node->next;
} else {
/* First item in list. */
ut_ad(list->first == node);
list->first = node->next;
}
if (node->next) {
node->next->prev = node->prev;
} else {
/* Last item in list. */
ut_ad(list->last == node);
list->last = node->prev;
}
}

View File

@@ -20,18 +20,20 @@ Created 5/11/1994 Heikki Tuuri
ibool ut_always_false = FALSE; ibool ut_always_false = FALSE;
#ifndef UNIV_HOTBACKUP
/********************************************************************* /*********************************************************************
Get the quote character to be used in SQL identifiers. Display an SQL identifier.
This definition must match the one in sql/ha_innodb.cc! */ This definition must match the one in sql/ha_innodb.cc! */
extern extern
int void
mysql_get_identifier_quote_char( innobase_print_identifier(
/*============================*/ /*======================*/
/* out: quote character to be FILE* f, /* in: output stream */
used in SQL identifiers; EOF if none */
trx_t* trx, /* in: transaction */ trx_t* trx, /* in: transaction */
ibool table_id,/* in: TRUE=decode table name */
const char* name, /* in: name to print */ const char* name, /* in: name to print */
ulint namelen);/* in: length of name */ ulint namelen);/* in: length of name */
#endif /* !UNIV_HOTBACKUP */
/************************************************************ /************************************************************
Gets the high 32 bits in a ulint. That is makes a shift >> 32, Gets the high 32 bits in a ulint. That is makes a shift >> 32,
@@ -398,9 +400,10 @@ ut_print_name(
/*==========*/ /*==========*/
FILE* f, /* in: output stream */ FILE* f, /* in: output stream */
trx_t* trx, /* in: transaction */ trx_t* trx, /* in: transaction */
ibool table_id,/* in: TRUE=decode table name */
const char* name) /* in: name to print */ const char* name) /* in: name to print */
{ {
ut_print_namel(f, trx, name, strlen(name)); ut_print_namel(f, trx, table_id, name, strlen(name));
} }
/************************************************************************** /**************************************************************************
@@ -411,29 +414,27 @@ ut_print_namel(
/*===========*/ /*===========*/
FILE* f, /* in: output stream */ FILE* f, /* in: output stream */
trx_t* trx, /* in: transaction (NULL=no quotes) */ trx_t* trx, /* in: transaction (NULL=no quotes) */
ibool table_id,/* in: TRUE=decode table name */
const char* name, /* in: name to print */ const char* name, /* in: name to print */
ulint namelen)/* in: length of name */ ulint namelen)/* in: length of name */
{ {
const char* s = name;
const char* e = s + namelen;
#ifdef UNIV_HOTBACKUP #ifdef UNIV_HOTBACKUP
int q = '"'; fwrite(name, 1, namelen, f);
#else #else
int q = mysql_get_identifier_quote_char(trx, name, namelen); char* slash = strchr(name, '/');
if (UNIV_LIKELY_NULL(slash)) {
/* Print the database name and table name separately. */
ut_ad(table_id);
innobase_print_identifier(f, trx, TRUE, name, slash - name);
putc('.', f);
innobase_print_identifier(f, trx, TRUE, slash + 1,
namelen - (slash - name) - 1);
} else {
innobase_print_identifier(f, trx, table_id, name, namelen);
}
#endif #endif
if (q == EOF) {
fwrite(name, 1, namelen, f);
return;
}
putc(q, f);
while (s < e) {
int c = *s++;
if (c == q) {
putc(c, f);
}
putc(c, f);
}
putc(q, f);
} }
/************************************************************************** /**************************************************************************

View File

@@ -0,0 +1,92 @@
#include "ut0wqueue.h"
/********************************************************************
Create a new work queue. */
ib_wqueue_t*
ib_wqueue_create(void)
/*===================*/
/* out: work queue */
{
ib_wqueue_t* wq = mem_alloc(sizeof(ib_wqueue_t));
mutex_create(&wq->mutex, SYNC_WORK_QUEUE);
wq->items = ib_list_create();
wq->event = os_event_create(NULL);
return(wq);
}
/********************************************************************
Free a work queue. */
void
ib_wqueue_free(
/*===========*/
ib_wqueue_t* wq) /* in: work queue */
{
ut_a(!ib_list_get_first(wq->items));
mutex_free(&wq->mutex);
ib_list_free(wq->items);
os_event_free(wq->event);
mem_free(wq);
}
/********************************************************************
Add a work item to the queue. */
void
ib_wqueue_add(
/*==========*/
ib_wqueue_t* wq, /* in: work queue */
void* item, /* in: work item */
mem_heap_t* heap) /* in: memory heap to use for allocating the
list node */
{
mutex_enter(&wq->mutex);
ib_list_add_last(wq->items, item, heap);
os_event_set(wq->event);
mutex_exit(&wq->mutex);
}
/********************************************************************
Wait for a work item to appear in the queue. */
void*
ib_wqueue_wait(
/* out: work item */
ib_wqueue_t* wq) /* in: work queue */
{
ib_list_node_t* node;
for (;;) {
os_event_wait(wq->event);
mutex_enter(&wq->mutex);
node = ib_list_get_first(wq->items);
if (node) {
ib_list_remove(wq->items, node);
if (!ib_list_get_first(wq->items)) {
/* We must reset the event when the list
gets emptied. */
os_event_reset(wq->event);
}
break;
}
mutex_exit(&wq->mutex);
}
mutex_exit(&wq->mutex);
return(node->data);
}