mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
Merge tag 'mariadb-5.5.45' into 5.5-galera
This commit is contained in:
2
VERSION
2
VERSION
@@ -1,4 +1,4 @@
|
|||||||
MYSQL_VERSION_MAJOR=5
|
MYSQL_VERSION_MAJOR=5
|
||||||
MYSQL_VERSION_MINOR=5
|
MYSQL_VERSION_MINOR=5
|
||||||
MYSQL_VERSION_PATCH=44
|
MYSQL_VERSION_PATCH=45
|
||||||
MYSQL_VERSION_EXTRA=
|
MYSQL_VERSION_EXTRA=
|
||||||
|
@@ -1066,7 +1066,7 @@ int main(int argc, char **argv)
|
|||||||
printf("This installation of MySQL is already upgraded to %s, "
|
printf("This installation of MySQL is already upgraded to %s, "
|
||||||
"use --force if you still need to run mysql_upgrade\n",
|
"use --force if you still need to run mysql_upgrade\n",
|
||||||
MYSQL_SERVER_VERSION);
|
MYSQL_SERVER_VERSION);
|
||||||
die(NULL);
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_version_check && check_version_match())
|
if (opt_version_check && check_version_match())
|
||||||
@@ -1089,6 +1089,7 @@ int main(int argc, char **argv)
|
|||||||
/* Create a file indicating upgrade has been performed */
|
/* Create a file indicating upgrade has been performed */
|
||||||
create_mysql_upgrade_info_file();
|
create_mysql_upgrade_info_file();
|
||||||
|
|
||||||
|
end:
|
||||||
free_used_memory();
|
free_used_memory();
|
||||||
my_end(my_end_arg);
|
my_end(my_end_arg);
|
||||||
exit(0);
|
exit(0);
|
||||||
|
@@ -66,6 +66,7 @@ ulong server_id = 0;
|
|||||||
ulong bytes_sent = 0L, bytes_received = 0L;
|
ulong bytes_sent = 0L, bytes_received = 0L;
|
||||||
ulong mysqld_net_retry_count = 10L;
|
ulong mysqld_net_retry_count = 10L;
|
||||||
ulong open_files_limit;
|
ulong open_files_limit;
|
||||||
|
ulong opt_binlog_rows_event_max_size;
|
||||||
uint test_flags = 0;
|
uint test_flags = 0;
|
||||||
static uint opt_protocol= 0;
|
static uint opt_protocol= 0;
|
||||||
static FILE *result_file;
|
static FILE *result_file;
|
||||||
@@ -1432,6 +1433,12 @@ that may lead to an endless loop.",
|
|||||||
"Used to reserve file descriptors for use by this program.",
|
"Used to reserve file descriptors for use by this program.",
|
||||||
&open_files_limit, &open_files_limit, 0, GET_ULONG,
|
&open_files_limit, &open_files_limit, 0, GET_ULONG,
|
||||||
REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
|
REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
|
||||||
|
{"binlog-row-event-max-size", 0,
|
||||||
|
"The maximum size of a row-based binary log event in bytes. Rows will be "
|
||||||
|
"grouped into events smaller than this size if possible. "
|
||||||
|
"This value must be a multiple of 256.",
|
||||||
|
&opt_binlog_rows_event_max_size, &opt_binlog_rows_event_max_size, 0,
|
||||||
|
GET_ULONG, REQUIRED_ARG, UINT_MAX, 256, ULONG_MAX, 0, 256, 0},
|
||||||
{"verify-binlog-checksum", 'c', "Verify checksum binlog events.",
|
{"verify-binlog-checksum", 'c', "Verify checksum binlog events.",
|
||||||
(uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum,
|
(uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum,
|
||||||
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2005, 2012, Oracle and/or its affiliates.
|
Copyright (c) 2005, 2015, Oracle and/or its affiliates.
|
||||||
|
Copyright (c) 2010, 2015, MariaDB
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -244,7 +245,7 @@ void print_conclusions_csv(conclusions *con);
|
|||||||
void generate_stats(conclusions *con, option_string *eng, stats *sptr);
|
void generate_stats(conclusions *con, option_string *eng, stats *sptr);
|
||||||
uint parse_comma(const char *string, uint **range);
|
uint parse_comma(const char *string, uint **range);
|
||||||
uint parse_delimiter(const char *script, statement **stmt, char delm);
|
uint parse_delimiter(const char *script, statement **stmt, char delm);
|
||||||
uint parse_option(const char *origin, option_string **stmt, char delm);
|
int parse_option(const char *origin, option_string **stmt, char delm);
|
||||||
static int drop_schema(MYSQL *mysql, const char *db);
|
static int drop_schema(MYSQL *mysql, const char *db);
|
||||||
uint get_random_string(char *buf);
|
uint get_random_string(char *buf);
|
||||||
static statement *build_table_string(void);
|
static statement *build_table_string(void);
|
||||||
@@ -1259,7 +1260,13 @@ get_options(int *argc,char ***argv)
|
|||||||
if (num_int_cols_opt)
|
if (num_int_cols_opt)
|
||||||
{
|
{
|
||||||
option_string *str;
|
option_string *str;
|
||||||
parse_option(num_int_cols_opt, &str, ',');
|
if(parse_option(num_int_cols_opt, &str, ',') == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Invalid value specified for the option "
|
||||||
|
"'number-int-cols'\n");
|
||||||
|
option_cleanup(str);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
num_int_cols= atoi(str->string);
|
num_int_cols= atoi(str->string);
|
||||||
if (str->option)
|
if (str->option)
|
||||||
num_int_cols_index= atoi(str->option);
|
num_int_cols_index= atoi(str->option);
|
||||||
@@ -1270,7 +1277,13 @@ get_options(int *argc,char ***argv)
|
|||||||
if (num_char_cols_opt)
|
if (num_char_cols_opt)
|
||||||
{
|
{
|
||||||
option_string *str;
|
option_string *str;
|
||||||
parse_option(num_char_cols_opt, &str, ',');
|
if(parse_option(num_char_cols_opt, &str, ',') == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Invalid value specified for the option "
|
||||||
|
"'number-char-cols'\n");
|
||||||
|
option_cleanup(str);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
num_char_cols= atoi(str->string);
|
num_char_cols= atoi(str->string);
|
||||||
if (str->option)
|
if (str->option)
|
||||||
num_char_cols_index= atoi(str->option);
|
num_char_cols_index= atoi(str->option);
|
||||||
@@ -1507,7 +1520,13 @@ get_options(int *argc,char ***argv)
|
|||||||
printf("Parsing engines to use.\n");
|
printf("Parsing engines to use.\n");
|
||||||
|
|
||||||
if (default_engine)
|
if (default_engine)
|
||||||
parse_option(default_engine, &engine_options, ',');
|
{
|
||||||
|
if(parse_option(default_engine, &engine_options, ',') == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Invalid value specified for the option 'engine'\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tty_password)
|
if (tty_password)
|
||||||
opt_password= get_tty_password(NullS);
|
opt_password= get_tty_password(NullS);
|
||||||
@@ -1984,7 +2003,7 @@ end:
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint
|
int
|
||||||
parse_option(const char *origin, option_string **stmt, char delm)
|
parse_option(const char *origin, option_string **stmt, char delm)
|
||||||
{
|
{
|
||||||
char *retstr;
|
char *retstr;
|
||||||
@@ -2009,6 +2028,13 @@ parse_option(const char *origin, option_string **stmt, char delm)
|
|||||||
char buffer[HUGE_STRING_LENGTH]= "";
|
char buffer[HUGE_STRING_LENGTH]= "";
|
||||||
char *buffer_ptr;
|
char *buffer_ptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Return an error if the length of the any of the comma seprated value
|
||||||
|
exceeds HUGE_STRING_LENGTH.
|
||||||
|
*/
|
||||||
|
if ((size_t)(retstr - ptr) > HUGE_STRING_LENGTH)
|
||||||
|
return -1;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
strncpy(buffer, ptr, (size_t)(retstr - ptr));
|
strncpy(buffer, ptr, (size_t)(retstr - ptr));
|
||||||
/*
|
/*
|
||||||
@@ -2048,6 +2074,13 @@ parse_option(const char *origin, option_string **stmt, char delm)
|
|||||||
{
|
{
|
||||||
char *origin_ptr;
|
char *origin_ptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Return an error if the length of the any of the comma seprated value
|
||||||
|
exceeds HUGE_STRING_LENGTH.
|
||||||
|
*/
|
||||||
|
if (strlen(ptr) > HUGE_STRING_LENGTH)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if ((origin_ptr= strchr(ptr, ':')))
|
if ((origin_ptr= strchr(ptr, ':')))
|
||||||
{
|
{
|
||||||
char *option_ptr;
|
char *option_ptr;
|
||||||
@@ -2058,13 +2091,13 @@ parse_option(const char *origin, option_string **stmt, char delm)
|
|||||||
option_ptr= (char *)ptr + 1 + tmp->length;
|
option_ptr= (char *)ptr + 1 + tmp->length;
|
||||||
|
|
||||||
/* Move past the : and the first string */
|
/* Move past the : and the first string */
|
||||||
tmp->option_length= (size_t)((ptr + length) - option_ptr);
|
tmp->option_length= strlen(option_ptr);
|
||||||
tmp->option= my_strndup(option_ptr, tmp->option_length,
|
tmp->option= my_strndup(option_ptr, tmp->option_length,
|
||||||
MYF(MY_FAE));
|
MYF(MY_FAE));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tmp->length= (size_t)((ptr + length) - ptr);
|
tmp->length= strlen(ptr);
|
||||||
tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE));
|
tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -228,7 +228,7 @@ rollback;
|
|||||||
create table t0 (n int);
|
create table t0 (n int);
|
||||||
insert t0 select * from t1;
|
insert t0 select * from t1;
|
||||||
set autocommit=1;
|
set autocommit=1;
|
||||||
insert into t0 select GET_LOCK("lock1",null);
|
insert into t0 select GET_LOCK("lock1",0);
|
||||||
set autocommit=0;
|
set autocommit=0;
|
||||||
create table t2 (n int) engine=innodb;
|
create table t2 (n int) engine=innodb;
|
||||||
insert into t2 values (3);
|
insert into t2 values (3);
|
||||||
|
@@ -4810,6 +4810,7 @@ sub extract_warning_lines ($$) {
|
|||||||
qr|Plugin 'FEEDBACK' registration as a INFORMATION SCHEMA failed|,
|
qr|Plugin 'FEEDBACK' registration as a INFORMATION SCHEMA failed|,
|
||||||
qr|Failed to setup SSL|,
|
qr|Failed to setup SSL|,
|
||||||
qr|SSL error: Failed to set ciphers to use|,
|
qr|SSL error: Failed to set ciphers to use|,
|
||||||
|
qr/Plugin 'InnoDB' will be forced to shutdown/,
|
||||||
);
|
);
|
||||||
|
|
||||||
my $matched_lines= [];
|
my $matched_lines= [];
|
||||||
|
@@ -1103,3 +1103,19 @@ ORDER BY field;
|
|||||||
field
|
field
|
||||||
c,c
|
c,c
|
||||||
drop table t3, t2, t1;
|
drop table t3, t2, t1;
|
||||||
|
#
|
||||||
|
# MDEV-7821 - Server crashes in Item_func_group_concat::fix_fields on 2nd
|
||||||
|
# execution of PS
|
||||||
|
#
|
||||||
|
CREATE TABLE t1(a INT);
|
||||||
|
INSERT INTO t1 VALUES(1),(2);
|
||||||
|
PREPARE stmt FROM "SELECT GROUP_CONCAT(t1a.a ORDER BY 1, t1a.a=0) FROM t1 AS t1a, t1 AS t1b GROUP BY t1a.a";
|
||||||
|
EXECUTE stmt;
|
||||||
|
GROUP_CONCAT(t1a.a ORDER BY 1, t1a.a=0)
|
||||||
|
1,1
|
||||||
|
2,2
|
||||||
|
EXECUTE stmt;
|
||||||
|
GROUP_CONCAT(t1a.a ORDER BY 1, t1a.a=0)
|
||||||
|
1,1
|
||||||
|
2,2
|
||||||
|
DROP TABLE t1;
|
||||||
|
@@ -361,5 +361,18 @@ set optimizer_switch=@optimizer_switch_save;
|
|||||||
drop view v_merge, vm;
|
drop view v_merge, vm;
|
||||||
drop table t1,tv;
|
drop table t1,tv;
|
||||||
#
|
#
|
||||||
|
# MDEV-4017 - GET_LOCK() with negative timeouts has strange behavior
|
||||||
|
#
|
||||||
|
SELECT GET_LOCK('ul1', NULL);
|
||||||
|
GET_LOCK('ul1', NULL)
|
||||||
|
NULL
|
||||||
|
Warnings:
|
||||||
|
Warning 1411 Incorrect timeout value: 'NULL' for function get_lock
|
||||||
|
SELECT GET_LOCK('ul1', -1);
|
||||||
|
GET_LOCK('ul1', -1)
|
||||||
|
NULL
|
||||||
|
Warnings:
|
||||||
|
Warning 1411 Incorrect timeout value: '-1' for function get_lock
|
||||||
|
#
|
||||||
# End of 5.5 tests
|
# End of 5.5 tests
|
||||||
#
|
#
|
||||||
|
@@ -18,3 +18,5 @@ mysqld-bin.000001 # Query # # use `test`; insert t1 values (2)
|
|||||||
mysqld-bin.000001 # Query # # COMMIT
|
mysqld-bin.000001 # Query # # COMMIT
|
||||||
drop table t1;
|
drop table t1;
|
||||||
uninstall plugin innodb;
|
uninstall plugin innodb;
|
||||||
|
Warnings:
|
||||||
|
Warning 1620 Plugin is busy and will be uninstalled on shutdown
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
#
|
#
|
||||||
# Test of MyISAM MRG tables with corrupted children.
|
# Tests for corrupted MyISAM tables and MyISAMMRG tables with corrupted
|
||||||
|
# children..
|
||||||
|
#
|
||||||
# Run with --myisam-recover=force option.
|
# Run with --myisam-recover=force option.
|
||||||
#
|
#
|
||||||
# Preparation: we need to make sure that the merge parent
|
# Preparation: we need to make sure that the merge parent
|
||||||
@@ -101,3 +103,48 @@ execute stmt;
|
|||||||
deallocate prepare stmt;
|
deallocate prepare stmt;
|
||||||
set @@global.table_definition_cache=default;
|
set @@global.table_definition_cache=default;
|
||||||
set @@global.table_open_cache=default;
|
set @@global.table_open_cache=default;
|
||||||
|
#
|
||||||
|
# 18075170 - sql node restart required to avoid deadlock after
|
||||||
|
# restore
|
||||||
|
#
|
||||||
|
# Check that auto-repair for MyISAM tables can now happen in the
|
||||||
|
# middle of transaction, without aborting it.
|
||||||
|
create table t1 (a int, key(a)) engine=myisam;
|
||||||
|
create table t2 (a int);
|
||||||
|
insert into t2 values (1);
|
||||||
|
# Create a table with a corrupted index file:
|
||||||
|
# save an old index file, insert more rows,
|
||||||
|
# overwrite the new index file with the old one.
|
||||||
|
insert into t1 (a) values (1);
|
||||||
|
flush table t1;
|
||||||
|
insert into t1 (a) values (4);
|
||||||
|
flush table t1;
|
||||||
|
# Check table is needed to mark the table as crashed.
|
||||||
|
check table t1;
|
||||||
|
Table Op Msg_type Msg_text
|
||||||
|
test.t1 check warning Size of datafile is: 14 Should be: 7
|
||||||
|
test.t1 check error Record-count is not ok; is 2 Should be: 1
|
||||||
|
test.t1 check warning Found 2 key parts. Should be: 1
|
||||||
|
test.t1 check error Corrupt
|
||||||
|
# At this point we have a corrupt t1
|
||||||
|
set autocommit = 0;
|
||||||
|
select * from t2;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
# Without fix select from t1 will break the transaction. After the fix
|
||||||
|
# transaction should be active and should hold lock on table t2. Alter
|
||||||
|
# table from con2 will wait only if the transaction is not broken.
|
||||||
|
select * from t1;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
4
|
||||||
|
Warnings:
|
||||||
|
Error 145 Table 't1' is marked as crashed and should be repaired
|
||||||
|
Error 1194 Table 't1' is marked as crashed and should be repaired
|
||||||
|
Error 1034 Number of rows changed from 1 to 2
|
||||||
|
ALTER TABLE t2 ADD val INT;
|
||||||
|
# With fix we should have alter table waiting for t2 lock here.
|
||||||
|
ROLLBACK;
|
||||||
|
SET autocommit = 1;
|
||||||
|
# Cleanup
|
||||||
|
drop table t1, t2;
|
156
mysql-test/r/sp-group.result
Normal file
156
mysql-test/r/sp-group.result
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
drop table if exists t1;
|
||||||
|
Warnings:
|
||||||
|
Note 1051 Unknown table 't1'
|
||||||
|
drop view if exists view_t1;
|
||||||
|
Warnings:
|
||||||
|
Note 1051 Unknown table 'test.view_t1'
|
||||||
|
SET sql_mode=ONLY_FULL_GROUP_BY;
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
pk INT,
|
||||||
|
f0 INT, f1 INT, f2 INT, f3 INT, f4 INT,
|
||||||
|
f5 INT, f6 INT, f7 INT, f8 INT, f9 INT,
|
||||||
|
PRIMARY KEY (pk)
|
||||||
|
);
|
||||||
|
CREATE VIEW view_t1 AS SELECT * FROM t1;
|
||||||
|
CREATE PROCEDURE s1()
|
||||||
|
SELECT * FROM (
|
||||||
|
INFORMATION_SCHEMA.`INNODB_BUFFER_PAGE_LRU` AS table1
|
||||||
|
LEFT JOIN test.view_t1 AS table2
|
||||||
|
ON ( table2.`f6` = table1.FREE_PAGE_CLOCK)
|
||||||
|
)
|
||||||
|
ORDER BY table1.NUMBER_RECORDS
|
||||||
|
LIMIT 0
|
||||||
|
;
|
||||||
|
CALL s1;
|
||||||
|
POOL_ID LRU_POSITION SPACE PAGE_NUMBER PAGE_TYPE FLUSH_TYPE FIX_COUNT IS_HASHED NEWEST_MODIFICATION OLDEST_MODIFICATION ACCESS_TIME TABLE_NAME INDEX_NAME NUMBER_RECORDS DATA_SIZE COMPRESSED_SIZE COMPRESSED IO_FIX IS_OLD FREE_PAGE_CLOCK pk f0 f1 f2 f3 f4 f5 f6 f7 f8 f9
|
||||||
|
CALL s1;
|
||||||
|
POOL_ID LRU_POSITION SPACE PAGE_NUMBER PAGE_TYPE FLUSH_TYPE FIX_COUNT IS_HASHED NEWEST_MODIFICATION OLDEST_MODIFICATION ACCESS_TIME TABLE_NAME INDEX_NAME NUMBER_RECORDS DATA_SIZE COMPRESSED_SIZE COMPRESSED IO_FIX IS_OLD FREE_PAGE_CLOCK pk f0 f1 f2 f3 f4 f5 f6 f7 f8 f9
|
||||||
|
drop table t1;
|
||||||
|
drop view view_t1;
|
||||||
|
drop procedure s1;
|
||||||
|
CREATE TABLE A (
|
||||||
|
pk INTEGER AUTO_INCREMENT,
|
||||||
|
col_int_key INTEGER,
|
||||||
|
col_varchar_key VARCHAR(1),
|
||||||
|
PRIMARY KEY (pk)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_A AS SELECT * FROM A;
|
||||||
|
CREATE TABLE C (
|
||||||
|
pk INTEGER AUTO_INCREMENT,
|
||||||
|
col_int_nokey INTEGER,
|
||||||
|
col_int_key INTEGER,
|
||||||
|
col_date_key DATE,
|
||||||
|
col_date_nokey DATE,
|
||||||
|
col_time_key TIME,
|
||||||
|
col_time_nokey TIME,
|
||||||
|
col_datetime_key DATETIME,
|
||||||
|
col_datetime_nokey DATETIME,
|
||||||
|
col_varchar_key VARCHAR(1),
|
||||||
|
col_varchar_nokey VARCHAR(1),
|
||||||
|
PRIMARY KEY (pk)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_C AS SELECT * FROM C;
|
||||||
|
CREATE TABLE AA (
|
||||||
|
pk INTEGER AUTO_INCREMENT,
|
||||||
|
col_int_nokey INTEGER,
|
||||||
|
col_int_key INTEGER,
|
||||||
|
col_date_key DATE,
|
||||||
|
col_date_nokey DATE,
|
||||||
|
col_time_key TIME,
|
||||||
|
col_time_nokey TIME,
|
||||||
|
col_datetime_key DATETIME,
|
||||||
|
col_datetime_nokey DATETIME,
|
||||||
|
col_varchar_key VARCHAR(1),
|
||||||
|
col_varchar_nokey VARCHAR(1),
|
||||||
|
PRIMARY KEY (pk),
|
||||||
|
KEY (col_varchar_key, col_int_key)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_AA AS SELECT * FROM AA;
|
||||||
|
CREATE TABLE BB (
|
||||||
|
pk INTEGER AUTO_INCREMENT,
|
||||||
|
col_int_key INTEGER,
|
||||||
|
col_varchar_key VARCHAR(1),
|
||||||
|
col_varchar_nokey VARCHAR(1),
|
||||||
|
PRIMARY KEY (pk),
|
||||||
|
KEY (col_varchar_key, col_int_key)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_BB AS SELECT * FROM BB;
|
||||||
|
CREATE TABLE DD (
|
||||||
|
pk INTEGER AUTO_INCREMENT,
|
||||||
|
col_int_key INTEGER,
|
||||||
|
col_date_key DATE,
|
||||||
|
col_time_key TIME,
|
||||||
|
col_datetime_key DATETIME,
|
||||||
|
col_varchar_key VARCHAR(1),
|
||||||
|
PRIMARY KEY (pk),
|
||||||
|
KEY (col_varchar_key, col_int_key)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_DD AS SELECT * FROM DD;
|
||||||
|
CREATE TRIGGER k BEFORE INSERT ON `DD` FOR EACH ROW INSERT INTO `view_BB` SELECT * FROM `view_A` LIMIT 0 ;
|
||||||
|
CREATE TRIGGER r BEFORE INSERT ON `A` FOR EACH ROW INSERT INTO `view_AA` SELECT * FROM `view_C` LIMIT 0 ;
|
||||||
|
ALTER TABLE `DD` DROP PRIMARY KEY;
|
||||||
|
ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key
|
||||||
|
INSERT INTO `view_A` ( `pk` ) VALUES (NULL);
|
||||||
|
INSERT INTO `DD` ( `pk` ) VALUES (NULL);
|
||||||
|
INSERT INTO `A` ( `pk` ) VALUES (NULL);
|
||||||
|
INSERT INTO `view_DD` ( `pk` ) VALUES (NULL);
|
||||||
|
drop trigger r;
|
||||||
|
drop trigger k;
|
||||||
|
drop view view_A,view_AA,view_C,view_BB,view_DD;
|
||||||
|
drop table A,C,AA,BB,DD;
|
||||||
|
CREATE TABLE A (
|
||||||
|
i INT,
|
||||||
|
i1 INT,
|
||||||
|
i2 INT,
|
||||||
|
d1 DATE,
|
||||||
|
d2 DATE,
|
||||||
|
col_time_nokey1 TIME,
|
||||||
|
col_time_nokey2 TIME,
|
||||||
|
col_datetime_nokey1 DATETIME,
|
||||||
|
col_datetime_nokey2 DATETIME,
|
||||||
|
col_varchar_nokey1 VARCHAR(1),
|
||||||
|
col_varchar_nokey2 VARCHAR(1)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_A AS SELECT * FROM A;
|
||||||
|
CREATE TABLE B (
|
||||||
|
col_varchar_nokey VARCHAR(1)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE TABLE AA (
|
||||||
|
i INT,
|
||||||
|
i1 INT,
|
||||||
|
i2 INT,
|
||||||
|
d1 DATE,
|
||||||
|
d2 DATE,
|
||||||
|
col_time_nokey1 TIME,
|
||||||
|
col_time_nokey2 TIME,
|
||||||
|
col_datetime_nokey1 DATETIME,
|
||||||
|
col_datetime_nokey2 DATETIME,
|
||||||
|
col_varchar_nokey1 VARCHAR(1),
|
||||||
|
col_varchar_nokey2 VARCHAR(1)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_AA AS SELECT * FROM AA;
|
||||||
|
CREATE TABLE DD (
|
||||||
|
i INT,
|
||||||
|
i1 INT,
|
||||||
|
i2 INT,
|
||||||
|
d1 DATE,
|
||||||
|
d2 DATE,
|
||||||
|
col_time_nokey1 TIME,
|
||||||
|
col_time_nokey2 TIME,
|
||||||
|
col_datetime_nokey1 DATETIME,
|
||||||
|
col_datetime_nokey2 DATETIME,
|
||||||
|
col_varchar_nokey1 VARCHAR(1),
|
||||||
|
col_varchar_nokey2 VARCHAR(1)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_DD AS SELECT * FROM DD;
|
||||||
|
CREATE TRIGGER tr1 BEFORE INSERT ON `AA` FOR EACH ROW INSERT INTO `view_A` SELECT * FROM `view_AA` LIMIT 0 ;
|
||||||
|
CREATE TRIGGER tr2 BEFORE INSERT ON `B` FOR EACH ROW INSERT INTO `D` SELECT * FROM `A` LIMIT 0 ;
|
||||||
|
INSERT INTO `view_AA` ( `i` ) VALUES (1);
|
||||||
|
INSERT INTO `AA` ( `i` ) VALUES (2);
|
||||||
|
DELETE FROM `B`;
|
||||||
|
INSERT INTO `view_DD` ( `i` ) VALUES (1);
|
||||||
|
INSERT INTO `view_AA` ( `i` ) VALUES (3);
|
||||||
|
drop trigger tr1;
|
||||||
|
drop trigger tr2;
|
||||||
|
drop view view_A, view_AA,view_DD;
|
||||||
|
drop table A,B,AA,DD;
|
@@ -2145,6 +2145,24 @@ drop database mysqltest1;
|
|||||||
drop database mysqltest2;
|
drop database mysqltest2;
|
||||||
drop database mysqltest3;
|
drop database mysqltest3;
|
||||||
drop database mysqltest4;
|
drop database mysqltest4;
|
||||||
|
#
|
||||||
|
# MDEV-7810 Wrong result on execution of a query as a PS
|
||||||
|
# (both 1st and further executions)
|
||||||
|
CREATE TABLE t1 (a INT NOT NULL) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t1 VALUES (0),(8);
|
||||||
|
SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2));
|
||||||
|
a
|
||||||
|
0
|
||||||
|
PREPARE stmt FROM "
|
||||||
|
SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2))
|
||||||
|
";
|
||||||
|
execute stmt;
|
||||||
|
a
|
||||||
|
0
|
||||||
|
execute stmt;
|
||||||
|
a
|
||||||
|
0
|
||||||
|
drop table t1;
|
||||||
# End of 5.5 tests
|
# End of 5.5 tests
|
||||||
set @subselect_mat_test_optimizer_switch_value=null;
|
set @subselect_mat_test_optimizer_switch_value=null;
|
||||||
set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off';
|
set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off';
|
||||||
|
@@ -2185,4 +2185,22 @@ drop database mysqltest1;
|
|||||||
drop database mysqltest2;
|
drop database mysqltest2;
|
||||||
drop database mysqltest3;
|
drop database mysqltest3;
|
||||||
drop database mysqltest4;
|
drop database mysqltest4;
|
||||||
|
#
|
||||||
|
# MDEV-7810 Wrong result on execution of a query as a PS
|
||||||
|
# (both 1st and further executions)
|
||||||
|
CREATE TABLE t1 (a INT NOT NULL) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t1 VALUES (0),(8);
|
||||||
|
SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2));
|
||||||
|
a
|
||||||
|
0
|
||||||
|
PREPARE stmt FROM "
|
||||||
|
SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2))
|
||||||
|
";
|
||||||
|
execute stmt;
|
||||||
|
a
|
||||||
|
0
|
||||||
|
execute stmt;
|
||||||
|
a
|
||||||
|
0
|
||||||
|
drop table t1;
|
||||||
# End of 5.5 tests
|
# End of 5.5 tests
|
||||||
|
@@ -5429,6 +5429,21 @@ View Create View character_set_client collation_connection
|
|||||||
v2 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select (`t1`.`b` + 1) AS `c` from `t1` latin1 latin1_swedish_ci
|
v2 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select (`t1`.`b` + 1) AS `c` from `t1` latin1 latin1_swedish_ci
|
||||||
drop view v2;
|
drop view v2;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
#
|
||||||
|
# MDEV-8554: Server crashes in base_list_iterator::next_fast on 1st execution of PS with a multi-table update
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (a INT) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t1 VALUES (1),(2);
|
||||||
|
CREATE TABLE t2 (b INT) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t2 VALUES (3),(4);
|
||||||
|
CREATE TABLE t3 (c INT) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t3 VALUES (5),(6);
|
||||||
|
CREATE OR REPLACE ALGORITHM=MERGE VIEW v3 AS SELECT * FROM t3;
|
||||||
|
PREPARE stmt FROM 'UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM t3 )';
|
||||||
|
UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM v3 );
|
||||||
|
EXECUTE stmt;
|
||||||
|
DROP TABLE t1, t2, t3;
|
||||||
|
DROP VIEW v3;
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
# -- End of 5.5 tests.
|
# -- End of 5.5 tests.
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
|
@@ -258,7 +258,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
|
|||||||
create table t0 (n int);
|
create table t0 (n int);
|
||||||
insert t0 select * from t1;
|
insert t0 select * from t1;
|
||||||
set autocommit=1;
|
set autocommit=1;
|
||||||
insert into t0 select GET_LOCK("lock1",null);
|
insert into t0 select GET_LOCK("lock1",0);
|
||||||
set autocommit=0;
|
set autocommit=0;
|
||||||
create table t2 (n int) engine=innodb;
|
create table t2 (n int) engine=innodb;
|
||||||
insert into t2 values (3);
|
insert into t2 values (3);
|
||||||
|
@@ -242,7 +242,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
|
|||||||
create table t0 (n int);
|
create table t0 (n int);
|
||||||
insert t0 select * from t1;
|
insert t0 select * from t1;
|
||||||
set autocommit=1;
|
set autocommit=1;
|
||||||
insert into t0 select GET_LOCK("lock1",null);
|
insert into t0 select GET_LOCK("lock1",0);
|
||||||
Warnings:
|
Warnings:
|
||||||
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave.
|
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave.
|
||||||
set autocommit=0;
|
set autocommit=0;
|
||||||
@@ -288,7 +288,7 @@ master-bin.000001 # Query # # BEGIN
|
|||||||
master-bin.000001 # Query # # use `test`; insert t0 select * from t1
|
master-bin.000001 # Query # # use `test`; insert t0 select * from t1
|
||||||
master-bin.000001 # Query # # COMMIT
|
master-bin.000001 # Query # # COMMIT
|
||||||
master-bin.000001 # Query # # BEGIN
|
master-bin.000001 # Query # # BEGIN
|
||||||
master-bin.000001 # Query # # use `test`; insert into t0 select GET_LOCK("lock1",null)
|
master-bin.000001 # Query # # use `test`; insert into t0 select GET_LOCK("lock1",0)
|
||||||
master-bin.000001 # Query # # COMMIT
|
master-bin.000001 # Query # # COMMIT
|
||||||
master-bin.000001 # Query # # use `test`; create table t2 (n int) engine=innodb
|
master-bin.000001 # Query # # use `test`; create table t2 (n int) engine=innodb
|
||||||
master-bin.000001 # Query # # use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `t1`,`ti`
|
master-bin.000001 # Query # # use `test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `t1`,`ti`
|
||||||
|
13
mysql-test/suite/innodb/r/add_constraint.result
Normal file
13
mysql-test/suite/innodb/r/add_constraint.result
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#
|
||||||
|
# Bug #20762798 FK DDL: CRASH IN DICT_FOREIGN_REMOVE_FROM_CACHE
|
||||||
|
#
|
||||||
|
create table t1(a int, b int, key(a),key(b))engine=innodb;
|
||||||
|
create table t2(a int, b int, key(a),key(b))engine=innodb;
|
||||||
|
alter table t2 add constraint b foreign key (b) references t1(a);
|
||||||
|
alter table t1 add constraint b1 foreign key (b) references t2(a);
|
||||||
|
alter table t2 add constraint b1 foreign key (b) references t1(a);
|
||||||
|
ERROR HY000: Can't create table '#sql-temporary' (errno: 121)
|
||||||
|
alter table t2 drop foreign key b;
|
||||||
|
alter table t1 drop foreign key b1;
|
||||||
|
drop table t2;
|
||||||
|
drop table t1;
|
105
mysql-test/suite/innodb/r/innodb-fk-warnings.result
Normal file
105
mysql-test/suite/innodb/r/innodb-fk-warnings.result
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
CREATE TABLE t1 (
|
||||||
|
id int(11) NOT NULL PRIMARY KEY,
|
||||||
|
a int(11) NOT NULL,
|
||||||
|
b int(11) NOT NULL,
|
||||||
|
c int not null,
|
||||||
|
CONSTRAINT test FOREIGN KEY (b) REFERENCES t1 (id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||||
|
CREATE TABLE t2 (
|
||||||
|
id int(11) NOT NULL PRIMARY KEY,
|
||||||
|
a int(11) NOT NULL,
|
||||||
|
b int(11) NOT NULL,
|
||||||
|
c int not null,
|
||||||
|
CONSTRAINT mytest FOREIGN KEY (c) REFERENCES t1(id),
|
||||||
|
CONSTRAINT test FOREIGN KEY (b) REFERENCES t2 (id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||||
|
ERROR HY000: Can't create table 'test.t2' (errno: 121)
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Warning 121 Create or Alter table `test`.`t2` with foreign key constraint failed. Foreign key constraint `test/test` already exists on data dictionary. Foreign key constraint names need to be unique in database. Error in foreign key definition: CONSTRAINT `test` FOREIGN KEY (`b`) REFERENCES `test`.`t2` (`id`).
|
||||||
|
Error 1005 Can't create table 'test.t2' (errno: 121)
|
||||||
|
drop table t1;
|
||||||
|
create table t1(a int) engine=innodb;
|
||||||
|
create table t2(a int, constraint a foreign key a (a) references t1(a)) engine=innodb;
|
||||||
|
ERROR HY000: Can't create table 'test.t2' (errno: 150)
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Warning 150 Create table '`test`.`t2`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns. Error close to foreign key a (a) references t1(a)) engine=innodb.
|
||||||
|
Error 1005 Can't create table 'test.t2' (errno: 150)
|
||||||
|
drop table t1;
|
||||||
|
create table t1(a int not null primary key, b int) engine=innodb;
|
||||||
|
create table t2(a int, b int, constraint a foreign key a (a) references t1(a),
|
||||||
|
constraint a foreign key a (a) references t1(b)) engine=innodb;
|
||||||
|
ERROR HY000: Can't create table 'test.t2' (errno: 150)
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Warning 150 Create table '`test`.`t2`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns. Error close to foreign key a (a) references t1(b)) engine=innodb.
|
||||||
|
Error 1005 Can't create table 'test.t2' (errno: 150)
|
||||||
|
create table t2(a int, b int, constraint a foreign key a (a) references t1(a)) engine=innodb;
|
||||||
|
alter table t2 add constraint b foreign key (b) references t2(b);
|
||||||
|
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Warning 150 Alter table '`test`.`t2`' with foreign key constraint failed. There is no index in the referenced table where the referenced columns appear as the first columns. Error close to foreign key (b) references t2(b).
|
||||||
|
Error 1005 Can't create table '#sql-temporary' (errno: 150)
|
||||||
|
drop table t2, t1;
|
||||||
|
create table t1 (f1 integer primary key) engine=innodb;
|
||||||
|
alter table t1 add constraint c1 foreign key (f1) references t11(f1);
|
||||||
|
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Warning 150 Alter table `test`.`t1` with foreign key constraint failed. Referenced table `test`.`t11` not found in the data dictionary close to foreign key (f1) references t11(f1).
|
||||||
|
Error 1005 Can't create table '#sql-temporary' (errno: 150)
|
||||||
|
drop table t1;
|
||||||
|
create temporary table t1(a int not null primary key, b int, key(b)) engine=innodb;
|
||||||
|
create temporary table t2(a int, foreign key(a) references t1(a)) engine=innodb;
|
||||||
|
ERROR HY000: Can't create table 'test.t2' (errno: 150)
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Warning 150 Create table `mysqld.1`.`t2` with foreign key constraint failed. Referenced table `mysqld.1`.`t1` not found in the data dictionary close to foreign key(a) references t1(a)) engine=innodb.
|
||||||
|
Error 1005 Can't create table 'test.t2' (errno: 150)
|
||||||
|
alter table t1 add foreign key(b) references t1(a);
|
||||||
|
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Warning 150 Alter table `mysqld.1`.`t1` with foreign key constraint failed. Referenced table `mysqld.1`.`t1` not found in the data dictionary close to foreign key(b) references t1(a).
|
||||||
|
Error 1005 Can't create table '#sql-temporary' (errno: 150)
|
||||||
|
drop table t1;
|
||||||
|
create table t1(a int not null primary key, b int, key(b)) engine=innodb;
|
||||||
|
alter table t1 add foreign key(a,b) references t1(a);
|
||||||
|
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Warning 150 Alter table `test`.`t1` with foreign key constraint failed. Foreign key constraint parse error in foreign key(a,b) references t1(a) close to ). Too few referenced columns, you have 1 when you should have 2.
|
||||||
|
Error 1005 Can't create table '#sql-temporary' (errno: 150)
|
||||||
|
drop table t1;
|
||||||
|
create table t1(a int not null primary key, b int, key(b)) engine=innodb;
|
||||||
|
alter table t1 add foreign key(a) references t1(a,b);
|
||||||
|
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Warning 150 Alter table `test`.`t1` with foreign key constraint failed. Foreign key constraint parse error in foreign key(a) references t1(a,b) close to ). Too few referenced columns, you have 2 when you should have 1.
|
||||||
|
Error 1005 Can't create table '#sql-temporary' (errno: 150)
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (f1 integer not null primary key) engine=innodb;
|
||||||
|
alter table t1 add constraint c1 foreign key (f1) references t1(f1) on update set null;
|
||||||
|
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Warning 150 Alter table `test`.`t1` with foreign key constraint failed. You have defined a SET NULL condition but column f1 is defined as NOT NULL in foreign key (f1) references t1(f1) on update set null close to on update set null.
|
||||||
|
Error 1005 Can't create table '#sql-temporary' (errno: 150)
|
||||||
|
create table t2(a int not null, foreign key(a) references t1(f1) on delete set null) engine=innodb;
|
||||||
|
ERROR HY000: Can't create table 'test.t2' (errno: 150)
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Warning 150 Create table `test`.`t2` with foreign key constraint failed. You have defined a SET NULL condition but column a is defined as NOT NULL in foreign key(a) references t1(f1) on delete set null) engine=innodb close to on delete set null) engine=innodb.
|
||||||
|
Error 1005 Can't create table 'test.t2' (errno: 150)
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (id int not null primary key, f1 int, f2 int, key(f1)) engine=innodb;
|
||||||
|
create table t2(a char(20), key(a), foreign key(a) references t1(f1)) engine=innodb;
|
||||||
|
ERROR HY000: Can't create table 'test.t2' (errno: 150)
|
||||||
|
show warnings;
|
||||||
|
Level Code Message
|
||||||
|
Warning 150 Create table `test`.`t2` with foreign key constraint failed. Field type or character set for column a does not mach referenced column f1 close to foreign key(a) references t1(f1)) engine=innodb
|
||||||
|
Error 1005 Can't create table 'test.t2' (errno: 150)
|
||||||
|
drop table t1;
|
@@ -50,6 +50,8 @@ CONSTRAINT fk3 FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE CASCADE
|
|||||||
ERROR HY000: Can't create table 'test.t2' (errno: 150)
|
ERROR HY000: Can't create table 'test.t2' (errno: 150)
|
||||||
show warnings;
|
show warnings;
|
||||||
Level Code Message
|
Level Code Message
|
||||||
|
Warning 150 Create table `test`.`t2` with foreign key constraint failed. Referenced table `test`.`t3` not found in the data dictionary close to FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB.
|
||||||
Error 1005 Can't create table 'test.t2' (errno: 150)
|
Error 1005 Can't create table 'test.t2' (errno: 150)
|
||||||
CREATE TABLE t2 (
|
CREATE TABLE t2 (
|
||||||
id int(11) NOT NULL AUTO_INCREMENT,
|
id int(11) NOT NULL AUTO_INCREMENT,
|
||||||
@@ -62,6 +64,7 @@ ALTER TABLE t2 ADD CONSTRAINT fk3 FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE
|
|||||||
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
|
ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
|
||||||
show warnings;
|
show warnings;
|
||||||
Level Code Message
|
Level Code Message
|
||||||
|
Warning 150 Alter table `test`.`t2` with foreign key constraint failed. Referenced table `test`.`t3` not found in the data dictionary close to FOREIGN KEY (f3) REFERENCES t3 (id) ON DELETE CASCADE.
|
||||||
Error 1005 Can't create table '#sql-temporary' (errno: 150)
|
Error 1005 Can't create table '#sql-temporary' (errno: 150)
|
||||||
drop table t2;
|
drop table t2;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
22
mysql-test/suite/innodb/r/innodb_uninstall.result
Normal file
22
mysql-test/suite/innodb/r/innodb_uninstall.result
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
install plugin innodb soname 'ha_innodb';
|
||||||
|
create table t1(a int not null primary key) engine=innodb;
|
||||||
|
begin;
|
||||||
|
insert into t1 values(1);
|
||||||
|
flush tables;
|
||||||
|
uninstall plugin innodb;
|
||||||
|
select sleep(1);
|
||||||
|
sleep(1)
|
||||||
|
0
|
||||||
|
Warnings:
|
||||||
|
Warning 1620 Plugin is busy and will be uninstalled on shutdown
|
||||||
|
drop table t1;
|
||||||
|
install plugin innodb soname 'ha_innodb';
|
||||||
|
create table t2(a int not null primary key) engine=innodb;
|
||||||
|
insert into t2 values(1);
|
||||||
|
drop table t2;
|
||||||
|
uninstall plugin innodb;
|
||||||
|
select sleep(1);
|
||||||
|
sleep(1)
|
||||||
|
0
|
||||||
|
Warnings:
|
||||||
|
Warning 1620 Plugin is busy and will be uninstalled on shutdown
|
21
mysql-test/suite/innodb/t/add_constraint.test
Normal file
21
mysql-test/suite/innodb/t/add_constraint.test
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
--source include/have_innodb.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug #20762798 FK DDL: CRASH IN DICT_FOREIGN_REMOVE_FROM_CACHE
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1(a int, b int, key(a),key(b))engine=innodb;
|
||||||
|
create table t2(a int, b int, key(a),key(b))engine=innodb;
|
||||||
|
|
||||||
|
alter table t2 add constraint b foreign key (b) references t1(a);
|
||||||
|
alter table t1 add constraint b1 foreign key (b) references t2(a);
|
||||||
|
|
||||||
|
--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
--error ER_CANT_CREATE_TABLE
|
||||||
|
alter table t2 add constraint b1 foreign key (b) references t1(a);
|
||||||
|
|
||||||
|
alter table t2 drop foreign key b;
|
||||||
|
alter table t1 drop foreign key b1;
|
||||||
|
|
||||||
|
drop table t2;
|
||||||
|
drop table t1;
|
130
mysql-test/suite/innodb/t/innodb-fk-warnings.test
Normal file
130
mysql-test/suite/innodb/t/innodb-fk-warnings.test
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
--source include/have_innodb.inc
|
||||||
|
|
||||||
|
#
|
||||||
|
# MDEV-8524: Improve error messaging when there is duplicate key or foreign key names
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
id int(11) NOT NULL PRIMARY KEY,
|
||||||
|
a int(11) NOT NULL,
|
||||||
|
b int(11) NOT NULL,
|
||||||
|
c int not null,
|
||||||
|
CONSTRAINT test FOREIGN KEY (b) REFERENCES t1 (id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Below create table fails because constraint name test
|
||||||
|
# is reserved for above table.
|
||||||
|
#
|
||||||
|
--error 1005
|
||||||
|
CREATE TABLE t2 (
|
||||||
|
id int(11) NOT NULL PRIMARY KEY,
|
||||||
|
a int(11) NOT NULL,
|
||||||
|
b int(11) NOT NULL,
|
||||||
|
c int not null,
|
||||||
|
CONSTRAINT mytest FOREIGN KEY (c) REFERENCES t1(id),
|
||||||
|
CONSTRAINT test FOREIGN KEY (b) REFERENCES t2 (id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||||
|
|
||||||
|
show warnings;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# MDEV-6697: Improve foreign keys warnings/errors
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# No index for referenced columns
|
||||||
|
#
|
||||||
|
create table t1(a int) engine=innodb;
|
||||||
|
--error 1005
|
||||||
|
create table t2(a int, constraint a foreign key a (a) references t1(a)) engine=innodb;
|
||||||
|
show warnings;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
create table t1(a int not null primary key, b int) engine=innodb;
|
||||||
|
--error 1005
|
||||||
|
create table t2(a int, b int, constraint a foreign key a (a) references t1(a),
|
||||||
|
constraint a foreign key a (a) references t1(b)) engine=innodb;
|
||||||
|
show warnings;
|
||||||
|
create table t2(a int, b int, constraint a foreign key a (a) references t1(a)) engine=innodb;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
--error 1005
|
||||||
|
alter table t2 add constraint b foreign key (b) references t2(b);
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
show warnings;
|
||||||
|
drop table t2, t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Referenced table does not exists
|
||||||
|
#
|
||||||
|
|
||||||
|
create table t1 (f1 integer primary key) engine=innodb;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
--error 1005
|
||||||
|
alter table t1 add constraint c1 foreign key (f1) references t11(f1);
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
show warnings;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Foreign key on temporal tables
|
||||||
|
#
|
||||||
|
|
||||||
|
create temporary table t1(a int not null primary key, b int, key(b)) engine=innodb;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
--error 1005
|
||||||
|
create temporary table t2(a int, foreign key(a) references t1(a)) engine=innodb;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
show warnings;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
--error 1005
|
||||||
|
alter table t1 add foreign key(b) references t1(a);
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
show warnings;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Column numbers do not match
|
||||||
|
#
|
||||||
|
create table t1(a int not null primary key, b int, key(b)) engine=innodb;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
--error 1005
|
||||||
|
alter table t1 add foreign key(a,b) references t1(a);
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
show warnings;
|
||||||
|
drop table t1;
|
||||||
|
create table t1(a int not null primary key, b int, key(b)) engine=innodb;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
--error 1005
|
||||||
|
alter table t1 add foreign key(a) references t1(a,b);
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
show warnings;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# ON UPDATE/DELETE SET NULL on NOT NULL column
|
||||||
|
#
|
||||||
|
create table t1 (f1 integer not null primary key) engine=innodb;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
--error 1005
|
||||||
|
alter table t1 add constraint c1 foreign key (f1) references t1(f1) on update set null;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
show warnings;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
--error 1005
|
||||||
|
create table t2(a int not null, foreign key(a) references t1(f1) on delete set null) engine=innodb;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
show warnings;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Incorrect types
|
||||||
|
#
|
||||||
|
create table t1 (id int not null primary key, f1 int, f2 int, key(f1)) engine=innodb;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
--error 1005
|
||||||
|
create table t2(a char(20), key(a), foreign key(a) references t1(f1)) engine=innodb;
|
||||||
|
--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||||
|
show warnings;
|
||||||
|
drop table t1;
|
3
mysql-test/suite/innodb/t/innodb_uninstall.opt
Normal file
3
mysql-test/suite/innodb/t/innodb_uninstall.opt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
--ignore-builtin-innodb
|
||||||
|
--loose-innodb
|
||||||
|
|
58
mysql-test/suite/innodb/t/innodb_uninstall.test
Normal file
58
mysql-test/suite/innodb/t/innodb_uninstall.test
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
--source include/not_embedded.inc
|
||||||
|
--source include/not_windows.inc
|
||||||
|
|
||||||
|
if (!$HA_INNODB_SO) {
|
||||||
|
--skip Need InnoDB plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# MDEV-8474: InnoDB sets per-connection data unsafely
|
||||||
|
# Below test caused hang
|
||||||
|
#
|
||||||
|
install plugin innodb soname 'ha_innodb';
|
||||||
|
create table t1(a int not null primary key) engine=innodb;
|
||||||
|
|
||||||
|
connect (con1, localhost, root);
|
||||||
|
connection con1;
|
||||||
|
begin;
|
||||||
|
insert into t1 values(1);
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
flush tables;
|
||||||
|
send uninstall plugin innodb;
|
||||||
|
|
||||||
|
connection con1;
|
||||||
|
select sleep(1);
|
||||||
|
disconnect con1;
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
reap;
|
||||||
|
|
||||||
|
--source include/restart_mysqld.inc
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Another test that caused hang.
|
||||||
|
#
|
||||||
|
|
||||||
|
connect (con1, localhost, root);
|
||||||
|
connection con1;
|
||||||
|
install plugin innodb soname 'ha_innodb';
|
||||||
|
create table t2(a int not null primary key) engine=innodb;
|
||||||
|
insert into t2 values(1);
|
||||||
|
drop table t2;
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
send uninstall plugin innodb;
|
||||||
|
|
||||||
|
connection con1;
|
||||||
|
select sleep(1);
|
||||||
|
disconnect con1;
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
reap;
|
||||||
|
|
||||||
|
--source include/restart_mysqld.inc
|
||||||
|
|
||||||
|
|
33
mysql-test/suite/ndb/r/ndb_restore_discover.result
Normal file
33
mysql-test/suite/ndb/r/ndb_restore_discover.result
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#
|
||||||
|
# 18075170 - sql node restart required to avoid deadlock after
|
||||||
|
# restore
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (id INT) ENGINE=NDBCluster;
|
||||||
|
CREATE TABLE t2 (id INT) ENGINE=NDBCluster;
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (1);
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
SET autocommit = 0;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
id
|
||||||
|
1
|
||||||
|
SELECT * FROM t2;
|
||||||
|
id
|
||||||
|
1
|
||||||
|
ROLLBACK;
|
||||||
|
SET autocommit = 1;
|
||||||
|
drop table t1;
|
||||||
|
drop table t2;
|
||||||
|
SET autocommit = 0;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
id
|
||||||
|
1
|
||||||
|
SELECT * FROM t2;
|
||||||
|
id
|
||||||
|
1
|
||||||
|
ALTER TABLE t1 ADD val INT;
|
||||||
|
ROLLBACK;
|
||||||
|
SET autocommit = 1;
|
||||||
|
drop table t1;
|
||||||
|
drop table t2;
|
70
mysql-test/suite/ndb/t/ndb_restore_discover.test
Normal file
70
mysql-test/suite/ndb/t/ndb_restore_discover.test
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
-- source include/have_ndb.inc
|
||||||
|
-- source include/count_sessions.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # 18075170 - sql node restart required to avoid deadlock after
|
||||||
|
--echo # restore
|
||||||
|
--echo #
|
||||||
|
# Test Auto Discover option within a transaction
|
||||||
|
# and make sure the transaction is not broken.
|
||||||
|
CREATE TABLE t1 (id INT) ENGINE=NDBCluster;
|
||||||
|
CREATE TABLE t2 (id INT) ENGINE=NDBCluster;
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (1);
|
||||||
|
|
||||||
|
-- source include/ndb_backup.inc
|
||||||
|
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
|
||||||
|
-- source include/ndb_restore_master.inc
|
||||||
|
|
||||||
|
SET autocommit = 0;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
|
||||||
|
# Without fix below select was resulting in DEADLOCK error. With fix select
|
||||||
|
# should succeed.
|
||||||
|
SELECT * FROM t2;
|
||||||
|
ROLLBACK;
|
||||||
|
SET autocommit = 1;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
drop table t2;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Checking lock preservation in transaction
|
||||||
|
#
|
||||||
|
# Using existing backup to create the scenario. Tables are deleted as part of
|
||||||
|
# above test cleanup. Thus restoring the backup will bring the system to
|
||||||
|
# required state.
|
||||||
|
-- source include/ndb_restore_master.inc
|
||||||
|
|
||||||
|
SET autocommit = 0;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
SELECT * FROM t2;
|
||||||
|
|
||||||
|
connect(con2, localhost, root);
|
||||||
|
--SEND ALTER TABLE t1 ADD val INT
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
# Alter from con2 will be in waiting state as there is a lock on t1 from
|
||||||
|
# default connection due to active transaction. We check for this condition
|
||||||
|
# then releasing the lock by rollbacking active transaction.
|
||||||
|
let $wait_condition=
|
||||||
|
SELECT count(*) = 1 FROM information_schema.processlist WHERE state
|
||||||
|
LIKE "Waiting%" AND info = "ALTER TABLE t1 ADD val INT";
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
ROLLBACK;
|
||||||
|
SET autocommit = 1;
|
||||||
|
|
||||||
|
connection con2;
|
||||||
|
--REAP
|
||||||
|
|
||||||
|
disconnect con2;
|
||||||
|
connection default;
|
||||||
|
drop table t1;
|
||||||
|
drop table t2;
|
||||||
|
|
||||||
|
# Wait till all disconnects are completed
|
||||||
|
-- source include/wait_until_count_sessions.inc
|
@@ -14,4 +14,109 @@ select * from mysqltest.t3;
|
|||||||
n
|
n
|
||||||
45
|
45
|
||||||
drop database mysqltest;
|
drop database mysqltest;
|
||||||
|
use test;
|
||||||
|
#
|
||||||
|
# Test bug where ALTER TABLE MODIFY didn't replicate properly
|
||||||
|
#
|
||||||
|
create table t1 (a int unsigned primary key, b int);
|
||||||
|
show create table t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`a` int(10) unsigned NOT NULL,
|
||||||
|
`b` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`a`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
insert into t1 (a) values (1),((1<<32)-1);
|
||||||
|
select * from t1;
|
||||||
|
a b
|
||||||
|
1 NULL
|
||||||
|
4294967295 NULL
|
||||||
|
alter table t1 modify a bigint;
|
||||||
|
show create table t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`a` bigint(20) NOT NULL DEFAULT '0',
|
||||||
|
`b` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`a`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
select * from t1;
|
||||||
|
a b
|
||||||
|
1 NULL
|
||||||
|
4294967295 NULL
|
||||||
|
alter table t1 modify a int unsigned;
|
||||||
|
show create table t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`a` int(10) unsigned NOT NULL DEFAULT '0',
|
||||||
|
`b` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`a`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
select * from t1;
|
||||||
|
a b
|
||||||
|
1 NULL
|
||||||
|
4294967295 NULL
|
||||||
|
alter table t1 modify a bigint unsigned;
|
||||||
|
show create table t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`a` bigint(20) unsigned NOT NULL DEFAULT '0',
|
||||||
|
`b` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`a`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
select * from t1;
|
||||||
|
a b
|
||||||
|
1 NULL
|
||||||
|
4294967295 NULL
|
||||||
|
use test;
|
||||||
|
select * from t1;
|
||||||
|
a b
|
||||||
|
1 NULL
|
||||||
|
4294967295 NULL
|
||||||
|
show create table t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`a` bigint(20) unsigned NOT NULL DEFAULT '0',
|
||||||
|
`b` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`a`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
create table t2 (a int unsigned auto_increment primary key, b int);
|
||||||
|
show create table t2;
|
||||||
|
Table Create Table
|
||||||
|
t2 CREATE TABLE `t2` (
|
||||||
|
`a` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`b` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`a`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
alter table t2 modify a bigint;
|
||||||
|
show create table t2;
|
||||||
|
Table Create Table
|
||||||
|
t2 CREATE TABLE `t2` (
|
||||||
|
`a` bigint(20) NOT NULL DEFAULT '0',
|
||||||
|
`b` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`a`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
alter table t2 modify a bigint auto_increment;
|
||||||
|
show create table t2;
|
||||||
|
Table Create Table
|
||||||
|
t2 CREATE TABLE `t2` (
|
||||||
|
`a` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
|
`b` int(11) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`a`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
drop table t1,t2;
|
||||||
|
#
|
||||||
|
# MDEV-8432: Slave cannot replicate signed integer-type values
|
||||||
|
# with high bit set to 1
|
||||||
|
# Test replication when we have int on master and bigint on slave
|
||||||
|
#
|
||||||
|
create table t1 (a int unsigned primary key, b int);
|
||||||
|
SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY';
|
||||||
|
alter table t1 modify a bigint unsigned;
|
||||||
|
insert into t1 (a) values (1),((1<<32)-1);
|
||||||
|
select * from t1;
|
||||||
|
a b
|
||||||
|
1 NULL
|
||||||
|
4294967295 NULL
|
||||||
|
SET GLOBAL SLAVE_TYPE_CONVERSIONS='';
|
||||||
|
drop table t1;
|
||||||
include/rpl_end.inc
|
include/rpl_end.inc
|
||||||
|
@@ -15,4 +15,57 @@ drop database mysqltest;
|
|||||||
sync_slave_with_master;
|
sync_slave_with_master;
|
||||||
|
|
||||||
# End of 4.1 tests
|
# End of 4.1 tests
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
use test;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Test bug where ALTER TABLE MODIFY didn't replicate properly
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (a int unsigned primary key, b int);
|
||||||
|
show create table t1;
|
||||||
|
insert into t1 (a) values (1),((1<<32)-1);
|
||||||
|
select * from t1;
|
||||||
|
alter table t1 modify a bigint;
|
||||||
|
show create table t1;
|
||||||
|
select * from t1;
|
||||||
|
alter table t1 modify a int unsigned;
|
||||||
|
show create table t1;
|
||||||
|
select * from t1;
|
||||||
|
alter table t1 modify a bigint unsigned;
|
||||||
|
show create table t1;
|
||||||
|
select * from t1;
|
||||||
|
sync_slave_with_master;
|
||||||
|
use test;
|
||||||
|
select * from t1;
|
||||||
|
show create table t1;
|
||||||
|
connection master;
|
||||||
|
#
|
||||||
|
create table t2 (a int unsigned auto_increment primary key, b int);
|
||||||
|
show create table t2;
|
||||||
|
alter table t2 modify a bigint;
|
||||||
|
show create table t2;
|
||||||
|
alter table t2 modify a bigint auto_increment;
|
||||||
|
show create table t2;
|
||||||
|
drop table t1,t2;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-8432: Slave cannot replicate signed integer-type values
|
||||||
|
--echo # with high bit set to 1
|
||||||
|
--echo # Test replication when we have int on master and bigint on slave
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
create table t1 (a int unsigned primary key, b int);
|
||||||
|
sync_slave_with_master;
|
||||||
|
SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY';
|
||||||
|
alter table t1 modify a bigint unsigned;
|
||||||
|
connection master;
|
||||||
|
insert into t1 (a) values (1),((1<<32)-1);
|
||||||
|
sync_slave_with_master;
|
||||||
|
select * from t1;
|
||||||
|
SET GLOBAL SLAVE_TYPE_CONVERSIONS='';
|
||||||
|
connection master;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
--source include/rpl_end.inc
|
--source include/rpl_end.inc
|
||||||
|
@@ -821,3 +821,14 @@ FROM ( SELECT * FROM t2 ) AS sq2, t3
|
|||||||
ORDER BY field;
|
ORDER BY field;
|
||||||
|
|
||||||
drop table t3, t2, t1;
|
drop table t3, t2, t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-7821 - Server crashes in Item_func_group_concat::fix_fields on 2nd
|
||||||
|
--echo # execution of PS
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1(a INT);
|
||||||
|
INSERT INTO t1 VALUES(1),(2);
|
||||||
|
PREPARE stmt FROM "SELECT GROUP_CONCAT(t1a.a ORDER BY 1, t1a.a=0) FROM t1 AS t1a, t1 AS t1b GROUP BY t1a.a";
|
||||||
|
EXECUTE stmt;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DROP TABLE t1;
|
||||||
|
@@ -391,6 +391,11 @@ set optimizer_switch=@optimizer_switch_save;
|
|||||||
drop view v_merge, vm;
|
drop view v_merge, vm;
|
||||||
drop table t1,tv;
|
drop table t1,tv;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-4017 - GET_LOCK() with negative timeouts has strange behavior
|
||||||
|
--echo #
|
||||||
|
SELECT GET_LOCK('ul1', NULL);
|
||||||
|
SELECT GET_LOCK('ul1', -1);
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 5.5 tests
|
--echo # End of 5.5 tests
|
||||||
|
@@ -17,3 +17,6 @@ commit;
|
|||||||
--source include/show_binlog_events.inc
|
--source include/show_binlog_events.inc
|
||||||
drop table t1;
|
drop table t1;
|
||||||
uninstall plugin innodb;
|
uninstall plugin innodb;
|
||||||
|
|
||||||
|
--source include/restart_mysqld.inc
|
||||||
|
|
||||||
|
@@ -1,5 +1,9 @@
|
|||||||
|
--source include/count_sessions.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Tests for corrupted MyISAM tables and MyISAMMRG tables with corrupted
|
||||||
|
--echo # children..
|
||||||
--echo #
|
--echo #
|
||||||
--echo # Test of MyISAM MRG tables with corrupted children.
|
|
||||||
--echo # Run with --myisam-recover=force option.
|
--echo # Run with --myisam-recover=force option.
|
||||||
--echo #
|
--echo #
|
||||||
--echo # Preparation: we need to make sure that the merge parent
|
--echo # Preparation: we need to make sure that the merge parent
|
||||||
@@ -111,3 +115,66 @@ set @@global.table_open_cache=default;
|
|||||||
disconnect con1;
|
disconnect con1;
|
||||||
connection default;
|
connection default;
|
||||||
--enable_ps_protocol
|
--enable_ps_protocol
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # 18075170 - sql node restart required to avoid deadlock after
|
||||||
|
--echo # restore
|
||||||
|
--echo #
|
||||||
|
--echo # Check that auto-repair for MyISAM tables can now happen in the
|
||||||
|
--echo # middle of transaction, without aborting it.
|
||||||
|
--enable_prepare_warnings
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
|
||||||
|
create table t1 (a int, key(a)) engine=myisam;
|
||||||
|
create table t2 (a int);
|
||||||
|
insert into t2 values (1);
|
||||||
|
|
||||||
|
--echo # Create a table with a corrupted index file:
|
||||||
|
--echo # save an old index file, insert more rows,
|
||||||
|
--echo # overwrite the new index file with the old one.
|
||||||
|
insert into t1 (a) values (1);
|
||||||
|
flush table t1;
|
||||||
|
--copy_file $MYSQLD_DATADIR/test/t1.MYI $MYSQLD_DATADIR/test/t1_copy.MYI
|
||||||
|
insert into t1 (a) values (4);
|
||||||
|
flush table t1;
|
||||||
|
--remove_file $MYSQLD_DATADIR/test/t1.MYI
|
||||||
|
--copy_file $MYSQLD_DATADIR/test/t1_copy.MYI $MYSQLD_DATADIR/test/t1.MYI
|
||||||
|
--remove_file $MYSQLD_DATADIR/test/t1_copy.MYI
|
||||||
|
|
||||||
|
--echo # Check table is needed to mark the table as crashed.
|
||||||
|
check table t1;
|
||||||
|
|
||||||
|
--echo # At this point we have a corrupt t1
|
||||||
|
set autocommit = 0;
|
||||||
|
select * from t2;
|
||||||
|
--echo # Without fix select from t1 will break the transaction. After the fix
|
||||||
|
--echo # transaction should be active and should hold lock on table t2. Alter
|
||||||
|
--echo # table from con2 will wait only if the transaction is not broken.
|
||||||
|
--replace_regex /'.*[\/\\]/'/
|
||||||
|
select * from t1;
|
||||||
|
|
||||||
|
connect(con2, localhost, root);
|
||||||
|
--SEND ALTER TABLE t2 ADD val INT
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
--echo # With fix we should have alter table waiting for t2 lock here.
|
||||||
|
let $wait_condition=
|
||||||
|
SELECT count(*) = 1 FROM information_schema.processlist WHERE state
|
||||||
|
LIKE "Waiting%" AND info = "ALTER TABLE t2 ADD val INT";
|
||||||
|
|
||||||
|
--source include/wait_condition.inc
|
||||||
|
ROLLBACK;
|
||||||
|
SET autocommit = 1;
|
||||||
|
|
||||||
|
connection con2;
|
||||||
|
--REAP
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
disconnect con2;
|
||||||
|
|
||||||
|
--echo # Cleanup
|
||||||
|
drop table t1, t2;
|
||||||
|
|
||||||
|
# Wait till all disconnects are completed
|
||||||
|
-- source include/wait_until_count_sessions.inc
|
@@ -14,7 +14,6 @@ file_exists $MYSQLD_DATADIR/mysql_upgrade_info;
|
|||||||
|
|
||||||
--echo Run it again - should say already completed
|
--echo Run it again - should say already completed
|
||||||
--replace_result $MYSQL_SERVER_VERSION VERSION
|
--replace_result $MYSQL_SERVER_VERSION VERSION
|
||||||
--error 1
|
|
||||||
--exec $MYSQL_UPGRADE 2>&1
|
--exec $MYSQL_UPGRADE 2>&1
|
||||||
|
|
||||||
# It should have created a file in the MySQL Servers datadir
|
# It should have created a file in the MySQL Servers datadir
|
||||||
|
187
mysql-test/t/sp-group.test
Normal file
187
mysql-test/t/sp-group.test
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
--source include/have_innodb.inc
|
||||||
|
|
||||||
|
drop table if exists t1;
|
||||||
|
drop view if exists view_t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test case for MDEV 7601, MDEV-7594 and MDEV-7555
|
||||||
|
# Server crashes in functions related to stored procedures
|
||||||
|
# Server crashes in different ways while executing concurrent
|
||||||
|
# flow involving views and non-empty sql_mode with ONLY_FULL_GROUP_BY
|
||||||
|
#
|
||||||
|
|
||||||
|
SET sql_mode=ONLY_FULL_GROUP_BY;
|
||||||
|
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
pk INT,
|
||||||
|
f0 INT, f1 INT, f2 INT, f3 INT, f4 INT,
|
||||||
|
f5 INT, f6 INT, f7 INT, f8 INT, f9 INT,
|
||||||
|
PRIMARY KEY (pk)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE VIEW view_t1 AS SELECT * FROM t1;
|
||||||
|
CREATE PROCEDURE s1()
|
||||||
|
SELECT * FROM (
|
||||||
|
INFORMATION_SCHEMA.`INNODB_BUFFER_PAGE_LRU` AS table1
|
||||||
|
LEFT JOIN test.view_t1 AS table2
|
||||||
|
ON ( table2.`f6` = table1.FREE_PAGE_CLOCK)
|
||||||
|
)
|
||||||
|
ORDER BY table1.NUMBER_RECORDS
|
||||||
|
LIMIT 0
|
||||||
|
;
|
||||||
|
CALL s1;
|
||||||
|
CALL s1;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
drop view view_t1;
|
||||||
|
drop procedure s1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# MDEV-7590
|
||||||
|
# Server crashes in st_select_lex_unit::cleanup on executing a trigger
|
||||||
|
#
|
||||||
|
|
||||||
|
CREATE TABLE A (
|
||||||
|
pk INTEGER AUTO_INCREMENT,
|
||||||
|
col_int_key INTEGER,
|
||||||
|
col_varchar_key VARCHAR(1),
|
||||||
|
PRIMARY KEY (pk)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_A AS SELECT * FROM A;
|
||||||
|
CREATE TABLE C (
|
||||||
|
pk INTEGER AUTO_INCREMENT,
|
||||||
|
col_int_nokey INTEGER,
|
||||||
|
col_int_key INTEGER,
|
||||||
|
col_date_key DATE,
|
||||||
|
col_date_nokey DATE,
|
||||||
|
col_time_key TIME,
|
||||||
|
col_time_nokey TIME,
|
||||||
|
col_datetime_key DATETIME,
|
||||||
|
col_datetime_nokey DATETIME,
|
||||||
|
col_varchar_key VARCHAR(1),
|
||||||
|
col_varchar_nokey VARCHAR(1),
|
||||||
|
PRIMARY KEY (pk)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_C AS SELECT * FROM C;
|
||||||
|
CREATE TABLE AA (
|
||||||
|
pk INTEGER AUTO_INCREMENT,
|
||||||
|
col_int_nokey INTEGER,
|
||||||
|
col_int_key INTEGER,
|
||||||
|
col_date_key DATE,
|
||||||
|
col_date_nokey DATE,
|
||||||
|
col_time_key TIME,
|
||||||
|
col_time_nokey TIME,
|
||||||
|
col_datetime_key DATETIME,
|
||||||
|
col_datetime_nokey DATETIME,
|
||||||
|
col_varchar_key VARCHAR(1),
|
||||||
|
col_varchar_nokey VARCHAR(1),
|
||||||
|
PRIMARY KEY (pk),
|
||||||
|
KEY (col_varchar_key, col_int_key)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_AA AS SELECT * FROM AA;
|
||||||
|
CREATE TABLE BB (
|
||||||
|
pk INTEGER AUTO_INCREMENT,
|
||||||
|
col_int_key INTEGER,
|
||||||
|
col_varchar_key VARCHAR(1),
|
||||||
|
col_varchar_nokey VARCHAR(1),
|
||||||
|
PRIMARY KEY (pk),
|
||||||
|
KEY (col_varchar_key, col_int_key)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_BB AS SELECT * FROM BB;
|
||||||
|
CREATE TABLE DD (
|
||||||
|
pk INTEGER AUTO_INCREMENT,
|
||||||
|
col_int_key INTEGER,
|
||||||
|
col_date_key DATE,
|
||||||
|
col_time_key TIME,
|
||||||
|
col_datetime_key DATETIME,
|
||||||
|
col_varchar_key VARCHAR(1),
|
||||||
|
PRIMARY KEY (pk),
|
||||||
|
KEY (col_varchar_key, col_int_key)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
CREATE VIEW view_DD AS SELECT * FROM DD;
|
||||||
|
CREATE TRIGGER k BEFORE INSERT ON `DD` FOR EACH ROW INSERT INTO `view_BB` SELECT * FROM `view_A` LIMIT 0 ;
|
||||||
|
CREATE TRIGGER r BEFORE INSERT ON `A` FOR EACH ROW INSERT INTO `view_AA` SELECT * FROM `view_C` LIMIT 0 ;
|
||||||
|
--error ER_WRONG_AUTO_KEY
|
||||||
|
ALTER TABLE `DD` DROP PRIMARY KEY;
|
||||||
|
INSERT INTO `view_A` ( `pk` ) VALUES (NULL);
|
||||||
|
--error 0,ER_WRONG_VALUE_COUNT_ON_ROW
|
||||||
|
INSERT INTO `DD` ( `pk` ) VALUES (NULL);
|
||||||
|
INSERT INTO `A` ( `pk` ) VALUES (NULL);
|
||||||
|
--error 0,ER_WRONG_VALUE_COUNT_ON_ROW
|
||||||
|
INSERT INTO `view_DD` ( `pk` ) VALUES (NULL);
|
||||||
|
|
||||||
|
drop trigger r;
|
||||||
|
drop trigger k;
|
||||||
|
drop view view_A,view_AA,view_C,view_BB,view_DD;
|
||||||
|
drop table A,C,AA,BB,DD;
|
||||||
|
|
||||||
|
#
|
||||||
|
# MDEV-7581
|
||||||
|
# Server crashes in st_select_lex_unit::cleanup after a sequence of statements
|
||||||
|
#
|
||||||
|
|
||||||
|
CREATE TABLE A (
|
||||||
|
i INT,
|
||||||
|
i1 INT,
|
||||||
|
i2 INT,
|
||||||
|
d1 DATE,
|
||||||
|
d2 DATE,
|
||||||
|
col_time_nokey1 TIME,
|
||||||
|
col_time_nokey2 TIME,
|
||||||
|
col_datetime_nokey1 DATETIME,
|
||||||
|
col_datetime_nokey2 DATETIME,
|
||||||
|
col_varchar_nokey1 VARCHAR(1),
|
||||||
|
col_varchar_nokey2 VARCHAR(1)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
|
||||||
|
CREATE VIEW view_A AS SELECT * FROM A;
|
||||||
|
|
||||||
|
CREATE TABLE B (
|
||||||
|
col_varchar_nokey VARCHAR(1)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
|
||||||
|
CREATE TABLE AA (
|
||||||
|
i INT,
|
||||||
|
i1 INT,
|
||||||
|
i2 INT,
|
||||||
|
d1 DATE,
|
||||||
|
d2 DATE,
|
||||||
|
col_time_nokey1 TIME,
|
||||||
|
col_time_nokey2 TIME,
|
||||||
|
col_datetime_nokey1 DATETIME,
|
||||||
|
col_datetime_nokey2 DATETIME,
|
||||||
|
col_varchar_nokey1 VARCHAR(1),
|
||||||
|
col_varchar_nokey2 VARCHAR(1)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
|
||||||
|
CREATE VIEW view_AA AS SELECT * FROM AA;
|
||||||
|
|
||||||
|
CREATE TABLE DD (
|
||||||
|
i INT,
|
||||||
|
i1 INT,
|
||||||
|
i2 INT,
|
||||||
|
d1 DATE,
|
||||||
|
d2 DATE,
|
||||||
|
col_time_nokey1 TIME,
|
||||||
|
col_time_nokey2 TIME,
|
||||||
|
col_datetime_nokey1 DATETIME,
|
||||||
|
col_datetime_nokey2 DATETIME,
|
||||||
|
col_varchar_nokey1 VARCHAR(1),
|
||||||
|
col_varchar_nokey2 VARCHAR(1)
|
||||||
|
) ENGINE=MyISAM;
|
||||||
|
|
||||||
|
CREATE VIEW view_DD AS SELECT * FROM DD;
|
||||||
|
|
||||||
|
CREATE TRIGGER tr1 BEFORE INSERT ON `AA` FOR EACH ROW INSERT INTO `view_A` SELECT * FROM `view_AA` LIMIT 0 ;
|
||||||
|
CREATE TRIGGER tr2 BEFORE INSERT ON `B` FOR EACH ROW INSERT INTO `D` SELECT * FROM `A` LIMIT 0 ;
|
||||||
|
|
||||||
|
INSERT INTO `view_AA` ( `i` ) VALUES (1);
|
||||||
|
INSERT INTO `AA` ( `i` ) VALUES (2);
|
||||||
|
DELETE FROM `B`;
|
||||||
|
INSERT INTO `view_DD` ( `i` ) VALUES (1);
|
||||||
|
INSERT INTO `view_AA` ( `i` ) VALUES (3);
|
||||||
|
|
||||||
|
drop trigger tr1;
|
||||||
|
drop trigger tr2;
|
||||||
|
drop view view_A, view_AA,view_DD;
|
||||||
|
drop table A,B,AA,DD;
|
@@ -1841,5 +1841,20 @@ drop database mysqltest2;
|
|||||||
drop database mysqltest3;
|
drop database mysqltest3;
|
||||||
drop database mysqltest4;
|
drop database mysqltest4;
|
||||||
|
|
||||||
--echo # End of 5.5 tests
|
--echo #
|
||||||
|
--echo # MDEV-7810 Wrong result on execution of a query as a PS
|
||||||
|
--echo # (both 1st and further executions)
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a INT NOT NULL) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t1 VALUES (0),(8);
|
||||||
|
|
||||||
|
SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2));
|
||||||
|
PREPARE stmt FROM "
|
||||||
|
SELECT a FROM (SELECT DISTINCT * FROM t1) AS sq WHERE a IN (SELECT MIN(t2.a) FROM (t1 AS t2))
|
||||||
|
";
|
||||||
|
execute stmt;
|
||||||
|
execute stmt;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
--echo # End of 5.5 tests
|
||||||
|
@@ -5380,6 +5380,27 @@ show create view v2;
|
|||||||
drop view v2;
|
drop view v2;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-8554: Server crashes in base_list_iterator::next_fast on 1st execution of PS with a multi-table update
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1 (a INT) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t1 VALUES (1),(2); # Not necessary, the table can be empty
|
||||||
|
|
||||||
|
CREATE TABLE t2 (b INT) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t2 VALUES (3),(4); # Not necessary, the table can be empty
|
||||||
|
|
||||||
|
CREATE TABLE t3 (c INT) ENGINE=MyISAM;
|
||||||
|
INSERT INTO t3 VALUES (5),(6); # Not necessary, the table can be empty
|
||||||
|
|
||||||
|
CREATE OR REPLACE ALGORITHM=MERGE VIEW v3 AS SELECT * FROM t3;
|
||||||
|
|
||||||
|
PREPARE stmt FROM 'UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM t3 )';
|
||||||
|
UPDATE t1, t2 SET a = 1 WHERE a IN ( SELECT 0 FROM v3 );
|
||||||
|
EXECUTE stmt;
|
||||||
|
|
||||||
|
DROP TABLE t1, t2, t3;
|
||||||
|
DROP VIEW v3;
|
||||||
|
|
||||||
--echo # -----------------------------------------------------------------
|
--echo # -----------------------------------------------------------------
|
||||||
--echo # -- End of 5.5 tests.
|
--echo # -- End of 5.5 tests.
|
||||||
--echo # -----------------------------------------------------------------
|
--echo # -----------------------------------------------------------------
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -91,6 +91,7 @@ static int ptr_compare(size_t *compare_length, uchar **a, uchar **b)
|
|||||||
reg3 int length= *compare_length;
|
reg3 int length= *compare_length;
|
||||||
reg1 uchar *first,*last;
|
reg1 uchar *first,*last;
|
||||||
|
|
||||||
|
DBUG_ASSERT(length > 0);
|
||||||
first= *a; last= *b;
|
first= *a; last= *b;
|
||||||
while (--length)
|
while (--length)
|
||||||
{
|
{
|
||||||
|
@@ -1,3 +1,11 @@
|
|||||||
|
/* Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved.
|
||||||
|
See file COPYRIGHT for details.
|
||||||
|
|
||||||
|
This file was modified by Oracle on 2015-05-18 for 32-bit compatibility.
|
||||||
|
|
||||||
|
Modifications copyright (c) 2015, Oracle and/or its affiliates. All rights
|
||||||
|
reserved. */
|
||||||
|
|
||||||
#include <my_global.h>
|
#include <my_global.h>
|
||||||
#include <m_string.h>
|
#include <m_string.h>
|
||||||
#include <m_ctype.h>
|
#include <m_ctype.h>
|
||||||
@@ -133,12 +141,26 @@ CHARSET_INFO *charset;
|
|||||||
} else
|
} else
|
||||||
len = strlen((char *)pattern);
|
len = strlen((char *)pattern);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find the maximum len we can safely process
|
||||||
|
without a rollover and a mis-malloc.
|
||||||
|
p->ssize is a sopno is a long (32+ bit signed);
|
||||||
|
size_t is 16+ bit unsigned.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
size_t new_ssize = len / (size_t)2 * (size_t)3 + (size_t)1; /* ugh */
|
||||||
|
if ((new_ssize < len) || /* size_t rolled over */
|
||||||
|
((SIZE_T_MAX / sizeof(sop)) < new_ssize) || /* malloc arg */
|
||||||
|
(new_ssize > LONG_MAX)) /* won't fit in ssize */
|
||||||
|
return(REG_ESPACE); /* MY_REG_ESPACE or MY_REG_INVARG */
|
||||||
|
p->ssize = new_ssize;
|
||||||
|
}
|
||||||
|
|
||||||
/* do the mallocs early so failure handling is easy */
|
/* do the mallocs early so failure handling is easy */
|
||||||
g = (struct re_guts *)malloc(sizeof(struct re_guts) +
|
g = (struct re_guts *)malloc(sizeof(struct re_guts) +
|
||||||
(NC-1)*sizeof(cat_t));
|
(NC-1)*sizeof(cat_t));
|
||||||
if (g == NULL)
|
if (g == NULL)
|
||||||
return(REG_ESPACE);
|
return(REG_ESPACE);
|
||||||
p->ssize = (long) (len/(size_t)2*(size_t)3 + (size_t)1); /* ugh */
|
|
||||||
p->strip = (sop *)malloc(p->ssize * sizeof(sop));
|
p->strip = (sop *)malloc(p->ssize * sizeof(sop));
|
||||||
p->slen = 0;
|
p->slen = 0;
|
||||||
if (p->strip == NULL) {
|
if (p->strip == NULL) {
|
||||||
|
@@ -7612,7 +7612,8 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Field_blob::store_length(length);
|
Field_blob::store_length(length);
|
||||||
if (table->copy_blobs || length <= MAX_FIELD_WIDTH)
|
if ((table->copy_blobs || length <= MAX_FIELD_WIDTH) &&
|
||||||
|
from != value.ptr())
|
||||||
{ // Must make a copy
|
{ // Must make a copy
|
||||||
value.copy(from, length, cs);
|
value.copy(from, length, cs);
|
||||||
from= value.ptr();
|
from= value.ptr();
|
||||||
|
58
sql/item.cc
58
sql/item.cc
@@ -1146,18 +1146,24 @@ Item *Item::safe_charset_converter(CHARSET_INFO *tocs)
|
|||||||
because Item_singlerow_subselect later calls Item_cache-specific methods,
|
because Item_singlerow_subselect later calls Item_cache-specific methods,
|
||||||
e.g. row[i]->store() and row[i]->cache_value().
|
e.g. row[i]->store() and row[i]->cache_value().
|
||||||
|
|
||||||
Let's wrap Item_func_conv_charset to a new Item_cache,
|
Let's wrap Item_func_conv_charset in a new Item_cache,
|
||||||
so the Item_cache-specific methods can still be used for
|
so the Item_cache-specific methods can still be used for
|
||||||
Item_singlerow_subselect::row[i] safely.
|
Item_singlerow_subselect::row[i] safely.
|
||||||
|
|
||||||
|
As a bonus we cache the converted value, instead of converting every time
|
||||||
|
|
||||||
TODO: we should eventually check all other use cases of change_item_tree().
|
TODO: we should eventually check all other use cases of change_item_tree().
|
||||||
Perhaps some more potentially dangerous substitution examples exist.
|
Perhaps some more potentially dangerous substitution examples exist.
|
||||||
*/
|
*/
|
||||||
Item *Item_cache::safe_charset_converter(CHARSET_INFO *tocs)
|
Item *Item_cache::safe_charset_converter(CHARSET_INFO *tocs)
|
||||||
{
|
{
|
||||||
Item_func_conv_charset *conv= new Item_func_conv_charset(example, tocs, 1);
|
if (!example)
|
||||||
|
return Item::safe_charset_converter(tocs);
|
||||||
|
Item *conv= example->safe_charset_converter(tocs);
|
||||||
|
if (conv == example)
|
||||||
|
return this;
|
||||||
Item_cache *cache;
|
Item_cache *cache;
|
||||||
if (!conv || !conv->safe || !(cache= new Item_cache_str(conv)))
|
if (!conv || !(cache= new Item_cache_str(conv)))
|
||||||
return NULL; // Safe conversion is not possible, or OEM
|
return NULL; // Safe conversion is not possible, or OEM
|
||||||
cache->setup(conv);
|
cache->setup(conv);
|
||||||
cache->fixed= false; // Make Item::fix_fields() happy
|
cache->fixed= false; // Make Item::fix_fields() happy
|
||||||
@@ -4408,19 +4414,24 @@ bool Item_ref_null_helper::get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
|
|||||||
static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
|
static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
|
||||||
Item_ident *resolved_item,
|
Item_ident *resolved_item,
|
||||||
Item_ident *mark_item)
|
Item_ident *mark_item)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("mark_as_dependent");
|
||||||
|
|
||||||
|
/* store pointer on SELECT_LEX from which item is dependent */
|
||||||
|
if (mark_item && mark_item->can_be_depended)
|
||||||
|
{
|
||||||
|
DBUG_PRINT("info", ("mark_item: %p lex: %p", mark_item, last));
|
||||||
|
mark_item->depended_from= last;
|
||||||
|
}
|
||||||
|
if (current->mark_as_dependent(thd, last,
|
||||||
|
/** resolved_item psergey-thu **/ mark_item))
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
if (thd->lex->describe & DESCRIBE_EXTENDED)
|
||||||
{
|
{
|
||||||
const char *db_name= (resolved_item->db_name ?
|
const char *db_name= (resolved_item->db_name ?
|
||||||
resolved_item->db_name : "");
|
resolved_item->db_name : "");
|
||||||
const char *table_name= (resolved_item->table_name ?
|
const char *table_name= (resolved_item->table_name ?
|
||||||
resolved_item->table_name : "");
|
resolved_item->table_name : "");
|
||||||
/* store pointer on SELECT_LEX from which item is dependent */
|
|
||||||
if (mark_item && mark_item->can_be_depended)
|
|
||||||
mark_item->depended_from= last;
|
|
||||||
if (current->mark_as_dependent(thd, last, /** resolved_item psergey-thu
|
|
||||||
**/mark_item))
|
|
||||||
return TRUE;
|
|
||||||
if (thd->lex->describe & DESCRIBE_EXTENDED)
|
|
||||||
{
|
|
||||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||||
ER_WARN_FIELD_RESOLVED, ER(ER_WARN_FIELD_RESOLVED),
|
ER_WARN_FIELD_RESOLVED, ER(ER_WARN_FIELD_RESOLVED),
|
||||||
db_name, (db_name[0] ? "." : ""),
|
db_name, (db_name[0] ? "." : ""),
|
||||||
@@ -4428,7 +4439,7 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
|
|||||||
resolved_item->field_name,
|
resolved_item->field_name,
|
||||||
current->select_number, last->select_number);
|
current->select_number, last->select_number);
|
||||||
}
|
}
|
||||||
return FALSE;
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4877,7 +4888,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
|
|||||||
non aggregated fields of the outer select.
|
non aggregated fields of the outer select.
|
||||||
*/
|
*/
|
||||||
marker= select->cur_pos_in_select_list;
|
marker= select->cur_pos_in_select_list;
|
||||||
select->non_agg_fields.push_back(this);
|
select->join->non_agg_fields.push_back(this);
|
||||||
}
|
}
|
||||||
if (*from_field != view_ref_found)
|
if (*from_field != view_ref_found)
|
||||||
{
|
{
|
||||||
@@ -5293,9 +5304,10 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
|
|||||||
fixed= 1;
|
fixed= 1;
|
||||||
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
|
if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
|
||||||
!outer_fixed && !thd->lex->in_sum_func &&
|
!outer_fixed && !thd->lex->in_sum_func &&
|
||||||
thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS)
|
thd->lex->current_select->cur_pos_in_select_list != UNDEF_POS &&
|
||||||
|
thd->lex->current_select->join)
|
||||||
{
|
{
|
||||||
thd->lex->current_select->non_agg_fields.push_back(this);
|
thd->lex->current_select->join->non_agg_fields.push_back(this);
|
||||||
marker= thd->lex->current_select->cur_pos_in_select_list;
|
marker= thd->lex->current_select->cur_pos_in_select_list;
|
||||||
}
|
}
|
||||||
mark_non_agg_field:
|
mark_non_agg_field:
|
||||||
@@ -6742,7 +6754,7 @@ Item_ref::Item_ref(Name_resolution_context *context_arg,
|
|||||||
/*
|
/*
|
||||||
This constructor used to create some internals references over fixed items
|
This constructor used to create some internals references over fixed items
|
||||||
*/
|
*/
|
||||||
if (ref && *ref && (*ref)->fixed)
|
if ((set_properties_only= (ref && *ref && (*ref)->fixed)))
|
||||||
set_properties();
|
set_properties();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6786,7 +6798,7 @@ Item_ref::Item_ref(TABLE_LIST *view_arg, Item **item,
|
|||||||
/*
|
/*
|
||||||
This constructor is used to create some internal references over fixed items
|
This constructor is used to create some internal references over fixed items
|
||||||
*/
|
*/
|
||||||
if (ref && *ref && (*ref)->fixed)
|
if ((set_properties_only= (ref && *ref && (*ref)->fixed)))
|
||||||
set_properties();
|
set_properties();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6861,7 +6873,11 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||||||
DBUG_ASSERT(fixed == 0);
|
DBUG_ASSERT(fixed == 0);
|
||||||
SELECT_LEX *current_sel= thd->lex->current_select;
|
SELECT_LEX *current_sel= thd->lex->current_select;
|
||||||
|
|
||||||
if (!ref || ref == not_found_item)
|
if (set_properties_only)
|
||||||
|
{
|
||||||
|
/* do nothing */
|
||||||
|
}
|
||||||
|
else if (!ref || ref == not_found_item)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(reference_trough_name != 0);
|
DBUG_ASSERT(reference_trough_name != 0);
|
||||||
if (!(ref= resolve_ref_in_select_and_group(thd, this,
|
if (!(ref= resolve_ref_in_select_and_group(thd, this,
|
||||||
@@ -6879,7 +6895,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||||||
{
|
{
|
||||||
/* The current reference cannot be resolved in this query. */
|
/* The current reference cannot be resolved in this query. */
|
||||||
my_error(ER_BAD_FIELD_ERROR,MYF(0),
|
my_error(ER_BAD_FIELD_ERROR,MYF(0),
|
||||||
this->full_name(), current_thd->where);
|
this->full_name(), thd->where);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7014,7 +7030,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||||||
goto error;
|
goto error;
|
||||||
thd->change_item_tree(reference, fld);
|
thd->change_item_tree(reference, fld);
|
||||||
mark_as_dependent(thd, last_checked_context->select_lex,
|
mark_as_dependent(thd, last_checked_context->select_lex,
|
||||||
thd->lex->current_select, fld, fld);
|
current_sel, fld, fld);
|
||||||
/*
|
/*
|
||||||
A reference is resolved to a nest level that's outer or the same as
|
A reference is resolved to a nest level that's outer or the same as
|
||||||
the nest level of the enclosing set function : adjust the value of
|
the nest level of the enclosing set function : adjust the value of
|
||||||
@@ -7031,7 +7047,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
|
|||||||
{
|
{
|
||||||
/* The item was not a table field and not a reference */
|
/* The item was not a table field and not a reference */
|
||||||
my_error(ER_BAD_FIELD_ERROR, MYF(0),
|
my_error(ER_BAD_FIELD_ERROR, MYF(0),
|
||||||
this->full_name(), current_thd->where);
|
this->full_name(), thd->where);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
/* Should be checked in resolve_ref_in_select_and_group(). */
|
/* Should be checked in resolve_ref_in_select_and_group(). */
|
||||||
|
@@ -631,7 +631,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
uint name_length; /* Length of name */
|
uint name_length; /* Length of name */
|
||||||
uint decimals;
|
uint decimals;
|
||||||
int8 marker;
|
int marker;
|
||||||
bool maybe_null; /* If item may be null */
|
bool maybe_null; /* If item may be null */
|
||||||
bool in_rollup; /* If used in GROUP BY list
|
bool in_rollup; /* If used in GROUP BY list
|
||||||
of a query with ROLLUP */
|
of a query with ROLLUP */
|
||||||
@@ -2946,6 +2946,7 @@ class Item_ref :public Item_ident
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
void set_properties();
|
void set_properties();
|
||||||
|
bool set_properties_only; // the item doesn't need full fix_fields
|
||||||
public:
|
public:
|
||||||
enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF, AGGREGATE_REF };
|
enum Ref_Type { REF, DIRECT_REF, VIEW_REF, OUTER_REF, AGGREGATE_REF };
|
||||||
Field *result_field; /* Save result here */
|
Field *result_field; /* Save result here */
|
||||||
@@ -2955,7 +2956,7 @@ public:
|
|||||||
const char *db_arg, const char *table_name_arg,
|
const char *db_arg, const char *table_name_arg,
|
||||||
const char *field_name_arg)
|
const char *field_name_arg)
|
||||||
:Item_ident(context_arg, db_arg, table_name_arg, field_name_arg),
|
:Item_ident(context_arg, db_arg, table_name_arg, field_name_arg),
|
||||||
result_field(0), ref(0), reference_trough_name(1) {}
|
set_properties_only(0), result_field(0), ref(0), reference_trough_name(1) {}
|
||||||
/*
|
/*
|
||||||
This constructor is used in two scenarios:
|
This constructor is used in two scenarios:
|
||||||
A) *item = NULL
|
A) *item = NULL
|
||||||
@@ -2978,7 +2979,7 @@ public:
|
|||||||
|
|
||||||
/* Constructor need to process subselect with temporary tables (see Item) */
|
/* Constructor need to process subselect with temporary tables (see Item) */
|
||||||
Item_ref(THD *thd, Item_ref *item)
|
Item_ref(THD *thd, Item_ref *item)
|
||||||
:Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {}
|
:Item_ident(thd, item), set_properties_only(0), result_field(item->result_field), ref(item->ref) {}
|
||||||
enum Type type() const { return REF_ITEM; }
|
enum Type type() const { return REF_ITEM; }
|
||||||
enum Type real_type() const { return ref ? (*ref)->type() :
|
enum Type real_type() const { return ref ? (*ref)->type() :
|
||||||
REF_ITEM; }
|
REF_ITEM; }
|
||||||
|
@@ -4196,7 +4196,25 @@ longlong Item_func_get_lock::val_int()
|
|||||||
it's not guaranteed to be same as on master.
|
it's not guaranteed to be same as on master.
|
||||||
*/
|
*/
|
||||||
if (thd->slave_thread)
|
if (thd->slave_thread)
|
||||||
|
{
|
||||||
|
null_value= 0;
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[1]->null_value ||
|
||||||
|
(!args[1]->unsigned_flag && ((longlong) timeout < 0)))
|
||||||
|
{
|
||||||
|
char buf[22];
|
||||||
|
if (args[1]->null_value)
|
||||||
|
strmov(buf, "NULL");
|
||||||
|
else
|
||||||
|
llstr(((longlong) timeout), buf);
|
||||||
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||||
|
ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE),
|
||||||
|
"timeout", buf, "get_lock");
|
||||||
|
null_value= 1;
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
mysql_mutex_lock(&LOCK_user_locks);
|
mysql_mutex_lock(&LOCK_user_locks);
|
||||||
|
|
||||||
|
@@ -464,6 +464,7 @@ void Item_subselect::recalc_used_tables(st_select_lex *new_parent,
|
|||||||
{
|
{
|
||||||
List_iterator<Ref_to_outside> it(upper_refs);
|
List_iterator<Ref_to_outside> it(upper_refs);
|
||||||
Ref_to_outside *upper;
|
Ref_to_outside *upper;
|
||||||
|
DBUG_ENTER("recalc_used_tables");
|
||||||
|
|
||||||
used_tables_cache= 0;
|
used_tables_cache= 0;
|
||||||
while ((upper= it++))
|
while ((upper= it++))
|
||||||
@@ -523,6 +524,8 @@ void Item_subselect::recalc_used_tables(st_select_lex *new_parent,
|
|||||||
he has done const table detection, and that will be our chance to update
|
he has done const table detection, and that will be our chance to update
|
||||||
const_tables_cache.
|
const_tables_cache.
|
||||||
*/
|
*/
|
||||||
|
DBUG_PRINT("exit", ("used_tables_cache: %llx", used_tables_cache));
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1999,7 +2002,6 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN * join,
|
|||||||
during JOIN::optimize: this->tmp_having= this->having; this->having= 0;
|
during JOIN::optimize: this->tmp_having= this->having; this->having= 0;
|
||||||
*/
|
*/
|
||||||
Item* join_having= join->having ? join->having : join->tmp_having;
|
Item* join_having= join->having ? join->having : join->tmp_having;
|
||||||
|
|
||||||
DBUG_ENTER("Item_in_subselect::create_single_in_to_exists_cond");
|
DBUG_ENTER("Item_in_subselect::create_single_in_to_exists_cond");
|
||||||
|
|
||||||
*where_item= NULL;
|
*where_item= NULL;
|
||||||
|
@@ -3514,9 +3514,17 @@ bool Item_func_group_concat::setup(THD *thd)
|
|||||||
"all_fields". The resulting field list is used as input to create
|
"all_fields". The resulting field list is used as input to create
|
||||||
tmp table columns.
|
tmp table columns.
|
||||||
*/
|
*/
|
||||||
if (arg_count_order &&
|
if (arg_count_order)
|
||||||
setup_order(thd, args, context->table_list, list, all_fields, *order))
|
{
|
||||||
|
uint n_elems= arg_count_order + all_fields.elements;
|
||||||
|
ref_pointer_array= static_cast<Item**>(thd->alloc(sizeof(Item*) * n_elems));
|
||||||
|
if (!ref_pointer_array)
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
|
memcpy(ref_pointer_array, args, arg_count * sizeof(Item*));
|
||||||
|
if (setup_order(thd, ref_pointer_array, context->table_list, list,
|
||||||
|
all_fields, *order))
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
count_field_types(select_lex, tmp_table_param, all_fields, 0);
|
count_field_types(select_lex, tmp_table_param, all_fields, 0);
|
||||||
tmp_table_param->force_copy_fields= force_copy_fields;
|
tmp_table_param->force_copy_fields= force_copy_fields;
|
||||||
|
@@ -1394,6 +1394,7 @@ class Item_func_group_concat : public Item_sum
|
|||||||
String *separator;
|
String *separator;
|
||||||
TREE tree_base;
|
TREE tree_base;
|
||||||
TREE *tree;
|
TREE *tree;
|
||||||
|
Item **ref_pointer_array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
If DISTINCT is used with this GROUP_CONCAT, this member is used to filter
|
If DISTINCT is used with this GROUP_CONCAT, this member is used to filter
|
||||||
|
25
sql/log.cc
25
sql/log.cc
@@ -3778,6 +3778,7 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
|
|||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
char *to_purge_if_included= NULL;
|
char *to_purge_if_included= NULL;
|
||||||
|
ulonglong log_space_reclaimed= 0;
|
||||||
DBUG_ENTER("purge_first_log");
|
DBUG_ENTER("purge_first_log");
|
||||||
|
|
||||||
DBUG_ASSERT(is_open());
|
DBUG_ASSERT(is_open());
|
||||||
@@ -3826,17 +3827,13 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
|
|||||||
|
|
||||||
DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_SUICIDE(););
|
DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_SUICIDE(););
|
||||||
|
|
||||||
mysql_mutex_lock(&rli->log_space_lock);
|
|
||||||
rli->relay_log.purge_logs(to_purge_if_included, included,
|
rli->relay_log.purge_logs(to_purge_if_included, included,
|
||||||
0, 0, &rli->log_space_total);
|
0, 0, &log_space_reclaimed);
|
||||||
mysql_mutex_unlock(&rli->log_space_lock);
|
|
||||||
|
|
||||||
/*
|
mysql_mutex_lock(&rli->log_space_lock);
|
||||||
Ok to broadcast after the critical region as there is no risk of
|
rli->log_space_total-= log_space_reclaimed;
|
||||||
the mutex being destroyed by this thread later - this helps save
|
|
||||||
context switches
|
|
||||||
*/
|
|
||||||
mysql_cond_broadcast(&rli->log_space_cond);
|
mysql_cond_broadcast(&rli->log_space_cond);
|
||||||
|
mysql_mutex_unlock(&rli->log_space_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need to update the log pos because purge logs has been called
|
* Need to update the log pos because purge logs has been called
|
||||||
@@ -3885,7 +3882,7 @@ int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads
|
|||||||
@param need_mutex
|
@param need_mutex
|
||||||
@param need_update_threads If we want to update the log coordinates of
|
@param need_update_threads If we want to update the log coordinates of
|
||||||
all threads. False for relay logs, true otherwise.
|
all threads. False for relay logs, true otherwise.
|
||||||
@param freed_log_space If not null, decrement this variable of
|
@param reclaimeed_log_space If not null, increment this variable to
|
||||||
the amount of log space freed
|
the amount of log space freed
|
||||||
|
|
||||||
@note
|
@note
|
||||||
@@ -3905,7 +3902,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
|
|||||||
bool included,
|
bool included,
|
||||||
bool need_mutex,
|
bool need_mutex,
|
||||||
bool need_update_threads,
|
bool need_update_threads,
|
||||||
ulonglong *decrease_log_space)
|
ulonglong *reclaimed_space)
|
||||||
{
|
{
|
||||||
int error= 0;
|
int error= 0;
|
||||||
bool exit_loop= 0;
|
bool exit_loop= 0;
|
||||||
@@ -3970,7 +3967,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
|
|||||||
err:
|
err:
|
||||||
/* Read each entry from purge_index_file and delete the file. */
|
/* Read each entry from purge_index_file and delete the file. */
|
||||||
if (is_inited_purge_index_file() &&
|
if (is_inited_purge_index_file() &&
|
||||||
(error= purge_index_entry(thd, decrease_log_space, FALSE)))
|
(error= purge_index_entry(thd, reclaimed_space, FALSE)))
|
||||||
sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files"
|
sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files"
|
||||||
" that would be purged.");
|
" that would be purged.");
|
||||||
close_purge_index_file();
|
close_purge_index_file();
|
||||||
@@ -4075,7 +4072,7 @@ int MYSQL_BIN_LOG::register_create_index_entry(const char *entry)
|
|||||||
DBUG_RETURN(register_purge_index_entry(entry));
|
DBUG_RETURN(register_purge_index_entry(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
|
int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *reclaimed_space,
|
||||||
bool need_mutex)
|
bool need_mutex)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry");
|
DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry");
|
||||||
@@ -4195,8 +4192,8 @@ int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
|
|||||||
DBUG_PRINT("info",("purging %s",log_info.log_file_name));
|
DBUG_PRINT("info",("purging %s",log_info.log_file_name));
|
||||||
if (!my_delete(log_info.log_file_name, MYF(0)))
|
if (!my_delete(log_info.log_file_name, MYF(0)))
|
||||||
{
|
{
|
||||||
if (decrease_log_space)
|
if (reclaimed_space)
|
||||||
*decrease_log_space-= s.st_size;
|
*reclaimed_space+= s.st_size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -1252,9 +1252,10 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
|
|||||||
}
|
}
|
||||||
data_len= uint4korr(buf + EVENT_LEN_OFFSET);
|
data_len= uint4korr(buf + EVENT_LEN_OFFSET);
|
||||||
if (data_len < LOG_EVENT_MINIMAL_HEADER_LEN ||
|
if (data_len < LOG_EVENT_MINIMAL_HEADER_LEN ||
|
||||||
data_len > current_thd->variables.max_allowed_packet)
|
data_len > max(current_thd->variables.max_allowed_packet,
|
||||||
|
opt_binlog_rows_event_max_size + MAX_LOG_EVENT_HEADER))
|
||||||
{
|
{
|
||||||
DBUG_PRINT("error",("data_len: %ld", data_len));
|
DBUG_PRINT("error",("data_len: %lu", data_len));
|
||||||
result= ((data_len < LOG_EVENT_MINIMAL_HEADER_LEN) ? LOG_READ_BOGUS :
|
result= ((data_len < LOG_EVENT_MINIMAL_HEADER_LEN) ? LOG_READ_BOGUS :
|
||||||
LOG_READ_TOO_LARGE);
|
LOG_READ_TOO_LARGE);
|
||||||
goto end;
|
goto end;
|
||||||
@@ -1375,7 +1376,7 @@ failed my_b_read"));
|
|||||||
*/
|
*/
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
|
ulong data_len = uint4korr(head + EVENT_LEN_OFFSET);
|
||||||
char *buf= 0;
|
char *buf= 0;
|
||||||
const char *error= 0;
|
const char *error= 0;
|
||||||
Log_event *res= 0;
|
Log_event *res= 0;
|
||||||
@@ -1384,7 +1385,8 @@ failed my_b_read"));
|
|||||||
uint max_allowed_packet= thd ? slave_max_allowed_packet:~(uint)0;
|
uint max_allowed_packet= thd ? slave_max_allowed_packet:~(uint)0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (data_len > max_allowed_packet)
|
if (data_len > max(max_allowed_packet,
|
||||||
|
opt_binlog_rows_event_max_size + MAX_LOG_EVENT_HEADER))
|
||||||
{
|
{
|
||||||
error = "Event too big";
|
error = "Event too big";
|
||||||
goto err;
|
goto err;
|
||||||
@@ -1418,7 +1420,7 @@ err:
|
|||||||
{
|
{
|
||||||
DBUG_ASSERT(error != 0);
|
DBUG_ASSERT(error != 0);
|
||||||
sql_print_error("Error in Log_event::read_log_event(): "
|
sql_print_error("Error in Log_event::read_log_event(): "
|
||||||
"'%s', data_len: %d, event_type: %d",
|
"'%s', data_len: %lu, event_type: %d",
|
||||||
error,data_len,head[EVENT_TYPE_OFFSET]);
|
error,data_len,head[EVENT_TYPE_OFFSET]);
|
||||||
my_free(buf);
|
my_free(buf);
|
||||||
/*
|
/*
|
||||||
|
@@ -2644,7 +2644,6 @@ void unlink_thd(THD *thd)
|
|||||||
thd->add_status_to_global();
|
thd->add_status_to_global();
|
||||||
|
|
||||||
mysql_mutex_lock(&LOCK_thread_count);
|
mysql_mutex_lock(&LOCK_thread_count);
|
||||||
thread_count--;
|
|
||||||
thd->unlink();
|
thd->unlink();
|
||||||
/*
|
/*
|
||||||
Used by binlog_reset_master. It would be cleaner to use
|
Used by binlog_reset_master. It would be cleaner to use
|
||||||
@@ -2652,6 +2651,16 @@ void unlink_thd(THD *thd)
|
|||||||
sync feature has been shut down at this point.
|
sync feature has been shut down at this point.
|
||||||
*/
|
*/
|
||||||
DBUG_EXECUTE_IF("sleep_after_lock_thread_count_before_delete_thd", sleep(5););
|
DBUG_EXECUTE_IF("sleep_after_lock_thread_count_before_delete_thd", sleep(5););
|
||||||
|
if (unlikely(abort_loop))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
During shutdown, we have to delete thd inside the mutex
|
||||||
|
to not refer to mutexes that may be deleted during shutdown
|
||||||
|
*/
|
||||||
|
delete thd;
|
||||||
|
thd= 0;
|
||||||
|
}
|
||||||
|
thread_count--;
|
||||||
mysql_mutex_unlock(&LOCK_thread_count);
|
mysql_mutex_unlock(&LOCK_thread_count);
|
||||||
|
|
||||||
delete thd;
|
delete thd;
|
||||||
|
@@ -38,8 +38,6 @@ typedef struct Trans_binlog_info {
|
|||||||
char log_file[FN_REFLEN];
|
char log_file[FN_REFLEN];
|
||||||
} Trans_binlog_info;
|
} Trans_binlog_info;
|
||||||
|
|
||||||
static pthread_key(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
|
|
||||||
|
|
||||||
int get_user_var_int(const char *name,
|
int get_user_var_int(const char *name,
|
||||||
long long int *value, int *null_value)
|
long long int *value, int *null_value)
|
||||||
{
|
{
|
||||||
@@ -143,13 +141,6 @@ int delegates_init()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pthread_key_create(&RPL_TRANS_BINLOG_INFO, NULL))
|
|
||||||
{
|
|
||||||
sql_print_error("Error while creating pthread specific data key for replication. "
|
|
||||||
"Please report a bug.");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,27 +186,27 @@ void delegates_destroy()
|
|||||||
int Trans_delegate::after_commit(THD *thd, bool all)
|
int Trans_delegate::after_commit(THD *thd, bool all)
|
||||||
{
|
{
|
||||||
Trans_param param;
|
Trans_param param;
|
||||||
|
Trans_binlog_info *log_info;
|
||||||
bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
|
bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
|
||||||
|
int ret= 0;
|
||||||
|
|
||||||
param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0;
|
param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0;
|
||||||
|
|
||||||
Trans_binlog_info *log_info=
|
log_info= thd->semisync_info;
|
||||||
my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
|
|
||||||
|
|
||||||
param.log_file= log_info ? log_info->log_file : 0;
|
param.log_file= log_info && log_info->log_file[0] ? log_info->log_file : 0;
|
||||||
param.log_pos= log_info ? log_info->log_pos : 0;
|
param.log_pos= log_info ? log_info->log_pos : 0;
|
||||||
|
|
||||||
int ret= 0;
|
|
||||||
FOREACH_OBSERVER(ret, after_commit, false, (¶m));
|
FOREACH_OBSERVER(ret, after_commit, false, (¶m));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is the end of a real transaction or autocommit statement, we
|
This is the end of a real transaction or autocommit statement, we
|
||||||
can free the memory allocated for binlog file and position.
|
can mark the memory unused.
|
||||||
*/
|
*/
|
||||||
if (is_real_trans && log_info)
|
if (is_real_trans && log_info)
|
||||||
{
|
{
|
||||||
my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, NULL);
|
log_info->log_file[0]= 0;
|
||||||
my_free(log_info);
|
log_info->log_pos= 0;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -223,27 +214,27 @@ int Trans_delegate::after_commit(THD *thd, bool all)
|
|||||||
int Trans_delegate::after_rollback(THD *thd, bool all)
|
int Trans_delegate::after_rollback(THD *thd, bool all)
|
||||||
{
|
{
|
||||||
Trans_param param;
|
Trans_param param;
|
||||||
|
Trans_binlog_info *log_info;
|
||||||
bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
|
bool is_real_trans= (all || thd->transaction.all.ha_list == 0);
|
||||||
|
int ret= 0;
|
||||||
|
|
||||||
param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0;
|
param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0;
|
||||||
|
|
||||||
Trans_binlog_info *log_info=
|
log_info= thd->semisync_info;
|
||||||
my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
|
|
||||||
|
|
||||||
param.log_file= log_info ? log_info->log_file : 0;
|
param.log_file= log_info && log_info->log_file[0] ? log_info->log_file : 0;
|
||||||
param.log_pos= log_info ? log_info->log_pos : 0;
|
param.log_pos= log_info ? log_info->log_pos : 0;
|
||||||
|
|
||||||
int ret= 0;
|
|
||||||
FOREACH_OBSERVER(ret, after_rollback, false, (¶m));
|
FOREACH_OBSERVER(ret, after_rollback, false, (¶m));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is the end of a real transaction or autocommit statement, we
|
This is the end of a real transaction or autocommit statement, we
|
||||||
can free the memory allocated for binlog file and position.
|
can mark the memory unused.
|
||||||
*/
|
*/
|
||||||
if (is_real_trans && log_info)
|
if (is_real_trans && log_info)
|
||||||
{
|
{
|
||||||
my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, NULL);
|
log_info->log_file[0]= 0;
|
||||||
my_free(log_info);
|
log_info->log_pos= 0;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -254,25 +245,24 @@ int Binlog_storage_delegate::after_flush(THD *thd,
|
|||||||
bool synced)
|
bool synced)
|
||||||
{
|
{
|
||||||
Binlog_storage_param param;
|
Binlog_storage_param param;
|
||||||
|
Trans_binlog_info *log_info;
|
||||||
uint32 flags=0;
|
uint32 flags=0;
|
||||||
|
int ret= 0;
|
||||||
|
|
||||||
if (synced)
|
if (synced)
|
||||||
flags |= BINLOG_STORAGE_IS_SYNCED;
|
flags |= BINLOG_STORAGE_IS_SYNCED;
|
||||||
|
|
||||||
Trans_binlog_info *log_info=
|
if (!(log_info= thd->semisync_info))
|
||||||
my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO);
|
|
||||||
|
|
||||||
if (!log_info)
|
|
||||||
{
|
{
|
||||||
if(!(log_info=
|
if(!(log_info=
|
||||||
(Trans_binlog_info*) my_malloc(sizeof(Trans_binlog_info), MYF(0))))
|
(Trans_binlog_info*) my_malloc(sizeof(Trans_binlog_info), MYF(0))))
|
||||||
return 1;
|
return 1;
|
||||||
my_pthread_setspecific_ptr(RPL_TRANS_BINLOG_INFO, log_info);
|
thd->semisync_info= log_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(log_info->log_file, log_file+dirname_length(log_file));
|
strcpy(log_info->log_file, log_file+dirname_length(log_file));
|
||||||
log_info->log_pos = log_pos;
|
log_info->log_pos = log_pos;
|
||||||
|
|
||||||
int ret= 0;
|
|
||||||
FOREACH_OBSERVER(ret, after_flush, false,
|
FOREACH_OBSERVER(ret, after_flush, false,
|
||||||
(¶m, log_info->log_file, log_info->log_pos, flags));
|
(¶m, log_info->log_file, log_info->log_pos, flags));
|
||||||
return ret;
|
return ret;
|
||||||
|
@@ -876,6 +876,7 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *
|
|||||||
{
|
{
|
||||||
Create_field *field_def=
|
Create_field *field_def=
|
||||||
(Create_field*) alloc_root(thd->mem_root, sizeof(Create_field));
|
(Create_field*) alloc_root(thd->mem_root, sizeof(Create_field));
|
||||||
|
bool unsigned_flag= 0;
|
||||||
if (field_list.push_back(field_def))
|
if (field_list.push_back(field_def))
|
||||||
DBUG_RETURN(NULL);
|
DBUG_RETURN(NULL);
|
||||||
|
|
||||||
@@ -885,8 +886,7 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *
|
|||||||
uint32 max_length=
|
uint32 max_length=
|
||||||
max_display_length_for_field(type(col), field_metadata(col));
|
max_display_length_for_field(type(col), field_metadata(col));
|
||||||
|
|
||||||
switch(type(col))
|
switch(type(col)) {
|
||||||
{
|
|
||||||
int precision;
|
int precision;
|
||||||
case MYSQL_TYPE_ENUM:
|
case MYSQL_TYPE_ENUM:
|
||||||
case MYSQL_TYPE_SET:
|
case MYSQL_TYPE_SET:
|
||||||
@@ -925,6 +925,18 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *
|
|||||||
pack_length= field_metadata(col) & 0x00ff;
|
pack_length= field_metadata(col) & 0x00ff;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MYSQL_TYPE_TINY:
|
||||||
|
case MYSQL_TYPE_SHORT:
|
||||||
|
case MYSQL_TYPE_INT24:
|
||||||
|
case MYSQL_TYPE_LONG:
|
||||||
|
case MYSQL_TYPE_LONGLONG:
|
||||||
|
/*
|
||||||
|
As we don't know if the integer was signed or not on the master,
|
||||||
|
assume we have same sign on master and slave. This is true when not
|
||||||
|
using conversions so it should be true also when using conversions.
|
||||||
|
*/
|
||||||
|
unsigned_flag= ((Field_num*) target_table->field[col])->unsigned_flag;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -932,12 +944,13 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE *
|
|||||||
DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d,"
|
DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d,"
|
||||||
" maybe_null: %d, unsigned_flag: %d, pack_length: %u",
|
" maybe_null: %d, unsigned_flag: %d, pack_length: %u",
|
||||||
type(col), target_table->field[col]->field_name,
|
type(col), target_table->field[col]->field_name,
|
||||||
max_length, decimals, TRUE, FALSE, pack_length));
|
max_length, decimals, TRUE, unsigned_flag,
|
||||||
|
pack_length));
|
||||||
field_def->init_for_tmp_table(type(col),
|
field_def->init_for_tmp_table(type(col),
|
||||||
max_length,
|
max_length,
|
||||||
decimals,
|
decimals,
|
||||||
TRUE, // maybe_null
|
TRUE, // maybe_null
|
||||||
FALSE, // unsigned_flag
|
unsigned_flag,
|
||||||
pack_length);
|
pack_length);
|
||||||
field_def->charset= target_table->field[col]->charset();
|
field_def->charset= target_table->field[col]->charset();
|
||||||
field_def->interval= interval;
|
field_def->interval= interval;
|
||||||
|
10
sql/slave.cc
10
sql/slave.cc
@@ -3531,9 +3531,7 @@ pthread_handler_t handle_slave_sql(void *arg)
|
|||||||
rli->clear_error();
|
rli->clear_error();
|
||||||
|
|
||||||
//tell the I/O thread to take relay_log_space_limit into account from now on
|
//tell the I/O thread to take relay_log_space_limit into account from now on
|
||||||
mysql_mutex_lock(&rli->log_space_lock);
|
|
||||||
rli->ignore_log_space_limit= 0;
|
rli->ignore_log_space_limit= 0;
|
||||||
mysql_mutex_unlock(&rli->log_space_lock);
|
|
||||||
rli->trans_retries= 0; // start from "no error"
|
rli->trans_retries= 0; // start from "no error"
|
||||||
DBUG_PRINT("info", ("rli->trans_retries: %lu", rli->trans_retries));
|
DBUG_PRINT("info", ("rli->trans_retries: %lu", rli->trans_retries));
|
||||||
|
|
||||||
@@ -5235,14 +5233,8 @@ static Log_event* next_event(Relay_log_info* rli)
|
|||||||
rli->ignore_log_space_limit= true;
|
rli->ignore_log_space_limit= true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
If the I/O thread is blocked, unblock it. Ok to broadcast
|
|
||||||
after unlock, because the mutex is only destroyed in
|
|
||||||
~Relay_log_info(), i.e. when rli is destroyed, and rli will
|
|
||||||
not be destroyed before we exit the present function.
|
|
||||||
*/
|
|
||||||
mysql_mutex_unlock(&rli->log_space_lock);
|
|
||||||
mysql_cond_broadcast(&rli->log_space_cond);
|
mysql_cond_broadcast(&rli->log_space_cond);
|
||||||
|
mysql_mutex_unlock(&rli->log_space_lock);
|
||||||
// Note that wait_for_update_relay_log unlocks lock_log !
|
// Note that wait_for_update_relay_log unlocks lock_log !
|
||||||
rli->relay_log.wait_for_update_relay_log(rli->sql_thd);
|
rli->relay_log.wait_for_update_relay_log(rli->sql_thd);
|
||||||
// re-acquire data lock since we released it earlier
|
// re-acquire data lock since we released it earlier
|
||||||
|
@@ -4067,10 +4067,11 @@ request_backoff_action(enum_open_table_action action_arg,
|
|||||||
* We met a broken table that needs repair, or a table that
|
* We met a broken table that needs repair, or a table that
|
||||||
is not present on this MySQL server and needs re-discovery.
|
is not present on this MySQL server and needs re-discovery.
|
||||||
To perform the action, we need an exclusive metadata lock on
|
To perform the action, we need an exclusive metadata lock on
|
||||||
the table. Acquiring an X lock while holding other shared
|
the table. Acquiring X lock while holding other shared
|
||||||
locks is very deadlock-prone. If this is a multi- statement
|
locks can easily lead to deadlocks. We rely on MDL deadlock
|
||||||
transaction that holds metadata locks for completed
|
detector to discover them. If this is a multi-statement
|
||||||
statements, we don't do it, and report an error instead.
|
transaction that holds metadata locks for completed statements,
|
||||||
|
we should keep these locks after discovery/repair.
|
||||||
The action type in this case is OT_DISCOVER or OT_REPAIR.
|
The action type in this case is OT_DISCOVER or OT_REPAIR.
|
||||||
* Our attempt to acquire an MDL lock lead to a deadlock,
|
* Our attempt to acquire an MDL lock lead to a deadlock,
|
||||||
detected by the MDL deadlock detector. The current
|
detected by the MDL deadlock detector. The current
|
||||||
@@ -4111,7 +4112,7 @@ request_backoff_action(enum_open_table_action action_arg,
|
|||||||
keep tables open between statements and a livelock
|
keep tables open between statements and a livelock
|
||||||
is not possible.
|
is not possible.
|
||||||
*/
|
*/
|
||||||
if (action_arg != OT_REOPEN_TABLES && m_has_locks)
|
if (action_arg == OT_BACKOFF_AND_RETRY && m_has_locks)
|
||||||
{
|
{
|
||||||
my_error(ER_LOCK_DEADLOCK, MYF(0));
|
my_error(ER_LOCK_DEADLOCK, MYF(0));
|
||||||
m_thd->mark_transaction_to_rollback(true);
|
m_thd->mark_transaction_to_rollback(true);
|
||||||
@@ -4138,6 +4139,32 @@ request_backoff_action(enum_open_table_action action_arg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
An error handler to mark transaction to rollback on DEADLOCK error
|
||||||
|
during DISCOVER / REPAIR.
|
||||||
|
*/
|
||||||
|
class MDL_deadlock_discovery_repair_handler : public Internal_error_handler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool handle_condition(THD *thd,
|
||||||
|
uint sql_errno,
|
||||||
|
const char* sqlstate,
|
||||||
|
MYSQL_ERROR::enum_warning_level level,
|
||||||
|
const char* msg,
|
||||||
|
MYSQL_ERROR ** cond_hdl)
|
||||||
|
{
|
||||||
|
if (sql_errno == ER_LOCK_DEADLOCK)
|
||||||
|
{
|
||||||
|
thd->mark_transaction_to_rollback(true);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
We have marked this transaction to rollback. Return false to allow
|
||||||
|
error to be reported or handled by other handlers.
|
||||||
|
*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Recover from failed attempt of open table by performing requested action.
|
Recover from failed attempt of open table by performing requested action.
|
||||||
|
|
||||||
@@ -4153,6 +4180,12 @@ Open_table_context::
|
|||||||
recover_from_failed_open()
|
recover_from_failed_open()
|
||||||
{
|
{
|
||||||
bool result= FALSE;
|
bool result= FALSE;
|
||||||
|
MDL_deadlock_discovery_repair_handler handler;
|
||||||
|
/*
|
||||||
|
Install error handler to mark transaction to rollback on DEADLOCK error.
|
||||||
|
*/
|
||||||
|
m_thd->push_internal_handler(&handler);
|
||||||
|
|
||||||
/* Execute the action. */
|
/* Execute the action. */
|
||||||
switch (m_action)
|
switch (m_action)
|
||||||
{
|
{
|
||||||
@@ -4174,7 +4207,12 @@ recover_from_failed_open()
|
|||||||
|
|
||||||
m_thd->warning_info->clear_warning_info(m_thd->query_id);
|
m_thd->warning_info->clear_warning_info(m_thd->query_id);
|
||||||
m_thd->clear_error(); // Clear error message
|
m_thd->clear_error(); // Clear error message
|
||||||
m_thd->mdl_context.release_transactional_locks();
|
/*
|
||||||
|
Rollback to start of the current statement to release exclusive lock
|
||||||
|
on table which was discovered but preserve locks from previous statements
|
||||||
|
in current transaction.
|
||||||
|
*/
|
||||||
|
m_thd->mdl_context.rollback_to_savepoint(start_of_statement_svp());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OT_REPAIR:
|
case OT_REPAIR:
|
||||||
@@ -4188,12 +4226,18 @@ recover_from_failed_open()
|
|||||||
m_failed_table->table_name, FALSE);
|
m_failed_table->table_name, FALSE);
|
||||||
|
|
||||||
result= auto_repair_table(m_thd, m_failed_table);
|
result= auto_repair_table(m_thd, m_failed_table);
|
||||||
m_thd->mdl_context.release_transactional_locks();
|
/*
|
||||||
|
Rollback to start of the current statement to release exclusive lock
|
||||||
|
on table which was discovered but preserve locks from previous statements
|
||||||
|
in current transaction.
|
||||||
|
*/
|
||||||
|
m_thd->mdl_context.rollback_to_savepoint(start_of_statement_svp());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
DBUG_ASSERT(0);
|
DBUG_ASSERT(0);
|
||||||
}
|
}
|
||||||
|
m_thd->pop_internal_handler();
|
||||||
/*
|
/*
|
||||||
Reset the pointers to conflicting MDL request and the
|
Reset the pointers to conflicting MDL request and the
|
||||||
TABLE_LIST element, set when we need auto-discovery or repair,
|
TABLE_LIST element, set when we need auto-discovery or repair,
|
||||||
@@ -6879,6 +6923,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
|
|||||||
|
|
||||||
if (item->cached_table)
|
if (item->cached_table)
|
||||||
{
|
{
|
||||||
|
DBUG_PRINT("info", ("using cached table"));
|
||||||
/*
|
/*
|
||||||
This shortcut is used by prepared statements. We assume that
|
This shortcut is used by prepared statements. We assume that
|
||||||
TABLE_LIST *first_table is not changed during query execution (which
|
TABLE_LIST *first_table is not changed during query execution (which
|
||||||
|
@@ -1058,6 +1058,7 @@ THD::THD()
|
|||||||
file_id = 0;
|
file_id = 0;
|
||||||
query_id= 0;
|
query_id= 0;
|
||||||
query_name_consts= 0;
|
query_name_consts= 0;
|
||||||
|
semisync_info= 0;
|
||||||
db_charset= global_system_variables.collation_database;
|
db_charset= global_system_variables.collation_database;
|
||||||
bzero(ha_data, sizeof(ha_data));
|
bzero(ha_data, sizeof(ha_data));
|
||||||
mysys_var=0;
|
mysys_var=0;
|
||||||
@@ -1467,6 +1468,8 @@ void THD::init(void)
|
|||||||
bzero((char *) &status_var, sizeof(status_var));
|
bzero((char *) &status_var, sizeof(status_var));
|
||||||
bzero((char *) &org_status_var, sizeof(org_status_var));
|
bzero((char *) &org_status_var, sizeof(org_status_var));
|
||||||
start_bytes_received= 0;
|
start_bytes_received= 0;
|
||||||
|
status_in_global= 0;
|
||||||
|
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
wsrep_exec_mode= wsrep_applier ? REPL_RECV : LOCAL_STATE;
|
wsrep_exec_mode= wsrep_applier ? REPL_RECV : LOCAL_STATE;
|
||||||
wsrep_conflict_state= NO_CONFLICT;
|
wsrep_conflict_state= NO_CONFLICT;
|
||||||
@@ -1491,8 +1494,8 @@ void THD::init(void)
|
|||||||
*/
|
*/
|
||||||
if (variables.wsrep_causal_reads)
|
if (variables.wsrep_causal_reads)
|
||||||
variables.wsrep_sync_wait|= WSREP_SYNC_WAIT_BEFORE_READ;
|
variables.wsrep_sync_wait|= WSREP_SYNC_WAIT_BEFORE_READ;
|
||||||
|
#endif /* WITH_WSREP */
|
||||||
|
|
||||||
#endif
|
|
||||||
if (variables.sql_log_bin)
|
if (variables.sql_log_bin)
|
||||||
variables.option_bits|= OPTION_BIN_LOG;
|
variables.option_bits|= OPTION_BIN_LOG;
|
||||||
else
|
else
|
||||||
@@ -1595,6 +1598,7 @@ void THD::change_user(void)
|
|||||||
cleanup();
|
cleanup();
|
||||||
reset_killed();
|
reset_killed();
|
||||||
cleanup_done= 0;
|
cleanup_done= 0;
|
||||||
|
status_in_global= 0;
|
||||||
init();
|
init();
|
||||||
stmt_map.reset();
|
stmt_map.reset();
|
||||||
my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
|
my_hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
|
||||||
@@ -1727,6 +1731,7 @@ THD::~THD()
|
|||||||
mysql_audit_free_thd(this);
|
mysql_audit_free_thd(this);
|
||||||
if (rli_slave)
|
if (rli_slave)
|
||||||
rli_slave->cleanup_after_session();
|
rli_slave->cleanup_after_session();
|
||||||
|
my_free(semisync_info);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
free_root(&main_mem_root, MYF(0));
|
free_root(&main_mem_root, MYF(0));
|
||||||
|
@@ -59,7 +59,6 @@ struct wsrep_thd_shadow {
|
|||||||
#endif
|
#endif
|
||||||
class Reprepare_observer;
|
class Reprepare_observer;
|
||||||
class Relay_log_info;
|
class Relay_log_info;
|
||||||
|
|
||||||
class Query_log_event;
|
class Query_log_event;
|
||||||
class Load_log_event;
|
class Load_log_event;
|
||||||
class Slave_log_event;
|
class Slave_log_event;
|
||||||
@@ -71,6 +70,7 @@ class Rows_log_event;
|
|||||||
class Sroutine_hash_entry;
|
class Sroutine_hash_entry;
|
||||||
class User_level_lock;
|
class User_level_lock;
|
||||||
class user_var_entry;
|
class user_var_entry;
|
||||||
|
struct Trans_binlog_info;
|
||||||
|
|
||||||
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
|
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
|
||||||
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME };
|
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME };
|
||||||
@@ -1689,6 +1689,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
const char *where;
|
const char *where;
|
||||||
|
|
||||||
|
/* Needed by MariaDB semi sync replication */
|
||||||
|
Trans_binlog_info *semisync_info;
|
||||||
|
|
||||||
ulong client_capabilities; /* What the client supports */
|
ulong client_capabilities; /* What the client supports */
|
||||||
ulong max_client_packet_length;
|
ulong max_client_packet_length;
|
||||||
|
|
||||||
@@ -1752,11 +1755,11 @@ public:
|
|||||||
/* Do not set socket timeouts for wait_timeout (used with threadpool) */
|
/* Do not set socket timeouts for wait_timeout (used with threadpool) */
|
||||||
bool skip_wait_timeout;
|
bool skip_wait_timeout;
|
||||||
|
|
||||||
/* container for handler's private per-connection data */
|
|
||||||
Ha_data ha_data[MAX_HA];
|
|
||||||
|
|
||||||
bool prepare_derived_at_open;
|
bool prepare_derived_at_open;
|
||||||
|
|
||||||
|
/* Set to 1 if status of this THD is already in global status */
|
||||||
|
bool status_in_global;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
To signal that the tmp table to be created is created for materialized
|
To signal that the tmp table to be created is created for materialized
|
||||||
derived table or a view.
|
derived table or a view.
|
||||||
@@ -1765,6 +1768,9 @@ public:
|
|||||||
|
|
||||||
bool save_prep_leaf_list;
|
bool save_prep_leaf_list;
|
||||||
|
|
||||||
|
/* container for handler's private per-connection data */
|
||||||
|
Ha_data ha_data[MAX_HA];
|
||||||
|
|
||||||
#ifndef MYSQL_CLIENT
|
#ifndef MYSQL_CLIENT
|
||||||
binlog_cache_mngr * binlog_setup_trx_data();
|
binlog_cache_mngr * binlog_setup_trx_data();
|
||||||
|
|
||||||
@@ -3175,6 +3181,8 @@ public:
|
|||||||
{
|
{
|
||||||
mysql_mutex_lock(&LOCK_status);
|
mysql_mutex_lock(&LOCK_status);
|
||||||
add_to_status(&global_status_var, &status_var);
|
add_to_status(&global_status_var, &status_var);
|
||||||
|
/* Mark that this THD status has already been added in global status */
|
||||||
|
status_in_global= 1;
|
||||||
mysql_mutex_unlock(&LOCK_status);
|
mysql_mutex_unlock(&LOCK_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1928,7 +1928,6 @@ void st_select_lex::init_select()
|
|||||||
with_sum_func= 0;
|
with_sum_func= 0;
|
||||||
is_correlated= 0;
|
is_correlated= 0;
|
||||||
cur_pos_in_select_list= UNDEF_POS;
|
cur_pos_in_select_list= UNDEF_POS;
|
||||||
non_agg_fields.empty();
|
|
||||||
cond_value= having_value= Item::COND_UNDEF;
|
cond_value= having_value= Item::COND_UNDEF;
|
||||||
inner_refs_list.empty();
|
inner_refs_list.empty();
|
||||||
insert_tables= 0;
|
insert_tables= 0;
|
||||||
@@ -1936,6 +1935,7 @@ void st_select_lex::init_select()
|
|||||||
m_non_agg_field_used= false;
|
m_non_agg_field_used= false;
|
||||||
m_agg_func_used= false;
|
m_agg_func_used= false;
|
||||||
name_visibility_map= 0;
|
name_visibility_map= 0;
|
||||||
|
join= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -877,8 +877,6 @@ public:
|
|||||||
bool no_wrap_view_item;
|
bool no_wrap_view_item;
|
||||||
/* exclude this select from check of unique_table() */
|
/* exclude this select from check of unique_table() */
|
||||||
bool exclude_from_table_unique_test;
|
bool exclude_from_table_unique_test;
|
||||||
/* List of fields that aren't under an aggregate function */
|
|
||||||
List<Item_field> non_agg_fields;
|
|
||||||
/* index in the select list of the expression currently being fixed */
|
/* index in the select list of the expression currently being fixed */
|
||||||
int cur_pos_in_select_list;
|
int cur_pos_in_select_list;
|
||||||
|
|
||||||
|
@@ -6175,6 +6175,8 @@ void THD::reset_for_next_command()
|
|||||||
thd->reset_current_stmt_binlog_format_row();
|
thd->reset_current_stmt_binlog_format_row();
|
||||||
thd->binlog_unsafe_warning_flags= 0;
|
thd->binlog_unsafe_warning_flags= 0;
|
||||||
|
|
||||||
|
thd->save_prep_leaf_list= false;
|
||||||
|
|
||||||
DBUG_PRINT("debug",
|
DBUG_PRINT("debug",
|
||||||
("is_current_stmt_binlog_format_row(): %d",
|
("is_current_stmt_binlog_format_row(): %d",
|
||||||
thd->is_current_stmt_binlog_format_row()));
|
thd->is_current_stmt_binlog_format_row()));
|
||||||
|
@@ -4904,6 +4904,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|||||||
KEY_FIELD *key_fields, *end, *field;
|
KEY_FIELD *key_fields, *end, *field;
|
||||||
uint sz;
|
uint sz;
|
||||||
uint m= max(select_lex->max_equal_elems,1);
|
uint m= max(select_lex->max_equal_elems,1);
|
||||||
|
DBUG_ENTER("update_ref_and_keys");
|
||||||
|
DBUG_PRINT("enter", ("normal_tables: %llx", normal_tables));
|
||||||
|
|
||||||
SELECT_LEX *sel=thd->lex->current_select;
|
SELECT_LEX *sel=thd->lex->current_select;
|
||||||
sel->cond_count= 0;
|
sel->cond_count= 0;
|
||||||
@@ -4950,7 +4952,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|||||||
sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))*
|
sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))*
|
||||||
((sel->cond_count*2 + sel->between_count)*m+1);
|
((sel->cond_count*2 + sel->between_count)*m+1);
|
||||||
if (!(key_fields=(KEY_FIELD*) thd->alloc(sz)))
|
if (!(key_fields=(KEY_FIELD*) thd->alloc(sz)))
|
||||||
return TRUE; /* purecov: inspected */
|
DBUG_RETURN(TRUE); /* purecov: inspected */
|
||||||
and_level= 0;
|
and_level= 0;
|
||||||
field= end= key_fields;
|
field= end= key_fields;
|
||||||
*sargables= (SARGABLE_PARAM *) key_fields +
|
*sargables= (SARGABLE_PARAM *) key_fields +
|
||||||
@@ -4959,7 +4961,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|||||||
(*sargables)[0].field= 0;
|
(*sargables)[0].field= 0;
|
||||||
|
|
||||||
if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64))
|
if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64))
|
||||||
return TRUE;
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
if (cond)
|
if (cond)
|
||||||
{
|
{
|
||||||
@@ -5009,16 +5011,16 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|||||||
for ( ; field != end ; field++)
|
for ( ; field != end ; field++)
|
||||||
{
|
{
|
||||||
if (add_key_part(keyuse,field))
|
if (add_key_part(keyuse,field))
|
||||||
return TRUE;
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (select_lex->ftfunc_list->elements)
|
if (select_lex->ftfunc_list->elements)
|
||||||
{
|
{
|
||||||
if (add_ft_keys(keyuse,join_tab,cond,normal_tables))
|
if (add_ft_keys(keyuse,join_tab,cond,normal_tables))
|
||||||
return TRUE;
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -20705,7 +20707,7 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
|||||||
Item_field *field;
|
Item_field *field;
|
||||||
int cur_pos_in_select_list= 0;
|
int cur_pos_in_select_list= 0;
|
||||||
List_iterator<Item> li(fields);
|
List_iterator<Item> li(fields);
|
||||||
List_iterator<Item_field> naf_it(thd->lex->current_select->non_agg_fields);
|
List_iterator<Item_field> naf_it(thd->lex->current_select->join->non_agg_fields);
|
||||||
|
|
||||||
field= naf_it++;
|
field= naf_it++;
|
||||||
while (field && (item=li++))
|
while (field && (item=li++))
|
||||||
|
@@ -922,6 +922,9 @@ public:
|
|||||||
Item *pre_sort_idx_pushed_cond;
|
Item *pre_sort_idx_pushed_cond;
|
||||||
void clean_pre_sort_join_tab();
|
void clean_pre_sort_join_tab();
|
||||||
|
|
||||||
|
/* List of fields that aren't under an aggregate function */
|
||||||
|
List<Item_field> non_agg_fields;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
For "Using temporary+Using filesort" queries, JOIN::join_tab can point to
|
For "Using temporary+Using filesort" queries, JOIN::join_tab can point to
|
||||||
either:
|
either:
|
||||||
@@ -1301,6 +1304,7 @@ public:
|
|||||||
all_fields= fields_arg;
|
all_fields= fields_arg;
|
||||||
if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
|
if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
|
||||||
fields_list= fields_arg;
|
fields_list= fields_arg;
|
||||||
|
non_agg_fields.empty();
|
||||||
bzero((char*) &keyuse,sizeof(keyuse));
|
bzero((char*) &keyuse,sizeof(keyuse));
|
||||||
tmp_table_param.init();
|
tmp_table_param.init();
|
||||||
tmp_table_param.end_write_records= HA_POS_ERROR;
|
tmp_table_param.end_write_records= HA_POS_ERROR;
|
||||||
|
@@ -3126,7 +3126,10 @@ void calc_sum_of_all_status(STATUS_VAR *to)
|
|||||||
|
|
||||||
/* Add to this status from existing threads */
|
/* Add to this status from existing threads */
|
||||||
while ((tmp= it++))
|
while ((tmp= it++))
|
||||||
|
{
|
||||||
|
if (!tmp->status_in_global)
|
||||||
add_to_status(to, &tmp->status_var);
|
add_to_status(to, &tmp->status_var);
|
||||||
|
}
|
||||||
|
|
||||||
mysql_mutex_unlock(&LOCK_thread_count);
|
mysql_mutex_unlock(&LOCK_thread_count);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
|
@@ -248,7 +248,7 @@ TEST_join(JOIN *join)
|
|||||||
|
|
||||||
#define FT_KEYPART (MAX_REF_PARTS+10)
|
#define FT_KEYPART (MAX_REF_PARTS+10)
|
||||||
|
|
||||||
void print_keyuse(KEYUSE *keyuse)
|
static void print_keyuse(KEYUSE *keyuse)
|
||||||
{
|
{
|
||||||
char buff[256];
|
char buff[256];
|
||||||
char buf2[64];
|
char buf2[64];
|
||||||
@@ -266,14 +266,11 @@ void print_keyuse(KEYUSE *keyuse)
|
|||||||
else
|
else
|
||||||
fieldname= key_info->key_part[keyuse->keypart].field->field_name;
|
fieldname= key_info->key_part[keyuse->keypart].field->field_name;
|
||||||
ll2str(keyuse->used_tables, buf2, 16, 0);
|
ll2str(keyuse->used_tables, buf2, 16, 0);
|
||||||
DBUG_LOCK_FILE;
|
|
||||||
fprintf(DBUG_FILE, "KEYUSE: %s.%s=%s optimize: %u used_tables: %s "
|
fprintf(DBUG_FILE, "KEYUSE: %s.%s=%s optimize: %u used_tables: %s "
|
||||||
"ref_table_rows: %lu keypart_map: %0lx\n",
|
"ref_table_rows: %lu keypart_map: %0lx\n",
|
||||||
keyuse->table->alias.c_ptr(), fieldname, str.ptr(),
|
keyuse->table->alias.c_ptr(), fieldname, str.ptr(),
|
||||||
(uint) keyuse->optimize, buf2, (ulong) keyuse->ref_table_rows,
|
(uint) keyuse->optimize, buf2, (ulong) keyuse->ref_table_rows,
|
||||||
(ulong) keyuse->keypart_map);
|
(ulong) keyuse->keypart_map);
|
||||||
DBUG_UNLOCK_FILE;
|
|
||||||
//key_part_map keypart_map; --?? there can be several?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -282,9 +279,9 @@ void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array)
|
|||||||
{
|
{
|
||||||
DBUG_LOCK_FILE;
|
DBUG_LOCK_FILE;
|
||||||
fprintf(DBUG_FILE, "KEYUSE array (%d elements)\n", keyuse_array->elements);
|
fprintf(DBUG_FILE, "KEYUSE array (%d elements)\n", keyuse_array->elements);
|
||||||
DBUG_UNLOCK_FILE;
|
|
||||||
for(uint i=0; i < keyuse_array->elements; i++)
|
for(uint i=0; i < keyuse_array->elements; i++)
|
||||||
print_keyuse((KEYUSE*)dynamic_array_ptr(keyuse_array, i));
|
print_keyuse((KEYUSE*)dynamic_array_ptr(keyuse_array, i));
|
||||||
|
DBUG_UNLOCK_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1021,7 +1021,6 @@ bool st_select_lex::cleanup()
|
|||||||
{
|
{
|
||||||
error= (bool) ((uint) error | (uint) lex_unit->cleanup());
|
error= (bool) ((uint) error | (uint) lex_unit->cleanup());
|
||||||
}
|
}
|
||||||
non_agg_fields.empty();
|
|
||||||
inner_refs_list.empty();
|
inner_refs_list.empty();
|
||||||
exclude_from_table_unique_test= FALSE;
|
exclude_from_table_unique_test= FALSE;
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
@@ -1032,6 +1031,7 @@ void st_select_lex::cleanup_all_joins(bool full)
|
|||||||
{
|
{
|
||||||
SELECT_LEX_UNIT *unit;
|
SELECT_LEX_UNIT *unit;
|
||||||
SELECT_LEX *sl;
|
SELECT_LEX *sl;
|
||||||
|
DBUG_ENTER("st_select_lex::cleanup_all_joins");
|
||||||
|
|
||||||
if (join)
|
if (join)
|
||||||
join->cleanup(full);
|
join->cleanup(full);
|
||||||
@@ -1039,6 +1039,7 @@ void st_select_lex::cleanup_all_joins(bool full)
|
|||||||
for (unit= first_inner_unit(); unit; unit= unit->next_unit())
|
for (unit= first_inner_unit(); unit; unit= unit->next_unit())
|
||||||
for (sl= unit->first_select(); sl; sl= sl->next_select())
|
for (sl= unit->first_select(); sl; sl= sl->next_select())
|
||||||
sl->cleanup_all_joins(full);
|
sl->cleanup_all_joins(full);
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -5203,7 +5203,7 @@ Item *Field_iterator_table::create_item(THD *thd)
|
|||||||
if (item && thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
|
if (item && thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
|
||||||
!thd->lex->in_sum_func && select->cur_pos_in_select_list != UNDEF_POS)
|
!thd->lex->in_sum_func && select->cur_pos_in_select_list != UNDEF_POS)
|
||||||
{
|
{
|
||||||
select->non_agg_fields.push_back(item);
|
select->join->non_agg_fields.push_back(item);
|
||||||
item->marker= select->cur_pos_in_select_list;
|
item->marker= select->cur_pos_in_select_list;
|
||||||
select->set_non_agg_field_used(true);
|
select->set_non_agg_field_used(true);
|
||||||
}
|
}
|
||||||
|
@@ -1419,6 +1419,104 @@ dict_create_add_foreign_field_to_dictionary(
|
|||||||
table, foreign, trx));
|
table, foreign, trx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************//**
|
||||||
|
Construct foreign key constraint defintion from data dictionary information.
|
||||||
|
*/
|
||||||
|
UNIV_INTERN
|
||||||
|
char*
|
||||||
|
dict_foreign_def_get(
|
||||||
|
/*=================*/
|
||||||
|
dict_foreign_t* foreign,/*!< in: foreign */
|
||||||
|
trx_t* trx) /*!< in: trx */
|
||||||
|
{
|
||||||
|
char* fk_def = mem_heap_alloc(foreign->heap, 4*1024);
|
||||||
|
const char* tbname;
|
||||||
|
char tablebuf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
int i;
|
||||||
|
char* bufend;
|
||||||
|
|
||||||
|
tbname = dict_remove_db_name(foreign->id);
|
||||||
|
bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
|
||||||
|
tbname, strlen(tbname), trx->mysql_thd, FALSE);
|
||||||
|
tablebuf[bufend - tablebuf] = '\0';
|
||||||
|
|
||||||
|
sprintf(fk_def,
|
||||||
|
(char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf);
|
||||||
|
|
||||||
|
for(i = 0; i < foreign->n_fields; i++) {
|
||||||
|
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->foreign_col_names[i],
|
||||||
|
strlen(foreign->foreign_col_names[i]),
|
||||||
|
trx->mysql_thd, FALSE);
|
||||||
|
strcat(fk_def, buf);
|
||||||
|
if (i < foreign->n_fields-1) {
|
||||||
|
strcat(fk_def, (char *)",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(fk_def,(char *)") REFERENCES ");
|
||||||
|
|
||||||
|
bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->referenced_table_name,
|
||||||
|
strlen(foreign->referenced_table_name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
tablebuf[bufend - tablebuf] = '\0';
|
||||||
|
|
||||||
|
strcat(fk_def, tablebuf);
|
||||||
|
strcat(fk_def, " (");
|
||||||
|
|
||||||
|
for(i = 0; i < foreign->n_fields; i++) {
|
||||||
|
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->referenced_col_names[i],
|
||||||
|
strlen(foreign->referenced_col_names[i]),
|
||||||
|
trx->mysql_thd, FALSE);
|
||||||
|
buf[bufend - buf] = '\0';
|
||||||
|
strcat(fk_def, buf);
|
||||||
|
if (i < foreign->n_fields-1) {
|
||||||
|
strcat(fk_def, (char *)",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strcat(fk_def, (char *)")");
|
||||||
|
|
||||||
|
return fk_def;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************//**
|
||||||
|
Convert foreign key column names from data dictionary to SQL-layer.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
dict_foreign_def_get_fields(
|
||||||
|
/*========================*/
|
||||||
|
dict_foreign_t* foreign,/*!< in: foreign */
|
||||||
|
trx_t* trx, /*!< in: trx */
|
||||||
|
char** field, /*!< out: foreign column */
|
||||||
|
char** field2, /*!< out: referenced column */
|
||||||
|
int col_no) /*!< in: column number */
|
||||||
|
{
|
||||||
|
char* bufend;
|
||||||
|
char* fieldbuf = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
|
||||||
|
char* fieldbuf2 = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
|
||||||
|
|
||||||
|
bufend = innobase_convert_name(fieldbuf, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->foreign_col_names[col_no],
|
||||||
|
strlen(foreign->foreign_col_names[col_no]),
|
||||||
|
trx->mysql_thd, FALSE);
|
||||||
|
|
||||||
|
fieldbuf[bufend - fieldbuf] = '\0';
|
||||||
|
|
||||||
|
bufend = innobase_convert_name(fieldbuf2, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->referenced_col_names[col_no],
|
||||||
|
strlen(foreign->referenced_col_names[col_no]),
|
||||||
|
trx->mysql_thd, FALSE);
|
||||||
|
|
||||||
|
fieldbuf2[bufend - fieldbuf2] = '\0';
|
||||||
|
*field = fieldbuf;
|
||||||
|
*field2 = fieldbuf2;
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************//**
|
/********************************************************************//**
|
||||||
Add a single foreign key definition to the data dictionary tables in the
|
Add a single foreign key definition to the data dictionary tables in the
|
||||||
database. We also generate names to constraints that were not named by the
|
database. We also generate names to constraints that were not named by the
|
||||||
@@ -1501,6 +1599,29 @@ dict_create_add_foreign_to_dictionary(
|
|||||||
|
|
||||||
if (error != DB_SUCCESS) {
|
if (error != DB_SUCCESS) {
|
||||||
|
|
||||||
|
if (error == DB_DUPLICATE_KEY) {
|
||||||
|
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
char tablename[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
char* fk_def;
|
||||||
|
|
||||||
|
innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
|
||||||
|
table->name, strlen(table->name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
|
||||||
|
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
|
||||||
|
|
||||||
|
fk_def = dict_foreign_def_get(foreign, trx);
|
||||||
|
|
||||||
|
ib_push_warning(trx, error,
|
||||||
|
"Create or Alter table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint %s"
|
||||||
|
" already exists on data dictionary."
|
||||||
|
" Foreign key constraint names need to be unique in database."
|
||||||
|
" Error in foreign key definition: %s.",
|
||||||
|
tablename, buf, fk_def);
|
||||||
|
}
|
||||||
|
|
||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1509,6 +1630,26 @@ dict_create_add_foreign_to_dictionary(
|
|||||||
i, table, foreign, trx);
|
i, table, foreign, trx);
|
||||||
|
|
||||||
if (error != DB_SUCCESS) {
|
if (error != DB_SUCCESS) {
|
||||||
|
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
char tablename[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
char* field=NULL;
|
||||||
|
char* field2=NULL;
|
||||||
|
char* fk_def;
|
||||||
|
|
||||||
|
innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
|
||||||
|
table->name, strlen(table->name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
|
||||||
|
fk_def = dict_foreign_def_get(foreign, trx);
|
||||||
|
dict_foreign_def_get_fields(foreign, trx, &field, &field2, i);
|
||||||
|
|
||||||
|
ib_push_warning(trx, error,
|
||||||
|
"Create or Alter table %s with foreign key constraint"
|
||||||
|
" failed. Error adding foreign key constraint name %s"
|
||||||
|
" fields %s or %s to the dictionary."
|
||||||
|
" Error in foreign key definition: %s.",
|
||||||
|
tablename, buf, i+1, fk_def);
|
||||||
|
|
||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
|
@@ -2534,8 +2534,9 @@ dict_foreign_remove_from_cache(
|
|||||||
const ib_rbt_node_t* node
|
const ib_rbt_node_t* node
|
||||||
= rbt_lookup(rbt, foreign->id);
|
= rbt_lookup(rbt, foreign->id);
|
||||||
|
|
||||||
if (node) {
|
if (node != NULL) {
|
||||||
dict_foreign_t* val = *(dict_foreign_t**) node->value;
|
dict_foreign_t* val
|
||||||
|
= *(dict_foreign_t**) node->value;
|
||||||
|
|
||||||
if (val == foreign) {
|
if (val == foreign) {
|
||||||
rbt_delete(rbt, foreign->id);
|
rbt_delete(rbt, foreign->id);
|
||||||
@@ -2555,9 +2556,10 @@ dict_foreign_remove_from_cache(
|
|||||||
if (rbt != NULL && foreign->id != NULL) {
|
if (rbt != NULL && foreign->id != NULL) {
|
||||||
const ib_rbt_node_t* node
|
const ib_rbt_node_t* node
|
||||||
= rbt_lookup(rbt, foreign->id);
|
= rbt_lookup(rbt, foreign->id);
|
||||||
if (node) {
|
|
||||||
|
|
||||||
dict_foreign_t* val = *(dict_foreign_t**) node->value;
|
if (node != NULL) {
|
||||||
|
dict_foreign_t* val
|
||||||
|
= *(dict_foreign_t**) node->value;
|
||||||
|
|
||||||
if (val == foreign) {
|
if (val == foreign) {
|
||||||
rbt_delete(rbt, foreign->id);
|
rbt_delete(rbt, foreign->id);
|
||||||
@@ -2614,6 +2616,11 @@ dict_foreign_find(
|
|||||||
DBUG_RETURN(NULL);
|
DBUG_RETURN(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DB_FOREIGN_KEY_IS_PREFIX_INDEX 200
|
||||||
|
#define DB_FOREIGN_KEY_COL_NOT_NULL 201
|
||||||
|
#define DB_FOREIGN_KEY_COLS_NOT_EQUAL 202
|
||||||
|
#define DB_FOREIGN_KEY_INDEX_NOT_FOUND 203
|
||||||
|
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
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 and is not marked for deletion and is not the same
|
in the same order and is not marked for deletion and is not the same
|
||||||
@@ -2631,12 +2638,21 @@ dict_foreign_find_index(
|
|||||||
ibool check_charsets,
|
ibool check_charsets,
|
||||||
/*!< in: whether to check charsets.
|
/*!< in: whether to check charsets.
|
||||||
only has an effect if types_idx != NULL */
|
only has an effect if types_idx != NULL */
|
||||||
ulint check_null)
|
ulint check_null,
|
||||||
/*!< in: nonzero if none of the columns must
|
/*!< in: nonzero if none of the columns must
|
||||||
be declared NOT NULL */
|
be declared NOT NULL */
|
||||||
|
ulint* error, /*!< out: error code */
|
||||||
|
ulint* err_col_no,
|
||||||
|
/*!< out: column number where error happened */
|
||||||
|
dict_index_t** err_index)
|
||||||
|
/*!< out: index where error happened */
|
||||||
{
|
{
|
||||||
dict_index_t* index;
|
dict_index_t* index;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
*error = DB_FOREIGN_KEY_INDEX_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
index = dict_table_get_first_index(table);
|
index = dict_table_get_first_index(table);
|
||||||
|
|
||||||
while (index != NULL) {
|
while (index != NULL) {
|
||||||
@@ -2662,6 +2678,12 @@ dict_foreign_find_index(
|
|||||||
/* We do not accept column prefix
|
/* We do not accept column prefix
|
||||||
indexes here */
|
indexes here */
|
||||||
|
|
||||||
|
if (error && err_col_no && err_index) {
|
||||||
|
*error = DB_FOREIGN_KEY_IS_PREFIX_INDEX;
|
||||||
|
*err_col_no = i;
|
||||||
|
*err_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2673,6 +2695,11 @@ dict_foreign_find_index(
|
|||||||
if (check_null
|
if (check_null
|
||||||
&& (field->col->prtype & DATA_NOT_NULL)) {
|
&& (field->col->prtype & DATA_NOT_NULL)) {
|
||||||
|
|
||||||
|
if (error && err_col_no && err_index) {
|
||||||
|
*error = DB_FOREIGN_KEY_COL_NOT_NULL;
|
||||||
|
*err_col_no = i;
|
||||||
|
*err_index = index;
|
||||||
|
}
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2682,6 +2709,12 @@ dict_foreign_find_index(
|
|||||||
i),
|
i),
|
||||||
check_charsets)) {
|
check_charsets)) {
|
||||||
|
|
||||||
|
if (error && err_col_no && err_index) {
|
||||||
|
*error = DB_FOREIGN_KEY_COLS_NOT_EQUAL;
|
||||||
|
*err_col_no = i;
|
||||||
|
*err_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2689,6 +2722,10 @@ dict_foreign_find_index(
|
|||||||
if (i == n_cols) {
|
if (i == n_cols) {
|
||||||
/* We found a matching index */
|
/* We found a matching index */
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
*error = DB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
return(index);
|
return(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2715,8 +2752,9 @@ wsrep_dict_foreign_find_index(
|
|||||||
/*!< in: nonzero if none of the columns must
|
/*!< in: nonzero if none of the columns must
|
||||||
be declared NOT NULL */
|
be declared NOT NULL */
|
||||||
{
|
{
|
||||||
return dict_foreign_find_index(
|
return dict_foreign_find_index(table, columns, n_cols, types_idx,
|
||||||
table, columns, n_cols, types_idx, check_charsets, check_null);
|
check_charsets, check_null,
|
||||||
|
NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
/**********************************************************************//**
|
/**********************************************************************//**
|
||||||
@@ -2739,7 +2777,7 @@ dict_foreign_find_equiv_index(
|
|||||||
foreign->foreign_table,
|
foreign->foreign_table,
|
||||||
foreign->foreign_col_names, foreign->n_fields,
|
foreign->foreign_col_names, foreign->n_fields,
|
||||||
foreign->foreign_index, TRUE, /* check types */
|
foreign->foreign_index, TRUE, /* check types */
|
||||||
FALSE/* allow columns to be NULL */));
|
FALSE/* allow columns to be NULL */, NULL, NULL, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !UNIV_HOTBACKUP */
|
#endif /* !UNIV_HOTBACKUP */
|
||||||
@@ -2902,11 +2940,15 @@ dict_foreign_add_to_cache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (for_in_cache->referenced_table == NULL && ref_table) {
|
if (for_in_cache->referenced_table == NULL && ref_table) {
|
||||||
|
ulint index_error;
|
||||||
|
ulint err_col;
|
||||||
|
dict_index_t *err_index=NULL;
|
||||||
|
|
||||||
index = dict_foreign_find_index(
|
index = dict_foreign_find_index(
|
||||||
ref_table,
|
ref_table,
|
||||||
for_in_cache->referenced_col_names,
|
for_in_cache->referenced_col_names,
|
||||||
for_in_cache->n_fields, for_in_cache->foreign_index,
|
for_in_cache->n_fields, for_in_cache->foreign_index,
|
||||||
check_charsets, FALSE);
|
check_charsets, FALSE, &index_error, &err_col, &err_index);
|
||||||
|
|
||||||
if (index == NULL
|
if (index == NULL
|
||||||
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
|
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
|
||||||
@@ -2938,6 +2980,9 @@ dict_foreign_add_to_cache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (for_in_cache->foreign_table == NULL && for_table) {
|
if (for_in_cache->foreign_table == NULL && for_table) {
|
||||||
|
ulint index_error;
|
||||||
|
ulint err_col;
|
||||||
|
dict_index_t* err_index=NULL;
|
||||||
|
|
||||||
index = dict_foreign_find_index(
|
index = dict_foreign_find_index(
|
||||||
for_table,
|
for_table,
|
||||||
@@ -2946,7 +2991,8 @@ dict_foreign_add_to_cache(
|
|||||||
for_in_cache->referenced_index, check_charsets,
|
for_in_cache->referenced_index, check_charsets,
|
||||||
for_in_cache->type
|
for_in_cache->type
|
||||||
& (DICT_FOREIGN_ON_DELETE_SET_NULL
|
& (DICT_FOREIGN_ON_DELETE_SET_NULL
|
||||||
| DICT_FOREIGN_ON_UPDATE_SET_NULL));
|
| DICT_FOREIGN_ON_UPDATE_SET_NULL),
|
||||||
|
&index_error, &err_col, &err_index);
|
||||||
|
|
||||||
if (index == NULL
|
if (index == NULL
|
||||||
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
|
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
|
||||||
@@ -3557,6 +3603,8 @@ static
|
|||||||
void
|
void
|
||||||
dict_foreign_report_syntax_err(
|
dict_foreign_report_syntax_err(
|
||||||
/*===========================*/
|
/*===========================*/
|
||||||
|
const char* fmt, /*!< in: syntax err msg */
|
||||||
|
const char* oper, /*!< in: operation */
|
||||||
const char* name, /*!< in: table name */
|
const char* name, /*!< in: table name */
|
||||||
const char* start_of_latest_foreign,
|
const char* start_of_latest_foreign,
|
||||||
/*!< in: start of the foreign key clause
|
/*!< in: start of the foreign key clause
|
||||||
@@ -3567,11 +3615,101 @@ dict_foreign_report_syntax_err(
|
|||||||
|
|
||||||
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);
|
||||||
fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
|
fprintf(ef, fmt, oper, name, start_of_latest_foreign, ptr);
|
||||||
start_of_latest_foreign, ptr);
|
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************//**
|
||||||
|
Push warning message to SQL-layer based on foreign key constraint
|
||||||
|
index match error. */
|
||||||
|
static
|
||||||
|
void
|
||||||
|
dict_foreign_push_index_error(
|
||||||
|
/*==========================*/
|
||||||
|
trx_t* trx, /*!< in: trx */
|
||||||
|
const char* operation, /*!< in: operation create or alter
|
||||||
|
*/
|
||||||
|
const char* create_name, /*!< in: table name in create or
|
||||||
|
alter table */
|
||||||
|
const char* latest_foreign, /*!< in: start of latest foreign key
|
||||||
|
constraint name */
|
||||||
|
const char** columns, /*!< in: foreign key columns */
|
||||||
|
ulint index_error, /*!< in: error code */
|
||||||
|
ulint err_col, /*!< in: column where error happened
|
||||||
|
*/
|
||||||
|
dict_index_t* err_index, /*!< in: index where error happened
|
||||||
|
*/
|
||||||
|
dict_table_t* table, /*!< in: table */
|
||||||
|
FILE* ef) /*!< in: output stream */
|
||||||
|
{
|
||||||
|
switch (index_error) {
|
||||||
|
case DB_FOREIGN_KEY_INDEX_NOT_FOUND: {
|
||||||
|
fprintf(ef,
|
||||||
|
"%s table '%s' with foreign key constraint"
|
||||||
|
" failed. There is no index in the referenced"
|
||||||
|
" table where the referenced columns appear"
|
||||||
|
" as the first columns. Error close to %s.\n",
|
||||||
|
operation, create_name, latest_foreign);
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table '%s' with foreign key constraint"
|
||||||
|
" failed. There is no index in the referenced"
|
||||||
|
" table where the referenced columns appear"
|
||||||
|
" as the first columns. Error close to %s.",
|
||||||
|
operation, create_name, latest_foreign);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DB_FOREIGN_KEY_IS_PREFIX_INDEX: {
|
||||||
|
fprintf(ef,
|
||||||
|
"%s table '%s' with foreign key constraint"
|
||||||
|
" failed. There is only prefix index in the referenced"
|
||||||
|
" table where the referenced columns appear"
|
||||||
|
" as the first columns. Error close to %s.\n",
|
||||||
|
operation, create_name, latest_foreign);
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table '%s' with foreign key constraint"
|
||||||
|
" failed. There is only prefix index in the referenced"
|
||||||
|
" table where the referenced columns appear"
|
||||||
|
" as the first columns. Error close to %s.",
|
||||||
|
operation, create_name, latest_foreign);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DB_FOREIGN_KEY_COL_NOT_NULL: {
|
||||||
|
fprintf(ef,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. You have defined a SET NULL condition but "
|
||||||
|
"field %s on index is defined as NOT NULL close to %s\n",
|
||||||
|
operation, create_name, columns[err_col], latest_foreign);
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. You have defined a SET NULL condition but "
|
||||||
|
"field %s on index is defined as NOT NULL close to %s",
|
||||||
|
operation, create_name, columns[err_col], latest_foreign);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DB_FOREIGN_KEY_COLS_NOT_EQUAL: {
|
||||||
|
dict_field_t* field;
|
||||||
|
const char* col_name;
|
||||||
|
field = dict_index_get_nth_field(err_index, err_col);
|
||||||
|
|
||||||
|
col_name = dict_table_get_col_name(
|
||||||
|
table, dict_col_get_no(field->col));
|
||||||
|
fprintf(ef,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Field type or character set for column %s "
|
||||||
|
"does not mach referenced column %s close to %s\n",
|
||||||
|
operation, create_name, columns[err_col], col_name, latest_foreign);
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Field type or character set for column %s "
|
||||||
|
"does not mach referenced column %s close to %s",
|
||||||
|
operation, create_name, columns[err_col], col_name, latest_foreign);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ut_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
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
|
||||||
@@ -3600,15 +3738,20 @@ dict_create_foreign_constraints_low(
|
|||||||
DB_CANNOT_ADD_CONSTRAINT if any foreign
|
DB_CANNOT_ADD_CONSTRAINT if any foreign
|
||||||
keys are found. */
|
keys are found. */
|
||||||
{
|
{
|
||||||
dict_table_t* table;
|
dict_table_t* table = NULL;
|
||||||
dict_table_t* referenced_table;
|
dict_table_t* referenced_table = NULL;
|
||||||
dict_table_t* table_to_alter;
|
dict_table_t* table_to_alter = NULL;
|
||||||
|
dict_table_t* table_to_create = NULL;
|
||||||
ulint highest_id_so_far = 0;
|
ulint highest_id_so_far = 0;
|
||||||
dict_index_t* index;
|
dict_index_t* index = NULL;
|
||||||
dict_foreign_t* foreign;
|
dict_foreign_t* foreign = NULL;
|
||||||
const char* ptr = sql_string;
|
const char* ptr = sql_string;
|
||||||
const char* start_of_latest_foreign = sql_string;
|
const char* start_of_latest_foreign = sql_string;
|
||||||
|
const char* start_of_latest_set = NULL;
|
||||||
FILE* ef = dict_foreign_err_file;
|
FILE* ef = dict_foreign_err_file;
|
||||||
|
ulint index_error = DB_SUCCESS;
|
||||||
|
dict_index_t* err_index = NULL;
|
||||||
|
ulint err_col;
|
||||||
const char* constraint_name;
|
const char* constraint_name;
|
||||||
ibool success;
|
ibool success;
|
||||||
ulint error;
|
ulint error;
|
||||||
@@ -3621,29 +3764,68 @@ dict_create_foreign_constraints_low(
|
|||||||
ulint n_on_updates;
|
ulint n_on_updates;
|
||||||
const dict_col_t*columns[500];
|
const dict_col_t*columns[500];
|
||||||
const char* column_names[500];
|
const char* column_names[500];
|
||||||
|
const char* ref_column_names[500];
|
||||||
const char* referenced_table_name;
|
const char* referenced_table_name;
|
||||||
|
const char* create_table_name;
|
||||||
|
const char* orig;
|
||||||
|
char create_name[MAX_TABLE_NAME_LEN + 1];
|
||||||
|
const char operation[8];
|
||||||
|
|
||||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||||
|
|
||||||
table = dict_table_get_low(name, DICT_ERR_IGNORE_NONE);
|
table = dict_table_get_low(name, DICT_ERR_IGNORE_NONE);
|
||||||
|
/* First check if we are actually doing an ALTER TABLE, and in that
|
||||||
|
case look for the table being altered */
|
||||||
|
ptr = dict_accept(cs, ptr, "ALTER", &success);
|
||||||
|
|
||||||
|
strcpy((char *)operation, success ? "Alter " : "Create ");
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
orig = ptr;
|
||||||
|
ptr = dict_scan_to(ptr, "CREATE");
|
||||||
|
ptr = dict_scan_to(ptr, "TABLE");
|
||||||
|
ptr = dict_accept(cs, ptr, "TABLE", &success);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
ptr = dict_scan_table_name(cs, ptr, &table_to_create, name,
|
||||||
|
&success, heap, &create_table_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
char *bufend;
|
||||||
|
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
|
||||||
|
create_table_name, strlen(create_table_name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
create_name[bufend-create_name]='\0';
|
||||||
|
ptr = orig;
|
||||||
|
} else {
|
||||||
|
char *bufend;
|
||||||
|
ptr = orig;
|
||||||
|
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
|
||||||
|
name, strlen(name), trx->mysql_thd, TRUE);
|
||||||
|
create_name[bufend-create_name]='\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
||||||
if (table == NULL) {
|
if (table == NULL) {
|
||||||
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, create_name);
|
||||||
fprintf(ef,
|
fprintf(ef, "%s table %s with foreign key constraint"
|
||||||
"Cannot find the table in the internal"
|
" failed. Table %s not found from data dictionary."
|
||||||
" data dictionary of InnoDB.\n"
|
" Error close to %s.\n",
|
||||||
"Create table statement:\n%s\n", sql_string);
|
operation, create_name, create_name, start_of_latest_foreign);
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
ib_push_warning(trx, DB_ERROR,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Table %s not found from data dictionary."
|
||||||
|
" Error close to %s.",
|
||||||
|
operation, create_name, create_name, start_of_latest_foreign);
|
||||||
return(DB_ERROR);
|
return(DB_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First check if we are actually doing an ALTER TABLE, and in that
|
/* If not alter table jump to loop */
|
||||||
case look for the table being altered */
|
|
||||||
|
|
||||||
ptr = dict_accept(cs, ptr, "ALTER", &success);
|
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
|
||||||
goto loop;
|
goto loop;
|
||||||
@@ -3658,13 +3840,40 @@ 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 */
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_scan_table_name(cs, 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 (table_to_alter) {
|
||||||
|
char *bufend;
|
||||||
|
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
|
||||||
|
table_to_alter->name, strlen(table_to_alter->name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
create_name[bufend-create_name]='\0';
|
||||||
|
} else {
|
||||||
|
char *bufend;
|
||||||
|
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
|
||||||
|
referenced_table_name, strlen(referenced_table_name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
create_name[bufend-create_name]='\0';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
fprintf(stderr,
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
"InnoDB: Error: could not find"
|
dict_foreign_error_report_low(ef, create_name);
|
||||||
" the table being ALTERED in:\n%s\n",
|
fprintf(ef,
|
||||||
sql_string);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Table %s not found from data dictionary."
|
||||||
|
" Error close to %s.\n",
|
||||||
|
operation, create_name, create_name, orig);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_ERROR,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Table %s not found from data dictionary."
|
||||||
|
" Error close to %s.",
|
||||||
|
operation, create_name, create_name, orig);
|
||||||
|
|
||||||
return(DB_ERROR);
|
return(DB_ERROR);
|
||||||
}
|
}
|
||||||
@@ -3730,7 +3939,19 @@ 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)) {
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
dict_foreign_error_report_low(ef, create_name);
|
||||||
|
fprintf(ef, "%s table %s with foreign key constraint"
|
||||||
|
" failed. Temporary tables can't have foreign key constraints."
|
||||||
|
" Error close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Temporary tables can't have foreign key constraints."
|
||||||
|
" Error close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3766,11 +3987,21 @@ loop:
|
|||||||
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 */
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_skip_word(cs, ptr, &success);
|
ptr = dict_skip_word(cs, ptr, &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_report_syntax_err(
|
dict_foreign_report_syntax_err(
|
||||||
name, start_of_latest_foreign, ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
@@ -3790,15 +4021,26 @@ 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);
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_scan_col(cs, 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);
|
||||||
dict_foreign_error_report_low(ef, name);
|
dict_foreign_error_report_low(ef, create_name);
|
||||||
fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
|
fprintf(ef,
|
||||||
start_of_latest_foreign, ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3810,11 +4052,22 @@ col_loop1:
|
|||||||
goto col_loop1;
|
goto col_loop1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, ")", &success);
|
ptr = dict_accept(cs, ptr, ")", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_report_syntax_err(
|
dict_foreign_report_syntax_err(
|
||||||
name, start_of_latest_foreign, ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3822,27 +4075,41 @@ col_loop1:
|
|||||||
as the first fields and in the right order */
|
as the first fields and in the right order */
|
||||||
|
|
||||||
index = dict_foreign_find_index(table, column_names, i,
|
index = dict_foreign_find_index(table, column_names, i,
|
||||||
NULL, TRUE, FALSE);
|
NULL, TRUE, FALSE, &index_error, &err_col, &err_index);
|
||||||
|
|
||||||
if (!index) {
|
if (!index) {
|
||||||
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, create_name);
|
||||||
fputs("There is no index in table ", ef);
|
fputs("There is no index in table ", ef);
|
||||||
ut_print_name(ef, NULL, TRUE, name);
|
ut_print_name(ef, NULL, TRUE, create_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 " REFMAN "innodb-foreign-key-constraints.html\n"
|
"See " REFMAN "innodb-foreign-key-constraints.html\n"
|
||||||
"for correct foreign key definition.\n",
|
"for correct foreign key definition.\n",
|
||||||
start_of_latest_foreign);
|
start_of_latest_foreign);
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
|
||||||
|
|
||||||
return(DB_CHILD_NO_INDEX);
|
dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign,
|
||||||
|
column_names, index_error, err_col, err_index, table, ef);
|
||||||
|
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
|
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
|
||||||
|
|
||||||
if (!success || !my_isspace(cs, *ptr)) {
|
if (!success || !my_isspace(cs, *ptr)) {
|
||||||
dict_foreign_report_syntax_err(
|
dict_foreign_report_syntax_err(
|
||||||
name, start_of_latest_foreign, ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3891,24 +4158,50 @@ col_loop1:
|
|||||||
checking of foreign key constraints! */
|
checking of foreign key constraints! */
|
||||||
|
|
||||||
if (!success || (!referenced_table && trx->check_foreigns)) {
|
if (!success || (!referenced_table && trx->check_foreigns)) {
|
||||||
|
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
char* bufend;
|
||||||
|
|
||||||
|
bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||||
|
referenced_table_name, strlen(referenced_table_name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
buf[bufend - buf] = '\0';
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
|
||||||
|
"close to %s.",
|
||||||
|
operation, create_name, buf, start_of_latest_foreign);
|
||||||
|
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
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, create_name);
|
||||||
fprintf(ef, "%s:\nCannot resolve table name close to:\n"
|
fprintf(ef,
|
||||||
"%s\n",
|
"%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
|
||||||
start_of_latest_foreign, ptr);
|
"close to %s.\n",
|
||||||
|
operation, create_name, buf, start_of_latest_foreign);
|
||||||
|
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "(", &success);
|
ptr = dict_accept(cs, ptr, "(", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
dict_foreign_report_syntax_err(
|
||||||
ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3916,20 +4209,29 @@ col_loop1:
|
|||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
col_loop2:
|
col_loop2:
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
|
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
|
||||||
heap, column_names + i);
|
heap, ref_column_names + i);
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
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, create_name);
|
||||||
fprintf(ef, "%s:\nCannot resolve column name close to:\n"
|
fprintf(ef,
|
||||||
"%s\n",
|
"%s table %s with foreign key constraint"
|
||||||
start_of_latest_foreign, ptr);
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3939,13 +4241,23 @@ col_loop2:
|
|||||||
goto col_loop2;
|
goto col_loop2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, 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);
|
||||||
|
|
||||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
dict_foreign_report_syntax_err(
|
||||||
ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s. Too few referenced columns.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s. Too few referenced columns, you have %d when you should have %d.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig, i, foreign->n_fields);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3955,6 +4267,7 @@ 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 */
|
||||||
|
|
||||||
|
start_of_latest_set = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "ON", &success);
|
ptr = dict_accept(cs, ptr, "ON", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -3965,13 +4278,24 @@ scan_on_conditions:
|
|||||||
ptr = dict_accept(cs, ptr, "DELETE", &success);
|
ptr = dict_accept(cs, ptr, "DELETE", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "UPDATE", &success);
|
ptr = dict_accept(cs, ptr, "UPDATE", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
dict_foreign_report_syntax_err(
|
dict_foreign_report_syntax_err(
|
||||||
name, start_of_latest_foreign, ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4003,12 +4327,22 @@ scan_on_conditions:
|
|||||||
ptr = dict_accept(cs, ptr, "NO", &success);
|
ptr = dict_accept(cs, ptr, "NO", &success);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "ACTION", &success);
|
ptr = dict_accept(cs, ptr, "ACTION", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
dict_foreign_report_syntax_err(
|
dict_foreign_report_syntax_err(
|
||||||
name, start_of_latest_foreign, ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
@@ -4022,42 +4356,73 @@ scan_on_conditions:
|
|||||||
goto scan_on_conditions;
|
goto scan_on_conditions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "SET", &success);
|
ptr = dict_accept(cs, ptr, "SET", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
dict_foreign_report_syntax_err(
|
||||||
ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "NULL", &success);
|
ptr = dict_accept(cs, ptr, "NULL", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
dict_foreign_report_syntax_err(
|
||||||
ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < foreign->n_fields; j++) {
|
for (j = 0; j < foreign->n_fields; j++) {
|
||||||
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
|
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
|
||||||
& DATA_NOT_NULL) {
|
& DATA_NOT_NULL) {
|
||||||
|
const dict_col_t* col
|
||||||
|
= dict_index_get_nth_col(foreign->foreign_index, j);
|
||||||
|
const char* col_name = dict_table_get_col_name(foreign->foreign_index->table,
|
||||||
|
dict_col_get_no(col));
|
||||||
|
|
||||||
/* It is not sensible to define SET NULL
|
/* It is not sensible to define SET NULL
|
||||||
if the column is not allowed to be NULL! */
|
if the column is not allowed to be NULL! */
|
||||||
|
|
||||||
dict_foreign_free(foreign);
|
|
||||||
|
|
||||||
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, create_name);
|
||||||
fprintf(ef, "%s:\n"
|
fprintf(ef,
|
||||||
"You have defined a SET NULL condition"
|
"%s table %s with foreign key constraint"
|
||||||
" though some of the\n"
|
" failed. You have defined a SET NULL condition but column %s is defined as NOT NULL"
|
||||||
"columns are defined as NOT NULL.\n",
|
" in %s close to %s.\n",
|
||||||
start_of_latest_foreign);
|
operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. You have defined a SET NULL condition but column %s is defined as NOT NULL"
|
||||||
|
" in %s close to %s.",
|
||||||
|
operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
|
dict_foreign_free(foreign);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4074,16 +4439,22 @@ try_find_index:
|
|||||||
if (n_on_deletes > 1 || n_on_updates > 1) {
|
if (n_on_deletes > 1 || n_on_updates > 1) {
|
||||||
/* It is an error to define more than 1 action */
|
/* It is an error to define more than 1 action */
|
||||||
|
|
||||||
dict_foreign_free(foreign);
|
|
||||||
|
|
||||||
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, create_name);
|
||||||
fprintf(ef, "%s:\n"
|
fprintf(ef,
|
||||||
"You have twice an ON DELETE clause"
|
"%s table %s with foreign key constraint"
|
||||||
" or twice an ON UPDATE clause.\n",
|
" failed. You have more than one on delete or on update clause"
|
||||||
start_of_latest_foreign);
|
" in %s close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. You have more than one on delete or on update clause"
|
||||||
|
" in %s close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
dict_foreign_free(foreign);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4093,13 +4464,13 @@ try_find_index:
|
|||||||
|
|
||||||
if (referenced_table) {
|
if (referenced_table) {
|
||||||
index = dict_foreign_find_index(referenced_table,
|
index = dict_foreign_find_index(referenced_table,
|
||||||
column_names, i,
|
ref_column_names, i,
|
||||||
foreign->foreign_index,
|
foreign->foreign_index,
|
||||||
TRUE, FALSE);
|
TRUE, FALSE, &index_error, &err_col, &err_index);
|
||||||
if (!index) {
|
if (!index) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
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, create_name);
|
||||||
fprintf(ef, "%s:\n"
|
fprintf(ef, "%s:\n"
|
||||||
"Cannot find an index in the"
|
"Cannot find an index in the"
|
||||||
" referenced table where the\n"
|
" referenced table where the\n"
|
||||||
@@ -4117,9 +4488,13 @@ try_find_index:
|
|||||||
"innodb-foreign-key-constraints.html\n"
|
"innodb-foreign-key-constraints.html\n"
|
||||||
"for correct foreign key definition.\n",
|
"for correct foreign key definition.\n",
|
||||||
start_of_latest_foreign);
|
start_of_latest_foreign);
|
||||||
|
|
||||||
|
dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign,
|
||||||
|
column_names, index_error, err_col, err_index, referenced_table, ef);
|
||||||
|
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_PARENT_NO_INDEX);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ut_a(trx->check_foreigns == FALSE);
|
ut_a(trx->check_foreigns == FALSE);
|
||||||
@@ -4137,7 +4512,7 @@ try_find_index:
|
|||||||
i * sizeof(void*));
|
i * sizeof(void*));
|
||||||
for (i = 0; i < foreign->n_fields; i++) {
|
for (i = 0; i < foreign->n_fields; i++) {
|
||||||
foreign->referenced_col_names[i]
|
foreign->referenced_col_names[i]
|
||||||
= mem_heap_strdup(foreign->heap, column_names[i]);
|
= mem_heap_strdup(foreign->heap, ref_column_names[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We found an ok constraint definition: add to the lists */
|
/* We found an ok constraint definition: add to the lists */
|
||||||
@@ -5270,7 +5645,8 @@ dict_table_replace_index_in_foreign_list(
|
|||||||
foreign->referenced_table,
|
foreign->referenced_table,
|
||||||
foreign->referenced_col_names,
|
foreign->referenced_col_names,
|
||||||
foreign->n_fields, index,
|
foreign->n_fields, index,
|
||||||
/*check_charsets=*/TRUE, /*check_null=*/FALSE);
|
/*check_charsets=*/TRUE, /*check_null=*/FALSE,
|
||||||
|
NULL, NULL, NULL);
|
||||||
ut_ad(new_index || !trx->check_foreigns);
|
ut_ad(new_index || !trx->check_foreigns);
|
||||||
ut_ad(!new_index || new_index->table == index->table);
|
ut_ad(!new_index || new_index->table == index->table);
|
||||||
|
|
||||||
|
@@ -1654,6 +1654,7 @@ check_trx_exists(
|
|||||||
|
|
||||||
if (trx == NULL) {
|
if (trx == NULL) {
|
||||||
trx = innobase_trx_allocate(thd);
|
trx = innobase_trx_allocate(thd);
|
||||||
|
thd_set_ha_data(thd, innodb_hton_ptr, trx);
|
||||||
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
|
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
|
||||||
mem_analyze_corruption(trx);
|
mem_analyze_corruption(trx);
|
||||||
ut_error;
|
ut_error;
|
||||||
@@ -13711,3 +13712,29 @@ ib_warn_row_too_big(const dict_table_t* table)
|
|||||||
" ROW_FORMAT=COMPRESSED ": ""
|
" ROW_FORMAT=COMPRESSED ": ""
|
||||||
, prefix ? DICT_MAX_FIXED_COL_LEN : 0);
|
, prefix ? DICT_MAX_FIXED_COL_LEN : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************//**
|
||||||
|
Helper function to push warnings from InnoDB internals to SQL-layer. */
|
||||||
|
extern "C" UNIV_INTERN
|
||||||
|
void
|
||||||
|
ib_push_warning(
|
||||||
|
trx_t* trx, /*!< in: trx */
|
||||||
|
ulint error, /*!< in: error code to push as warning */
|
||||||
|
const char *format,/*!< in: warning message */
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
THD *thd = (THD *)trx->mysql_thd;
|
||||||
|
char *buf;
|
||||||
|
#define MAX_BUF_SIZE 4*1024
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
|
||||||
|
vsprintf(buf,format, args);
|
||||||
|
|
||||||
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||||
|
convert_error_code_to_mysql(error, 0, thd),
|
||||||
|
buf);
|
||||||
|
my_free(buf);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
@@ -106,6 +106,17 @@ UNIV_INTERN
|
|||||||
ulint
|
ulint
|
||||||
dict_create_or_check_foreign_constraint_tables(void);
|
dict_create_or_check_foreign_constraint_tables(void);
|
||||||
/*================================================*/
|
/*================================================*/
|
||||||
|
|
||||||
|
/********************************************************************//**
|
||||||
|
Construct foreign key constraint defintion from data dictionary information.
|
||||||
|
*/
|
||||||
|
UNIV_INTERN
|
||||||
|
char*
|
||||||
|
dict_foreign_def_get(
|
||||||
|
/*=================*/
|
||||||
|
dict_foreign_t* foreign,/*!< in: foreign */
|
||||||
|
trx_t* trx); /*!< in: trx */
|
||||||
|
|
||||||
/********************************************************************//**
|
/********************************************************************//**
|
||||||
Adds foreign key definitions to data dictionary tables in the database. We
|
Adds foreign key definitions to data dictionary tables in the database. We
|
||||||
look at table->foreign_list, and also generate names to constraints that were
|
look at table->foreign_list, and also generate names to constraints that were
|
||||||
|
@@ -339,5 +339,14 @@ innobase_convert_to_filename_charset(
|
|||||||
const char* from, /* in: identifier to convert */
|
const char* from, /* in: identifier to convert */
|
||||||
ulint len); /* in: length of 'to', in bytes */
|
ulint len); /* in: length of 'to', in bytes */
|
||||||
|
|
||||||
|
/********************************************************************//**
|
||||||
|
Helper function to push warnings from InnoDB internals to SQL-layer. */
|
||||||
|
UNIV_INTERN
|
||||||
|
void
|
||||||
|
ib_push_warning(
|
||||||
|
trx_t* trx, /*!< in: trx */
|
||||||
|
ulint error, /*!< in: error code to push as warning */
|
||||||
|
const char *format,/*!< in: warning message */
|
||||||
|
...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
|
Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -111,6 +111,17 @@ struct purge_node_struct{
|
|||||||
purge of a row */
|
purge of a row */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef UNIV_DEBUG
|
||||||
|
/***********************************************************//**
|
||||||
|
Validate the persisent cursor in the purge node. The purge node has two
|
||||||
|
references to the clustered index record - one via the ref member, and the
|
||||||
|
other via the persistent cursor. These two references must match each
|
||||||
|
other if the found_clust flag is set.
|
||||||
|
@return true if the persistent cursor is consistent with the ref member.*/
|
||||||
|
ibool
|
||||||
|
row_purge_validate_pcur(purge_node_t* node);
|
||||||
|
#endif /* UNIV_DEBUG */
|
||||||
|
|
||||||
#ifndef UNIV_NONINL
|
#ifndef UNIV_NONINL
|
||||||
#include "row0purge.ic"
|
#include "row0purge.ic"
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
|
||||||
Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
|
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2009, Percona Inc.
|
Copyright (c) 2009, Percona Inc.
|
||||||
|
|
||||||
Portions of this file contain modifications contributed and copyrighted
|
Portions of this file contain modifications contributed and copyrighted
|
||||||
@@ -1287,18 +1287,21 @@ os_file_create_simple_no_error_handling_func(
|
|||||||
#else /* __WIN__ */
|
#else /* __WIN__ */
|
||||||
os_file_t file;
|
os_file_t file;
|
||||||
int create_flag;
|
int create_flag;
|
||||||
|
const char* mode_str = NULL;
|
||||||
|
|
||||||
ut_a(name);
|
ut_a(name);
|
||||||
if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
|
if (create_mode != OS_FILE_OPEN && create_mode != OS_FILE_OPEN_RAW)
|
||||||
WAIT_ALLOW_WRITES();
|
WAIT_ALLOW_WRITES();
|
||||||
|
|
||||||
if (create_mode == OS_FILE_OPEN) {
|
if (create_mode == OS_FILE_OPEN) {
|
||||||
|
mode_str = "OPEN";
|
||||||
if (access_type == OS_FILE_READ_ONLY) {
|
if (access_type == OS_FILE_READ_ONLY) {
|
||||||
create_flag = O_RDONLY;
|
create_flag = O_RDONLY;
|
||||||
} else {
|
} else {
|
||||||
create_flag = O_RDWR;
|
create_flag = O_RDWR;
|
||||||
}
|
}
|
||||||
} else if (create_mode == OS_FILE_CREATE) {
|
} else if (create_mode == OS_FILE_CREATE) {
|
||||||
|
mode_str = "CREATE";
|
||||||
create_flag = O_RDWR | O_CREAT | O_EXCL;
|
create_flag = O_RDWR | O_CREAT | O_EXCL;
|
||||||
} else {
|
} else {
|
||||||
create_flag = 0;
|
create_flag = 0;
|
||||||
@@ -1323,6 +1326,14 @@ os_file_create_simple_no_error_handling_func(
|
|||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
*success = TRUE;
|
*success = TRUE;
|
||||||
|
|
||||||
|
/* This function is always called for data files, we should
|
||||||
|
disable OS caching (O_DIRECT) here as we do in
|
||||||
|
os_file_create_func(), so we open the same file in the same
|
||||||
|
mode, see man page of open(2). */
|
||||||
|
if (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT) {
|
||||||
|
os_file_set_nocache(file, name, mode_str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return(file);
|
return(file);
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -43,6 +43,7 @@ Created 3/14/1997 Heikki Tuuri
|
|||||||
#include "row0vers.h"
|
#include "row0vers.h"
|
||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
#include "log0log.h"
|
#include "log0log.h"
|
||||||
|
#include "rem0cmp.h"
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
IMPORTANT NOTE: Any operation that generates redo MUST check that there
|
IMPORTANT NOTE: Any operation that generates redo MUST check that there
|
||||||
@@ -80,7 +81,7 @@ row_purge_node_create(
|
|||||||
|
|
||||||
/***********************************************************//**
|
/***********************************************************//**
|
||||||
Repositions the pcur in the purge node on the clustered index record,
|
Repositions the pcur in the purge node on the clustered index record,
|
||||||
if found.
|
if found. If the record is not found, close pcur.
|
||||||
@return TRUE if the record was found */
|
@return TRUE if the record was found */
|
||||||
static
|
static
|
||||||
ibool
|
ibool
|
||||||
@@ -90,23 +91,28 @@ row_purge_reposition_pcur(
|
|||||||
purge_node_t* node, /*!< in: row purge node */
|
purge_node_t* node, /*!< in: row purge node */
|
||||||
mtr_t* mtr) /*!< in: mtr */
|
mtr_t* mtr) /*!< in: mtr */
|
||||||
{
|
{
|
||||||
ibool found;
|
if (node->found_clust) {
|
||||||
|
ut_ad(row_purge_validate_pcur(node));
|
||||||
|
|
||||||
|
node->found_clust = btr_pcur_restore_position(
|
||||||
|
mode, &(node->pcur), mtr);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
node->found_clust = row_search_on_row_ref(
|
||||||
|
&(node->pcur), mode, node->table, node->ref, mtr);
|
||||||
|
|
||||||
if (node->found_clust) {
|
if (node->found_clust) {
|
||||||
found = btr_pcur_restore_position(mode, &(node->pcur), mtr);
|
|
||||||
|
|
||||||
return(found);
|
|
||||||
}
|
|
||||||
|
|
||||||
found = row_search_on_row_ref(&(node->pcur), mode, node->table,
|
|
||||||
node->ref, mtr);
|
|
||||||
node->found_clust = found;
|
|
||||||
|
|
||||||
if (found) {
|
|
||||||
btr_pcur_store_position(&(node->pcur), mtr);
|
btr_pcur_store_position(&(node->pcur), mtr);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return(found);
|
/* Close the current cursor if we fail to position it correctly. */
|
||||||
|
if (!node->found_clust) {
|
||||||
|
btr_pcur_close(&node->pcur);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(node->found_clust);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************//**
|
/***********************************************************//**
|
||||||
@@ -143,8 +149,8 @@ row_purge_remove_clust_if_poss_low(
|
|||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
/* The record is already removed */
|
/* The record is already removed */
|
||||||
|
/* Persistent cursor is closed if reposition fails. */
|
||||||
btr_pcur_commit_specify_mtr(pcur, &mtr);
|
mtr_commit(&mtr);
|
||||||
|
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
}
|
}
|
||||||
@@ -258,7 +264,12 @@ row_purge_poss_sec(
|
|||||||
btr_pcur_get_rec(&node->pcur),
|
btr_pcur_get_rec(&node->pcur),
|
||||||
&mtr, index, entry);
|
&mtr, index, entry);
|
||||||
|
|
||||||
|
/* Persistent cursor is closed if reposition fails. */
|
||||||
|
if (node->found_clust) {
|
||||||
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
|
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
|
||||||
|
} else {
|
||||||
|
mtr_commit(&mtr);
|
||||||
|
}
|
||||||
|
|
||||||
return(can_delete);
|
return(can_delete);
|
||||||
}
|
}
|
||||||
@@ -806,3 +817,53 @@ row_purge_step(
|
|||||||
|
|
||||||
return(thr);
|
return(thr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef UNIV_DEBUG
|
||||||
|
/***********************************************************//**
|
||||||
|
Validate the persisent cursor in the purge node. The purge node has two
|
||||||
|
references to the clustered index record - one via the ref member, and the
|
||||||
|
other via the persistent cursor. These two references must match each
|
||||||
|
other if the found_clust flag is set.
|
||||||
|
@return true if the stored copy of persistent cursor is consistent
|
||||||
|
with the ref member.*/
|
||||||
|
ibool
|
||||||
|
row_purge_validate_pcur(
|
||||||
|
purge_node_t* node)
|
||||||
|
{
|
||||||
|
dict_index_t* clust_index;
|
||||||
|
ulint* offsets;
|
||||||
|
int st;
|
||||||
|
|
||||||
|
if (!node->found_clust) {
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->index == NULL) {
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->pcur.old_stored != BTR_PCUR_OLD_STORED) {
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
clust_index = node->pcur.btr_cur.index;
|
||||||
|
|
||||||
|
offsets = rec_get_offsets(node->pcur.old_rec, clust_index, NULL,
|
||||||
|
node->pcur.old_n_fields, &node->heap);
|
||||||
|
|
||||||
|
/* Here we are comparing the purge ref record and the stored initial
|
||||||
|
part in persistent cursor. Both cases we store n_uniq fields of the
|
||||||
|
cluster index and so it is fine to do the comparison. We note this
|
||||||
|
dependency here as pcur and ref belong to different modules. */
|
||||||
|
st = cmp_dtuple_rec(node->ref, node->pcur.old_rec, offsets);
|
||||||
|
|
||||||
|
if (st != 0) {
|
||||||
|
fprintf(stderr, "Purge node pcur validation failed\n");
|
||||||
|
dtuple_print(stderr, node->ref);
|
||||||
|
rec_print(stderr, node->pcur.old_rec, clust_index);
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
#endif /* UNIV_DEBUG */
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2008, Google Inc.
|
Copyright (c) 2008, Google Inc.
|
||||||
|
|
||||||
Portions of this file contain modifications contributed and copyrighted by
|
Portions of this file contain modifications contributed and copyrighted by
|
||||||
@@ -1666,6 +1666,10 @@ buf_pool_watch_set(
|
|||||||
|
|
||||||
/* buf_pool->watch is protected by zip_mutex for now */
|
/* buf_pool->watch is protected by zip_mutex for now */
|
||||||
mutex_enter(&buf_pool->zip_mutex);
|
mutex_enter(&buf_pool->zip_mutex);
|
||||||
|
|
||||||
|
/* The maximum number of purge threads should never exceed
|
||||||
|
BUF_POOL_WATCH_SIZE. So there is no way for purge thread
|
||||||
|
instance to hold a watch when setting another watch. */
|
||||||
for (i = 0; i < BUF_POOL_WATCH_SIZE; i++) {
|
for (i = 0; i < BUF_POOL_WATCH_SIZE; i++) {
|
||||||
bpage = &buf_pool->watch[i];
|
bpage = &buf_pool->watch[i];
|
||||||
|
|
||||||
|
@@ -1626,6 +1626,104 @@ dict_create_add_foreign_field_to_dictionary(
|
|||||||
table, foreign, trx));
|
table, foreign, trx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************//**
|
||||||
|
Construct foreign key constraint defintion from data dictionary information.
|
||||||
|
*/
|
||||||
|
UNIV_INTERN
|
||||||
|
char*
|
||||||
|
dict_foreign_def_get(
|
||||||
|
/*=================*/
|
||||||
|
dict_foreign_t* foreign,/*!< in: foreign */
|
||||||
|
trx_t* trx) /*!< in: trx */
|
||||||
|
{
|
||||||
|
char* fk_def = mem_heap_alloc(foreign->heap, 4*1024);
|
||||||
|
const char* tbname;
|
||||||
|
char tablebuf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
int i;
|
||||||
|
char* bufend;
|
||||||
|
|
||||||
|
tbname = dict_remove_db_name(foreign->id);
|
||||||
|
bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
|
||||||
|
tbname, strlen(tbname), trx->mysql_thd, FALSE);
|
||||||
|
tablebuf[bufend - tablebuf] = '\0';
|
||||||
|
|
||||||
|
sprintf(fk_def,
|
||||||
|
(char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf);
|
||||||
|
|
||||||
|
for(i = 0; i < foreign->n_fields; i++) {
|
||||||
|
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->foreign_col_names[i],
|
||||||
|
strlen(foreign->foreign_col_names[i]),
|
||||||
|
trx->mysql_thd, FALSE);
|
||||||
|
strcat(fk_def, buf);
|
||||||
|
if (i < foreign->n_fields-1) {
|
||||||
|
strcat(fk_def, (char *)",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strcat(fk_def,(char *)") REFERENCES ");
|
||||||
|
|
||||||
|
bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->referenced_table_name,
|
||||||
|
strlen(foreign->referenced_table_name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
tablebuf[bufend - tablebuf] = '\0';
|
||||||
|
|
||||||
|
strcat(fk_def, tablebuf);
|
||||||
|
strcat(fk_def, " (");
|
||||||
|
|
||||||
|
for(i = 0; i < foreign->n_fields; i++) {
|
||||||
|
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->referenced_col_names[i],
|
||||||
|
strlen(foreign->referenced_col_names[i]),
|
||||||
|
trx->mysql_thd, FALSE);
|
||||||
|
buf[bufend - buf] = '\0';
|
||||||
|
strcat(fk_def, buf);
|
||||||
|
if (i < foreign->n_fields-1) {
|
||||||
|
strcat(fk_def, (char *)",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strcat(fk_def, (char *)")");
|
||||||
|
|
||||||
|
return fk_def;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************//**
|
||||||
|
Convert foreign key column names from data dictionary to SQL-layer.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
dict_foreign_def_get_fields(
|
||||||
|
/*========================*/
|
||||||
|
dict_foreign_t* foreign,/*!< in: foreign */
|
||||||
|
trx_t* trx, /*!< in: trx */
|
||||||
|
char** field, /*!< out: foreign column */
|
||||||
|
char** field2, /*!< out: referenced column */
|
||||||
|
int col_no) /*!< in: column number */
|
||||||
|
{
|
||||||
|
char* bufend;
|
||||||
|
char* fieldbuf = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
|
||||||
|
char* fieldbuf2 = mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
|
||||||
|
|
||||||
|
bufend = innobase_convert_name(fieldbuf, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->foreign_col_names[col_no],
|
||||||
|
strlen(foreign->foreign_col_names[col_no]),
|
||||||
|
trx->mysql_thd, FALSE);
|
||||||
|
|
||||||
|
fieldbuf[bufend - fieldbuf] = '\0';
|
||||||
|
|
||||||
|
bufend = innobase_convert_name(fieldbuf2, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->referenced_col_names[col_no],
|
||||||
|
strlen(foreign->referenced_col_names[col_no]),
|
||||||
|
trx->mysql_thd, FALSE);
|
||||||
|
|
||||||
|
fieldbuf2[bufend - fieldbuf2] = '\0';
|
||||||
|
*field = fieldbuf;
|
||||||
|
*field2 = fieldbuf2;
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************//**
|
/********************************************************************//**
|
||||||
Add a single foreign key definition to the data dictionary tables in the
|
Add a single foreign key definition to the data dictionary tables in the
|
||||||
database. We also generate names to constraints that were not named by the
|
database. We also generate names to constraints that were not named by the
|
||||||
@@ -1708,6 +1806,29 @@ dict_create_add_foreign_to_dictionary(
|
|||||||
|
|
||||||
if (error != DB_SUCCESS) {
|
if (error != DB_SUCCESS) {
|
||||||
|
|
||||||
|
if (error == DB_DUPLICATE_KEY) {
|
||||||
|
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
char tablename[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
char* fk_def;
|
||||||
|
|
||||||
|
innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
|
||||||
|
table->name, strlen(table->name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
|
||||||
|
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
|
||||||
|
|
||||||
|
fk_def = dict_foreign_def_get(foreign, trx);
|
||||||
|
|
||||||
|
ib_push_warning(trx, error,
|
||||||
|
"Create or Alter table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint %s"
|
||||||
|
" already exists on data dictionary."
|
||||||
|
" Foreign key constraint names need to be unique in database."
|
||||||
|
" Error in foreign key definition: %s.",
|
||||||
|
tablename, buf, fk_def);
|
||||||
|
}
|
||||||
|
|
||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1716,6 +1837,26 @@ dict_create_add_foreign_to_dictionary(
|
|||||||
i, table, foreign, trx);
|
i, table, foreign, trx);
|
||||||
|
|
||||||
if (error != DB_SUCCESS) {
|
if (error != DB_SUCCESS) {
|
||||||
|
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
char tablename[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
char* field=NULL;
|
||||||
|
char* field2=NULL;
|
||||||
|
char* fk_def;
|
||||||
|
|
||||||
|
innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
|
||||||
|
table->name, strlen(table->name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||||
|
foreign->id, strlen(foreign->id), trx->mysql_thd, FALSE);
|
||||||
|
fk_def = dict_foreign_def_get(foreign, trx);
|
||||||
|
dict_foreign_def_get_fields(foreign, trx, &field, &field2, i);
|
||||||
|
|
||||||
|
ib_push_warning(trx, error,
|
||||||
|
"Create or Alter table %s with foreign key constraint"
|
||||||
|
" failed. Error adding foreign key constraint name %s"
|
||||||
|
" fields %s or %s to the dictionary."
|
||||||
|
" Error in foreign key definition: %s.",
|
||||||
|
tablename, buf, i+1, fk_def);
|
||||||
|
|
||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -2663,6 +2663,7 @@ dict_foreign_remove_from_cache(
|
|||||||
foreign);
|
foreign);
|
||||||
|
|
||||||
rbt = foreign->referenced_table->referenced_rbt;
|
rbt = foreign->referenced_table->referenced_rbt;
|
||||||
|
|
||||||
if (rbt != NULL && foreign->id != NULL) {
|
if (rbt != NULL && foreign->id != NULL) {
|
||||||
const ib_rbt_node_t* node
|
const ib_rbt_node_t* node
|
||||||
= rbt_lookup(rbt, foreign->id);
|
= rbt_lookup(rbt, foreign->id);
|
||||||
@@ -2747,6 +2748,11 @@ dict_foreign_find(
|
|||||||
DBUG_RETURN(NULL);
|
DBUG_RETURN(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DB_FOREIGN_KEY_IS_PREFIX_INDEX 200
|
||||||
|
#define DB_FOREIGN_KEY_COL_NOT_NULL 201
|
||||||
|
#define DB_FOREIGN_KEY_COLS_NOT_EQUAL 202
|
||||||
|
#define DB_FOREIGN_KEY_INDEX_NOT_FOUND 203
|
||||||
|
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
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 and is not marked for deletion and is not the same
|
in the same order and is not marked for deletion and is not the same
|
||||||
@@ -2764,12 +2770,21 @@ dict_foreign_find_index(
|
|||||||
ibool check_charsets,
|
ibool check_charsets,
|
||||||
/*!< in: whether to check charsets.
|
/*!< in: whether to check charsets.
|
||||||
only has an effect if types_idx != NULL */
|
only has an effect if types_idx != NULL */
|
||||||
ulint check_null)
|
ulint check_null,
|
||||||
/*!< in: nonzero if none of the columns must
|
/*!< in: nonzero if none of the columns must
|
||||||
be declared NOT NULL */
|
be declared NOT NULL */
|
||||||
|
ulint* error, /*!< out: error code */
|
||||||
|
ulint* err_col_no,
|
||||||
|
/*!< out: column number where error happened */
|
||||||
|
dict_index_t** err_index)
|
||||||
|
/*!< out: index where error happened */
|
||||||
{
|
{
|
||||||
dict_index_t* index;
|
dict_index_t* index;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
*error = DB_FOREIGN_KEY_INDEX_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
index = dict_table_get_first_index(table);
|
index = dict_table_get_first_index(table);
|
||||||
|
|
||||||
while (index != NULL) {
|
while (index != NULL) {
|
||||||
@@ -2795,6 +2810,12 @@ dict_foreign_find_index(
|
|||||||
/* We do not accept column prefix
|
/* We do not accept column prefix
|
||||||
indexes here */
|
indexes here */
|
||||||
|
|
||||||
|
if (error && err_col_no && err_index) {
|
||||||
|
*error = DB_FOREIGN_KEY_IS_PREFIX_INDEX;
|
||||||
|
*err_col_no = i;
|
||||||
|
*err_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2806,6 +2827,11 @@ dict_foreign_find_index(
|
|||||||
if (check_null
|
if (check_null
|
||||||
&& (field->col->prtype & DATA_NOT_NULL)) {
|
&& (field->col->prtype & DATA_NOT_NULL)) {
|
||||||
|
|
||||||
|
if (error && err_col_no && err_index) {
|
||||||
|
*error = DB_FOREIGN_KEY_COL_NOT_NULL;
|
||||||
|
*err_col_no = i;
|
||||||
|
*err_index = index;
|
||||||
|
}
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2815,6 +2841,12 @@ dict_foreign_find_index(
|
|||||||
i),
|
i),
|
||||||
check_charsets)) {
|
check_charsets)) {
|
||||||
|
|
||||||
|
if (error && err_col_no && err_index) {
|
||||||
|
*error = DB_FOREIGN_KEY_COLS_NOT_EQUAL;
|
||||||
|
*err_col_no = i;
|
||||||
|
*err_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2822,6 +2854,10 @@ dict_foreign_find_index(
|
|||||||
if (i == n_cols) {
|
if (i == n_cols) {
|
||||||
/* We found a matching index */
|
/* We found a matching index */
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
*error = DB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
return(index);
|
return(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2848,8 +2884,9 @@ wsrep_dict_foreign_find_index(
|
|||||||
/*!< in: nonzero if none of the columns must
|
/*!< in: nonzero if none of the columns must
|
||||||
be declared NOT NULL */
|
be declared NOT NULL */
|
||||||
{
|
{
|
||||||
return dict_foreign_find_index(
|
return dict_foreign_find_index(table, columns, n_cols, types_idx,
|
||||||
table, columns, n_cols, types_idx, check_charsets, check_null);
|
check_charsets, check_null,
|
||||||
|
NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
/**********************************************************************//**
|
/**********************************************************************//**
|
||||||
@@ -2872,7 +2909,7 @@ dict_foreign_find_equiv_index(
|
|||||||
foreign->foreign_table,
|
foreign->foreign_table,
|
||||||
foreign->foreign_col_names, foreign->n_fields,
|
foreign->foreign_col_names, foreign->n_fields,
|
||||||
foreign->foreign_index, TRUE, /* check types */
|
foreign->foreign_index, TRUE, /* check types */
|
||||||
FALSE/* allow columns to be NULL */));
|
FALSE/* allow columns to be NULL */, NULL, NULL, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !UNIV_HOTBACKUP */
|
#endif /* !UNIV_HOTBACKUP */
|
||||||
@@ -3035,11 +3072,15 @@ dict_foreign_add_to_cache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (for_in_cache->referenced_table == NULL && ref_table) {
|
if (for_in_cache->referenced_table == NULL && ref_table) {
|
||||||
|
ulint index_error;
|
||||||
|
ulint err_col;
|
||||||
|
dict_index_t *err_index=NULL;
|
||||||
|
|
||||||
index = dict_foreign_find_index(
|
index = dict_foreign_find_index(
|
||||||
ref_table,
|
ref_table,
|
||||||
for_in_cache->referenced_col_names,
|
for_in_cache->referenced_col_names,
|
||||||
for_in_cache->n_fields, for_in_cache->foreign_index,
|
for_in_cache->n_fields, for_in_cache->foreign_index,
|
||||||
check_charsets, FALSE);
|
check_charsets, FALSE, &index_error, &err_col, &err_index);
|
||||||
|
|
||||||
if (index == NULL
|
if (index == NULL
|
||||||
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
|
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
|
||||||
@@ -3071,6 +3112,9 @@ dict_foreign_add_to_cache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (for_in_cache->foreign_table == NULL && for_table) {
|
if (for_in_cache->foreign_table == NULL && for_table) {
|
||||||
|
ulint index_error;
|
||||||
|
ulint err_col;
|
||||||
|
dict_index_t* err_index=NULL;
|
||||||
|
|
||||||
index = dict_foreign_find_index(
|
index = dict_foreign_find_index(
|
||||||
for_table,
|
for_table,
|
||||||
@@ -3079,7 +3123,8 @@ dict_foreign_add_to_cache(
|
|||||||
for_in_cache->referenced_index, check_charsets,
|
for_in_cache->referenced_index, check_charsets,
|
||||||
for_in_cache->type
|
for_in_cache->type
|
||||||
& (DICT_FOREIGN_ON_DELETE_SET_NULL
|
& (DICT_FOREIGN_ON_DELETE_SET_NULL
|
||||||
| DICT_FOREIGN_ON_UPDATE_SET_NULL));
|
| DICT_FOREIGN_ON_UPDATE_SET_NULL),
|
||||||
|
&index_error, &err_col, &err_index);
|
||||||
|
|
||||||
if (index == NULL
|
if (index == NULL
|
||||||
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
|
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
|
||||||
@@ -3690,6 +3735,8 @@ static
|
|||||||
void
|
void
|
||||||
dict_foreign_report_syntax_err(
|
dict_foreign_report_syntax_err(
|
||||||
/*===========================*/
|
/*===========================*/
|
||||||
|
const char* fmt, /*!< in: syntax err msg */
|
||||||
|
const char* oper, /*!< in: operation */
|
||||||
const char* name, /*!< in: table name */
|
const char* name, /*!< in: table name */
|
||||||
const char* start_of_latest_foreign,
|
const char* start_of_latest_foreign,
|
||||||
/*!< in: start of the foreign key clause
|
/*!< in: start of the foreign key clause
|
||||||
@@ -3700,11 +3747,101 @@ dict_foreign_report_syntax_err(
|
|||||||
|
|
||||||
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);
|
||||||
fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
|
fprintf(ef, fmt, oper, name, start_of_latest_foreign, ptr);
|
||||||
start_of_latest_foreign, ptr);
|
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************//**
|
||||||
|
Push warning message to SQL-layer based on foreign key constraint
|
||||||
|
index match error. */
|
||||||
|
static
|
||||||
|
void
|
||||||
|
dict_foreign_push_index_error(
|
||||||
|
/*==========================*/
|
||||||
|
trx_t* trx, /*!< in: trx */
|
||||||
|
const char* operation, /*!< in: operation create or alter
|
||||||
|
*/
|
||||||
|
const char* create_name, /*!< in: table name in create or
|
||||||
|
alter table */
|
||||||
|
const char* latest_foreign, /*!< in: start of latest foreign key
|
||||||
|
constraint name */
|
||||||
|
const char** columns, /*!< in: foreign key columns */
|
||||||
|
ulint index_error, /*!< in: error code */
|
||||||
|
ulint err_col, /*!< in: column where error happened
|
||||||
|
*/
|
||||||
|
dict_index_t* err_index, /*!< in: index where error happened
|
||||||
|
*/
|
||||||
|
dict_table_t* table, /*!< in: table */
|
||||||
|
FILE* ef) /*!< in: output stream */
|
||||||
|
{
|
||||||
|
switch (index_error) {
|
||||||
|
case DB_FOREIGN_KEY_INDEX_NOT_FOUND: {
|
||||||
|
fprintf(ef,
|
||||||
|
"%s table '%s' with foreign key constraint"
|
||||||
|
" failed. There is no index in the referenced"
|
||||||
|
" table where the referenced columns appear"
|
||||||
|
" as the first columns. Error close to %s.\n",
|
||||||
|
operation, create_name, latest_foreign);
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table '%s' with foreign key constraint"
|
||||||
|
" failed. There is no index in the referenced"
|
||||||
|
" table where the referenced columns appear"
|
||||||
|
" as the first columns. Error close to %s.",
|
||||||
|
operation, create_name, latest_foreign);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DB_FOREIGN_KEY_IS_PREFIX_INDEX: {
|
||||||
|
fprintf(ef,
|
||||||
|
"%s table '%s' with foreign key constraint"
|
||||||
|
" failed. There is only prefix index in the referenced"
|
||||||
|
" table where the referenced columns appear"
|
||||||
|
" as the first columns. Error close to %s.\n",
|
||||||
|
operation, create_name, latest_foreign);
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table '%s' with foreign key constraint"
|
||||||
|
" failed. There is only prefix index in the referenced"
|
||||||
|
" table where the referenced columns appear"
|
||||||
|
" as the first columns. Error close to %s.",
|
||||||
|
operation, create_name, latest_foreign);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DB_FOREIGN_KEY_COL_NOT_NULL: {
|
||||||
|
fprintf(ef,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. You have defined a SET NULL condition but "
|
||||||
|
"field %s on index is defined as NOT NULL close to %s\n",
|
||||||
|
operation, create_name, columns[err_col], latest_foreign);
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. You have defined a SET NULL condition but "
|
||||||
|
"field %s on index is defined as NOT NULL close to %s",
|
||||||
|
operation, create_name, columns[err_col], latest_foreign);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DB_FOREIGN_KEY_COLS_NOT_EQUAL: {
|
||||||
|
dict_field_t* field;
|
||||||
|
const char* col_name;
|
||||||
|
field = dict_index_get_nth_field(err_index, err_col);
|
||||||
|
|
||||||
|
col_name = dict_table_get_col_name(
|
||||||
|
table, dict_col_get_no(field->col));
|
||||||
|
fprintf(ef,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Field type or character set for column %s "
|
||||||
|
"does not mach referenced column %s close to %s\n",
|
||||||
|
operation, create_name, columns[err_col], col_name, latest_foreign);
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Field type or character set for column %s "
|
||||||
|
"does not mach referenced column %s close to %s",
|
||||||
|
operation, create_name, columns[err_col], col_name, latest_foreign);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ut_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
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
|
||||||
@@ -3733,15 +3870,20 @@ dict_create_foreign_constraints_low(
|
|||||||
DB_CANNOT_ADD_CONSTRAINT if any foreign
|
DB_CANNOT_ADD_CONSTRAINT if any foreign
|
||||||
keys are found. */
|
keys are found. */
|
||||||
{
|
{
|
||||||
dict_table_t* table;
|
dict_table_t* table = NULL;
|
||||||
dict_table_t* referenced_table;
|
dict_table_t* referenced_table = NULL;
|
||||||
dict_table_t* table_to_alter;
|
dict_table_t* table_to_alter = NULL;
|
||||||
|
dict_table_t* table_to_create = NULL;
|
||||||
ulint highest_id_so_far = 0;
|
ulint highest_id_so_far = 0;
|
||||||
dict_index_t* index;
|
dict_index_t* index = NULL;
|
||||||
dict_foreign_t* foreign;
|
dict_foreign_t* foreign = NULL;
|
||||||
const char* ptr = sql_string;
|
const char* ptr = sql_string;
|
||||||
const char* start_of_latest_foreign = sql_string;
|
const char* start_of_latest_foreign = sql_string;
|
||||||
|
const char* start_of_latest_set = NULL;
|
||||||
FILE* ef = dict_foreign_err_file;
|
FILE* ef = dict_foreign_err_file;
|
||||||
|
ulint index_error = DB_SUCCESS;
|
||||||
|
dict_index_t* err_index = NULL;
|
||||||
|
ulint err_col;
|
||||||
const char* constraint_name;
|
const char* constraint_name;
|
||||||
ibool success;
|
ibool success;
|
||||||
ulint error;
|
ulint error;
|
||||||
@@ -3754,29 +3896,68 @@ dict_create_foreign_constraints_low(
|
|||||||
ulint n_on_updates;
|
ulint n_on_updates;
|
||||||
const dict_col_t*columns[500];
|
const dict_col_t*columns[500];
|
||||||
const char* column_names[500];
|
const char* column_names[500];
|
||||||
|
const char* ref_column_names[500];
|
||||||
const char* referenced_table_name;
|
const char* referenced_table_name;
|
||||||
|
const char* create_table_name;
|
||||||
|
const char* orig;
|
||||||
|
char create_name[MAX_TABLE_NAME_LEN + 1];
|
||||||
|
const char operation[8];
|
||||||
|
|
||||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||||
|
|
||||||
table = dict_table_get_low(name, DICT_ERR_IGNORE_NONE);
|
table = dict_table_get_low(name, DICT_ERR_IGNORE_NONE);
|
||||||
|
/* First check if we are actually doing an ALTER TABLE, and in that
|
||||||
|
case look for the table being altered */
|
||||||
|
ptr = dict_accept(cs, ptr, "ALTER", &success);
|
||||||
|
|
||||||
|
strcpy((char *)operation, success ? "Alter " : "Create ");
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
orig = ptr;
|
||||||
|
ptr = dict_scan_to(ptr, "CREATE");
|
||||||
|
ptr = dict_scan_to(ptr, "TABLE");
|
||||||
|
ptr = dict_accept(cs, ptr, "TABLE", &success);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
ptr = dict_scan_table_name(cs, ptr, &table_to_create, name,
|
||||||
|
&success, heap, &create_table_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
char *bufend;
|
||||||
|
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
|
||||||
|
create_table_name, strlen(create_table_name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
create_name[bufend-create_name]='\0';
|
||||||
|
ptr = orig;
|
||||||
|
} else {
|
||||||
|
char *bufend;
|
||||||
|
ptr = orig;
|
||||||
|
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
|
||||||
|
name, strlen(name), trx->mysql_thd, TRUE);
|
||||||
|
create_name[bufend-create_name]='\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
||||||
if (table == NULL) {
|
if (table == NULL) {
|
||||||
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, create_name);
|
||||||
fprintf(ef,
|
fprintf(ef, "%s table %s with foreign key constraint"
|
||||||
"Cannot find the table in the internal"
|
" failed. Table %s not found from data dictionary."
|
||||||
" data dictionary of InnoDB.\n"
|
" Error close to %s.\n",
|
||||||
"Create table statement:\n%s\n", sql_string);
|
operation, create_name, create_name, start_of_latest_foreign);
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
ib_push_warning(trx, DB_ERROR,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Table %s not found from data dictionary."
|
||||||
|
" Error close to %s.",
|
||||||
|
operation, create_name, create_name, start_of_latest_foreign);
|
||||||
return(DB_ERROR);
|
return(DB_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First check if we are actually doing an ALTER TABLE, and in that
|
/* If not alter table jump to loop */
|
||||||
case look for the table being altered */
|
|
||||||
|
|
||||||
ptr = dict_accept(cs, ptr, "ALTER", &success);
|
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
|
||||||
goto loop;
|
goto loop;
|
||||||
@@ -3791,13 +3972,40 @@ 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 */
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_scan_table_name(cs, 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 (table_to_alter) {
|
||||||
|
char *bufend;
|
||||||
|
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
|
||||||
|
table_to_alter->name, strlen(table_to_alter->name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
create_name[bufend-create_name]='\0';
|
||||||
|
} else {
|
||||||
|
char *bufend;
|
||||||
|
bufend = innobase_convert_name((char *)create_name, MAX_TABLE_NAME_LEN,
|
||||||
|
referenced_table_name, strlen(referenced_table_name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
create_name[bufend-create_name]='\0';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
fprintf(stderr,
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
"InnoDB: Error: could not find"
|
dict_foreign_error_report_low(ef, create_name);
|
||||||
" the table being ALTERED in:\n%s\n",
|
fprintf(ef,
|
||||||
sql_string);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Table %s not found from data dictionary."
|
||||||
|
" Error close to %s.\n",
|
||||||
|
operation, create_name, create_name, orig);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_ERROR,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Table %s not found from data dictionary."
|
||||||
|
" Error close to %s.",
|
||||||
|
operation, create_name, create_name, orig);
|
||||||
|
|
||||||
return(DB_ERROR);
|
return(DB_ERROR);
|
||||||
}
|
}
|
||||||
@@ -3863,7 +4071,19 @@ 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)) {
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
dict_foreign_error_report_low(ef, create_name);
|
||||||
|
fprintf(ef, "%s table %s with foreign key constraint"
|
||||||
|
" failed. Temporary tables can't have foreign key constraints."
|
||||||
|
" Error close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Temporary tables can't have foreign key constraints."
|
||||||
|
" Error close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3899,11 +4119,21 @@ loop:
|
|||||||
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 */
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_skip_word(cs, ptr, &success);
|
ptr = dict_skip_word(cs, ptr, &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_report_syntax_err(
|
dict_foreign_report_syntax_err(
|
||||||
name, start_of_latest_foreign, ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
@@ -3923,15 +4153,26 @@ 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);
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_scan_col(cs, 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);
|
||||||
dict_foreign_error_report_low(ef, name);
|
dict_foreign_error_report_low(ef, create_name);
|
||||||
fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
|
fprintf(ef,
|
||||||
start_of_latest_foreign, ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3943,11 +4184,22 @@ col_loop1:
|
|||||||
goto col_loop1;
|
goto col_loop1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, ")", &success);
|
ptr = dict_accept(cs, ptr, ")", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_report_syntax_err(
|
dict_foreign_report_syntax_err(
|
||||||
name, start_of_latest_foreign, ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3955,27 +4207,41 @@ col_loop1:
|
|||||||
as the first fields and in the right order */
|
as the first fields and in the right order */
|
||||||
|
|
||||||
index = dict_foreign_find_index(table, column_names, i,
|
index = dict_foreign_find_index(table, column_names, i,
|
||||||
NULL, TRUE, FALSE);
|
NULL, TRUE, FALSE, &index_error, &err_col, &err_index);
|
||||||
|
|
||||||
if (!index) {
|
if (!index) {
|
||||||
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, create_name);
|
||||||
fputs("There is no index in table ", ef);
|
fputs("There is no index in table ", ef);
|
||||||
ut_print_name(ef, NULL, TRUE, name);
|
ut_print_name(ef, NULL, TRUE, create_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 " REFMAN "innodb-foreign-key-constraints.html\n"
|
"See " REFMAN "innodb-foreign-key-constraints.html\n"
|
||||||
"for correct foreign key definition.\n",
|
"for correct foreign key definition.\n",
|
||||||
start_of_latest_foreign);
|
start_of_latest_foreign);
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
|
||||||
|
|
||||||
return(DB_CHILD_NO_INDEX);
|
dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign,
|
||||||
|
column_names, index_error, err_col, err_index, table, ef);
|
||||||
|
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
|
ptr = dict_accept(cs, ptr, "REFERENCES", &success);
|
||||||
|
|
||||||
if (!success || !my_isspace(cs, *ptr)) {
|
if (!success || !my_isspace(cs, *ptr)) {
|
||||||
dict_foreign_report_syntax_err(
|
dict_foreign_report_syntax_err(
|
||||||
name, start_of_latest_foreign, ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4024,24 +4290,50 @@ col_loop1:
|
|||||||
checking of foreign key constraints! */
|
checking of foreign key constraints! */
|
||||||
|
|
||||||
if (!success || (!referenced_table && trx->check_foreigns)) {
|
if (!success || (!referenced_table && trx->check_foreigns)) {
|
||||||
|
char buf[MAX_TABLE_NAME_LEN + 1] = "";
|
||||||
|
char* bufend;
|
||||||
|
|
||||||
|
bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
|
||||||
|
referenced_table_name, strlen(referenced_table_name),
|
||||||
|
trx->mysql_thd, TRUE);
|
||||||
|
buf[bufend - buf] = '\0';
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
|
||||||
|
"close to %s.",
|
||||||
|
operation, create_name, buf, start_of_latest_foreign);
|
||||||
|
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
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, create_name);
|
||||||
fprintf(ef, "%s:\nCannot resolve table name close to:\n"
|
fprintf(ef,
|
||||||
"%s\n",
|
"%s table %s with foreign key constraint failed. Referenced table %s not found in the data dictionary "
|
||||||
start_of_latest_foreign, ptr);
|
"close to %s.\n",
|
||||||
|
operation, create_name, buf, start_of_latest_foreign);
|
||||||
|
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "(", &success);
|
ptr = dict_accept(cs, ptr, "(", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
dict_foreign_report_syntax_err(
|
||||||
ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4049,20 +4341,29 @@ col_loop1:
|
|||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
col_loop2:
|
col_loop2:
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
|
ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
|
||||||
heap, column_names + i);
|
heap, ref_column_names + i);
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
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, create_name);
|
||||||
fprintf(ef, "%s:\nCannot resolve column name close to:\n"
|
fprintf(ef,
|
||||||
"%s\n",
|
"%s table %s with foreign key constraint"
|
||||||
start_of_latest_foreign, ptr);
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4072,13 +4373,23 @@ col_loop2:
|
|||||||
goto col_loop2;
|
goto col_loop2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, 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);
|
||||||
|
|
||||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
dict_foreign_report_syntax_err(
|
||||||
ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s. Too few referenced columns\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s. Too few referenced columns, you have %d when you should have %d.",
|
||||||
|
operation, create_name, start_of_latest_foreign, orig, i, foreign->n_fields);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4088,6 +4399,7 @@ 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 */
|
||||||
|
|
||||||
|
start_of_latest_set = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "ON", &success);
|
ptr = dict_accept(cs, ptr, "ON", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -4098,13 +4410,24 @@ scan_on_conditions:
|
|||||||
ptr = dict_accept(cs, ptr, "DELETE", &success);
|
ptr = dict_accept(cs, ptr, "DELETE", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "UPDATE", &success);
|
ptr = dict_accept(cs, ptr, "UPDATE", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
dict_foreign_report_syntax_err(
|
dict_foreign_report_syntax_err(
|
||||||
name, start_of_latest_foreign, ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4136,12 +4459,22 @@ scan_on_conditions:
|
|||||||
ptr = dict_accept(cs, ptr, "NO", &success);
|
ptr = dict_accept(cs, ptr, "NO", &success);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "ACTION", &success);
|
ptr = dict_accept(cs, ptr, "ACTION", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
dict_foreign_report_syntax_err(
|
dict_foreign_report_syntax_err(
|
||||||
name, start_of_latest_foreign, ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
@@ -4155,42 +4488,73 @@ scan_on_conditions:
|
|||||||
goto scan_on_conditions;
|
goto scan_on_conditions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "SET", &success);
|
ptr = dict_accept(cs, ptr, "SET", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
dict_foreign_report_syntax_err(
|
||||||
ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orig = ptr;
|
||||||
ptr = dict_accept(cs, ptr, "NULL", &success);
|
ptr = dict_accept(cs, ptr, "NULL", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
dict_foreign_report_syntax_err(
|
||||||
ptr);
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. Foreign key constraint parse error in %s"
|
||||||
|
" close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < foreign->n_fields; j++) {
|
for (j = 0; j < foreign->n_fields; j++) {
|
||||||
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
|
if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
|
||||||
& DATA_NOT_NULL) {
|
& DATA_NOT_NULL) {
|
||||||
|
const dict_col_t* col
|
||||||
|
= dict_index_get_nth_col(foreign->foreign_index, j);
|
||||||
|
const char* col_name = dict_table_get_col_name(foreign->foreign_index->table,
|
||||||
|
dict_col_get_no(col));
|
||||||
|
|
||||||
/* It is not sensible to define SET NULL
|
/* It is not sensible to define SET NULL
|
||||||
if the column is not allowed to be NULL! */
|
if the column is not allowed to be NULL! */
|
||||||
|
|
||||||
dict_foreign_free(foreign);
|
|
||||||
|
|
||||||
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, create_name);
|
||||||
fprintf(ef, "%s:\n"
|
fprintf(ef,
|
||||||
"You have defined a SET NULL condition"
|
"%s table %s with foreign key constraint"
|
||||||
" though some of the\n"
|
" failed. You have defined a SET NULL condition but column %s is defined as NOT NULL"
|
||||||
"columns are defined as NOT NULL.\n",
|
" in %s close to %s.\n",
|
||||||
start_of_latest_foreign);
|
operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. You have defined a SET NULL condition but column %s is defined as NOT NULL"
|
||||||
|
" in %s close to %s.",
|
||||||
|
operation, create_name, col_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
|
||||||
|
dict_foreign_free(foreign);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4207,16 +4571,22 @@ try_find_index:
|
|||||||
if (n_on_deletes > 1 || n_on_updates > 1) {
|
if (n_on_deletes > 1 || n_on_updates > 1) {
|
||||||
/* It is an error to define more than 1 action */
|
/* It is an error to define more than 1 action */
|
||||||
|
|
||||||
dict_foreign_free(foreign);
|
|
||||||
|
|
||||||
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, create_name);
|
||||||
fprintf(ef, "%s:\n"
|
fprintf(ef,
|
||||||
"You have twice an ON DELETE clause"
|
"%s table %s with foreign key constraint"
|
||||||
" or twice an ON UPDATE clause.\n",
|
" failed. You have more than one on delete or on update clause"
|
||||||
start_of_latest_foreign);
|
" in %s close to %s.\n",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
|
||||||
|
"%s table %s with foreign key constraint"
|
||||||
|
" failed. You have more than one on delete or on update clause"
|
||||||
|
" in %s close to %s.",
|
||||||
|
operation, create_name, start_of_latest_foreign, start_of_latest_set);
|
||||||
|
dict_foreign_free(foreign);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4226,13 +4596,13 @@ try_find_index:
|
|||||||
|
|
||||||
if (referenced_table) {
|
if (referenced_table) {
|
||||||
index = dict_foreign_find_index(referenced_table,
|
index = dict_foreign_find_index(referenced_table,
|
||||||
column_names, i,
|
ref_column_names, i,
|
||||||
foreign->foreign_index,
|
foreign->foreign_index,
|
||||||
TRUE, FALSE);
|
TRUE, FALSE, &index_error, &err_col, &err_index);
|
||||||
if (!index) {
|
if (!index) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
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, create_name);
|
||||||
fprintf(ef, "%s:\n"
|
fprintf(ef, "%s:\n"
|
||||||
"Cannot find an index in the"
|
"Cannot find an index in the"
|
||||||
" referenced table where the\n"
|
" referenced table where the\n"
|
||||||
@@ -4250,9 +4620,13 @@ try_find_index:
|
|||||||
"innodb-foreign-key-constraints.html\n"
|
"innodb-foreign-key-constraints.html\n"
|
||||||
"for correct foreign key definition.\n",
|
"for correct foreign key definition.\n",
|
||||||
start_of_latest_foreign);
|
start_of_latest_foreign);
|
||||||
|
|
||||||
|
dict_foreign_push_index_error(trx, operation, create_name, start_of_latest_foreign,
|
||||||
|
column_names, index_error, err_col, err_index, referenced_table, ef);
|
||||||
|
|
||||||
mutex_exit(&dict_foreign_err_mutex);
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_PARENT_NO_INDEX);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ut_a(trx->check_foreigns == FALSE);
|
ut_a(trx->check_foreigns == FALSE);
|
||||||
@@ -4270,7 +4644,7 @@ try_find_index:
|
|||||||
i * sizeof(void*));
|
i * sizeof(void*));
|
||||||
for (i = 0; i < foreign->n_fields; i++) {
|
for (i = 0; i < foreign->n_fields; i++) {
|
||||||
foreign->referenced_col_names[i]
|
foreign->referenced_col_names[i]
|
||||||
= mem_heap_strdup(foreign->heap, column_names[i]);
|
= mem_heap_strdup(foreign->heap, ref_column_names[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We found an ok constraint definition: add to the lists */
|
/* We found an ok constraint definition: add to the lists */
|
||||||
@@ -5815,7 +6189,8 @@ dict_table_replace_index_in_foreign_list(
|
|||||||
foreign->referenced_table,
|
foreign->referenced_table,
|
||||||
foreign->referenced_col_names,
|
foreign->referenced_col_names,
|
||||||
foreign->n_fields, index,
|
foreign->n_fields, index,
|
||||||
/*check_charsets=*/TRUE, /*check_null=*/FALSE);
|
/*check_charsets=*/TRUE, /*check_null=*/FALSE,
|
||||||
|
NULL, NULL, NULL);
|
||||||
ut_ad(new_index || !trx->check_foreigns);
|
ut_ad(new_index || !trx->check_foreigns);
|
||||||
ut_ad(!new_index || new_index->table == index->table);
|
ut_ad(!new_index || new_index->table == index->table);
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 2000, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2008, 2009 Google Inc.
|
Copyright (c) 2008, 2009 Google Inc.
|
||||||
Copyright (c) 2009, Percona Inc.
|
Copyright (c) 2009, Percona Inc.
|
||||||
|
|
||||||
@@ -1910,6 +1910,7 @@ check_trx_exists(
|
|||||||
|
|
||||||
if (trx == NULL) {
|
if (trx == NULL) {
|
||||||
trx = innobase_trx_allocate(thd);
|
trx = innobase_trx_allocate(thd);
|
||||||
|
thd_set_ha_data(thd, innodb_hton_ptr, trx);
|
||||||
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
|
} else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
|
||||||
mem_analyze_corruption(trx);
|
mem_analyze_corruption(trx);
|
||||||
ut_error;
|
ut_error;
|
||||||
@@ -10169,6 +10170,13 @@ ha_innobase::estimate_rows_upper_bound(void)
|
|||||||
estimate = 2 * local_data_file_length /
|
estimate = 2 * local_data_file_length /
|
||||||
dict_index_calc_min_rec_len(index);
|
dict_index_calc_min_rec_len(index);
|
||||||
|
|
||||||
|
/* Set num_rows less than MERGEBUFF to simulate the case where we do
|
||||||
|
not have enough space to merge the externally sorted file blocks. */
|
||||||
|
DBUG_EXECUTE_IF("set_num_rows_lt_MERGEBUFF",
|
||||||
|
estimate = 2;
|
||||||
|
DBUG_SET("-d,set_num_rows_lt_MERGEBUFF");
|
||||||
|
);
|
||||||
|
|
||||||
prebuilt->trx->op_info = (char*)"";
|
prebuilt->trx->op_info = (char*)"";
|
||||||
|
|
||||||
DBUG_RETURN((ha_rows) estimate);
|
DBUG_RETURN((ha_rows) estimate);
|
||||||
@@ -10448,17 +10456,6 @@ ha_innobase::info_low(
|
|||||||
prebuilt->trx->op_info = "returning various info to MySQL";
|
prebuilt->trx->op_info = "returning various info to MySQL";
|
||||||
}
|
}
|
||||||
|
|
||||||
my_snprintf(path, sizeof(path), "%s/%s%s",
|
|
||||||
mysql_data_home, ib_table->name, reg_ext);
|
|
||||||
|
|
||||||
unpack_filename(path,path);
|
|
||||||
|
|
||||||
/* Note that we do not know the access time of the table,
|
|
||||||
nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
|
|
||||||
|
|
||||||
if (os_file_get_status(path,&stat_info)) {
|
|
||||||
stats.create_time = (ulong) stat_info.ctime;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag & HA_STATUS_VARIABLE) {
|
if (flag & HA_STATUS_VARIABLE) {
|
||||||
@@ -10702,6 +10699,20 @@ ha_innobase::info_low(
|
|||||||
}
|
}
|
||||||
|
|
||||||
dict_table_stats_unlock(ib_table, RW_S_LATCH);
|
dict_table_stats_unlock(ib_table, RW_S_LATCH);
|
||||||
|
|
||||||
|
my_snprintf(path, sizeof(path), "%s/%s%s",
|
||||||
|
mysql_data_home,
|
||||||
|
table->s->normalized_path.str,
|
||||||
|
reg_ext);
|
||||||
|
|
||||||
|
unpack_filename(path,path);
|
||||||
|
|
||||||
|
/* Note that we do not know the access time of the table,
|
||||||
|
nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
|
||||||
|
|
||||||
|
if (os_file_get_status(path,&stat_info)) {
|
||||||
|
stats.create_time = (ulong) stat_info.ctime;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
|
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
|
||||||
@@ -15514,3 +15525,28 @@ ha_innobase::idx_cond_push(
|
|||||||
DBUG_RETURN(NULL);
|
DBUG_RETURN(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************//**
|
||||||
|
Helper function to push warnings from InnoDB internals to SQL-layer. */
|
||||||
|
extern "C" UNIV_INTERN
|
||||||
|
void
|
||||||
|
ib_push_warning(
|
||||||
|
trx_t* trx, /*!< in: trx */
|
||||||
|
ulint error, /*!< in: error code to push as warning */
|
||||||
|
const char *format,/*!< in: warning message */
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
THD *thd = (THD *)trx->mysql_thd;
|
||||||
|
char *buf;
|
||||||
|
#define MAX_BUF_SIZE 4*1024
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
|
||||||
|
vsprintf(buf,format, args);
|
||||||
|
|
||||||
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||||
|
convert_error_code_to_mysql(error, 0, thd),
|
||||||
|
buf);
|
||||||
|
my_free(buf);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
@@ -121,6 +121,17 @@ UNIV_INTERN
|
|||||||
ulint
|
ulint
|
||||||
dict_create_or_check_foreign_constraint_tables(void);
|
dict_create_or_check_foreign_constraint_tables(void);
|
||||||
/*================================================*/
|
/*================================================*/
|
||||||
|
|
||||||
|
/********************************************************************//**
|
||||||
|
Construct foreign key constraint defintion from data dictionary information.
|
||||||
|
*/
|
||||||
|
UNIV_INTERN
|
||||||
|
char*
|
||||||
|
dict_foreign_def_get(
|
||||||
|
/*=================*/
|
||||||
|
dict_foreign_t* foreign,/*!< in: foreign */
|
||||||
|
trx_t* trx); /*!< in: trx */
|
||||||
|
|
||||||
/********************************************************************//**
|
/********************************************************************//**
|
||||||
Adds foreign key definitions to data dictionary tables in the database. We
|
Adds foreign key definitions to data dictionary tables in the database. We
|
||||||
look at table->foreign_list, and also generate names to constraints that were
|
look at table->foreign_list, and also generate names to constraints that were
|
||||||
|
@@ -366,5 +366,14 @@ innobase_convert_to_filename_charset(
|
|||||||
const char* from, /* in: identifier to convert */
|
const char* from, /* in: identifier to convert */
|
||||||
ulint len); /* in: length of 'to', in bytes */
|
ulint len); /* in: length of 'to', in bytes */
|
||||||
|
|
||||||
|
/********************************************************************//**
|
||||||
|
Helper function to push warnings from InnoDB internals to SQL-layer. */
|
||||||
|
UNIV_INTERN
|
||||||
|
void
|
||||||
|
ib_push_warning(
|
||||||
|
trx_t* trx, /*!< in: trx */
|
||||||
|
ulint error, /*!< in: error code to push as warning */
|
||||||
|
const char *format,/*!< in: warning message */
|
||||||
|
...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -64,10 +64,10 @@ component, i.e. we show M.N.P as M.N */
|
|||||||
(INNODB_VERSION_MAJOR << 8 | INNODB_VERSION_MINOR)
|
(INNODB_VERSION_MAJOR << 8 | INNODB_VERSION_MINOR)
|
||||||
|
|
||||||
#ifndef PERCONA_INNODB_VERSION
|
#ifndef PERCONA_INNODB_VERSION
|
||||||
#define PERCONA_INNODB_VERSION 37.2
|
#define PERCONA_INNODB_VERSION 37.3
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define INNODB_VERSION_STR "5.5.43-MariaDB-" IB_TO_STR(PERCONA_INNODB_VERSION)
|
#define INNODB_VERSION_STR "5.5.44-MariaDB-" IB_TO_STR(PERCONA_INNODB_VERSION)
|
||||||
|
|
||||||
#define REFMAN "http://dev.mysql.com/doc/refman/" \
|
#define REFMAN "http://dev.mysql.com/doc/refman/" \
|
||||||
IB_TO_STR(MYSQL_MAJOR_VERSION) "." \
|
IB_TO_STR(MYSQL_MAJOR_VERSION) "." \
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
|
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
Copyright (c) 2008, Google Inc.
|
Copyright (c) 2008, Google Inc.
|
||||||
Copyright (c) 2009, Percona Inc.
|
Copyright (c) 2009, Percona Inc.
|
||||||
|
|
||||||
@@ -2511,9 +2511,9 @@ innobase_shutdown_for_mysql(void)
|
|||||||
|
|
||||||
ibuf_close();
|
ibuf_close();
|
||||||
log_shutdown();
|
log_shutdown();
|
||||||
lock_sys_close();
|
|
||||||
trx_sys_file_format_close();
|
trx_sys_file_format_close();
|
||||||
trx_sys_close();
|
trx_sys_close();
|
||||||
|
lock_sys_close();
|
||||||
|
|
||||||
mutex_free(&srv_monitor_file_mutex);
|
mutex_free(&srv_monitor_file_mutex);
|
||||||
mutex_free(&srv_dict_tmpfile_mutex);
|
mutex_free(&srv_dict_tmpfile_mutex);
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2008, Google Inc.
|
Copyright (c) 2008, Google Inc.
|
||||||
Copyright (c) 2013, 2014, MariaDB Corporation. All Rights Reserved.
|
Copyright (c) 2013, 2014, MariaDB Corporation. All Rights Reserved.
|
||||||
|
|
||||||
@@ -1114,8 +1114,9 @@ sync_array_output_info(
|
|||||||
os_thread_id_t r;
|
os_thread_id_t r;
|
||||||
|
|
||||||
fprintf(file,
|
fprintf(file,
|
||||||
"OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n",
|
"OS WAIT ARRAY INFO: reservation count " ULINTPF
|
||||||
(long) arr->res_count, (long) arr->sg_count);
|
", signal count " ULINTPF "\n",
|
||||||
|
arr->res_count, arr->sg_count);
|
||||||
i = 0;
|
i = 0;
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
|
@@ -771,9 +771,9 @@ trx_lists_init_at_db_start(void)
|
|||||||
" anyway.\n");
|
" anyway.\n");
|
||||||
|
|
||||||
trx->state = TRX_ACTIVE;
|
trx->state = TRX_ACTIVE;
|
||||||
trx_reserve_descriptor(
|
|
||||||
trx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trx_reserve_descriptor(trx);
|
||||||
} else {
|
} else {
|
||||||
trx->state
|
trx->state
|
||||||
= TRX_COMMITTED_IN_MEMORY;
|
= TRX_COMMITTED_IN_MEMORY;
|
||||||
|
@@ -21,31 +21,42 @@
|
|||||||
static my_bool ssl_algorithms_added = FALSE;
|
static my_bool ssl_algorithms_added = FALSE;
|
||||||
static my_bool ssl_error_strings_loaded= FALSE;
|
static my_bool ssl_error_strings_loaded= FALSE;
|
||||||
|
|
||||||
/* the function below was generated with "openssl dhparam -2 -C 1024" */
|
/* the function below was generated with "openssl dhparam -2 -C 2048" */
|
||||||
static
|
static
|
||||||
DH *get_dh1024()
|
DH *get_dh2048()
|
||||||
{
|
{
|
||||||
static unsigned char dh1024_p[]={
|
static unsigned char dh2048_p[]={
|
||||||
0xEC,0x46,0x7E,0xF9,0x4E,0x10,0x29,0xDC,0x44,0x97,0x71,0xFD,
|
0xA1,0xBB,0x7C,0x20,0xC5,0x5B,0xC0,0x7B,0x21,0x8B,0xD6,0xA8,
|
||||||
0x71,0xC6,0x9F,0x0D,0xD1,0x09,0xF6,0x58,0x6F,0xAD,0xCA,0xF4,
|
0x15,0xFC,0x3B,0xBA,0xAB,0x9F,0xDF,0x68,0xC4,0x79,0x78,0x0D,
|
||||||
0x37,0xD5,0xC3,0xBD,0xC3,0x9A,0x51,0x66,0x2C,0x58,0xBD,0x02,
|
0xC1,0x12,0x64,0xE4,0x15,0xC9,0x66,0xDB,0xF6,0xCB,0xB3,0x39,
|
||||||
0xBD,0xBA,0xBA,0xFC,0xE7,0x0E,0x5A,0xE5,0x97,0x81,0xC3,0xF3,
|
0x02,0x5B,0x78,0x62,0xFB,0x09,0xAE,0x09,0x6B,0xDD,0xD4,0x5D,
|
||||||
0x28,0x2D,0xAD,0x00,0x91,0xEF,0xF8,0xF0,0x5D,0xE9,0xE7,0x18,
|
0x97,0xBC,0xDC,0x7F,0xE6,0xD6,0xF1,0xCB,0xF5,0xEB,0xDA,0xA7,
|
||||||
0xE2,0xAD,0xC4,0x70,0xC5,0x3C,0x12,0x8A,0x80,0x6A,0x9F,0x3B,
|
0x2E,0x5A,0x43,0x2B,0xE9,0x40,0xE2,0x85,0x00,0x1C,0xC0,0x0A,
|
||||||
0x00,0xA2,0x8F,0xA9,0x26,0xB0,0x0E,0x7F,0xED,0xF6,0xC2,0x03,
|
0x98,0x77,0xA9,0x31,0xDE,0x0B,0x75,0x4D,0x1E,0x1F,0x16,0x83,
|
||||||
0x81,0xB5,0xC5,0x41,0xD0,0x00,0x2B,0x21,0xD4,0x4B,0x74,0xA6,
|
0xCA,0xDE,0xBD,0x21,0xFC,0xC1,0x82,0x37,0x36,0x33,0x0B,0x66,
|
||||||
0xD7,0x1A,0x0E,0x82,0xC8,0xEE,0xD4,0xB1,0x6F,0xB4,0x79,0x01,
|
0x06,0x3C,0xF3,0xAF,0x21,0x57,0x57,0x80,0xF6,0x94,0x1B,0xA9,
|
||||||
0x8A,0xF1,0x12,0xD7,0x3C,0xFD,0xCB,0x9B,0xAE,0x1C,0xA9,0x0F,
|
0xD4,0xF6,0x8F,0x18,0x62,0x0E,0xC4,0x22,0xF9,0x5B,0x62,0xCC,
|
||||||
0x3D,0x0F,0xF8,0xD6,0x7D,0xDE,0xD6,0x0B,
|
0x3F,0x19,0x95,0xCF,0x4B,0x00,0xA6,0x6C,0x0B,0xAF,0x9F,0xD5,
|
||||||
|
0xFA,0x3D,0x6D,0xDA,0x30,0x83,0x07,0x91,0xAC,0x15,0xFF,0x8F,
|
||||||
|
0x59,0x54,0xEA,0x25,0xBC,0x4E,0xEB,0x6A,0x54,0xDF,0x75,0x09,
|
||||||
|
0x72,0x0F,0xEF,0x23,0x70,0xE0,0xA8,0x04,0xEA,0xFF,0x90,0x54,
|
||||||
|
0xCD,0x84,0x18,0xC0,0x75,0x91,0x99,0x0F,0xA1,0x78,0x0C,0x07,
|
||||||
|
0xB7,0xC5,0xDE,0x55,0x06,0x7B,0x95,0x68,0x2C,0x33,0x39,0xBC,
|
||||||
|
0x2C,0xD0,0x6D,0xDD,0xFA,0xDC,0xB5,0x8F,0x82,0x39,0xF8,0x67,
|
||||||
|
0x44,0xF1,0xD8,0xF7,0x78,0x11,0x9A,0x77,0x9B,0x53,0x47,0xD6,
|
||||||
|
0x2B,0x5D,0x67,0xB8,0xB7,0xBC,0xC1,0xD7,0x79,0x62,0x15,0xC2,
|
||||||
|
0xC5,0x83,0x97,0xA7,0xF8,0xB4,0x9C,0xF6,0x8F,0x9A,0xC7,0xDA,
|
||||||
|
0x1B,0xBB,0x87,0x07,0xA7,0x71,0xAD,0xB2,0x8A,0x50,0xF8,0x26,
|
||||||
|
0x12,0xB7,0x3E,0x0B,
|
||||||
};
|
};
|
||||||
static unsigned char dh1024_g[]={
|
static unsigned char dh2048_g[]={
|
||||||
0x02,
|
0x02,
|
||||||
};
|
};
|
||||||
DH *dh;
|
DH *dh;
|
||||||
|
|
||||||
if ((dh=DH_new()) == NULL) return(NULL);
|
if ((dh=DH_new()) == NULL) return(NULL);
|
||||||
dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL);
|
dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
|
||||||
dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL);
|
dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
|
||||||
if ((dh->p == NULL) || (dh->g == NULL))
|
if ((dh->p == NULL) || (dh->g == NULL))
|
||||||
{ DH_free(dh); return(NULL); }
|
{ DH_free(dh); return(NULL); }
|
||||||
return(dh);
|
return(dh);
|
||||||
@@ -259,7 +270,7 @@ new_VioSSLFd(const char *key_file, const char *cert_file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* DH stuff */
|
/* DH stuff */
|
||||||
dh=get_dh1024();
|
dh=get_dh2048();
|
||||||
SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh);
|
SSL_CTX_set_tmp_dh(ssl_fd->ssl_context, dh);
|
||||||
DH_free(dh);
|
DH_free(dh);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user