From 40ec012c905be0262ba5c36bbccfa0db0105e31f Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 25 Nov 2009 16:25:01 +0400 Subject: Backport from 6.0-codebase. WL#3951 - MyISAM: Additional Error Logs for Data Corruption When table corruption is detected, in addition to current error message provide following information: - list of threads (and queries) accessing a table; - thread_id of a thread that detected corruption; - source file name and line number where this corruption was detected; - optional extra information (string). mysql-test/r/myisam_crash_before_flush_keys.result: Adjusted a test case according to WL#3951. mysql-test/t/myisam_crash_before_flush_keys.test: Adjusted a test case according to WL#3951. storage/myisam/CMakeLists.txt: Added mi_extrafunc.h to myisam sources list. storage/myisam/Makefile.am: Added mi_extrafunc.h to myisam headers list. storage/myisam/ha_myisam.cc: Added _mi_report_crashed() function (reports additional information whenever table corruption is detected). storage/myisam/mi_extrafunc.h: All standalone programs must define their version of _mi_report_crashed() by including mi_extrafunc.h. storage/myisam/mi_locking.c: For every call to mi_lock_database(F_[RD|WR|EXTRA_]LCK) - add current thread to the list of threads accessing this table. For every call to mi_lock_database(F_UNLCK) - remove current thread from the list of threads accessing this table. storage/myisam/mi_test1.c: All standalone programs must define their version of _mi_report_crashed() by including mi_extrafunc.h. storage/myisam/mi_test2.c: All standalone programs must define their version of _mi_report_crashed() by including mi_extrafunc.h. storage/myisam/mi_test3.c: All standalone programs must define their version of _mi_report_crashed() by including mi_extrafunc.h. storage/myisam/myisam_ftdump.c: All standalone programs must define their version of _mi_report_crashed() by including mi_extrafunc.h. storage/myisam/myisamchk.c: All standalone programs must define their version of _mi_report_crashed() by including mi_extrafunc.h. storage/myisam/myisamdef.h: Extra elements are added to MI_INFO and MYISAM_SHARE structures. MI_INFO is extended with LIST element, that holds a pointer to THD object accessing a table. MYISAM_SHARE is extended with LIST (list of threads accessing a table). Whenever table is marked as crashed, call mi_report_crashed() macro to provide useful information. storage/myisam/myisamlog.c: All standalone programs must define their version of _mi_report_crashed() by including mi_extrafunc.h. storage/myisam/myisampack.c: All standalone programs must define their version of _mi_report_crashed() by including mi_extrafunc.h. storage/myisam/rt_test.c: All standalone programs must define their version of _mi_report_crashed() by including mi_extrafunc.h. storage/myisam/sp_test.c: All standalone programs must define their version of _mi_report_crashed() by including mi_extrafunc.h. storage/myisammrg/ha_myisammrg.cc: For each unedrlying table initialize `in_use' variable. --- storage/myisam/CMakeLists.txt | 3 ++- storage/myisam/Makefile.am | 2 +- storage/myisam/ha_myisam.cc | 40 +++++++++++++++++++++++++++++++++++++++ storage/myisam/mi_extrafunc.h | 21 ++++++++++++++++++++ storage/myisam/mi_locking.c | 4 ++++ storage/myisam/mi_test1.c | 2 ++ storage/myisam/mi_test2.c | 2 ++ storage/myisam/mi_test3.c | 2 ++ storage/myisam/myisam_ftdump.c | 2 ++ storage/myisam/myisamchk.c | 2 ++ storage/myisam/myisamdef.h | 6 ++++++ storage/myisam/myisamlog.c | 2 ++ storage/myisam/myisampack.c | 2 +- storage/myisam/rt_test.c | 2 ++ storage/myisam/sp_test.c | 1 + storage/myisammrg/ha_myisammrg.cc | 3 +++ 16 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 storage/myisam/mi_extrafunc.h (limited to 'storage') diff --git a/storage/myisam/CMakeLists.txt b/storage/myisam/CMakeLists.txt index 829d89a798a..9a0aa06e861 100755 --- a/storage/myisam/CMakeLists.txt +++ b/storage/myisam/CMakeLists.txt @@ -26,7 +26,8 @@ SET(MYISAM_SOURCES ft_boolean_search.c ft_nlq_search.c ft_parser.c ft_static.c mi_rfirst.c mi_rlast.c mi_rnext.c mi_rnext_same.c mi_rprev.c mi_rrnd.c mi_rsame.c mi_rsamepos.c mi_scan.c mi_search.c mi_static.c mi_statrec.c mi_unique.c mi_update.c mi_write.c rt_index.c rt_key.c rt_mbr.c - rt_split.c sort.c sp_key.c ft_eval.h myisamdef.h rt_index.h mi_rkey.c) + rt_split.c sort.c sp_key.c ft_eval.h mi_extrafunc.h myisamdef.h + rt_index.h mi_rkey.c) MYSQL_STORAGE_ENGINE(MYISAM) diff --git a/storage/myisam/Makefile.am b/storage/myisam/Makefile.am index 6dd0d2bcbdb..c659d05be40 100644 --- a/storage/myisam/Makefile.am +++ b/storage/myisam/Makefile.am @@ -50,7 +50,7 @@ myisampack_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmyisam.a \ noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 rt_test sp_test #ft_test1 ft_eval noinst_HEADERS = myisamdef.h rt_index.h rt_key.h rt_mbr.h sp_defs.h \ fulltext.h ftdefs.h ft_test1.h ft_eval.h \ - ha_myisam.h + ha_myisam.h mi_extrafunc.h mi_test1_DEPENDENCIES= $(LIBRARIES) mi_test1_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmyisam.a \ $(top_builddir)/mysys/libmysys.a \ diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 612d02bbcd3..1dd964f520e 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -539,6 +539,45 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...) va_end(args); } + +/** + Report list of threads (and queries) accessing a table, thread_id of a + thread that detected corruption, ource file name and line number where + this corruption was detected, optional extra information (string). + + This function is intended to be used when table corruption is detected. + + @param[in] file MI_INFO object. + @param[in] message Optional error message. + @param[in] sfile Name of source file. + @param[in] sline Line number in source file. + + @return void +*/ + +void _mi_report_crashed(MI_INFO *file, const char *message, + const char *sfile, uint sline) +{ + THD *cur_thd; + LIST *element; + char buf[1024]; + pthread_mutex_lock(&file->s->intern_lock); + if ((cur_thd= (THD*) file->in_use.data)) + sql_print_error("Got an error from thread_id=%lu, %s:%d", cur_thd->thread_id, + sfile, sline); + else + sql_print_error("Got an error from unknown thread, %s:%d", sfile, sline); + if (message) + sql_print_error("%s", message); + for (element= file->s->in_use; element; element= list_rest(element)) + { + THD *thd= (THD*) element->data; + sql_print_error("%s", thd ? thd_security_context(thd, buf, sizeof(buf), 0) + : "Unknown thread accessing table"); + } + pthread_mutex_unlock(&file->s->intern_lock); +} + } @@ -1894,6 +1933,7 @@ int ha_myisam::delete_table(const char *name) int ha_myisam::external_lock(THD *thd, int lock_type) { + file->in_use.data= thd; return mi_lock_database(file, !table->s->tmp_table ? lock_type : ((lock_type == F_UNLCK) ? F_UNLCK : F_EXTRA_LCK)); diff --git a/storage/myisam/mi_extrafunc.h b/storage/myisam/mi_extrafunc.h new file mode 100644 index 00000000000..4aa28832c6d --- /dev/null +++ b/storage/myisam/mi_extrafunc.h @@ -0,0 +1,21 @@ +/* Copyright (C) 2000-2006 MySQL AB + + 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 Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +void _mi_report_crashed(MI_INFO *file __attribute__((unused)), + const char *message __attribute__((unused)), + const char *sfile __attribute__((unused)), + uint sline __attribute__((unused))) +{ +} diff --git a/storage/myisam/mi_locking.c b/storage/myisam/mi_locking.c index 8a5866ae763..fd2094caa54 100644 --- a/storage/myisam/mi_locking.c +++ b/storage/myisam/mi_locking.c @@ -45,6 +45,7 @@ int mi_lock_database(MI_INFO *info, int lock_type) ++share->w_locks; ++share->tot_locks; info->lock_type= lock_type; + info->s->in_use= list_add(info->s->in_use, &info->in_use); DBUG_RETURN(0); } @@ -136,6 +137,7 @@ int mi_lock_database(MI_INFO *info, int lock_type) } info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); info->lock_type= F_UNLCK; + info->s->in_use= list_delete(info->s->in_use, &info->in_use); break; case F_RDLCK: if (info->lock_type == F_WRLCK) @@ -182,6 +184,7 @@ int mi_lock_database(MI_INFO *info, int lock_type) share->r_locks++; share->tot_locks++; info->lock_type=lock_type; + info->s->in_use= list_add(info->s->in_use, &info->in_use); break; case F_WRLCK: if (info->lock_type == F_RDLCK) @@ -231,6 +234,7 @@ int mi_lock_database(MI_INFO *info, int lock_type) info->invalidator=info->s->invalidator; share->w_locks++; share->tot_locks++; + info->s->in_use= list_add(info->s->in_use, &info->in_use); break; default: break; /* Impossible */ diff --git a/storage/myisam/mi_test1.c b/storage/myisam/mi_test1.c index f218bf4e77f..6a938c6e269 100644 --- a/storage/myisam/mi_test1.c +++ b/storage/myisam/mi_test1.c @@ -679,3 +679,5 @@ static void usage() my_print_help(my_long_options); my_print_variables(my_long_options); } + +#include "mi_extrafunc.h" diff --git a/storage/myisam/mi_test2.c b/storage/myisam/mi_test2.c index 23c58638166..40732db3d4f 100644 --- a/storage/myisam/mi_test2.c +++ b/storage/myisam/mi_test2.c @@ -1055,3 +1055,5 @@ static void copy_key(MI_INFO *info,uint inx,uchar *rec,uchar *key_buff) } return; } + +#include "mi_extrafunc.h" diff --git a/storage/myisam/mi_test3.c b/storage/myisam/mi_test3.c index 5bdc33b8518..44f194f5c9b 100644 --- a/storage/myisam/mi_test3.c +++ b/storage/myisam/mi_test3.c @@ -488,6 +488,8 @@ int test_update(MI_INFO *file,int id,int lock_type) return 0; } +#include "mi_extrafunc.h" + #else /* __NETWARE__ */ #include diff --git a/storage/myisam/myisam_ftdump.c b/storage/myisam/myisam_ftdump.c index 63d954242a0..7c14ae37de2 100644 --- a/storage/myisam/myisam_ftdump.c +++ b/storage/myisam/myisam_ftdump.c @@ -274,3 +274,5 @@ static void complain(int val) /* Kinda assert :-) */ exit(1); } } + +#include "mi_extrafunc.h" diff --git a/storage/myisam/myisamchk.c b/storage/myisam/myisamchk.c index 611fb6325c8..b26f3200504 100644 --- a/storage/myisam/myisamchk.c +++ b/storage/myisam/myisamchk.c @@ -1815,3 +1815,5 @@ void mi_check_print_error(MI_CHECK *param, const char *fmt,...) va_end(args); DBUG_VOID_RETURN; } + +#include "mi_extrafunc.h" diff --git a/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h index b64c7f6bd7f..9866b44ba15 100644 --- a/storage/myisam/myisamdef.h +++ b/storage/myisam/myisamdef.h @@ -165,6 +165,7 @@ typedef struct st_mi_isam_share { /* Shared between opens */ MI_COLUMNDEF *rec; /* Pointer to field information */ MI_PACK pack; /* Data about packed records */ MI_BLOB *blobs; /* Pointer to blobs */ + LIST *in_use; /* List of threads using this table */ char *unique_file_name; /* realpath() of index file */ char *data_file_name, /* Resolved path names from symlinks */ *index_file_name; @@ -242,6 +243,7 @@ struct st_myisam_info { DYNAMIC_ARRAY *ft1_to_ft2; /* used only in ft1->ft2 conversion */ MEM_ROOT ft_memroot; /* used by the parser */ MYSQL_FTPARSER_PARAM *ftparser_param; /* share info between init/deinit */ + LIST in_use; /* Thread using this table */ char *filename; /* parameter to open filename */ uchar *buff, /* Temp area for key */ *lastkey,*lastkey2; /* Last used search key */ @@ -385,8 +387,10 @@ typedef struct st_mi_sort_param #define mi_putint(x,y,nod) { uint16 boh=(nod ? (uint16) 32768 : 0) + (uint16) (y);\ mi_int2store(x,boh); } #define mi_test_if_nod(x) (x[0] & 128 ? info->s->base.key_reflength : 0) +#define mi_report_crashed(A, B) _mi_report_crashed((A), (B), __FILE__, __LINE__) #define mi_mark_crashed(x) do{(x)->s->state.changed|= STATE_CRASHED; \ DBUG_PRINT("error", ("Marked table crashed")); \ + mi_report_crashed((x), 0); \ }while(0) #define mi_mark_crashed_on_repair(x) do{(x)->s->state.changed|= \ STATE_CRASHED|STATE_CRASHED_ON_REPAIR; \ @@ -764,6 +768,8 @@ int mi_open_keyfile(MYISAM_SHARE *share); void mi_setup_functions(register MYISAM_SHARE *share); my_bool mi_dynmap_file(MI_INFO *info, my_off_t size); void mi_remap_file(MI_INFO *info, my_off_t size); +void _mi_report_crashed(MI_INFO *file, const char *message, + const char *sfile, uint sline); /* Functions needed by mi_check */ volatile int *killed_ptr(MI_CHECK *param); diff --git a/storage/myisam/myisamlog.c b/storage/myisam/myisamlog.c index fafb5140a5e..47667a52d16 100644 --- a/storage/myisam/myisamlog.c +++ b/storage/myisam/myisamlog.c @@ -845,3 +845,5 @@ static my_bool cmp_filename(struct file_info *file_info, char * name) return 1; return strcmp(file_info->name,name) ? 1 : 0; } + +#include "mi_extrafunc.h" diff --git a/storage/myisam/myisampack.c b/storage/myisam/myisampack.c index 908c32e48d3..f63e8087fd5 100644 --- a/storage/myisam/myisampack.c +++ b/storage/myisam/myisampack.c @@ -3201,4 +3201,4 @@ static int fakecmp(my_off_t **count1, my_off_t **count2) } #endif - +#include "mi_extrafunc.h" diff --git a/storage/myisam/rt_test.c b/storage/myisam/rt_test.c index 7d15afd12ef..4a9b61605d9 100644 --- a/storage/myisam/rt_test.c +++ b/storage/myisam/rt_test.c @@ -468,3 +468,5 @@ int main(int argc __attribute__((unused)),char *argv[] __attribute__((unused))) exit(0); } #endif /*HAVE_RTREE_KEYS*/ + +#include "mi_extrafunc.h" diff --git a/storage/myisam/sp_test.c b/storage/myisam/sp_test.c index f572c7ab19b..069f43c320d 100644 --- a/storage/myisam/sp_test.c +++ b/storage/myisam/sp_test.c @@ -562,3 +562,4 @@ int main(int argc __attribute__((unused)),char *argv[] __attribute__((unused))) } #endif /*HAVE_SPATIAL*/ +#include "mi_extrafunc.h" diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 471e2243aac..b28529b08e7 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -1009,7 +1009,10 @@ int ha_myisammrg::extra_opt(enum ha_extra_function operation, ulong cache_size) int ha_myisammrg::external_lock(THD *thd, int lock_type) { + MYRG_TABLE *tmp; DBUG_ASSERT(this->file->children_attached); + for (tmp= file->open_tables; tmp != file->end_table; tmp++) + tmp->table->in_use.data= thd; return myrg_lock_database(file,lock_type); } -- cgit v1.2.1 From a5aa3b3c919ab53cdcaa657a6446051348371245 Mon Sep 17 00:00:00 2001 From: V Narayanan Date: Thu, 3 Dec 2009 17:18:43 +0530 Subject: Bug#40814 CSV engine does not parse \X characters when they occur in unquoted fields When a .CSV file for table in the CSV engine contains \X characters as part of unquoted fields, e.g. 2,naraya\nan \n is not interpreted as a new line (it is however interpreted as a newline in a quoted field). The old algorithm copied the entire value for a unquoted field without parsing the \X characters. The new algorithm adds the capability to handle \X characters in the unquoted fields of a .CSV file. mysql-test/r/csv.result: Bug#40814 CSV engine does not parse \X characters when they occur in unquoted fields Contains additional test output corresponding to the new tests added. mysql-test/t/csv.test: Bug#40814 CSV engine does not parse \X characters when they occur in unquoted fields Contains additional tests for testing the behaviour of the CSV storage engine when the fields are not enclosed in quotes and contain \X characters. storage/csv/ha_tina.cc: Bug#40814 CSV engine does not parse \X characters when they occur in unquoted fields Changes the parsing logic of the rows in a CSV file, to parse \X characters that might be present in the unquoted fields. --- storage/csv/ha_tina.cc | 73 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 8 deletions(-) (limited to 'storage') diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc index 9cc0f1e607b..fac78986563 100644 --- a/storage/csv/ha_tina.cc +++ b/storage/csv/ha_tina.cc @@ -614,6 +614,33 @@ int ha_tina::find_current_row(uchar *buf) memset(buf, 0, table->s->null_bytes); + /* + Parse the line obtained using the following algorithm + + BEGIN + 1) Store the EOL (end of line) for the current row + 2) Until all the fields in the current query have not been + filled + 2.1) If the current character is a quote + 2.1.1) Until EOL has not been reached + a) If end of current field is reached, move + to next field and jump to step 2.3 + b) If current character is a \\ handle + \\n, \\r, \\, \\" + c) else append the current character into the buffer + before checking that EOL has not been reached. + 2.2) If the current character does not begin with a quote + 2.2.1) Until EOL has not been reached + a) If the end of field has been reached move to the + next field and jump to step 2.3 + b) If current character begins with \\ handle + \\n, \\r, \\, \\" + c) else append the current character into the buffer + before checking that EOL has not been reached. + 2.3) Store the current field value and jump to 2) + TERMINATE + */ + for (Field **field=table->field ; *field ; field++) { char curr_char; @@ -622,19 +649,23 @@ int ha_tina::find_current_row(uchar *buf) if (curr_offset >= end_offset) goto err; curr_char= file_buff->get_value(curr_offset); + /* Handle the case where the first character is a quote */ if (curr_char == '"') { - curr_offset++; // Incrementpast the first quote + /* Increment past the first quote */ + curr_offset++; - for(; curr_offset < end_offset; curr_offset++) + /* Loop through the row to extract the values for the current field */ + for ( ; curr_offset < end_offset; curr_offset++) { curr_char= file_buff->get_value(curr_offset); - // Need to convert line feeds! + /* check for end of the current field */ if (curr_char == '"' && (curr_offset == end_offset - 1 || file_buff->get_value(curr_offset + 1) == ',')) { - curr_offset+= 2; // Move past the , and the " + /* Move past the , and the " */ + curr_offset+= 2; break; } if (curr_char == '\\' && curr_offset != (end_offset - 1)) @@ -656,7 +687,7 @@ int ha_tina::find_current_row(uchar *buf) else // ordinary symbol { /* - We are at final symbol and no last quote was found => + If we are at final symbol and no last quote was found => we are working with a damaged file. */ if (curr_offset == end_offset - 1) @@ -667,15 +698,41 @@ int ha_tina::find_current_row(uchar *buf) } else { - for(; curr_offset < end_offset; curr_offset++) + for ( ; curr_offset < end_offset; curr_offset++) { curr_char= file_buff->get_value(curr_offset); + /* Move past the ,*/ if (curr_char == ',') { - curr_offset++; // Skip the , + curr_offset++; break; } - buffer.append(curr_char); + if (curr_char == '\\' && curr_offset != (end_offset - 1)) + { + curr_offset++; + curr_char= file_buff->get_value(curr_offset); + if (curr_char == 'r') + buffer.append('\r'); + else if (curr_char == 'n' ) + buffer.append('\n'); + else if (curr_char == '\\' || curr_char == '"') + buffer.append(curr_char); + else /* This could only happed with an externally created file */ + { + buffer.append('\\'); + buffer.append(curr_char); + } + } + else + { + /* + We are at the final symbol and a quote was found for the + unquoted field => We are working with a damaged field. + */ + if (curr_offset == end_offset - 1 && curr_char == '"') + goto err; + buffer.append(curr_char); + } } } -- cgit v1.2.1