From f4820ea62ef2635f2d79476deb001f3ae662470e Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 15 Sep 2010 15:48:15 +0300 Subject: [PATCH] mysqltest now gives error messages with error code for my_delete, my_rename, my_copy etc. Fixed crashing bug when doing ALTER TABLE RENAME with transactional tables. client/mysqltest.cc: Added errno to error message for system calls (delete, rename etc) Write error message for failures of system calls mysql-test/include/cleanup_fake_relay_log.inc: Disable warnings for remove_file mysql-test/include/diff_tables.inc: Disable warnings for remove_file mysql-test/include/maria_empty_logs.inc: Disable warnings for remove_file mysql-test/include/maria_make_snapshot.inc: Disable warnings for remove_file mysql-test/include/maria_make_snapshot_for_feeding_recovery.inc: Disable warnings for remove_file mysql-test/include/mysqlhotcopy.inc: Disable warnings for remove_file mysql-test/include/ndb_backup.inc: Disable warnings for remove_file mysql-test/include/ndb_backup_print.inc: Disable warnings for remove_file mysql-test/r/alter_table_trans.result: Test of crashing ALTER TABLE RENAME bug mysql-test/t/alter_table_trans.test: Test of crashing ALTER TABLE RENAME bug mysql-test/t/mysqltest.test: Disable warnings for remove_file and move_file mysys/my_copy.c: Fixed wrong error message sql/sql_table.cc: Fixed crashing bug when doing ALTER TABLE RENAME with transactional tables. --- client/mysqltest.cc | 66 +++++++++++-------- mysql-test/include/cleanup_fake_relay_log.inc | 2 + mysql-test/include/diff_tables.inc | 3 +- mysql-test/include/maria_empty_logs.inc | 2 + mysql-test/include/maria_make_snapshot.inc | 4 ++ ...ria_make_snapshot_for_feeding_recovery.inc | 2 + mysql-test/include/mysqlhotcopy.inc | 2 + mysql-test/include/ndb_backup.inc | 2 + mysql-test/include/ndb_backup_print.inc | 2 + mysql-test/r/alter_table_trans.result | 6 ++ mysql-test/t/alter_table_trans.test | 15 +++++ mysql-test/t/mysqltest.test | 12 +++- mysys/my_copy.c | 2 +- sql/sql_table.cc | 6 ++ 14 files changed, 93 insertions(+), 33 deletions(-) create mode 100644 mysql-test/r/alter_table_trans.result create mode 100644 mysql-test/t/alter_table_trans.test diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 055d8da5097..e4981bec997 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -1079,7 +1079,8 @@ void check_command_args(struct st_command *command, DBUG_VOID_RETURN; } -void handle_command_error(struct st_command *command, uint error) +void handle_command_error(struct st_command *command, uint error, + int sys_errno) { DBUG_ENTER("handle_command_error"); DBUG_PRINT("enter", ("error: %d", error)); @@ -1095,12 +1096,13 @@ void handle_command_error(struct st_command *command, uint error) if (i >= 0) { - DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %d", - command->first_word_len, command->query, error)); + DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %u, errno: %d", + command->first_word_len, command->query, error, + sys_errno)); DBUG_VOID_RETURN; } - die("command \"%.*s\" failed with wrong error: %d", - command->first_word_len, command->query, error); + die("command \"%.*s\" failed with wrong error: %u, errno: %d", + command->first_word_len, command->query, error, sys_errno); } else if (command->expected_errors.err[0].type == ERR_ERRNO && command->expected_errors.err[0].code.errnum != 0) @@ -1809,7 +1811,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) { my_close(fd, MYF(0)); /* Remove the temporary file */ - my_delete(temp_file_path, MYF(0)); + my_delete(temp_file_path, MYF(MY_WME)); die("Failed to write file '%s'", temp_file_path); } @@ -1817,7 +1819,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) my_close(fd, MYF(0)); /* Remove the temporary file */ - my_delete(temp_file_path, MYF(0)); + my_delete(temp_file_path, MYF(MY_WME)); DBUG_RETURN(error); } @@ -2931,8 +2933,8 @@ void do_remove_file(struct st_command *command) ' '); DBUG_PRINT("info", ("removing file: %s", ds_filename.str)); - error= my_delete(ds_filename.str, MYF(0)) != 0; - handle_command_error(command, error); + error= my_delete(ds_filename.str, MYF(disable_warnings ? 0 : MY_WME)) != 0; + handle_command_error(command, error, my_errno); dynstr_free(&ds_filename); DBUG_VOID_RETURN; } @@ -2950,7 +2952,7 @@ void do_remove_file(struct st_command *command) void do_remove_files_wildcard(struct st_command *command) { - int error= 0; + int error= 0, sys_errno= 0; uint i; MY_DIR *dir_info; FILEINFO *file; @@ -2974,9 +2976,10 @@ void do_remove_files_wildcard(struct st_command *command) DBUG_PRINT("info", ("listing directory: %s", dirname)); /* Note that my_dir sorts the list if not given any flags */ - if (!(dir_info= my_dir(dirname, MYF(MY_DONT_SORT | MY_WANT_STAT)))) + if (!(dir_info= my_dir(dirname, MYF(MY_DONT_SORT | MY_WANT_STAT | MY_WME)))) { error= 1; + sys_errno= my_errno; goto end; } init_dynamic_string(&ds_file_to_remove, dirname, 1024, 1024); @@ -2998,14 +3001,15 @@ void do_remove_files_wildcard(struct st_command *command) ds_file_to_remove.str[ds_directory.length + 1]= 0; dynstr_append(&ds_file_to_remove, file->name); DBUG_PRINT("info", ("removing file: %s", ds_file_to_remove.str)); - error= my_delete(ds_file_to_remove.str, MYF(0)) != 0; + if ((error= (my_delete(ds_file_to_remove.str, MYF(MY_WME)) != 0))) + sys_errno= my_errno; if (error) break; } my_dirend(dir_info); end: - handle_command_error(command, error); + handle_command_error(command, error, sys_errno); dynstr_free(&ds_directory); dynstr_free(&ds_wild); dynstr_free(&ds_file_to_remove); @@ -3043,8 +3047,8 @@ void do_copy_file(struct st_command *command) DBUG_PRINT("info", ("Copy %s to %s", ds_from_file.str, ds_to_file.str)); error= (my_copy(ds_from_file.str, ds_to_file.str, - MYF(MY_DONT_OVERWRITE_FILE)) != 0); - handle_command_error(command, error); + MYF(MY_DONT_OVERWRITE_FILE | MY_WME)) != 0); + handle_command_error(command, error, my_errno); dynstr_free(&ds_from_file); dynstr_free(&ds_to_file); DBUG_VOID_RETURN; @@ -3079,8 +3083,8 @@ void do_move_file(struct st_command *command) DBUG_PRINT("info", ("Move %s to %s", ds_from_file.str, ds_to_file.str)); error= (my_rename(ds_from_file.str, ds_to_file.str, - MYF(0)) != 0); - handle_command_error(command, error); + MYF(disable_warnings ? 0 : MY_WME)) != 0); + handle_command_error(command, error, my_errno); dynstr_free(&ds_from_file); dynstr_free(&ds_to_file); DBUG_VOID_RETURN; @@ -3100,6 +3104,7 @@ void do_move_file(struct st_command *command) void do_chmod_file(struct st_command *command) { + int error; long mode= 0; static DYNAMIC_STRING ds_mode; static DYNAMIC_STRING ds_file; @@ -3120,7 +3125,10 @@ void do_chmod_file(struct st_command *command) die("You must write a 4 digit octal number for mode"); DBUG_PRINT("info", ("chmod %o %s", (uint)mode, ds_file.str)); - handle_command_error(command, chmod(ds_file.str, mode)); + error= 0; + if (chmod(ds_file.str, mode)) + error= 1; + handle_command_error(command, error, errno); dynstr_free(&ds_mode); dynstr_free(&ds_file); DBUG_VOID_RETURN; @@ -3153,7 +3161,7 @@ void do_file_exist(struct st_command *command) DBUG_PRINT("info", ("Checking for existence of file: %s", ds_filename.str)); error= (access(ds_filename.str, F_OK) != 0); - handle_command_error(command, error); + handle_command_error(command, error, errno); dynstr_free(&ds_filename); DBUG_VOID_RETURN; } @@ -3183,8 +3191,8 @@ void do_mkdir(struct st_command *command) ' '); DBUG_PRINT("info", ("creating directory: %s", ds_dirname.str)); - error= my_mkdir(ds_dirname.str, 0777, MYF(0)) != 0; - handle_command_error(command, error); + error= my_mkdir(ds_dirname.str, 0777, MYF(MY_WME)) != 0; + handle_command_error(command, error, my_errno); dynstr_free(&ds_dirname); DBUG_VOID_RETURN; } @@ -3214,7 +3222,7 @@ void do_rmdir(struct st_command *command) DBUG_PRINT("info", ("removing directory: %s", ds_dirname.str)); error= rmdir(ds_dirname.str) != 0; - handle_command_error(command, error); + handle_command_error(command, error, errno); dynstr_free(&ds_dirname); DBUG_VOID_RETURN; } @@ -3288,7 +3296,7 @@ static void do_list_files(struct st_command *command) sizeof(list_files_args)/sizeof(struct command_arg), ' '); error= get_list_files(&ds_res, &ds_dirname, &ds_wild); - handle_command_error(command, error); + handle_command_error(command, error, my_errno); dynstr_free(&ds_dirname); dynstr_free(&ds_wild); DBUG_VOID_RETURN; @@ -3330,7 +3338,7 @@ static void do_list_files_write_file_command(struct st_command *command, init_dynamic_string(&ds_content, "", 1024, 1024); error= get_list_files(&ds_content, &ds_dirname, &ds_wild); - handle_command_error(command, error); + handle_command_error(command, error, my_errno); str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append); dynstr_free(&ds_content); dynstr_free(&ds_filename); @@ -3612,7 +3620,7 @@ void do_diff_files(struct st_command *command) dynstr_free(&ds_filename); dynstr_free(&ds_filename2); - handle_command_error(command, error); + handle_command_error(command, error, -1); DBUG_VOID_RETURN; } @@ -3818,9 +3826,9 @@ void do_perl(struct st_command *command) error= pclose(res_file); /* Remove the temporary file */ - my_delete(temp_file_path, MYF(0)); + my_delete(temp_file_path, MYF(MY_WME)); - handle_command_error(command, WEXITSTATUS(error)); + handle_command_error(command, WEXITSTATUS(error), my_errno); } dynstr_free(&ds_delimiter); DBUG_VOID_RETURN; @@ -8199,12 +8207,12 @@ int main(int argc, char **argv) command->last_argument= command->end; break; case Q_PING: - handle_command_error(command, mysql_ping(&cur_con->mysql)); + handle_command_error(command, mysql_ping(&cur_con->mysql), -1); break; case Q_SEND_SHUTDOWN: handle_command_error(command, mysql_shutdown(&cur_con->mysql, - SHUTDOWN_DEFAULT)); + SHUTDOWN_DEFAULT), -1); break; case Q_SHUTDOWN_SERVER: do_shutdown_server(command); diff --git a/mysql-test/include/cleanup_fake_relay_log.inc b/mysql-test/include/cleanup_fake_relay_log.inc index 43aa46cb657..c55e2937242 100644 --- a/mysql-test/include/cleanup_fake_relay_log.inc +++ b/mysql-test/include/cleanup_fake_relay_log.inc @@ -9,8 +9,10 @@ --echo Cleaning up after setup_fake_relay_log.inc # Remove files. +--disable_warnings remove_file $_fake_relay_log; remove_file $_fake_relay_index; +--enable_warnings --disable_query_log eval SET @@global.relay_log_purge= $_fake_relay_log_purge; --enable_query_log diff --git a/mysql-test/include/diff_tables.inc b/mysql-test/include/diff_tables.inc index 81362e8643b..8a463686fdb 100644 --- a/mysql-test/include/diff_tables.inc +++ b/mysql-test/include/diff_tables.inc @@ -54,11 +54,12 @@ --echo Comparing tables $diff_table_1 and $diff_table_2 disable_query_log; - +disable_warnings; --error 0,1 --remove_file $MYSQLTEST_VARDIR/tmp/diff_table_1 --error 0,1 --remove_file $MYSQLTEST_VARDIR/tmp/diff_table_2 +enable_warnings; let $_diff_table=$diff_table_2; let $_diff_i=2; diff --git a/mysql-test/include/maria_empty_logs.inc b/mysql-test/include/maria_empty_logs.inc index cc93e214348..e8b6a423953 100644 --- a/mysql-test/include/maria_empty_logs.inc +++ b/mysql-test/include/maria_empty_logs.inc @@ -24,6 +24,7 @@ EOF --source include/mysqladmin_shutdown.inc +--disable_warnings if (!$mel_keep_control_file) { --error 0,1 @@ -73,6 +74,7 @@ remove_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log.00000020; -- error 0,1 remove_file $MYSQLD_DATADIR/maria_recovery.trace; +--enable_warnings append_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect; restart-maria_empty_logs.inc diff --git a/mysql-test/include/maria_make_snapshot.inc b/mysql-test/include/maria_make_snapshot.inc index 2f480ac1a45..8f45f6b63a9 100644 --- a/mysql-test/include/maria_make_snapshot.inc +++ b/mysql-test/include/maria_make_snapshot.inc @@ -26,12 +26,16 @@ if ($mms_copy) if ($mms_reverse_copy) { # do not call this without flushing target table first! + --disable_warnings --echo * copied $mms_tname$mms_table_to_use back for $mms_purpose -- error 0,1 remove_file $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.MAD; + --enable_warnings copy_file $MYSQLD_DATADIR/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.MAD $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.MAD; + --disable_warnings -- error 0,1 remove_file $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.MAI; + --enable_warnings copy_file $MYSQLD_DATADIR/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.MAI $MYSQLD_DATADIR/mysqltest/$mms_tname$mms_table_to_use.MAI; } diff --git a/mysql-test/include/maria_make_snapshot_for_feeding_recovery.inc b/mysql-test/include/maria_make_snapshot_for_feeding_recovery.inc index 62f5250cab4..c204409de4d 100644 --- a/mysql-test/include/maria_make_snapshot_for_feeding_recovery.inc +++ b/mysql-test/include/maria_make_snapshot_for_feeding_recovery.inc @@ -31,8 +31,10 @@ while ($mms_table_to_use) let $mms_copy=0; let $MYSQLD_DATADIR= `SELECT @@datadir`; +--disable_warnings -- error 0,1 remove_file $MYSQLTEST_VARDIR/tmp/mms_for_$mms_purpose.maria_log_control; +--enable_warnings copy_file $MYSQLD_DATADIR/$MARIA_LOG/maria_log_control $MYSQLTEST_VARDIR/tmp/mms_for_$mms_purpose.maria_log_control; connection default; diff --git a/mysql-test/include/mysqlhotcopy.inc b/mysql-test/include/mysqlhotcopy.inc index b3fd5e47179..2596994b59a 100644 --- a/mysql-test/include/mysqlhotcopy.inc +++ b/mysql-test/include/mysqlhotcopy.inc @@ -75,7 +75,9 @@ USE hotcopy_test; --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --list_files $MYSQLTEST_VARDIR/tmp/hotcopy_test #--exec rm -rf $MYSQLTEST_VARDIR/tmp/hotcopy_test +--disable_warnings --remove_files_wildcard $MYSQLTEST_VARDIR/tmp/hotcopy_test * +--enable_warnings --rmdir $MYSQLTEST_VARDIR/tmp/hotcopy_test # backup without full index files diff --git a/mysql-test/include/ndb_backup.inc b/mysql-test/include/ndb_backup.inc index 5262f1231a2..eef3bf2bd1e 100644 --- a/mysql-test/include/ndb_backup.inc +++ b/mysql-test/include/ndb_backup.inc @@ -18,8 +18,10 @@ CREATE TABLE helper1(c1 VARCHAR(20)); # dump raw data to file let $ndb_backup_file1= $MYSQLTEST_VARDIR/ndb_backup_tmp.dat; let $ndb_backup_file2= $MYSQLTEST_VARDIR/tmp.dat; +--disable_warnings --error 0,1 --remove_file $ndb_backup_file1 +--enable_warnings --exec $NDB_TOOLS_DIR/ndb_select_all --ndb-connectstring="$NDB_CONNECTSTRING" -d sys --delimiter=',' SYSTAB_0 > $ndb_backup_file1 # load the table from the raw data file eval LOAD DATA INFILE '$ndb_backup_file1' INTO TABLE helper1; diff --git a/mysql-test/include/ndb_backup_print.inc b/mysql-test/include/ndb_backup_print.inc index 7527f125686..69faa8f421b 100644 --- a/mysql-test/include/ndb_backup_print.inc +++ b/mysql-test/include/ndb_backup_print.inc @@ -1,7 +1,9 @@ --exec $NDB_TOOLS_DIR/ndb_restore --no-defaults $ndb_restore_opts -b $the_backup_id -n 1 $NDB_BACKUP_DIR/BACKUP/BACKUP-$the_backup_id $ndb_restore_filter > $MYSQLTEST_VARDIR/tmp/tmp.dat --exec $NDB_TOOLS_DIR/ndb_restore --no-defaults $ndb_restore_opts -b $the_backup_id -n 2 $NDB_BACKUP_DIR/BACKUP/BACKUP-$the_backup_id $ndb_restore_filter >> $MYSQLTEST_VARDIR/tmp/tmp.dat --exec sort $MYSQLTEST_VARDIR/tmp/tmp.dat +--disable_warnings --error 0,1 --remove_file $MYSQLTEST_VARDIR/tmp/tmp.dat +--enable_warnings --let ndb_restore_opts= --let ndb_restore_filter= diff --git a/mysql-test/r/alter_table_trans.result b/mysql-test/r/alter_table_trans.result new file mode 100644 index 00000000000..3dd5c00d3d8 --- /dev/null +++ b/mysql-test/r/alter_table_trans.result @@ -0,0 +1,6 @@ +drop table if exists t1,t2; +CREATE TABLE t1 (a INT, INDEX(a)) engine=innodb; +ALTER TABLE t1 RENAME TO t2, DISABLE KEYS; +Warnings: +Note 1031 Table storage engine for 't1' doesn't have this option +DROP TABLE t2; diff --git a/mysql-test/t/alter_table_trans.test b/mysql-test/t/alter_table_trans.test new file mode 100644 index 00000000000..9096a392af4 --- /dev/null +++ b/mysql-test/t/alter_table_trans.test @@ -0,0 +1,15 @@ +# +# Test of alter table with transactional tables +# + +--source include/have_innodb.inc +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +# +# This test caused a crash in wait_if_global_read_lock() +# +CREATE TABLE t1 (a INT, INDEX(a)) engine=innodb; +ALTER TABLE t1 RENAME TO t2, DISABLE KEYS; +DROP TABLE t2; diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index b103140190f..edc4da4e37f 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -106,7 +106,7 @@ select otto from (select 1 as otto) as t1; # expecting a SQL-state for a command that can't give one should fail --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --error 1 ---exec echo "error S00000; remove_file $MYSQLTEST_VARDIR/tmp/test_nonexistent.tmp;" | $MYSQL_TEST 2>&1 +--exec echo "disable_warnings ; error S00000; remove_file $MYSQLTEST_VARDIR/tmp/test_nonexistent.tmp;" | $MYSQL_TEST 2>&1 # ---------------------------------------------------------------------------- @@ -1551,12 +1551,14 @@ select "this will be executed"; --exec $MYSQL_TEST -x $MYSQLTEST_VARDIR/tmp/query.sql -R $MYSQLTEST_VARDIR/tmp/zero_length_file.result > /dev/null 2>&1 remove_file $MYSQLTEST_VARDIR/tmp/zero_length_file.result; +--disable_warnings --error 0,1 remove_file $MYSQLTEST_VARDIR/tmp/zero_length_file.reject; --error 0,1 remove_file $MYSQLTEST_VARDIR/tmp/zero_length_file.log; --error 0,1 remove_file $MYSQL_TEST_DIR/r/zero_length_file.reject; +--enable_warnings # # Test that a test file that does not generate any output fails. @@ -1741,11 +1743,13 @@ drop table t1; # test for remove_file # ---------------------------------------------------------------------------- +--disable_warnings --error 1 --exec echo "remove_file ;" | $MYSQL_TEST 2>&1 --error 1 remove_file non_existing_file; +--enable_warnings # ---------------------------------------------------------------------------- # test for remove_files_wildcard @@ -1785,7 +1789,7 @@ Content for test_file1 contains EOF END_DELIMITER file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; -# write to already exisiting file +# write to already existing file --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --error 1 --exec echo "write_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp;" | $MYSQL_TEST 2>&1 @@ -1901,8 +1905,10 @@ EOF --error 1 --exec echo "file_exists ;" | $MYSQL_TEST 2>&1 +--disable_warnings --error 0,1 remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +--enable_warnings --error 1 file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; write_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; @@ -1939,6 +1945,7 @@ remove_file $MYSQLTEST_VARDIR/tmp/file2.tmp; # - Check that if source file does not exist, nothing will be created. +--disable_warnings --error 1 file_exists $MYSQLTEST_VARDIR/tmp/file1.tmp; --error 1 @@ -1949,6 +1956,7 @@ move_file $MYSQLTEST_VARDIR/tmp/file1.tmp $MYSQLTEST_VARDIR/tmp/file2.tmp; file_exists $MYSQLTEST_VARDIR/tmp/file1.tmp; --error 1 file_exists $MYSQLTEST_VARDIR/tmp/file2.tmp; +--enable_warnings # - Check that if source file exists, everything works properly. diff --git a/mysys/my_copy.c b/mysys/my_copy.c index 8ea9620b20b..e1c549f4676 100644 --- a/mysys/my_copy.c +++ b/mysys/my_copy.c @@ -112,7 +112,7 @@ int my_copy(const char *from, const char *to, myf MyFlags) { my_errno= errno; if (MyFlags & MY_WME) - my_error(EE_CHANGE_PERMISSIONS, MYF(ME_BELL+ME_WAITTANG), from, errno); + my_error(EE_CHANGE_PERMISSIONS, MYF(ME_BELL+ME_WAITTANG), to, errno); if (MyFlags & MY_FAE) goto err; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 96be7c4437c..26464901930 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6886,8 +6886,14 @@ view_err: Workaround InnoDB ending the transaction when the table instance is unlocked/closed (close_cached_table below), otherwise the trx state will differ between the server and storage engine layers. + + We have to unlock LOCK_open here as otherwise we can get deadlock + in wait_if_global_readlock(). This is still safe as we have a + name lock on the table object. */ + VOID(pthread_mutex_unlock(&LOCK_open)); ha_autocommit_or_rollback(thd, 0); + VOID(pthread_mutex_lock(&LOCK_open)); /* Then do a 'simple' rename of the table. First we need to close all