Commit 730a3c8b authored by unknown's avatar unknown

Merge gweir@bk-internal.mysql.com:/home/bk/mysql-4.0

into mysql.com:/bk/mysql-4.0

parents eb7c18d6 65ec6a41
...@@ -37,6 +37,7 @@ EXTRA_DIST = FINISH.sh \ ...@@ -37,6 +37,7 @@ EXTRA_DIST = FINISH.sh \
compile-pentium-pgcc \ compile-pentium-pgcc \
compile-solaris-sparc \ compile-solaris-sparc \
compile-solaris-sparc-debug \ compile-solaris-sparc-debug \
compile-irix-mips64-mipspro \
compile-solaris-sparc-forte \ compile-solaris-sparc-forte \
compile-solaris-sparc-purify compile-solaris-sparc-purify
......
...@@ -59,13 +59,14 @@ static MYSQL* mysql = NULL; ...@@ -59,13 +59,14 @@ static MYSQL* mysql = NULL;
static const char* dirname_for_local_load= 0; static const char* dirname_for_local_load= 0;
static void dump_local_log_entries(const char* logname); static int dump_local_log_entries(const char* logname);
static void dump_remote_log_entries(const char* logname); static int dump_remote_log_entries(const char* logname);
static void dump_log_entries(const char* logname); static int dump_log_entries(const char* logname);
static void dump_remote_file(NET* net, const char* fname); static int dump_remote_file(NET* net, const char* fname);
static void die(const char* fmt, ...); static void die(const char* fmt, ...);
static MYSQL* safe_connect(); static MYSQL* safe_connect();
class Load_log_processor class Load_log_processor
{ {
char target_dir_name[MY_NFILE]; char target_dir_name[MY_NFILE];
...@@ -150,39 +151,14 @@ public: ...@@ -150,39 +151,14 @@ public:
return res; return res;
} }
int process(Create_file_log_event *ce); int process(Create_file_log_event *ce);
int process(Append_block_log_event *ae) int process(Append_block_log_event *ae);
{
File file;
Create_file_log_event* ce= (ae->file_id < file_names.elements) ?
*((Create_file_log_event**)file_names.buffer + ae->file_id) : 0;
if (ce)
{
if (((file= my_open(ce->fname,
O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0) ||
my_write(file,(byte*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP)) ||
my_close(file,MYF(MY_WME)))
return -1;
}
else
{
/*
There is no Create_file event (a bad binlog or a big
--position). Assuming it's a big --position, we just do nothing and
print a warning.
*/
fprintf(stderr,"Warning: ignoring Append_block as there is no \
Create_file event for file_id: %u\n",ae->file_id);
return -1;
}
return 0;
}
File prepare_new_file_for_old_format(Load_log_event *le, char *filename); File prepare_new_file_for_old_format(Load_log_event *le, char *filename);
int load_old_format_file(NET* net, const char *server_fname, int load_old_format_file(NET* net, const char *server_fname,
uint server_fname_len, File file); uint server_fname_len, File file);
}; };
File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le, File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le,
char *filename) char *filename)
{ {
...@@ -205,6 +181,7 @@ File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le, ...@@ -205,6 +181,7 @@ File Load_log_processor::prepare_new_file_for_old_format(Load_log_event *le,
return file; return file;
} }
int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, int Load_log_processor::load_old_format_file(NET* net, const char*server_fname,
uint server_fname_len, File file) uint server_fname_len, File file)
{ {
...@@ -248,21 +225,24 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname, ...@@ -248,21 +225,24 @@ int Load_log_processor::load_old_format_file(NET* net, const char*server_fname,
return 0; return 0;
} }
int Load_log_processor::process(Create_file_log_event *ce) int Load_log_processor::process(Create_file_log_event *ce)
{ {
const char *bname= ce->fname+dirname_length(ce->fname); const char *bname= ce->fname+dirname_length(ce->fname);
uint blen= ce->fname_len - (bname-ce->fname); uint blen= ce->fname_len - (bname-ce->fname);
uint full_len= target_dir_name_len + blen + 9 + 9 + 1; uint full_len= target_dir_name_len + blen + 9 + 9 + 1;
int error= 0;
char *fname, *ptr; char *fname, *ptr;
File file; File file;
if (!(fname= my_malloc(full_len,MYF(MY_WME))) || if (set_dynamic(&file_names,(gptr)&ce,ce->file_id))
set_dynamic(&file_names,(gptr)&ce,ce->file_id))
{ {
sql_print_error("Could not construct local filename %s%s", sql_print_error("Could not construct local filename %s%s",
target_dir_name,bname); target_dir_name,bname);
return -1; return -1;
} }
if (!(fname= my_malloc(full_len,MYF(MY_WME))))
return -1;
memcpy(fname, target_dir_name, target_dir_name_len); memcpy(fname, target_dir_name, target_dir_name_len);
ptr= fname + target_dir_name_len; ptr= fname + target_dir_name_len;
...@@ -278,14 +258,50 @@ int Load_log_processor::process(Create_file_log_event *ce) ...@@ -278,14 +258,50 @@ int Load_log_processor::process(Create_file_log_event *ce)
} }
ce->set_fname_outside_temp_buf(fname,strlen(fname)); ce->set_fname_outside_temp_buf(fname,strlen(fname));
if (my_write(file,(byte*) ce->block,ce->block_len,MYF(MY_WME|MY_NABP)) || if (my_write(file,(byte*) ce->block,ce->block_len,MYF(MY_WME|MY_NABP)))
my_close(file,MYF(MY_WME))) error= -1;
if (my_close(file,MYF(MY_WME)))
error= -1;
return error;
}
int Load_log_processor::process(Append_block_log_event *ae)
{
Create_file_log_event* ce= ((ae->file_id < file_names.elements) ?
*((Create_file_log_event**)file_names.buffer +
ae->file_id) :
0);
if (ce)
{
File file;
int error= 0;
if (((file= my_open(ce->fname,
O_APPEND|O_BINARY|O_WRONLY,MYF(MY_WME))) < 0))
return -1;
if (my_write(file,(byte*)ae->block,ae->block_len,MYF(MY_WME|MY_NABP)))
error= -1;
if (my_close(file,MYF(MY_WME)))
error= -1;
return error;
}
/*
There is no Create_file event (a bad binlog or a big
--position). Assuming it's a big --position, we just do nothing and
print a warning.
*/
fprintf(stderr,"Warning: ignoring Append_block as there is no \
Create_file event for file_id: %u\n",ae->file_id);
return -1; return -1;
} }
Load_log_processor load_processor; Load_log_processor load_processor;
void process_event(ulonglong *rec_count, char *last_db, Log_event *ev,
int process_event(ulonglong *rec_count, char *last_db, Log_event *ev,
my_off_t pos, int old_format) my_off_t pos, int old_format)
{ {
char ll_buff[21]; char ll_buff[21];
...@@ -303,7 +319,7 @@ void process_event(ulonglong *rec_count, char *last_db, Log_event *ev, ...@@ -303,7 +319,7 @@ void process_event(ulonglong *rec_count, char *last_db, Log_event *ev,
{ {
(*rec_count)++; (*rec_count)++;
delete ev; delete ev;
return; // next return 0; // Time for next event
} }
} }
ev->print(result_file, short_form, last_db); ev->print(result_file, short_form, last_db);
...@@ -324,7 +340,7 @@ void process_event(ulonglong *rec_count, char *last_db, Log_event *ev, ...@@ -324,7 +340,7 @@ void process_event(ulonglong *rec_count, char *last_db, Log_event *ev,
{ {
(*rec_count)++; (*rec_count)++;
delete ev; delete ev;
return; // next return 0; // next
} }
} }
/* /*
...@@ -337,14 +353,16 @@ void process_event(ulonglong *rec_count, char *last_db, Log_event *ev, ...@@ -337,14 +353,16 @@ void process_event(ulonglong *rec_count, char *last_db, Log_event *ev,
ce->print(result_file, short_form, last_db, true); ce->print(result_file, short_form, last_db, true);
if (!old_format) if (!old_format)
{ {
load_processor.process(ce); if (load_processor.process(ce))
break; // Error
ev= 0; ev= 0;
} }
break; break;
} }
case APPEND_BLOCK_EVENT: case APPEND_BLOCK_EVENT:
ev->print(result_file, short_form, last_db); ev->print(result_file, short_form, last_db);
load_processor.process((Append_block_log_event*)ev); if (load_processor.process((Append_block_log_event*) ev))
break; // Error
break; break;
case EXEC_LOAD_EVENT: case EXEC_LOAD_EVENT:
{ {
...@@ -374,8 +392,10 @@ Create_file event for file_id: %u\n",exv->file_id); ...@@ -374,8 +392,10 @@ Create_file event for file_id: %u\n",exv->file_id);
(*rec_count)++; (*rec_count)++;
if (ev) if (ev)
delete ev; delete ev;
return 0;
} }
static struct my_option my_long_options[] = static struct my_option my_long_options[] =
{ {
#ifndef DBUG_OFF #ifndef DBUG_OFF
...@@ -545,14 +565,15 @@ static MYSQL* safe_connect() ...@@ -545,14 +565,15 @@ static MYSQL* safe_connect()
return local_mysql; return local_mysql;
} }
static void dump_log_entries(const char* logname)
static int dump_log_entries(const char* logname)
{ {
if (remote_opt) if (remote_opt)
dump_remote_log_entries(logname); return dump_remote_log_entries(logname);
else return dump_local_log_entries(logname);
dump_local_log_entries(logname);
} }
static int check_master_version(MYSQL* mysql) static int check_master_version(MYSQL* mysql)
{ {
MYSQL_RES* res = 0; MYSQL_RES* res = 0;
...@@ -601,7 +622,7 @@ static int check_master_version(MYSQL* mysql) ...@@ -601,7 +622,7 @@ static int check_master_version(MYSQL* mysql)
} }
static void dump_remote_log_entries(const char* logname) static int dump_remote_log_entries(const char* logname)
{ {
char buf[128]; char buf[128];
char last_db[FN_REFLEN+1] = ""; char last_db[FN_REFLEN+1] = "";
...@@ -615,7 +636,7 @@ static void dump_remote_log_entries(const char* logname) ...@@ -615,7 +636,7 @@ static void dump_remote_log_entries(const char* logname)
if (position < BIN_LOG_HEADER_SIZE) if (position < BIN_LOG_HEADER_SIZE)
{ {
position = BIN_LOG_HEADER_SIZE; position = BIN_LOG_HEADER_SIZE;
// warn the guity // warn the user
sql_print_error("Warning: The position in the binary log can't be less than %d.\nStarting from position %d\n", BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE); sql_print_error("Warning: The position in the binary log can't be less than %d.\nStarting from position %d\n", BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE);
} }
int4store(buf, position); int4store(buf, position);
...@@ -624,7 +645,10 @@ static void dump_remote_log_entries(const char* logname) ...@@ -624,7 +645,10 @@ static void dump_remote_log_entries(const char* logname)
int4store(buf + 6, 0); int4store(buf + 6, 0);
memcpy(buf + 10, logname,len); memcpy(buf + 10, logname,len);
if (simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1)) if (simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1))
die("Error sending the log dump command"); {
fprintf(stderr,"Got fatal error sending the log dump command\n");
return 1;
}
my_off_t old_off= 0; my_off_t old_off= 0;
ulonglong rec_count= 0; ulonglong rec_count= 0;
...@@ -635,7 +659,11 @@ static void dump_remote_log_entries(const char* logname) ...@@ -635,7 +659,11 @@ static void dump_remote_log_entries(const char* logname)
const char *error; const char *error;
len = net_safe_read(mysql); len = net_safe_read(mysql);
if (len == packet_error) if (len == packet_error)
die("Error reading packet from server: %s", mysql_error(mysql)); {
fprintf(stderr, "Got error reading packet from server: %s\n",
mysql_error(mysql));
return 1;
}
if (len < 8 && net->read_pos[0] == 254) if (len < 8 && net->read_pos[0] == 254)
break; // end of data break; // end of data
DBUG_PRINT("info",( "len= %u, net->read_pos[5] = %d\n", DBUG_PRINT("info",( "len= %u, net->read_pos[5] = %d\n",
...@@ -644,28 +672,36 @@ static void dump_remote_log_entries(const char* logname) ...@@ -644,28 +672,36 @@ static void dump_remote_log_entries(const char* logname)
len - 1, &error, old_format); len - 1, &error, old_format);
if (!ev) if (!ev)
{ {
die("Could not construct log event object"); fprintf(stderr, "Could not construct log event object\n");
return 1;
} }
else
{
Log_event_type type= ev->get_type_code(); Log_event_type type= ev->get_type_code();
if (!old_format || ( type != LOAD_EVENT && type != CREATE_FILE_EVENT ) ) if (!old_format || ( type != LOAD_EVENT && type != CREATE_FILE_EVENT))
{ {
process_event(&rec_count,last_db,ev,old_off,old_format); if (process_event(&rec_count,last_db,ev,old_off,old_format))
return 1;
} }
else else
{ {
Load_log_event *le= (Load_log_event*)ev; Load_log_event *le= (Load_log_event*)ev;
const char *old_fname= le->fname; const char *old_fname= le->fname;
uint old_len= le->fname_len; uint old_len= le->fname_len;
File file= load_processor.prepare_new_file_for_old_format(le,fname); File file;
if (file >= 0)
if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
return 1;
if (process_event(&rec_count,last_db,ev,old_off,old_format))
{ {
process_event(&rec_count,last_db,ev,old_off,old_format);
load_processor.load_old_format_file(net,old_fname,old_len,file);
my_close(file,MYF(MY_WME)); my_close(file,MYF(MY_WME));
return 1;
} }
if (load_processor.load_old_format_file(net,old_fname,old_len,file))
{
my_close(file,MYF(MY_WME));
return 1;
} }
my_close(file,MYF(MY_WME));
} }
/* /*
...@@ -677,6 +713,7 @@ static void dump_remote_log_entries(const char* logname) ...@@ -677,6 +713,7 @@ static void dump_remote_log_entries(const char* logname)
else else
old_off= BIN_LOG_HEADER_SIZE; old_off= BIN_LOG_HEADER_SIZE;
} }
return 0;
} }
...@@ -706,7 +743,7 @@ static int check_header(IO_CACHE* file) ...@@ -706,7 +743,7 @@ static int check_header(IO_CACHE* file)
} }
static void dump_local_log_entries(const char* logname) static int dump_local_log_entries(const char* logname)
{ {
File fd = -1; File fd = -1;
IO_CACHE cache,*file= &cache; IO_CACHE cache,*file= &cache;
...@@ -714,23 +751,27 @@ static void dump_local_log_entries(const char* logname) ...@@ -714,23 +751,27 @@ static void dump_local_log_entries(const char* logname)
char last_db[FN_REFLEN+1]; char last_db[FN_REFLEN+1];
byte tmp_buff[BIN_LOG_HEADER_SIZE]; byte tmp_buff[BIN_LOG_HEADER_SIZE];
bool old_format = 0; bool old_format = 0;
int error= 0;
last_db[0]=0; last_db[0]= 0;
if (logname && logname[0] != '-') if (logname && logname[0] != '-')
{ {
if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0) if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
exit(1); return 1;
if (init_io_cache(file, fd, 0, READ_CACHE, (my_off_t) position, 0, if (init_io_cache(file, fd, 0, READ_CACHE, (my_off_t) position, 0,
MYF(MY_WME | MY_NABP))) MYF(MY_WME | MY_NABP)))
{
my_close(fd, MYF(MY_WME));
exit(1); exit(1);
}
old_format = check_header(file); old_format = check_header(file);
} }
else else
{ {
if (init_io_cache(file, fileno(result_file), 0, READ_CACHE, (my_off_t) 0, if (init_io_cache(file, fileno(result_file), 0, READ_CACHE, (my_off_t) 0,
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE))) 0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
exit(1); return 1;
old_format = check_header(file); old_format = check_header(file);
if (position) if (position)
{ {
...@@ -741,7 +782,10 @@ static void dump_local_log_entries(const char* logname) ...@@ -741,7 +782,10 @@ static void dump_local_log_entries(const char* logname)
{ {
tmp=min(length,sizeof(buff)); tmp=min(length,sizeof(buff));
if (my_b_read(file, buff, (uint) tmp)) if (my_b_read(file, buff, (uint) tmp))
exit(1); {
error= 1;
goto end;
}
} }
} }
file->pos_in_file=position; file->pos_in_file=position;
...@@ -749,7 +793,15 @@ static void dump_local_log_entries(const char* logname) ...@@ -749,7 +793,15 @@ static void dump_local_log_entries(const char* logname)
} }
if (!position) if (!position)
my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE); // Skip header {
// Skip header
if (my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
{
error= 1;
goto end;
}
}
for (;;) for (;;)
{ {
char llbuff[21]; char llbuff[21];
...@@ -759,19 +811,31 @@ static void dump_local_log_entries(const char* logname) ...@@ -759,19 +811,31 @@ static void dump_local_log_entries(const char* logname)
if (!ev) if (!ev)
{ {
if (file->error) if (file->error)
die("\ {
Could not read entry at offset %s : Error in log format or read error", fprintf(stderr,
"Could not read entry at offset %s:"
"Error in log format or read error\n",
llstr(old_off,llbuff)); llstr(old_off,llbuff));
error= 1;
}
// file->error == 0 means EOF, that's OK, we break in this case // file->error == 0 means EOF, that's OK, we break in this case
break; break;
} }
process_event(&rec_count,last_db,ev,old_off,false); if (process_event(&rec_count,last_db,ev,old_off,false))
{
error= 1;
break;
}
} }
end:
if (fd >= 0) if (fd >= 0)
my_close(fd, MYF(MY_WME)); my_close(fd, MYF(MY_WME));
end_io_cache(file); end_io_cache(file);
return error;
} }
#if MYSQL_VERSION_ID < 40101 #if MYSQL_VERSION_ID < 40101
typedef struct st_my_tmpdir typedef struct st_my_tmpdir
...@@ -842,9 +906,11 @@ void free_tmpdir(MY_TMPDIR *tmpdir) ...@@ -842,9 +906,11 @@ void free_tmpdir(MY_TMPDIR *tmpdir)
#endif #endif
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
static char **defaults_argv; static char **defaults_argv;
int exit_value;
MY_INIT(argv[0]); MY_INIT(argv[0]);
parse_args(&argc, (char***)&argv); parse_args(&argc, (char***)&argv);
...@@ -854,7 +920,7 @@ int main(int argc, char** argv) ...@@ -854,7 +920,7 @@ int main(int argc, char** argv)
{ {
usage(); usage();
free_defaults(defaults_argv); free_defaults(defaults_argv);
return -1; exit(1);
} }
if (remote_opt) if (remote_opt)
...@@ -874,8 +940,15 @@ int main(int argc, char** argv) ...@@ -874,8 +940,15 @@ int main(int argc, char** argv)
else else
load_processor.init_by_cur_dir(); load_processor.init_by_cur_dir();
exit_value= 0;
while (--argc >= 0) while (--argc >= 0)
dump_log_entries(*(argv++)); {
if (dump_log_entries(*(argv++)))
{
exit_value=1;
break;
}
}
if (tmpdir.list) if (tmpdir.list)
free_tmpdir(&tmpdir); free_tmpdir(&tmpdir);
...@@ -886,7 +959,8 @@ int main(int argc, char** argv) ...@@ -886,7 +959,8 @@ int main(int argc, char** argv)
cleanup(); cleanup();
free_defaults(defaults_argv); free_defaults(defaults_argv);
my_end(0); my_end(0);
return 0; exit(exit_value);
return exit_value; // Keep compilers happy
} }
/* /*
......
...@@ -348,7 +348,7 @@ AC_SUBST(CXXFLAGS) ...@@ -348,7 +348,7 @@ AC_SUBST(CXXFLAGS)
AC_SUBST(LD) AC_SUBST(LD)
AC_SUBST(INSTALL_SCRIPT) AC_SUBST(INSTALL_SCRIPT)
export CC CFLAGS LD LDFLAGS export CC CXX CFLAGS LD LDFLAGS AR
if test "$GXX" = "yes" if test "$GXX" = "yes"
then then
......
...@@ -1845,6 +1845,24 @@ dict_index_build_internal_non_clust( ...@@ -1845,6 +1845,24 @@ dict_index_build_internal_non_clust(
/*====================== FOREIGN KEY PROCESSING ========================*/ /*====================== FOREIGN KEY PROCESSING ========================*/
/*************************************************************************
Checks if a table is referenced by foreign keys. */
ibool
dict_table_referenced_by_foreign_key(
/*=================================*/
/* out: TRUE if table is referenced by a
foreign key */
dict_table_t* table) /* in: InnoDB table */
{
if (UT_LIST_GET_LEN(table->referenced_list) > 0) {
return(TRUE);
}
return(FALSE);
}
/************************************************************************* /*************************************************************************
Frees a foreign key struct. */ Frees a foreign key struct. */
static static
......
...@@ -206,6 +206,15 @@ dict_foreign_add_to_cache( ...@@ -206,6 +206,15 @@ dict_foreign_add_to_cache(
/* out: DB_SUCCESS or error code */ /* out: DB_SUCCESS or error code */
dict_foreign_t* foreign); /* in, own: foreign key constraint */ dict_foreign_t* foreign); /* in, own: foreign key constraint */
/************************************************************************* /*************************************************************************
Checks if a table is referenced by foreign keys. */
ibool
dict_table_referenced_by_foreign_key(
/*=================================*/
/* out: TRUE if table is referenced by a
foreign key */
dict_table_t* table); /* in: InnoDB table */
/*************************************************************************
Scans a table create SQL string and adds to the data dictionary Scans a table create SQL string and adds to the data dictionary
the foreign key constraints declared in the string. This function the foreign key constraints declared in the string. This function
should be called after the indexes for a table have been created. should be called after the indexes for a table have been created.
......
...@@ -1997,8 +1997,15 @@ row_drop_table_for_mysql( ...@@ -1997,8 +1997,15 @@ row_drop_table_for_mysql(
goto funct_exit; goto funct_exit;
} }
/* Check if the table is referenced by foreign key constraints from
some other table (not the table itself) */
foreign = UT_LIST_GET_FIRST(table->referenced_list); foreign = UT_LIST_GET_FIRST(table->referenced_list);
while (foreign && foreign->foreign_table == table) {
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
}
if (foreign && trx->check_foreigns) { if (foreign && trx->check_foreigns) {
char* buf = dict_foreign_err_buf; char* buf = dict_foreign_err_buf;
......
...@@ -4291,6 +4291,27 @@ ha_innobase::get_foreign_key_create_info(void) ...@@ -4291,6 +4291,27 @@ ha_innobase::get_foreign_key_create_info(void)
return(str); return(str);
} }
/***********************************************************************
Checks if a table is referenced by a foreign key. The MySQL manual states that
a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
delete is then allowed internally to resolve a duplicate key conflict in
REPLACE, not an update. */
uint
ha_innobase::referenced_by_foreign_key(void)
/*========================================*/
/* out: > 0 if referenced by a FOREIGN KEY */
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
if (dict_table_referenced_by_foreign_key(prebuilt->table)) {
return(1);
}
return(0);
}
/*********************************************************************** /***********************************************************************
Frees the foreign key create info for a table stored in InnoDB, if it is Frees the foreign key create info for a table stored in InnoDB, if it is
non-NULL. */ non-NULL. */
......
...@@ -179,6 +179,7 @@ class ha_innobase: public handler ...@@ -179,6 +179,7 @@ class ha_innobase: public handler
int check(THD* thd, HA_CHECK_OPT* check_opt); int check(THD* thd, HA_CHECK_OPT* check_opt);
char* update_table_comment(const char* comment); char* update_table_comment(const char* comment);
char* get_foreign_key_create_info(); char* get_foreign_key_create_info();
uint referenced_by_foreign_key();
void free_foreign_key_create_info(char* str); void free_foreign_key_create_info(char* str);
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type); enum thr_lock_type lock_type);
......
...@@ -319,6 +319,9 @@ public: ...@@ -319,6 +319,9 @@ public:
virtual void append_create_info(String *packet) {} virtual void append_create_info(String *packet) {}
virtual char* get_foreign_key_create_info() virtual char* get_foreign_key_create_info()
{ return(NULL);} /* gets foreign key create string from InnoDB */ { return(NULL);} /* gets foreign key create string from InnoDB */
/* used in REPLACE; is > 0 if table is referred by a FOREIGN KEY */
virtual uint referenced_by_foreign_key() { return 0;}
virtual void init_table_handle_for_HANDLER() virtual void init_table_handle_for_HANDLER()
{ return; } /* prepare InnoDB for HANDLER */ { return; } /* prepare InnoDB for HANDLER */
virtual void free_foreign_key_create_info(char* str) {} virtual void free_foreign_key_create_info(char* str) {}
......
...@@ -438,11 +438,20 @@ int write_record(TABLE *table,COPY_INFO *info) ...@@ -438,11 +438,20 @@ int write_record(TABLE *table,COPY_INFO *info)
key_copy((byte*) key,table,key_nr,0); key_copy((byte*) key,table,key_nr,0);
if ((error=(table->file->index_read_idx(table->record[1],key_nr, if ((error=(table->file->index_read_idx(table->record[1],key_nr,
(byte*) key, (byte*) key,
table->key_info[key_nr].key_length, table->key_info[key_nr].
key_length,
HA_READ_KEY_EXACT)))) HA_READ_KEY_EXACT))))
goto err; goto err;
} }
if (last_uniq_key(table,key_nr)) /*
The manual defines the REPLACE semantics that it is either an INSERT or
DELETE(s) + INSERT; FOREIGN KEY checks do not function in the defined
way if we allow MySQL to convert the latter operation internally to an
UPDATE.
*/
if (last_uniq_key(table,key_nr) &&
!table->file->referenced_by_foreign_key())
{ {
if ((error=table->file->update_row(table->record[1],table->record[0]))) if ((error=table->file->update_row(table->record[1],table->record[0])))
goto err; goto err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment