diff --git a/client/mysqldump.c b/client/mysqldump.c index ee6d7b9d12b..49d2b9ae78c 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -21,7 +21,7 @@ ** AUTHOR: Igor Romanenko (igor@frog.kiev.ua) ** DATE: December 3, 1994 ** WARRANTY: None, expressed, impressed, implied -** or other +** or other ** STATUS: Public domain ** Adapted and optimized for MySQL by ** Michael Widenius, Sinisa Milivojevic, Jani Tolonen @@ -77,22 +77,22 @@ #define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */ static char *add_load_option(char *ptr, const char *object, - const char *statement); + const char *statement); static ulong find_set(TYPELIB *lib, const char *x, uint length, - char **err_pos, uint *err_len); + char **err_pos, uint *err_len); static char *alloc_query_str(ulong size); static char *field_escape(char *to,const char *from,uint length); static my_bool verbose=0,tFlag=0,dFlag=0,quick= 1, extended_insert= 1, - lock_tables=1,ignore_errors=0,flush_logs=0, - opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0, + lock_tables=1,ignore_errors=0,flush_logs=0, + opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0, opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0, opt_alldbs=0,opt_create_db=0,opt_lock_all_tables=0, opt_set_charset=0, - opt_autocommit=0,opt_disable_keys=1,opt_xml=0, - opt_delete_master_logs=0, tty_password=0, - opt_single_transaction=0, opt_comments= 0, opt_compact= 0, - opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0, + opt_autocommit=0,opt_disable_keys=1,opt_xml=0, + opt_delete_master_logs=0, tty_password=0, + opt_single_transaction=0, opt_comments= 0, opt_compact= 0, + opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0, opt_complete_insert= 0, opt_drop_database= 0, opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1; static ulong opt_max_allowed_packet, opt_net_buffer_length; @@ -129,8 +129,8 @@ static const char *mysql_universal_client_charset= static char *default_charset; static CHARSET_INFO *charset_info= &my_charset_latin1; const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace"; -/* do we met VIEWs during tables scaning */ -my_bool was_views= 0; +/* have we seen any VIEWs during table scanning? */ +my_bool seen_views= 0; const char *compatible_mode_names[]= { @@ -149,7 +149,7 @@ const char *compatible_mode_names[]= (1<<10) /* ANSI */\ ) TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1, - "", compatible_mode_names, NULL}; + "", compatible_mode_names, NULL}; HASH ignore_table; @@ -276,7 +276,7 @@ static struct my_option my_long_options[] = {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...", (gptr*) &lines_terminated, (gptr*) &lines_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"lock-all-tables", 'x', "Locks all tables across all databases. This " + {"lock-all-tables", 'x', "Locks all tables across all databases. This " "is achieved by taking a global read lock for the duration of the whole " "dump. Automatically turns --single-transaction and --lock-tables off.", (gptr*) &opt_lock_all_tables, (gptr*) &opt_lock_all_tables, 0, GET_BOOL, NO_ARG, @@ -297,7 +297,7 @@ static struct my_option my_long_options[] = GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_MASTER_DATA_COMMENTED_SQL, 0, 0, 0}, {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "", (gptr*) &opt_max_allowed_packet, (gptr*) &opt_max_allowed_packet, 0, - GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096, + GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096, (longlong) 2L*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "", (gptr*) &opt_net_buffer_length, (gptr*) &opt_net_buffer_length, 0, @@ -411,8 +411,8 @@ static const char *load_default_groups[]= { "mysqldump","client",0 }; static void safe_exit(int error); static void write_header(FILE *sql_file, char *db_name); static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, - const char *prefix,const char *name, - int string_value); + const char *prefix,const char *name, + int string_value); static int dump_selected_tables(char *db, char **table_names, int tables); static int dump_all_tables_in_db(char *db); static int init_dumping(char *); @@ -428,10 +428,10 @@ static my_bool dump_all_views_in_db(char *database); /* exit with message if ferror(file) - + SYNOPSIS check_io() - file - checked file + file - checked file */ void check_io(FILE *file) @@ -456,7 +456,7 @@ static void short_usage_sub(void) { printf("Usage: %s [OPTIONS] database [tables]\n", my_progname); printf("OR %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n", - my_progname); + my_progname); printf("OR %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname); NETWARE_SET_SCREEN_MODE(1); } @@ -501,12 +501,12 @@ static void write_header(FILE *sql_file, char *db_name) { fprintf(sql_file, "-- MySQL dump %s\n--\n", DUMP_VERSION); fprintf(sql_file, "-- Host: %s Database: %s\n", - current_host ? current_host : "localhost", db_name ? db_name : - ""); + current_host ? current_host : "localhost", db_name ? db_name : + ""); fputs("-- ------------------------------------------------------\n", - sql_file); + sql_file); fprintf(sql_file, "-- Server version\t%s\n", - mysql_get_server_info(&mysql_connection)); + mysql_get_server_info(&mysql_connection)); } if (opt_set_charset) fprintf(sql_file, @@ -529,10 +529,10 @@ static void write_header(FILE *sql_file, char *db_name) "); } fprintf(sql_file, - "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n" - "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n", - path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",", - compatible_mode_normal_str); + "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n" + "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n", + path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",", + compatible_mode_normal_str); check_io(sql_file); } } /* write_header */ @@ -563,7 +563,7 @@ static void write_footer(FILE *sql_file) "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n" "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n"); fprintf(sql_file, - "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n"); + "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n"); fputs("\n", sql_file); check_io(sql_file); } @@ -577,7 +577,7 @@ static void free_table_ent(char *key) byte* get_table_key(const char *entry, uint *length, - my_bool not_used __attribute__((unused))) + my_bool not_used __attribute__((unused))) { *length= strlen(entry); return (byte*) entry; @@ -594,7 +594,7 @@ void init_table_rule_hash(HASH* h) static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), - char *argument) + char *argument) { switch (optid) { #ifdef __NETWARE__ @@ -608,9 +608,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *start=argument; my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); opt_password=my_strdup(argument,MYF(MY_FAE)); - while (*argument) *argument++= 'x'; /* Destroy argument */ + while (*argument) *argument++= 'x'; /* Destroy argument */ if (*start) - start[1]=0; /* Cut length of argument */ + start[1]=0; /* Cut length of argument */ tty_password= 0; } else @@ -618,7 +618,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'r': if (!(md_result_file = my_fopen(argument, O_WRONLY | FILE_BINARY, - MYF(MY_WME)))) + MYF(MY_WME)))) exit(1); break; case 'W': @@ -639,7 +639,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'V': print_version(); exit(0); case 'X': opt_xml = 1; - extended_insert= opt_drop= opt_lock= + extended_insert= opt_drop= opt_lock= opt_disable_keys= opt_autocommit= opt_create_db= 0; break; case 'I': @@ -692,36 +692,36 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_set_charset= 0; opt_compatible_mode_str= argument; opt_compatible_mode= find_set(&compatible_mode_typelib, - argument, strlen(argument), - &err_ptr, &err_len); + argument, strlen(argument), + &err_ptr, &err_len); if (err_len) { - strmake(buff, err_ptr, min(sizeof(buff), err_len)); - fprintf(stderr, "Invalid mode to --compatible: %s\n", buff); - exit(1); + strmake(buff, err_ptr, min(sizeof(buff), err_len)); + fprintf(stderr, "Invalid mode to --compatible: %s\n", buff); + exit(1); } #if !defined(DBUG_OFF) { - uint size_for_sql_mode= 0; - const char **ptr; - for (ptr= compatible_mode_names; *ptr; ptr++) - size_for_sql_mode+= strlen(*ptr); - size_for_sql_mode+= sizeof(compatible_mode_names)-1; - DBUG_ASSERT(sizeof(compatible_mode_normal_str)>=size_for_sql_mode); + uint size_for_sql_mode= 0; + const char **ptr; + for (ptr= compatible_mode_names; *ptr; ptr++) + size_for_sql_mode+= strlen(*ptr); + size_for_sql_mode+= sizeof(compatible_mode_names)-1; + DBUG_ASSERT(sizeof(compatible_mode_normal_str)>=size_for_sql_mode); } #endif mode= opt_compatible_mode; for (i= 0, mode= opt_compatible_mode; mode; mode>>= 1, i++) { - if (mode & 1) - { - end= strmov(end, compatible_mode_names[i]); - end= strmov(end, ","); - } + if (mode & 1) + { + end= strmov(end, compatible_mode_names[i]); + end= strmov(end, ","); + } } if (end!=compatible_mode_normal_str) - end[-1]= 0; - /* + end[-1]= 0; + /* Set charset to the default compiled value if it hasn't been reset yet by --default-character-set=xxx. */ @@ -733,8 +733,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), { if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) { - fprintf(stderr, "Unknown option to protocol: %s\n", argument); - exit(1); + fprintf(stderr, "Unknown option to protocol: %s\n", argument); + exit(1); } break; } @@ -760,12 +760,12 @@ static int get_options(int *argc, char ***argv) *mysql_params->p_net_buffer_length= opt_net_buffer_length; if (opt_delayed) - opt_lock=0; /* Can't have lock with delayed */ + opt_lock=0; /* Can't have lock with delayed */ if (!path && (enclosed || opt_enclosed || escaped || lines_terminated || - fields_terminated)) + fields_terminated)) { fprintf(stderr, - "%s: You must use option --tab with --fields-...\n", my_progname); + "%s: You must use option --tab with --fields-...\n", my_progname); return(1); } @@ -777,7 +777,7 @@ static int get_options(int *argc, char ***argv) fprintf(stderr, "%s: You can't use --single-transaction and " "--lock-all-tables at the same time.\n", my_progname); return(1); - } + } if (opt_master_data) opt_lock_all_tables= !opt_single_transaction; if (opt_single_transaction || opt_lock_all_tables) @@ -790,13 +790,13 @@ static int get_options(int *argc, char ***argv) if ((opt_databases || opt_alldbs) && path) { fprintf(stderr, - "%s: --databases or --all-databases can't be used with --tab.\n", - my_progname); + "%s: --databases or --all-databases can't be used with --tab.\n", + my_progname); return(1); } if (strcmp(default_charset, charset_info->csname) && - !(charset_info= get_charset_by_csname(default_charset, - MY_CS_PRIMARY, MYF(MY_WME)))) + !(charset_info= get_charset_by_csname(default_charset, + MY_CS_PRIMARY, MYF(MY_WME)))) exit(1); if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs)) { @@ -816,7 +816,7 @@ static void DB_error(MYSQL *mysql, const char *when) { DBUG_ENTER("DB_error"); my_printf_error(0,"Got error: %d: %s %s", MYF(0), - mysql_errno(mysql), mysql_error(mysql), when); + mysql_errno(mysql), mysql_error(mysql), when); safe_exit(EX_MYSQLERR); DBUG_VOID_RETURN; } /* DB_error */ @@ -830,14 +830,14 @@ static void DB_error(MYSQL *mysql, const char *when) mysql_query_with_error_report() mysql_con connection to use res if non zero, result will be put there with - mysql_store_result() + mysql_store_result() query query to send to server RETURN VALUES 0 query sending and (if res!=0) result reading went ok 1 error */ - + static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res, const char *query) { @@ -869,7 +869,7 @@ static FILE* open_sql_file_for_table(const char* table) char filename[FN_REFLEN], tmp_path[FN_REFLEN]; convert_dirname(tmp_path,path,NullS); res= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4), - O_WRONLY, MYF(MY_WME)); + O_WRONLY, MYF(MY_WME)); return res; } @@ -904,7 +904,7 @@ static int dbConnect(char *host, char *user,char *passwd) #ifdef HAVE_OPENSSL if (opt_use_ssl) mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, - opt_ssl_capath, opt_ssl_cipher); + opt_ssl_capath, opt_ssl_cipher); mysql_options(&mysql_connection,MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (char*)&opt_ssl_verify_server_cert); #endif @@ -933,7 +933,7 @@ static int dbConnect(char *host, char *user,char *passwd) */ sock->reconnect= 0; my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */", - compatible_mode_normal_str); + compatible_mode_normal_str); if (mysql_query_with_error_report(sock, 0, buff)) { mysql_close(sock); @@ -941,7 +941,7 @@ static int dbConnect(char *host, char *user,char *passwd) return 1; } /* - set time_zone to UTC to allow dumping date types between servers with + set time_zone to UTC to allow dumping date types between servers with different time zone settings */ if (opt_tz_utc) @@ -975,8 +975,8 @@ static void unescape(FILE *file,char *pos,uint length) DBUG_ENTER("unescape"); if (!(tmp=(char*) my_malloc(length*2+1, MYF(MY_WME)))) { - ignore_errors=0; /* Fatal error */ - safe_exit(EX_MYSQLERR); /* Force exit */ + ignore_errors=0; /* Fatal error */ + safe_exit(EX_MYSQLERR); /* Force exit */ } mysql_real_escape_string(&mysql_connection, tmp, pos, length); fputc('\'', file); @@ -1003,13 +1003,13 @@ static my_bool test_if_special_chars(const char *str) /* quote_name(name, buff, force) - Quotes char string, taking into account compatible mode + Quotes char string, taking into account compatible mode Args name Unquoted string containing that which will be quoted buff The buffer that contains the quoted value, also returned - force Flag to make it ignore 'test_if_special_chars' + force Flag to make it ignore 'test_if_special_chars' Returns @@ -1082,13 +1082,13 @@ static char *quote_for_like(const char *name, char *buff) /* Quote and print a string. - + SYNOPSIS print_quoted_xml() - output - output file - str - string to print - len - its length - + output - output file + str - string to print + len - its length + DESCRIPTION Quote '<' '>' '&' '\"' chars and print a string to the xml_file. */ @@ -1096,7 +1096,7 @@ static char *quote_for_like(const char *name, char *buff) static void print_quoted_xml(FILE *xml_file, const char *str, ulong len) { const char *end; - + for (end= str + len; str != end; str++) { switch (*str) { @@ -1123,15 +1123,15 @@ static void print_quoted_xml(FILE *xml_file, const char *str, ulong len) /* Print xml tag with one attribute. - + SYNOPSIS print_xml_tag1() - xml_file - output file - sbeg - line beginning - stag_atr - tag and attribute - sval - value of attribute - send - line ending - + xml_file - output file + sbeg - line beginning + stag_atr - tag and attribute + sval - value of attribute + send - line ending + DESCRIPTION Print tag with one attribute to the xml_file. Format is: sbegsend @@ -1141,8 +1141,8 @@ static void print_quoted_xml(FILE *xml_file, const char *str, ulong len) */ static void print_xml_tag1(FILE * xml_file, const char* sbeg, - const char* stag_atr, const char* sval, - const char* send) + const char* stag_atr, const char* sval, + const char* send) { fputs(sbeg, xml_file); fputs("<", xml_file); @@ -1160,11 +1160,11 @@ static void print_xml_tag1(FILE * xml_file, const char* sbeg, SYNOPSIS print_xml_null_tag() - xml_file - output file - sbeg - line beginning - stag_atr - tag and attribute - sval - value of attribute - send - line ending + xml_file - output file + sbeg - line beginning + stag_atr - tag and attribute + sval - value of attribute + send - line ending DESCRIPTION Print tag with one attribute to the xml_file. Format is: @@ -1194,11 +1194,11 @@ static void print_xml_null_tag(FILE * xml_file, const char* sbeg, SYNOPSIS print_xml_row() - xml_file - output file - row_name - xml tag name - tableRes - query result - row - result row - + xml_file - output file + row_name - xml tag name + tableRes - query result + row - result row + DESCRIPTION Print tag with many attribute to the xml_file. Format is: \t\t @@ -1207,7 +1207,7 @@ static void print_xml_null_tag(FILE * xml_file, const char* sbeg, */ static void print_xml_row(FILE *xml_file, const char *row_name, - MYSQL_RES *tableRes, MYSQL_ROW *row) + MYSQL_RES *tableRes, MYSQL_ROW *row) { uint i; MYSQL_FIELD *field; @@ -1324,7 +1324,7 @@ static uint dump_routines_for_db(char *db) */ definer_begin= strstr(row[2], " DEFINER"); - + if (definer_begin) { char *definer_end= strstr(definer_begin, " PROCEDURE"); @@ -1388,7 +1388,7 @@ static uint dump_routines_for_db(char *db) ARGS table - table name db - db name - table_type - table type ie "InnoDB" + table_type - table type, e.g. "MyISAM" or "InnoDB", but also "VIEW" ignore_flag - what we must particularly ignore - see IGNORE_ defines above RETURN @@ -1400,10 +1400,10 @@ static uint get_table_structure(char *table, char *db, char *table_type, { my_bool init=0, delayed, write_data, complete_insert; my_ulonglong num_fields; - char *result_table, *opt_quoted_table; + char *result_table, *opt_quoted_table; const char *insert_option; - char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3]; - char table_buff2[NAME_LEN*2+3], query_buff[512]; + char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3]; + char table_buff2[NAME_LEN*2+3], query_buff[512]; FILE *sql_file = md_result_file; int len; MYSQL_RES *result; @@ -1473,21 +1473,30 @@ static uint get_table_structure(char *table, char *db, char *table_type, { if (!(sql_file= open_sql_file_for_table(table))) { - safe_exit(EX_MYSQLERR); - DBUG_RETURN(0); + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); } write_header(sql_file, db); } if (!opt_xml && opt_comments) { + if (strcmp (table_type, "VIEW") == 0) /* view */ + fprintf(sql_file, "\n--\n-- Temporary table structure for view %s\n--\n\n", + result_table); + else fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n", - result_table); - check_io(sql_file); + result_table); + check_io(sql_file); } if (opt_drop) { - fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table); - check_io(sql_file); + /* + Even if the "table" is a view, we do a DROP TABLE here. The + view-specific code below fills in the DROP VIEW. + */ + fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", + opt_quoted_table); + check_io(sql_file); } result= mysql_store_result(sock); @@ -1500,7 +1509,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, mysql_free_result(result); /* - Create a table with the same name as the view and with columns of + Create a table with the same name as the view and with columns of the same name in order to satisfy views that depend on this view. The table will be removed when the actual view is created. @@ -1524,10 +1533,13 @@ static uint get_table_structure(char *table, char *db, char *table_type, { if (opt_drop) { + /* + We have already dropped any table of the same name + above, so here we just drop the view. + */ + fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n", opt_quoted_table); - fprintf(sql_file, "/*!50001 DROP TABLE IF EXISTS %s*/;\n", - opt_quoted_table); check_io(sql_file); } @@ -1554,7 +1566,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, } mysql_free_result(result); - was_views= 1; + seen_views= 1; DBUG_RETURN(0); } @@ -1564,11 +1576,11 @@ static uint get_table_structure(char *table, char *db, char *table_type, mysql_free_result(result); } my_snprintf(query_buff, sizeof(query_buff), "show fields from %s", - result_table); + result_table); if (mysql_query_with_error_report(sock, &result, query_buff)) { if (path) - my_fclose(sql_file, MYF(MY_WME)); + my_fclose(sql_file, MYF(MY_WME)); safe_exit(EX_MYSQLERR); DBUG_RETURN(0); } @@ -1621,7 +1633,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, my_progname, mysql_error(sock)); my_snprintf(query_buff, sizeof(query_buff), "show fields from %s", - result_table); + result_table); if (mysql_query_with_error_report(sock, &result, query_buff)) { safe_exit(EX_MYSQLERR); @@ -1635,18 +1647,18 @@ static uint get_table_structure(char *table, char *db, char *table_type, { if (!(sql_file= open_sql_file_for_table(table))) { - safe_exit(EX_MYSQLERR); - DBUG_RETURN(0); + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); } write_header(sql_file, db); } if (!opt_xml && opt_comments) - fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n", - result_table); + fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n", + result_table); if (opt_drop) fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", result_table); if (!opt_xml) - fprintf(sql_file, "CREATE TABLE %s (\n", result_table); + fprintf(sql_file, "CREATE TABLE %s (\n", result_table); else print_xml_tag1(sql_file, "\t", "table_structure name=", table, "\n"); check_io(sql_file); @@ -1674,10 +1686,10 @@ static uint get_table_structure(char *table, char *db, char *table_type, if (init) { if (!opt_xml && !tFlag) - { - fputs(",\n",sql_file); - check_io(sql_file); - } + { + fputs(",\n",sql_file); + check_io(sql_file); + } if (complete_insert) dynstr_append_mem(&insert_pat, ", ", 2); } @@ -1687,30 +1699,30 @@ static uint get_table_structure(char *table, char *db, char *table_type, quote_name(row[SHOW_FIELDNAME], name_buff, 0)); if (!tFlag) { - if (opt_xml) - { - print_xml_row(sql_file, "field", result, &row); - continue; - } + if (opt_xml) + { + print_xml_row(sql_file, "field", result, &row); + continue; + } if (opt_keywords) - fprintf(sql_file, " %s.%s %s", result_table, - quote_name(row[SHOW_FIELDNAME],name_buff, 0), - row[SHOW_TYPE]); + fprintf(sql_file, " %s.%s %s", result_table, + quote_name(row[SHOW_FIELDNAME],name_buff, 0), + row[SHOW_TYPE]); else - fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME], - name_buff, 0), - row[SHOW_TYPE]); + fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME], + name_buff, 0), + row[SHOW_TYPE]); if (row[SHOW_DEFAULT]) { - fputs(" DEFAULT ", sql_file); - unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]); + fputs(" DEFAULT ", sql_file); + unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]); } if (!row[SHOW_NULL][0]) - fputs(" NOT NULL", sql_file); + fputs(" NOT NULL", sql_file); if (row[SHOW_EXTRA][0]) - fprintf(sql_file, " %s",row[SHOW_EXTRA]); - check_io(sql_file); + fprintf(sql_file, " %s",row[SHOW_EXTRA]); + check_io(sql_file); } } num_fields= mysql_num_rows(result); @@ -1730,9 +1742,9 @@ static uint get_table_structure(char *table, char *db, char *table_type, goto continue_xml; } fprintf(stderr, "%s: Can't get keys for table %s (%s)\n", - my_progname, result_table, mysql_error(sock)); + my_progname, result_table, mysql_error(sock)); if (path) - my_fclose(sql_file, MYF(MY_WME)); + my_fclose(sql_file, MYF(MY_WME)); safe_exit(EX_MYSQLERR); DBUG_RETURN(0); } @@ -1744,102 +1756,102 @@ static uint get_table_structure(char *table, char *db, char *table_type, { if (atoi(row[3]) == 1) { - keynr++; + keynr++; #ifdef FORCE_PRIMARY_KEY - if (atoi(row[1]) == 0 && primary_key == INT_MAX) - primary_key=keynr; + if (atoi(row[1]) == 0 && primary_key == INT_MAX) + primary_key=keynr; #endif - if (!strcmp(row[2],"PRIMARY")) - { - primary_key=keynr; - break; - } + if (!strcmp(row[2],"PRIMARY")) + { + primary_key=keynr; + break; + } } } mysql_data_seek(result,0); keynr=0; while ((row= mysql_fetch_row(result))) { - if (opt_xml) - { - print_xml_row(sql_file, "key", result, &row); - continue; - } + if (opt_xml) + { + print_xml_row(sql_file, "key", result, &row); + continue; + } if (atoi(row[3]) == 1) { - if (keynr++) - putc(')', sql_file); - if (atoi(row[1])) /* Test if duplicate key */ - /* Duplicate allowed */ - fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff,0)); - else if (keynr == primary_key) - fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */ - else - fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff, - 0)); + if (keynr++) + putc(')', sql_file); + if (atoi(row[1])) /* Test if duplicate key */ + /* Duplicate allowed */ + fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff,0)); + else if (keynr == primary_key) + fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */ + else + fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff, + 0)); } else - putc(',', sql_file); + putc(',', sql_file); fputs(quote_name(row[4], name_buff, 0), sql_file); if (row[7]) - fprintf(sql_file, " (%s)",row[7]); /* Sub key */ - check_io(sql_file); + fprintf(sql_file, " (%s)",row[7]); /* Sub key */ + check_io(sql_file); } if (!opt_xml) { - if (keynr) - putc(')', sql_file); - fputs("\n)",sql_file); - check_io(sql_file); + if (keynr) + putc(')', sql_file); + fputs("\n)",sql_file); + check_io(sql_file); } /* Get MySQL specific create options */ if (create_options) { - char show_name_buff[NAME_LEN*2+2+24]; + char show_name_buff[NAME_LEN*2+2+24]; - /* Check memory for quote_for_like() */ + /* Check memory for quote_for_like() */ my_snprintf(buff, sizeof(buff), "show table status like %s", - quote_for_like(table, show_name_buff)); + quote_for_like(table, show_name_buff)); if (mysql_query_with_error_report(sock, &result, buff)) { - if (mysql_errno(sock) != ER_PARSE_ERROR) - { /* If old MySQL version */ - if (verbose) - fprintf(stderr, - "-- Warning: Couldn't get status information for table %s (%s)\n", - result_table,mysql_error(sock)); - } + if (mysql_errno(sock) != ER_PARSE_ERROR) + { /* If old MySQL version */ + if (verbose) + fprintf(stderr, + "-- Warning: Couldn't get status information for table %s (%s)\n", + result_table,mysql_error(sock)); + } } else if (!(row= mysql_fetch_row(result))) { - fprintf(stderr, - "Error: Couldn't read status information for table %s (%s)\n", - result_table,mysql_error(sock)); + fprintf(stderr, + "Error: Couldn't read status information for table %s (%s)\n", + result_table,mysql_error(sock)); } else { - if (opt_xml) - print_xml_row(sql_file, "options", result, &row); - else - { - fputs("/*!",sql_file); - print_value(sql_file,result,row,"engine=","Engine",0); - print_value(sql_file,result,row,"","Create_options",0); - print_value(sql_file,result,row,"comment=","Comment",1); - fputs(" */",sql_file); - check_io(sql_file); - } + if (opt_xml) + print_xml_row(sql_file, "options", result, &row); + else + { + fputs("/*!",sql_file); + print_value(sql_file,result,row,"engine=","Engine",0); + print_value(sql_file,result,row,"","Create_options",0); + print_value(sql_file,result,row,"comment=","Comment",1); + fputs(" */",sql_file); + check_io(sql_file); + } } - mysql_free_result(result); /* Is always safe to free */ + mysql_free_result(result); /* Is always safe to free */ } continue_xml: if (!opt_xml) - fputs(";\n", sql_file); + fputs(";\n", sql_file); else - fputs("\t\n", sql_file); + fputs("\t\n", sql_file); check_io(sql_file); } } @@ -1871,8 +1883,8 @@ continue_xml: static void dump_triggers_for_table (char *table, char *db) { - char *result_table; - char name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3]; + char *result_table; + char name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3]; char query_buff[512]; uint old_opt_compatible_mode=opt_compatible_mode; FILE *sql_file = md_result_file; @@ -1921,7 +1933,7 @@ DELIMITER ;;\n"); uint host_name_len; char host_name_str[HOSTNAME_LENGTH + 1]; char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3]; - + parse_user(row[7], strlen(row[7]), user_name_str, &user_name_len, host_name_str, &host_name_len); @@ -1937,7 +1949,7 @@ DELIMITER ;;\n"); row[4], /* Timing */ row[1], /* Event */ result_table, - (strchr(" \t\n\r", *(row[3]))) ? "" : " ", + (strchr(" \t\n\r", *(row[3]))) ? "" : " ", row[3] /* Statement */); } if (mysql_num_rows(result)) @@ -1946,7 +1958,7 @@ DELIMITER ;;\n"); "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n"); mysql_free_result(result); /* - make sure to set back opt_compatible mode to + make sure to set back opt_compatible mode to original value */ opt_compatible_mode=old_opt_compatible_mode; @@ -1954,7 +1966,7 @@ DELIMITER ;;\n"); } static char *add_load_option(char *ptr,const char *object, - const char *statement) + const char *statement) { if (object) { @@ -1993,7 +2005,7 @@ static char *field_escape(char *to,const char *from,uint length) else { if (*from == '\'' && !end_backslashes) - *to++= *from; /* We want a duplicate of "'" for MySQL */ + *to++= *from; /* We want a duplicate of "'" for MySQL */ end_backslashes=0; } } @@ -2010,8 +2022,8 @@ static char *alloc_query_str(ulong size) if (!(query= (char*) my_malloc(size, MYF(MY_WME)))) { - ignore_errors= 0; /* Fatal error */ - safe_exit(EX_MYSQLERR); /* Force exit */ + ignore_errors= 0; /* Fatal error */ + safe_exit(EX_MYSQLERR); /* Force exit */ } return query; } @@ -2040,11 +2052,11 @@ static void dump_table(char *table, char *db) char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table; char *query= query_buf; int error= 0; - ulong rownr, row_break, total_length, init_length; + ulong rownr, row_break, total_length, init_length; uint num_fields; - MYSQL_RES *res; - MYSQL_FIELD *field; - MYSQL_ROW row; + MYSQL_RES *res; + MYSQL_FIELD *field; + MYSQL_ROW row; DBUG_ENTER("dump_table"); /* @@ -2053,13 +2065,19 @@ static void dump_table(char *table, char *db) */ num_fields= get_table_structure(table, db, table_type, &ignore_flag); + /* + The "table" could be a view. If so, we don't do anything here. + */ + if (strcmp (table_type, "VIEW") == 0) + return; + /* Check --no-data flag */ if (dFlag) { if (verbose) fprintf(stderr, "-- Skipping dump data for table '%s', --no-data was used\n", - table); + table); DBUG_VOID_RETURN; } @@ -2074,8 +2092,8 @@ static void dump_table(char *table, char *db) { if (verbose) fprintf(stderr, - "-- Warning: Skipping data for table '%s' because it's of type %s\n", - table, table_type); + "-- Warning: Skipping data for table '%s' because it's of type %s\n", + table, table_type); DBUG_VOID_RETURN; } /* Check that there are any fields in the table */ @@ -2083,8 +2101,8 @@ static void dump_table(char *table, char *db) { if (verbose) fprintf(stderr, - "-- Skipping dump data for table '%s', it has no fields\n", - table); + "-- Skipping dump data for table '%s', it has no fields\n", + table); DBUG_VOID_RETURN; } @@ -2100,11 +2118,11 @@ static void dump_table(char *table, char *db) my_load_path(tmp_path, tmp_path, NULL); fn_format(filename, table, tmp_path, ".txt", 4); my_delete(filename, MYF(0)); /* 'INTO OUTFILE' doesn't work, if - filename wasn't deleted */ + filename wasn't deleted */ to_unix_path(filename); - my_snprintf(query, QUERY_LENGTH, - "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'", - filename); + my_snprintf(query, QUERY_LENGTH, + "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'", + filename); end= strend(query); if (fields_terminated || enclosed || opt_enclosed || escaped) @@ -2141,12 +2159,12 @@ static void dump_table(char *table, char *db) if (!opt_xml && opt_comments) { fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n", - result_table); + result_table); check_io(md_result_file); } my_snprintf(query, QUERY_LENGTH, - "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s", - result_table); + "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s", + result_table); if (where || order_by) { query = alloc_query_str((ulong) (strlen(query) + 1 + @@ -2194,7 +2212,7 @@ static void dump_table(char *table, char *db) if (mysql_num_fields(res) != num_fields) { fprintf(stderr,"%s: Error in field count for table: %s ! Aborting.\n", - my_progname, result_table); + my_progname, result_table); error= EX_CONSCHECK; goto err; } @@ -2202,7 +2220,7 @@ static void dump_table(char *table, char *db) if (opt_disable_keys) { fprintf(md_result_file, "\n/*!40000 ALTER TABLE %s DISABLE KEYS */;\n", - opt_quoted_table); + opt_quoted_table); check_io(md_result_file); } if (opt_lock) @@ -2211,7 +2229,7 @@ static void dump_table(char *table, char *db) check_io(md_result_file); } - total_length= opt_net_buffer_length; /* Force row break */ + total_length= opt_net_buffer_length; /* Force row break */ row_break=0; rownr=0; init_length=(uint) insert_pat.length+4; @@ -2231,15 +2249,15 @@ static void dump_table(char *table, char *db) rownr++; if (!extended_insert && !opt_xml) { - fputs(insert_pat.str,md_result_file); - check_io(md_result_file); + fputs(insert_pat.str,md_result_file); + check_io(md_result_file); } mysql_field_seek(res,0); if (opt_xml) { fputs("\t\n", md_result_file); - check_io(md_result_file); + check_io(md_result_file); } for (i = 0; i < mysql_num_fields(res); i++) @@ -2247,21 +2265,21 @@ static void dump_table(char *table, char *db) int is_blob; ulong length= lengths[i]; - if (!(field = mysql_fetch_field(res))) - { - my_snprintf(query, QUERY_LENGTH, - "%s: Not enough fields from table %s! Aborting.\n", - my_progname, result_table); - fputs(query,stderr); - error= EX_CONSCHECK; - goto err; - } + if (!(field = mysql_fetch_field(res))) + { + my_snprintf(query, QUERY_LENGTH, + "%s: Not enough fields from table %s! Aborting.\n", + my_progname, result_table); + fputs(query,stderr); + error= EX_CONSCHECK; + goto err; + } - /* - 63 is my_charset_bin. If charsetnr is not 63, - we have not a BLOB but a TEXT column. - we'll dump in hex only BLOB columns. - */ + /* + 63 is my_charset_bin. If charsetnr is not 63, + we have not a BLOB but a TEXT column. + we'll dump in hex only BLOB columns. + */ is_blob= (opt_hex_blob && field->charsetnr == 63 && (field->type == MYSQL_TYPE_BIT || field->type == MYSQL_TYPE_STRING || @@ -2271,36 +2289,36 @@ static void dump_table(char *table, char *db) field->type == MYSQL_TYPE_LONG_BLOB || field->type == MYSQL_TYPE_MEDIUM_BLOB || field->type == MYSQL_TYPE_TINY_BLOB)) ? 1 : 0; - if (extended_insert) - { - if (i == 0) - dynstr_set(&extended_row,"("); - else - dynstr_append(&extended_row,","); + if (extended_insert) + { + if (i == 0) + dynstr_set(&extended_row,"("); + else + dynstr_append(&extended_row,","); - if (row[i]) - { - if (length) - { - if (!IS_NUM_FIELD(field)) - { - /* - "length * 2 + 2" is OK for both HEX and non-HEX modes: - - In HEX mode we need exactly 2 bytes per character - plus 2 bytes for '0x' prefix. - - In non-HEX mode we need up to 2 bytes per character, - plus 2 bytes for leading and trailing '\'' characters. - */ - if (dynstr_realloc(&extended_row,length * 2+2)) - { - fputs("Aborting dump (out of memory)",stderr); - error= EX_EOM; - goto err; - } + if (row[i]) + { + if (length) + { + if (!IS_NUM_FIELD(field)) + { + /* + "length * 2 + 2" is OK for both HEX and non-HEX modes: + - In HEX mode we need exactly 2 bytes per character + plus 2 bytes for '0x' prefix. + - In non-HEX mode we need up to 2 bytes per character, + plus 2 bytes for leading and trailing '\'' characters. + */ + if (dynstr_realloc(&extended_row,length * 2+2)) + { + fputs("Aborting dump (out of memory)",stderr); + error= EX_EOM; + goto err; + } if (opt_hex_blob && is_blob) { dynstr_append(&extended_row, "0x"); - extended_row.length+= mysql_hex_string(extended_row.str + + extended_row.length+= mysql_hex_string(extended_row.str + extended_row.length, row[i], length); extended_row.str[extended_row.length]= '\0'; @@ -2315,94 +2333,94 @@ static void dump_table(char *table, char *db) extended_row.str[extended_row.length]='\0'; dynstr_append(&extended_row,"'"); } - } - else - { - /* change any strings ("inf", "-inf", "nan") into NULL */ - char *ptr = row[i]; - if (my_isalpha(charset_info, *ptr) || (*ptr == '-' && - my_isalpha(charset_info, ptr[1]))) - dynstr_append(&extended_row, "NULL"); - else - { - if (field->type == FIELD_TYPE_DECIMAL) - { - /* add " signs around */ - dynstr_append(&extended_row, "'"); - dynstr_append(&extended_row, ptr); - dynstr_append(&extended_row, "'"); - } - else - dynstr_append(&extended_row, ptr); - } - } - } - else - dynstr_append(&extended_row,"''"); - } - else if (dynstr_append(&extended_row,"NULL")) - { - fputs("Aborting dump (out of memory)",stderr); - error= EX_EOM; - goto err; - } - } - else - { - if (i && !opt_xml) - { - fputc(',', md_result_file); - check_io(md_result_file); - } - if (row[i]) - { - if (!IS_NUM_FIELD(field)) - { - if (opt_xml) - { - print_xml_tag1(md_result_file, "\t\t", "field name=", - field->name, ""); - print_quoted_xml(md_result_file, row[i], length); - fputs("\n", md_result_file); - } - else if (opt_hex_blob && is_blob && length) + } + else + { + /* change any strings ("inf", "-inf", "nan") into NULL */ + char *ptr = row[i]; + if (my_isalpha(charset_info, *ptr) || (*ptr == '-' && + my_isalpha(charset_info, ptr[1]))) + dynstr_append(&extended_row, "NULL"); + else + { + if (field->type == FIELD_TYPE_DECIMAL) + { + /* add " signs around */ + dynstr_append(&extended_row, "'"); + dynstr_append(&extended_row, ptr); + dynstr_append(&extended_row, "'"); + } + else + dynstr_append(&extended_row, ptr); + } + } + } + else + dynstr_append(&extended_row,"''"); + } + else if (dynstr_append(&extended_row,"NULL")) + { + fputs("Aborting dump (out of memory)",stderr); + error= EX_EOM; + goto err; + } + } + else + { + if (i && !opt_xml) + { + fputc(',', md_result_file); + check_io(md_result_file); + } + if (row[i]) + { + if (!IS_NUM_FIELD(field)) + { + if (opt_xml) + { + print_xml_tag1(md_result_file, "\t\t", "field name=", + field->name, ""); + print_quoted_xml(md_result_file, row[i], length); + fputs("\n", md_result_file); + } + else if (opt_hex_blob && is_blob && length) { /* sakaik got the idea to to provide blob's in hex notation. */ char *ptr= row[i], *end= ptr + length; fputs("0x", md_result_file); for (; ptr < end ; ptr++) - fprintf(md_result_file, "%02X", *((uchar *)ptr)); + fprintf(md_result_file, "%02X", *((uchar *)ptr)); } else unescape(md_result_file, row[i], length); - } - else - { - /* change any strings ("inf", "-inf", "nan") into NULL */ - char *ptr = row[i]; - if (opt_xml) - { - print_xml_tag1(md_result_file, "\t\t", "field name=", - field->name, ""); - fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL", - md_result_file); - fputs("\n", md_result_file); - } - else if (my_isalpha(charset_info, *ptr) || - (*ptr == '-' && my_isalpha(charset_info, ptr[1]))) - fputs("NULL", md_result_file); - else if (field->type == FIELD_TYPE_DECIMAL) - { - /* add " signs around */ - fputc('\'', md_result_file); - fputs(ptr, md_result_file); - fputc('\'', md_result_file); - } - else - fputs(ptr, md_result_file); - } - } - else + } + else + { + /* change any strings ("inf", "-inf", "nan") into NULL */ + char *ptr = row[i]; + if (opt_xml) + { + print_xml_tag1(md_result_file, "\t\t", "field name=", + field->name, ""); + fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL", + md_result_file); + fputs("\n", md_result_file); + } + else if (my_isalpha(charset_info, *ptr) || + (*ptr == '-' && my_isalpha(charset_info, ptr[1]))) + fputs("NULL", md_result_file); + else if (field->type == FIELD_TYPE_DECIMAL) + { + /* add " signs around */ + fputc('\'', md_result_file); + fputs(ptr, md_result_file); + fputc('\'', md_result_file); + } + else + fputs(ptr, md_result_file); + } + } + else { /* The field value is NULL */ if (!opt_xml) @@ -2412,61 +2430,61 @@ static void dump_table(char *table, char *db) field->name, "\n"); } check_io(md_result_file); - } + } } if (opt_xml) { fputs("\t\n", md_result_file); - check_io(md_result_file); + check_io(md_result_file); } if (extended_insert) { - ulong row_length; - dynstr_append(&extended_row,")"); + ulong row_length; + dynstr_append(&extended_row,")"); row_length = 2 + extended_row.length; if (total_length + row_length < opt_net_buffer_length) { - total_length += row_length; - fputc(',',md_result_file); /* Always row break */ - fputs(extended_row.str,md_result_file); - } + total_length += row_length; + fputc(',',md_result_file); /* Always row break */ + fputs(extended_row.str,md_result_file); + } else { - if (row_break) - fputs(";\n", md_result_file); - row_break=1; /* This is first row */ + if (row_break) + fputs(";\n", md_result_file); + row_break=1; /* This is first row */ fputs(insert_pat.str,md_result_file); fputs(extended_row.str,md_result_file); - total_length = row_length+init_length; + total_length = row_length+init_length; } - check_io(md_result_file); + check_io(md_result_file); } else if (!opt_xml) { - fputs(");\n", md_result_file); - check_io(md_result_file); + fputs(");\n", md_result_file); + check_io(md_result_file); } } /* XML - close table tag and supress regular output */ if (opt_xml) - fputs("\t\n", md_result_file); + fputs("\t\n", md_result_file); else if (extended_insert && row_break) - fputs(";\n", md_result_file); /* If not empty table */ + fputs(";\n", md_result_file); /* If not empty table */ fflush(md_result_file); check_io(md_result_file); if (mysql_errno(sock)) { my_snprintf(query, QUERY_LENGTH, - "%s: Error %d: %s when dumping table %s at row: %ld\n", - my_progname, - mysql_errno(sock), - mysql_error(sock), - result_table, - rownr); + "%s: Error %d: %s when dumping table %s at row: %ld\n", + my_progname, + mysql_errno(sock), + mysql_error(sock), + result_table, + rownr); fputs(query,stderr); error= EX_CONSCHECK; goto err; @@ -2479,7 +2497,7 @@ static void dump_table(char *table, char *db) if (opt_disable_keys) { fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n", - opt_quoted_table); + opt_quoted_table); check_io(md_result_file); } if (opt_autocommit) @@ -2538,7 +2556,7 @@ static int dump_all_databases() if (dump_all_tables_in_db(row[0])) result=1; } - if (was_views) + if (seen_views) { if (mysql_query(sock, "SHOW DATABASES") || !(tableres = mysql_store_result(sock))) @@ -2567,7 +2585,7 @@ static int dump_databases(char **db_names) if (dump_all_tables_in_db(*db)) result=1; } - if (!result && was_views) + if (!result && seen_views) { for (db= db_names ; *db ; db++) { @@ -2583,26 +2601,26 @@ static int init_dumping(char *database) { if (mysql_get_server_version(sock) >= 50003 && !my_strcasecmp(&my_charset_latin1, database, "information_schema")) - return 1; + return 1; if (mysql_select_db(sock, database)) { DB_error(sock, "when selecting the database"); - return 1; /* If --force */ + return 1; /* If --force */ } if (!path && !opt_xml) { if (opt_databases || opt_alldbs) { /* - length of table name * 2 (if name contains quotes), 2 quotes and 0 + length of table name * 2 (if name contains quotes), 2 quotes and 0 */ char quoted_database_buf[64*2+3]; char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted); if (opt_comments) { - fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase); - check_io(md_result_file); + fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase); + check_io(md_result_file); } if (!opt_create_db) { @@ -2610,9 +2628,9 @@ static int init_dumping(char *database) MYSQL_ROW row; MYSQL_RES *dbinfo; - my_snprintf(qbuf, sizeof(qbuf), - "SHOW CREATE DATABASE IF NOT EXISTS %s", - qdatabase); + my_snprintf(qbuf, sizeof(qbuf), + "SHOW CREATE DATABASE IF NOT EXISTS %s", + qdatabase); if (mysql_query(sock, qbuf) || !(dbinfo = mysql_store_result(sock))) { @@ -2621,22 +2639,22 @@ static int init_dumping(char *database) fprintf(md_result_file, "\n/*!40000 DROP DATABASE IF EXISTS %s;*/\n", qdatabase); - fprintf(md_result_file, - "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", - qdatabase); - } - else + fprintf(md_result_file, + "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", + qdatabase); + } + else { if (opt_drop_database) fprintf(md_result_file, "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n", qdatabase); - row = mysql_fetch_row(dbinfo); - if (row[1]) - { - fprintf(md_result_file,"\n%s;\n",row[1]); + row = mysql_fetch_row(dbinfo); + if (row[1]) + { + fprintf(md_result_file,"\n%s;\n",row[1]); } - } + } } fprintf(md_result_file,"\nUSE %s;\n", qdatabase); check_io(md_result_file); @@ -2741,8 +2759,6 @@ static my_bool dump_all_views_in_db(char *database) uint numrows; char table_buff[NAME_LEN*2+3]; - if (init_dumping(database)) - return 1; if (opt_xml) print_xml_tag1(md_result_file, "", "database name=", database, "\n"); if (lock_tables) @@ -2802,7 +2818,7 @@ static int get_actual_table_name(const char *old_table_name, /* Check memory for quote_for_like() */ DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff)); my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s", - quote_for_like(old_table_name, show_name_buff)); + quote_for_like(old_table_name, show_name_buff)); if (mysql_query_with_error_report(sock, 0, query)) { @@ -2908,7 +2924,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } /* Dump each selected view */ - if (was_views) + if (seen_views) { for(i=0; i < dump_tables.records; i++) { @@ -2961,14 +2977,14 @@ static int do_show_master_status(MYSQL *mysql_con) "recovery from\n--\n\n"); fprintf(md_result_file, "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", - comment_prefix, row[0], row[1]); + comment_prefix, row[0], row[1]); check_io(md_result_file); } else if (!ignore_errors) { /* SHOW MASTER STATUS reports nothing and --force is not enabled */ - my_printf_error(0, "Error: Binlogging on server not active", - MYF(0)); + my_printf_error(0, "Error: Binlogging on server not active", + MYF(0)); mysql_free_result(master); return 1; } @@ -2988,7 +3004,7 @@ static int do_flush_tables_read_lock(MYSQL *mysql_con) and most client connections are stalled. Of course, if a second long update starts between the two FLUSHes, we have that bad stall. */ - return + return ( mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES") || mysql_query_with_error_report(mysql_con, 0, "FLUSH TABLES WITH READ LOCK") ); @@ -3030,7 +3046,7 @@ static int start_transaction(MYSQL *mysql_con, my_bool consistent_read_now) static ulong find_set(TYPELIB *lib, const char *x, uint length, - char **err_pos, uint *err_len) + char **err_pos, uint *err_len) { const char *end= x + length; ulong found= 0; @@ -3072,10 +3088,10 @@ static ulong find_set(TYPELIB *lib, const char *x, uint length, /* Print a value with a prefix on file */ static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, - const char *prefix, const char *name, - int string_value) + const char *prefix, const char *name, + int string_value) { - MYSQL_FIELD *field; + MYSQL_FIELD *field; mysql_field_seek(result, 0); for ( ; (field = mysql_fetch_field(result)) ; row++) @@ -3084,18 +3100,18 @@ static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, { if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */ { - fputc(' ',file); - fputs(prefix, file); - if (string_value) - unescape(file,row[0],(uint) strlen(row[0])); - else - fputs(row[0], file); - check_io(file); - return; + fputc(' ',file); + fputs(prefix, file); + if (string_value) + unescape(file,row[0],(uint) strlen(row[0])); + else + fputs(row[0], file); + check_io(file); + return; } } } - return; /* This shouldn't happen */ + return; /* This shouldn't happen */ } /* print_value */ @@ -3106,19 +3122,19 @@ static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row, Check if we the table is one of the table types that should be ignored: MRG_ISAM, MRG_MYISAM, if opt_delayed, if that table supports delayed inserts. If the table should be altogether ignored, it returns a TRUE, FALSE if it - should not be ignored. If the user has selected to use INSERT DELAYED, it - sets the value of the bool pointer supports_delayed_inserts to 0 if not + should not be ignored. If the user has selected to use INSERT DELAYED, it + sets the value of the bool pointer supports_delayed_inserts to 0 if not supported, 1 if it is supported. ARGS check_if_ignore_table() - table_name Table name to check + table_name Table name to check table_type Type of table GLOBAL VARIABLES - sock MySQL socket - verbose Write warning messages + sock MySQL socket + verbose Write warning messages RETURN char (bit value) See IGNORE_ values at top @@ -3135,23 +3151,23 @@ char check_if_ignore_table(const char *table_name, char *table_type) /* Check memory for quote_for_like() */ DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff)); my_snprintf(buff, sizeof(buff), "show table status like %s", - quote_for_like(table_name, show_name_buff)); + quote_for_like(table_name, show_name_buff)); if (mysql_query_with_error_report(sock, &res, buff)) { if (mysql_errno(sock) != ER_PARSE_ERROR) - { /* If old MySQL version */ + { /* If old MySQL version */ if (verbose) - fprintf(stderr, - "-- Warning: Couldn't get status information for table %s (%s)\n", - table_name,mysql_error(sock)); + fprintf(stderr, + "-- Warning: Couldn't get status information for table %s (%s)\n", + table_name,mysql_error(sock)); DBUG_RETURN(result); /* assume table is ok */ } } if (!(row= mysql_fetch_row(res))) { fprintf(stderr, - "Error: Couldn't read status information for table %s (%s)\n", - table_name, mysql_error(sock)); + "Error: Couldn't read status information for table %s (%s)\n", + table_name, mysql_error(sock)); mysql_free_result(res); DBUG_RETURN(result); /* assume table is ok */ } @@ -3214,8 +3230,8 @@ static char *primary_key_fields(const char *table_name) uint result_length = 0; char *result = 0; - my_snprintf(show_keys_buff, sizeof(show_keys_buff), - "SHOW KEYS FROM %s", table_name); + my_snprintf(show_keys_buff, sizeof(show_keys_buff), + "SHOW KEYS FROM %s", table_name); if (mysql_query(sock, show_keys_buff) || !(res = mysql_store_result(sock))) { @@ -3291,7 +3307,7 @@ static int replace(DYNAMIC_STRING *ds_str, if (!start) return 1; init_dynamic_string(&ds_tmp, "", - ds_str->length + replace_len, 256); + ds_str->length + replace_len, 256); dynstr_append_mem(&ds_tmp, ds_str->str, start - ds_str->str); dynstr_append_mem(&ds_tmp, replace_str, replace_len); dynstr_append(&ds_tmp, start + search_len); @@ -3319,9 +3335,9 @@ static my_bool get_view_structure(char *table, char* db) MYSQL_RES *table_res; MYSQL_ROW row; MYSQL_FIELD *field; - char *result_table, *opt_quoted_table; - char table_buff[NAME_LEN*2+3]; - char table_buff2[NAME_LEN*2+3]; + char *result_table, *opt_quoted_table; + char table_buff[NAME_LEN*2+3]; + char table_buff2[NAME_LEN*2+3]; char query[QUERY_LENGTH]; FILE *sql_file = md_result_file; DBUG_ENTER("get_view_structure"); @@ -3334,7 +3350,7 @@ static my_bool get_view_structure(char *table, char* db) #ifdef NOT_REALLY_USED_YET sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d", - (opt_quoted || opt_keywords)); + (opt_quoted || opt_keywords)); #endif result_table= quote_name(table, table_buff, 1); @@ -3369,7 +3385,7 @@ static my_bool get_view_structure(char *table, char* db) if (!opt_xml && opt_comments) { - fprintf(sql_file, "\n--\n-- View structure for view %s\n--\n\n", + fprintf(sql_file, "\n--\n-- Final view structure for view %s\n--\n\n", result_table); check_io(sql_file); } @@ -3450,7 +3466,7 @@ static my_bool get_view_structure(char *table, char* db) char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3]; parse_user(row[1], lengths[1], user_name_str, &user_name_len, - host_name_str, &host_name_len); + host_name_str, &host_name_len); ptr= search_buf; search_len= diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 3b8f7576049..df819b73ea6 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -3699,6 +3699,37 @@ os_aio_posix_handle( } #endif +/************************************************************************** +Do a 'last millisecond' check that the page end is sensible; +reported page checksum errors from Linux seem to wipe over the page end. */ +static +void +os_file_check_page_trailers( +/*========================*/ + byte* combined_buf, /* in: combined write buffer */ + ulint total_len) /* in: size of combined_buf, in bytes + (a multiple of UNIV_PAGE_SIZE) */ +{ + ulint len; + + for (len = 0; len + UNIV_PAGE_SIZE <= total_len; + len += UNIV_PAGE_SIZE) { + byte* buf = combined_buf + len; + + if (memcmp(buf + (FIL_PAGE_LSN + 4), buf + (UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN_OLD_CHKSUM + 4), 4)) { + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: ERROR: The page to be written seems corrupt!\n" +"InnoDB: Writing a block of %lu bytes, currently at offset %lu\n", + (ulong)total_len, (ulong)len); + buf_page_print(buf); + fprintf(stderr, +"InnoDB: ERROR: The page to be written seems corrupt!\n"); + } + } +} + /************************************************************************** Does simulated aio. This function should be called by an i/o-handler thread. */ @@ -3736,7 +3767,6 @@ os_aio_simulated_handle( ibool ret; ulint n; ulint i; - ulint len2; segment = os_aio_get_array_and_local_segment(&array, global_segment); @@ -3943,33 +3973,16 @@ consecutive_loop: (ulong) total_len); ut_error; } - - /* Do a 'last millisecond' check that the page end - is sensible; reported page checksum errors from - Linux seem to wipe over the page end */ - for (len2 = 0; len2 + UNIV_PAGE_SIZE <= total_len; - len2 += UNIV_PAGE_SIZE) { - if (mach_read_from_4(combined_buf + len2 - + FIL_PAGE_LSN + 4) - != mach_read_from_4(combined_buf + len2 - + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) { - ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: ERROR: The page to be written seems corrupt!\n"); - fprintf(stderr, -"InnoDB: Writing a block of %lu bytes, currently writing at offset %lu\n", - (ulong)total_len, (ulong)len2); - buf_page_print(combined_buf + len2); - fprintf(stderr, -"InnoDB: ERROR: The page to be written seems corrupt!\n"); - } - } + os_file_check_page_trailers(combined_buf, total_len); } - + ret = os_file_write(slot->name, slot->file, combined_buf, slot->offset, slot->offset_high, total_len); + + if (array == os_aio_write_array) { + os_file_check_page_trailers(combined_buf, total_len); + } } else { ret = os_file_read(slot->file, combined_buf, slot->offset, slot->offset_high, total_len); diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 89b82882d93..9e922a3e04a 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -2570,14 +2570,14 @@ do not allow the discard. We also reserve the data dictionary latch. */ } } funct_exit: + trx_commit_for_mysql(trx); + row_mysql_unlock_data_dictionary(trx); if (graph) { que_graph_free(graph); } - trx_commit_for_mysql(trx); - trx->op_info = ""; return((int) err); @@ -2707,10 +2707,10 @@ row_import_tablespace_for_mysql( } funct_exit: - row_mysql_unlock_data_dictionary(trx); - trx_commit_for_mysql(trx); + row_mysql_unlock_data_dictionary(trx); + trx->op_info = ""; return((int) err); @@ -3398,6 +3398,8 @@ fputs(" InnoDB: You are trying to drop table ", stderr); } funct_exit: + trx_commit_for_mysql(trx); + if (locked_dictionary) { row_mysql_unlock_data_dictionary(trx); } @@ -3408,8 +3410,6 @@ funct_exit: que_graph_free(graph); - trx_commit_for_mysql(trx); - trx->op_info = ""; #ifndef UNIV_HOTBACKUP @@ -3488,10 +3488,10 @@ loop: } } - row_mysql_unlock_data_dictionary(trx); - trx_commit_for_mysql(trx); + row_mysql_unlock_data_dictionary(trx); + trx->op_info = ""; return(err); @@ -3905,6 +3905,8 @@ row_rename_table_for_mysql( } } funct_exit: + trx_commit_for_mysql(trx); + if (!recovering_temp_table) { row_mysql_unlock_data_dictionary(trx); } @@ -3917,8 +3919,6 @@ funct_exit: mem_heap_free(heap); } - trx_commit_for_mysql(trx); - trx->op_info = ""; return((int) err); diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 1402d3aaba6..23971767e7e 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -1064,11 +1064,12 @@ row_sel_try_search_shortcut( ut_ad(plan->pcur.latch_mode == node->latch_mode); plan->n_rows_fetched++; + ret = SEL_FOUND; func_exit: if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } - return(SEL_FOUND); + return(ret); } /************************************************************************* diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 973655a3eb6..6fa6bc73bdb 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -20,6 +20,7 @@ sub mtr_record_dead_children (); sub mtr_exit ($); sub sleep_until_file_created ($$$); sub mtr_kill_processes ($); +sub mtr_kill_process ($$$$); # static in C sub spawn_impl ($$$$$$$$); @@ -885,6 +886,25 @@ sub mtr_kill_processes ($) { } } + +sub mtr_kill_process ($$$$) { + my $pid= shift; + my $signal= shift; + my $retries= shift; + my $timeout= shift; + + while (1) + { + kill($signal, $pid); + + last unless kill (0, $pid) and $retries--; + + mtr_debug("Sleep $timeout second waiting for processes to die"); + + sleep($timeout); + } +} + ############################################################################## # # When we exit, we kill off all children diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index e57a5da2c79..4a9628c0721 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -918,6 +918,7 @@ sub command_line_setup () { path_err => "$opt_vardir/log/im.err", path_log => "$opt_vardir/log/im.log", path_pid => "$opt_vardir/run/im.pid", + path_angel_pid => "$opt_vardir/run/im.angel.pid", path_sock => "$sockdir/im.sock", port => $im_port, start_timeout => $master->[0]->{'start_timeout'}, @@ -1188,6 +1189,7 @@ sub environment_setup () { $ENV{'NDB_STATUS_OK'}= "YES"; $ENV{'IM_PATH_PID'}= $instance_manager->{path_pid}; + $ENV{'IM_PATH_ANGEL_PID'}= $instance_manager->{path_angel_pid}; $ENV{'IM_PORT'}= $instance_manager->{port}; $ENV{'IM_MYSQLD1_SOCK'}= $instance_manager->{instances}->[0]->{path_sock}; @@ -1813,6 +1815,7 @@ sub im_create_defaults_file($) { [manager] pid-file = $instance_manager->{path_pid} +angel-pid-file = $instance_manager->{path_angel_pid} socket = $instance_manager->{path_sock} port = $instance_manager->{port} password-file = $instance_manager->{password_file} @@ -1837,7 +1840,7 @@ log-slow-queries = $instance->{path_datadir}/mysqld$server_id.slow.log language = $path_language character-sets-dir = $path_charsetsdir basedir = $path_my_basedir -server_id =$server_id +server_id = $server_id skip-stack-trace skip-innodb skip-bdb @@ -2805,6 +2808,18 @@ sub im_start($$) { sub im_stop($) { my $instance_manager = shift; + # Obtain mysqld-process pids before we start stopping IM (it can delete pid + # files). + + my @mysqld_pids = (); + my $instances = $instance_manager->{'instances'}; + + push(@mysqld_pids, mtr_get_pid_from_file($instances->[0]->{'path_pid'})) + if -r $instances->[0]->{'path_pid'}; + + push(@mysqld_pids, mtr_get_pid_from_file($instances->[1]->{'path_pid'})) + if -r $instances->[1]->{'path_pid'}; + # Re-read pid from the file, since during tests Instance Manager could have # been restarted, so its pid could have been changed. @@ -2812,34 +2827,79 @@ sub im_stop($) { mtr_get_pid_from_file($instance_manager->{'path_pid'}) if -f $instance_manager->{'path_pid'}; + if (-f $instance_manager->{'path_angel_pid'}) + { + $instance_manager->{'angel_pid'} = + mtr_get_pid_from_file($instance_manager->{'path_angel_pid'}) + } + else + { + $instance_manager->{'angel_pid'} = undef; + } + # Inspired from mtr_stop_mysqld_servers(). start_reap_all(); - # Create list of pids. We should stop Instance Manager and all started - # mysqld-instances. Some of them may be nonguarded, so IM will not stop them - # on shutdown. + # Try graceful shutdown. - my @pids = ( $instance_manager->{'pid'} ); - my $instances = $instance_manager->{'instances'}; + mtr_kill_process($instance_manager->{'pid'}, 'TERM', 10, 1); - if ( -r $instances->[0]->{'path_pid'} ) + # Check that all processes died. + + my $clean_shutdown= 0; + + while (1) { - push(@pids, mtr_get_pid_from_file($instances->[0]->{'path_pid'})); + last if kill (0, $instance_manager->{'pid'}); + + last if (defined $instance_manager->{'angel_pid'}) && + kill (0, $instance_manager->{'angel_pid'}); + + foreach my $pid (@mysqld_pids) + { + last if kill (0, $pid); + } + + $clean_shutdown= 1; + last; } - if ( -r $instances->[1]->{'path_pid'} ) + # Kill leftovers (the order is important). + + unless ($clean_shutdown) { - push(@pids, mtr_get_pid_from_file($instances->[1]->{'path_pid'})); + mtr_kill_process($instance_manager->{'angel_pid'}, 'KILL', 10, 1) + if defined $instance_manager->{'angel_pid'}; + + mtr_kill_process($instance_manager->{'pid'}, 'KILL', 10, 1); + + # Shutdown managed mysqld-processes. Some of them may be nonguarded, so IM + # will not stop them on shutdown. So, we should firstly try to end them + # legally. + + mtr_kill_processes(\@mysqld_pids); + + # Complain in error log so that a warning will be shown. + + my $errlog= "$opt_vardir/log/mysql-test-run.pl.err"; + + open (ERRLOG, ">>$errlog") || + mtr_error("Can not open error log ($errlog)"); + + my $ts= localtime(); + print ERRLOG + "Warning: [$ts] Instance Manager did not shutdown gracefully.\n"; + + close ERRLOG; } - # Kill processes. - - mtr_kill_processes(\@pids); + # That's all. stop_reap_all(); $instance_manager->{'pid'} = undef; + $instance_manager->{'angel_pid'} = undef; } diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index 8349d6e9338..cf358e6a404 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -103,8 +103,8 @@ t1 CREATE TABLE `t1` ( `c2` varchar(1) character set latin1 collate latin1_danish_ci NOT NULL default '', `c3` varbinary(1) NOT NULL default '', `c4` varbinary(1) NOT NULL default '', - `c5` varbinary(3) NOT NULL default '', - `c6` varbinary(3) NOT NULL default '', + `c5` varbinary(4) NOT NULL default '', + `c6` varbinary(4) NOT NULL default '', `c7` decimal(2,1) NOT NULL default '0.0', `c8` decimal(2,1) NOT NULL default '0.0', `c9` decimal(2,1) default NULL, @@ -152,11 +152,11 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `COALESCE(1)` int(1) NOT NULL default '0', - `COALESCE(1.0)` decimal(2,1) unsigned NOT NULL default '0.0', + `COALESCE(1.0)` decimal(2,1) NOT NULL default '0.0', `COALESCE('a')` varchar(1) NOT NULL default '', `COALESCE(1,1.0)` decimal(2,1) NOT NULL default '0.0', `COALESCE(1,'1')` varbinary(1) NOT NULL default '', - `COALESCE(1.1,'1')` varbinary(3) NOT NULL default '', + `COALESCE(1.1,'1')` varbinary(4) NOT NULL default '', `COALESCE('a' COLLATE latin1_bin,'b')` varchar(1) character set latin1 collate latin1_bin NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index d66dec741bd..75e1548cdee 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -53,3 +53,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE ÔÁÂ ref ÉÎÄ0,ÉÎÄ01 ÉÎÄ0 5 const 1 Using where; Using index drop table ÔÁÂ; set names latin1; +select 3 into @v1; +explain select 3 into @v1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used diff --git a/mysql-test/r/im_options_set.result b/mysql-test/r/im_options_set.result index 0d2fa699fc7..5e6c740624e 100644 --- a/mysql-test/r/im_options_set.result +++ b/mysql-test/r/im_options_set.result @@ -1,11 +1,11 @@ -server_id =1 -server_id =2 +server_id = 1 +server_id = 2 SHOW VARIABLES LIKE 'server_id'; Variable_name Value server_id 1 SET mysqld1.server_id = 11; server_id =11 -server_id =2 +server_id = 2 SHOW VARIABLES LIKE 'server_id'; Variable_name Value server_id 1 diff --git a/mysql-test/r/im_options_unset.result b/mysql-test/r/im_options_unset.result index 834152c35d2..bf54025edb7 100644 --- a/mysql-test/r/im_options_unset.result +++ b/mysql-test/r/im_options_unset.result @@ -1,10 +1,10 @@ -server_id =1 -server_id =2 +server_id = 1 +server_id = 2 SHOW VARIABLES LIKE 'server_id'; Variable_name Value server_id 1 UNSET mysqld1.server_id; -server_id =2 +server_id = 2 SHOW VARIABLES LIKE 'server_id'; Variable_name Value server_id 1 diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 694bab2597c..712a60828f7 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -1154,3 +1154,25 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index PRIMARY,name name 23 NULL 3 Using where; Using index 1 SIMPLE t2 ref fkey fkey 5 test.t1.id 1 Using where; Using index DROP TABLE t1,t2; +DROP VIEW IF EXISTS v1,v2; +DROP TABLE IF EXISTS t1,t2; +CREATE TABLE t1 (a int); +CREATE table t2 (b int); +INSERT INTO t1 VALUES (1), (2), (3), (4), (1), (1), (3); +INSERT INTO t2 VALUES (2), (3); +CREATE VIEW v1 AS SELECT a FROM t1 JOIN t2 ON t1.a=t2.b; +CREATE VIEW v2 AS SELECT b FROM t2 JOIN t1 ON t2.b=t1.a; +SELECT v1.a, v2. b +FROM v1 LEFT OUTER JOIN v2 ON (v1.a=v2.b) AND (v1.a >= 3) +GROUP BY v1.a; +a b +2 NULL +3 3 +SELECT v1.a, v2. b +FROM { OJ v1 LEFT OUTER JOIN v2 ON (v1.a=v2.b) AND (v1.a >= 3) } +GROUP BY v1.a; +a b +2 NULL +3 3 +DROP VIEW v1,v2; +DROP TABLE t1,t2; diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index 0a170e16188..50b0b6ae294 100644 --- a/mysql-test/r/metadata.result +++ b/mysql-test/r/metadata.result @@ -2,7 +2,7 @@ drop table if exists t1,t2; select 1, 1.0, -1, "hello", NULL; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def 1 8 1 1 N 32897 0 63 -def 1.0 246 3 3 N 161 1 63 +def 1.0 246 4 3 N 129 1 63 def -1 8 2 2 N 32897 0 63 def hello 253 5 5 N 1 31 8 def NULL 6 0 0 Y 32896 0 63 diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index 50e4cc28d93..664833fab2a 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -189,4 +189,5 @@ HEX(f) select HEX(f) from t4; HEX(f) 835C +flush logs; drop table t1, t2, t03, t04, t3, t4; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 467e0818646..ad31b8e2a65 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1458,7 +1458,6 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t2` ENABLE KEYS */; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; -/*!50001 DROP TABLE IF EXISTS `v2`*/; /*!50001 CREATE TABLE `v2` ( `a` varchar(30) ) */; @@ -1763,7 +1762,6 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; -/*!50001 DROP TABLE IF EXISTS `v1`*/; /*!50001 CREATE TABLE `v1` ( `a` int(11) ) */; @@ -1821,7 +1819,6 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t2` ENABLE KEYS */; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; -/*!50001 DROP TABLE IF EXISTS `v2`*/; /*!50001 CREATE TABLE `v2` ( `a` varchar(30) ) */; @@ -1914,7 +1911,6 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; -/*!50001 DROP TABLE IF EXISTS `v1`*/; /*!50001 CREATE TABLE `v1` ( `a` int(11), `b` int(11), @@ -1922,13 +1918,11 @@ DROP TABLE IF EXISTS `v1`; ) */; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; -/*!50001 DROP TABLE IF EXISTS `v2`*/; /*!50001 CREATE TABLE `v2` ( `a` int(11) ) */; DROP TABLE IF EXISTS `v3`; /*!50001 DROP VIEW IF EXISTS `v3`*/; -/*!50001 DROP TABLE IF EXISTS `v3`*/; /*!50001 CREATE TABLE `v3` ( `a` int(11), `b` int(11), @@ -2489,7 +2483,6 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; DROP TABLE IF EXISTS `v0`; /*!50001 DROP VIEW IF EXISTS `v0`*/; -/*!50001 DROP TABLE IF EXISTS `v0`*/; /*!50001 CREATE TABLE `v0` ( `a` int(11), `b` varchar(32), @@ -2497,7 +2490,6 @@ DROP TABLE IF EXISTS `v0`; ) */; DROP TABLE IF EXISTS `v1`; /*!50001 DROP VIEW IF EXISTS `v1`*/; -/*!50001 DROP TABLE IF EXISTS `v1`*/; /*!50001 CREATE TABLE `v1` ( `a` int(11), `b` varchar(32), @@ -2505,16 +2497,11 @@ DROP TABLE IF EXISTS `v1`; ) */; DROP TABLE IF EXISTS `v2`; /*!50001 DROP VIEW IF EXISTS `v2`*/; -/*!50001 DROP TABLE IF EXISTS `v2`*/; /*!50001 CREATE TABLE `v2` ( `a` int(11), `b` varchar(32), `c` varchar(32) ) */; - -CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; - -USE `test`; /*!50001 DROP TABLE IF EXISTS `v0`*/; /*!50001 DROP VIEW IF EXISTS `v0`*/; /*!50001 CREATE ALGORITHM=UNDEFINED */ @@ -2731,3 +2718,61 @@ p CREATE DEFINER=`root`@`localhost` PROCEDURE `p`() select 42 drop function f; drop procedure p; +drop database if exists test; +create database test; +use test; +create table t1 (id int); +create view v1 as select * from t1; +insert into t1 values (1232131); +insert into t1 values (4711); +insert into t1 values (3231); +insert into t1 values (0815); + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +/*!40000 DROP DATABASE IF EXISTS `test`*/; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `test`; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `id` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES (1232131),(4711),(3231),(815); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; +DROP TABLE IF EXISTS `v1`; +/*!50001 DROP VIEW IF EXISTS `v1`*/; +/*!50001 CREATE TABLE `v1` ( + `id` int(11) +) */; +/*!50001 DROP TABLE IF EXISTS `v1`*/; +/*!50001 DROP VIEW IF EXISTS `v1`*/; +/*!50001 CREATE ALGORITHM=UNDEFINED */ +/*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */ +/*!50001 VIEW `v1` AS select `t1`.`id` AS `id` from `t1` */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +drop view v1; diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 603de2afe4e..207d9ea7475 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -1777,7 +1777,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1807,7 +1807,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 9e635f60f14..13aa549949c 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -1760,7 +1760,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1790,7 +1790,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index fd51c71cad6..a08dae945bd 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -1761,7 +1761,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1791,7 +1791,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index 876f7615672..6682b085097 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -1697,7 +1697,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1727,7 +1727,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 @@ -4711,7 +4711,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -4741,7 +4741,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index c39621d184f..dc3b984949d 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -1760,7 +1760,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1790,7 +1790,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index 7c83099311e..000a20da655 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -1760,7 +1760,7 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` decimal(2,1) unsigned NOT NULL default '0.0', + `const02` decimal(2,1) NOT NULL default '0.0', `param02` decimal(65,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, @@ -1790,7 +1790,7 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 246 3 3 N 33 1 63 +def test t5 t5 const02 const02 246 4 3 N 1 1 63 def test t5 t5 param02 param02 246 67 32 Y 0 30 63 def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 23 1 Y 32768 31 63 diff --git a/mysql-test/r/rpl_auto_increment_11932.result b/mysql-test/r/rpl_auto_increment_11932.result new file mode 100644 index 00000000000..25eda6ee454 --- /dev/null +++ b/mysql-test/r/rpl_auto_increment_11932.result @@ -0,0 +1,47 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +drop database if exists test1; +create database test1; +use test1; +CREATE TABLE `t1` ( +`id` int(10) unsigned NOT NULL auto_increment, +`fname` varchar(100) default NULL, +PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; +INSERT INTO `t1` VALUES (1, 'blablabla'); +CREATE TABLE `t2` ( +`id` int(10) NOT NULL auto_increment, +`comment` varchar(255) NOT NULL default '', +PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=3 ; +INSERT INTO `t2` VALUES (1, 'testtest 1'); +INSERT INTO `t2` VALUES (2, 'test 2'); +CREATE PROCEDURE simpleproc3 () +NOT DETERMINISTIC +BEGIN +INSERT INTO t1 (fname) (SELECT t2.comment FROM t2 WHERE t2.id = '1'); +INSERT INTO t1 (fname) VALUES('test'); +END +$ +CALL simpleproc3(); +select * from t2; +id comment +1 testtest 1 +2 test 2 +TRUNCATE TABLE `t1`; +CALL simpleproc3(); +select * from t1; +id fname +1 testtest 1 +2 test +use test1; +select * from t1; +id fname +1 testtest 1 +2 test +drop database test1; +drop database test1; diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result index da85ef5104d..751dc7754f7 100644 --- a/mysql-test/r/rpl_temporary.result +++ b/mysql-test/r/rpl_temporary.result @@ -103,15 +103,24 @@ f 1 drop temporary table t4; drop table t5; -set @session.pseudo_thread_id=100; +set @@session.pseudo_thread_id=100; create temporary table t101 (id int); create temporary table t102 (id int); -set @session.pseudo_thread_id=200; +set @@session.pseudo_thread_id=200; create temporary table t201 (id int); -create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); +create temporary table `t``201` (id int); +create temporary table `#sql_not_user_table202` (id int); +set @@session.pseudo_thread_id=300; +create temporary table t301 (id int); +create temporary table t302 (id int); +create temporary table `#sql_not_user_table303` (id int); create table t1(f int); insert into t1 values (1); select * from t1 /* must be 1 */; f 1 drop table t1; +select * from t1; +a +1 +drop table t1; diff --git a/mysql-test/r/rpl_until.result b/mysql-test/r/rpl_until.result index b584e04ed57..60b956785ba 100644 --- a/mysql-test/r/rpl_until.result +++ b/mysql-test/r/rpl_until.result @@ -29,9 +29,40 @@ n 2 3 4 -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 # No 0 0 319 # Master master-bin.000001 319 No # +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 776 +Relay_Log_File slave-relay-bin.000004 +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running # +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 319 +Relay_Log_Space # +Until_Condition Master +Until_Log_File master-bin.000001 +Until_Log_Pos 319 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # start slave until master_log_file='master-no-such-bin.000001', master_log_pos=291; select * from t1; n @@ -39,23 +70,116 @@ n 2 3 4 -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 # No 0 0 319 # Master master-no-such-bin.000001 291 No # +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 776 +Relay_Log_File slave-relay-bin.000004 +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running # +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 319 +Relay_Log_Space # +Until_Condition Master +Until_Log_File master-no-such-bin.000001 +Until_Log_Pos 291 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746; select * from t2; n 1 2 -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 # No 0 0 608 # Relay slave-relay-bin.000004 746 No # +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 776 +Relay_Log_File slave-relay-bin.000004 +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running # +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 608 +Relay_Log_Space # +Until_Condition Relay +Until_Log_File slave-relay-bin.000004 +Until_Log_Pos 746 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # start slave; stop slave; start slave until master_log_file='master-bin.000001', master_log_pos=776; -show slave status; -Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 776 slave-relay-bin.000004 # master-bin.000001 Yes No 0 0 776 # Master master-bin.000001 776 No # +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 776 +Relay_Log_File slave-relay-bin.000004 +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 776 +Relay_Log_Space # +Until_Condition Master +Until_Log_File master-bin.000001 +Until_Log_Pos 776 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # start slave until master_log_file='master-bin', master_log_pos=561; ERROR HY000: Incorrect parameter or combination of parameters for START SLAVE UNTIL start slave until master_log_file='master-bin.000001', master_log_pos=561, relay_log_pos=12; diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index a49b282ddb7..924963017eb 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -282,9 +282,9 @@ select @tmp_x, @tmp_y, @tmp_z| @tmp_x @tmp_y @tmp_z 42 45 87 call p(42, 43, @tmp_z)| -ERROR 42000: OUT or INOUT argument 2 for routine test.p is not a variable +ERROR 42000: OUT or INOUT argument 2 for routine test.p is not a variable or NEW pseudo-variable in BEFORE trigger call p(42, @tmp_y, 43)| -ERROR 42000: OUT or INOUT argument 3 for routine test.p is not a variable +ERROR 42000: OUT or INOUT argument 3 for routine test.p is not a variable or NEW pseudo-variable in BEFORE trigger drop procedure p| create procedure p() begin end| lock table t1 read| diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 59ce1d13d2b..746cd8f00d4 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -4904,4 +4904,60 @@ schema_name select routine_name,routine_schema from information_schema.routines where routine_schema like 'bug18344%'| routine_name routine_schema +drop function if exists bug12472| +create function bug12472() returns int return (select count(*) from t1)| +create table t3 as select bug12472() as i| +show create table t3| +Table Create Table +t3 CREATE TABLE `t3` ( + `i` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t3| +i +0 +drop table t3| +create view v1 as select bug12472() as j| +create table t3 as select * from v1| +show create table t3| +Table Create Table +t3 CREATE TABLE `t3` ( + `j` bigint(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t3| +j +0 +drop table t3| +drop view v1| +drop function bug12472| +DROP FUNCTION IF EXISTS bug18589_f1| +DROP PROCEDURE IF EXISTS bug18589_p1| +DROP PROCEDURE IF EXISTS bug18589_p2| +CREATE FUNCTION bug18589_f1(arg TEXT) RETURNS TEXT +BEGIN +RETURN CONCAT(arg, ""); +END| +CREATE PROCEDURE bug18589_p1(arg TEXT, OUT ret TEXT) +BEGIN +SET ret = CONCAT(arg, ""); +END| +CREATE PROCEDURE bug18589_p2(arg TEXT) +BEGIN +DECLARE v TEXT; +CALL bug18589_p1(arg, v); +SELECT v; +END| +SELECT bug18589_f1(REPEAT("a", 767))| +bug18589_f1(REPEAT("a", 767)) +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +SET @bug18589_v1 = ""| +CALL bug18589_p1(REPEAT("a", 767), @bug18589_v1)| +SELECT @bug18589_v1| +@bug18589_v1 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +CALL bug18589_p2(REPEAT("a", 767))| +v +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +DROP FUNCTION bug18589_f1| +DROP PROCEDURE bug18589_p1| +DROP PROCEDURE bug18589_p2| drop table t1,t2; diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result index b05680f9c54..474659f7dfc 100644 --- a/mysql-test/r/sql_mode.result +++ b/mysql-test/r/sql_mode.result @@ -485,6 +485,10 @@ set sql_mode=2097152; select @@sql_mode; @@sql_mode STRICT_TRANS_TABLES +set sql_mode=4194304; +select @@sql_mode; +@@sql_mode +STRICT_ALL_TABLES set sql_mode=16384+(65536*4); select @@sql_mode; @@sql_mode diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index e3d65882f81..39cb95be9e1 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3169,3 +3169,11 @@ create table t2 (a int, b int); insert into t2 values (2, 1), (1, 0); delete from t1 where c <= 1140006215 and (select b from t2 where a = 2) = 1; drop table t1, t2; +CREATE TABLE t1 (a INT); +CREATE VIEW v1 AS SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1); +ERROR 42S22: Unknown column 'no_such_column' in 'where clause' +CREATE VIEW v2 AS SELECT * FROM t1 WHERE no_such_column = (SELECT 1); +ERROR 42S22: Unknown column 'no_such_column' in 'where clause' +SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1); +ERROR 42S22: Unknown column 'no_such_column' in 'IN/ALL/ANY subquery' +DROP TABLE t1; diff --git a/mysql-test/r/trigger-grant.result b/mysql-test/r/trigger-grant.result index 87e5e11d779..f6384d479b7 100644 --- a/mysql-test/r/trigger-grant.result +++ b/mysql-test/r/trigger-grant.result @@ -310,3 +310,87 @@ SELECT @mysqltest_var; Hello, world! DROP USER mysqltest_u1@localhost; DROP DATABASE mysqltest_db1; +DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%'; +FLUSH PRIVILEGES; +DROP DATABASE IF EXISTS mysqltest_db1; +CREATE DATABASE mysqltest_db1; +USE mysqltest_db1; +CREATE TABLE t1 (i1 INT); +CREATE TABLE t2 (i1 INT); +CREATE USER mysqltest_dfn@localhost; +CREATE USER mysqltest_inv@localhost; +GRANT EXECUTE, CREATE ROUTINE, SUPER ON *.* TO mysqltest_dfn@localhost; +GRANT INSERT ON mysqltest_db1.* TO mysqltest_inv@localhost; +CREATE PROCEDURE p1(OUT i INT) DETERMINISTIC NO SQL SET i = 3; +CREATE PROCEDURE p2(INOUT i INT) DETERMINISTIC NO SQL SET i = i * 5; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW +CALL p2(NEW.i1); +INSERT INTO t1 VALUES (7); +ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't1' +INSERT INTO t2 VALUES (11); +ERROR 42000: SELECT,UPDATE command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't2' +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; +GRANT SELECT ON mysqltest_db1.* TO mysqltest_dfn@localhost; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW +CALL p2(NEW.i1); +INSERT INTO t1 VALUES (13); +ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't1' +INSERT INTO t2 VALUES (17); +ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't2' +REVOKE SELECT ON mysqltest_db1.* FROM mysqltest_dfn@localhost; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; +GRANT UPDATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW +CALL p2(NEW.i1); +INSERT INTO t1 VALUES (19); +INSERT INTO t2 VALUES (23); +ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't2' +REVOKE UPDATE ON mysqltest_db1.* FROM mysqltest_dfn@localhost; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; +GRANT SELECT, UPDATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW +CALL p2(NEW.i1); +INSERT INTO t1 VALUES (29); +INSERT INTO t2 VALUES (31); +REVOKE SELECT, UPDATE ON mysqltest_db1.* FROM mysqltest_dfn@localhost; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; +DROP PROCEDURE p2; +DROP PROCEDURE p1; +GRANT UPDATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; +CREATE PROCEDURE p1(OUT i INT) DETERMINISTIC NO SQL SET i = 37; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW +CALL p1(NEW.i1); +INSERT INTO t1 VALUES (41); +DROP PROCEDURE p1; +CREATE PROCEDURE p1(IN i INT) DETERMINISTIC NO SQL SET @v1 = i + 43; +INSERT INTO t1 VALUES (47); +ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't1' +DROP PROCEDURE p1; +CREATE PROCEDURE p1(INOUT i INT) DETERMINISTIC NO SQL SET i = i + 51; +INSERT INTO t1 VALUES (53); +ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for column 'i1' in table 't1' +DROP PROCEDURE p1; +REVOKE UPDATE ON mysqltest_db1.* FROM mysqltest_dfn@localhost; +DROP TRIGGER t1_bi; +DROP USER mysqltest_inv@localhost; +DROP USER mysqltest_dfn@localhost; +DROP TABLE t2; +DROP TABLE t1; +DROP DATABASE mysqltest_db1; +USE test; +End of 5.0 tests. diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 6a689437482..8b4aba367fb 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -998,3 +998,95 @@ SELECT * FROM t1 WHERE conn_id != trigger_conn_id; conn_id trigger_conn_id DROP TRIGGER t1_bi; DROP TABLE t1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (i1 INT); +SET @save_sql_mode=@@sql_mode; +SET SQL_MODE=''; +CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW +SET @x = 5/0; +SET SQL_MODE='traditional'; +CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW +SET @x = 5/0; +SET @x=1; +INSERT INTO t1 VALUES (@x); +SELECT @x; +@x +NULL +SET @x=2; +UPDATE t1 SET i1 = @x; +ERROR 22012: Division by 0 +SELECT @x; +@x +2 +SET SQL_MODE=''; +SET @x=3; +INSERT INTO t1 VALUES (@x); +SELECT @x; +@x +NULL +SET @x=4; +UPDATE t1 SET i1 = @x; +ERROR 22012: Division by 0 +SELECT @x; +@x +4 +SET @@sql_mode=@save_sql_mode; +DROP TRIGGER t1_ai; +DROP TRIGGER t1_au; +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +CREATE TABLE t1 (i1 INT); +INSERT INTO t1 VALUES (3); +CREATE PROCEDURE p1(OUT i1 INT) DETERMINISTIC NO SQL SET i1 = 5; +CREATE PROCEDURE p2(INOUT i1 INT) DETERMINISTIC NO SQL SET i1 = i1 * 7; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW +BEGIN +CALL p1(NEW.i1); +CALL p2(NEW.i1); +END// +UPDATE t1 SET i1 = 11 WHERE i1 = 3; +DROP TRIGGER t1_bu; +DROP PROCEDURE p2; +DROP PROCEDURE p1; +INSERT INTO t1 VALUES (13); +CREATE PROCEDURE p1(OUT i1 INT) DETERMINISTIC NO SQL SET @a = 17; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW +CALL p1(OLD.i1); +UPDATE t1 SET i1 = 19 WHERE i1 = 13; +ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger +DROP TRIGGER t1_bu; +DROP PROCEDURE p1; +INSERT INTO t1 VALUES (23); +CREATE PROCEDURE p1(INOUT i1 INT) DETERMINISTIC NO SQL SET @a = i1 * 29; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW +CALL p1(OLD.i1); +UPDATE t1 SET i1 = 31 WHERE i1 = 23; +ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger +DROP TRIGGER t1_bu; +DROP PROCEDURE p1; +INSERT INTO t1 VALUES (37); +CREATE PROCEDURE p1(OUT i1 INT) DETERMINISTIC NO SQL SET @a = 41; +CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW +CALL p1(NEW.i1); +UPDATE t1 SET i1 = 43 WHERE i1 = 37; +ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger +DROP TRIGGER t1_au; +DROP PROCEDURE p1; +INSERT INTO t1 VALUES (47); +CREATE PROCEDURE p1(INOUT i1 INT) DETERMINISTIC NO SQL SET @a = i1 * 49; +CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW +CALL p1(NEW.i1); +UPDATE t1 SET i1 = 51 WHERE i1 = 47; +ERROR 42000: OUT or INOUT argument 1 for routine test.p1 is not a variable or NEW pseudo-variable in BEFORE trigger +DROP TRIGGER t1_au; +DROP PROCEDURE p1; +SELECT * FROM t1; +i1 +35 +13 +23 +43 +51 +DROP TABLE t1; diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index e941e740fcb..61482ab282c 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -245,22 +245,22 @@ show warnings; Level Code Message desc t1; Field Type Null Key Default Extra -x decimal(21,2) unsigned NO 0.00 +x decimal(21,2) NO 0.00 drop table t1; create table t1 select 0.0 x; desc t1; Field Type Null Key Default Extra -x decimal(2,1) unsigned NO 0.0 +x decimal(2,1) NO 0.0 create table t2 select 105213674794682365.00 y; desc t2; Field Type Null Key Default Extra -y decimal(20,2) unsigned NO 0.00 +y decimal(20,2) NO 0.00 create table t3 select x+y a from t1,t2; show warnings; Level Code Message desc t3; Field Type Null Key Default Extra -a decimal(21,2) unsigned NO 0.00 +a decimal(21,2) NO 0.00 drop table t1,t2,t3; create table t1 (s1 float(0,2)); ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 's1'). diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 938dccc864c..968c6d3ec6f 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -68,10 +68,10 @@ NULL 1.1 NULL NULL NULL 1 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `nullif(1.1, 1.1)` decimal(2,1) unsigned default NULL, - `nullif(1.1, 1.2)` decimal(2,1) unsigned default NULL, - `nullif(1.1, 0.11e1)` decimal(2,1) unsigned default NULL, - `nullif(1.0, 1)` decimal(2,1) unsigned default NULL, + `nullif(1.1, 1.1)` decimal(2,1) default NULL, + `nullif(1.1, 1.2)` decimal(2,1) default NULL, + `nullif(1.1, 0.11e1)` decimal(2,1) default NULL, + `nullif(1.0, 1)` decimal(2,1) default NULL, `nullif(1, 1.0)` int(1) default NULL, `nullif(1, 1.1)` int(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -174,9 +174,9 @@ create table t1 select round(15.4,-1), truncate(-5678.123451,-3), abs(-1.1), -(- show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `round(15.4,-1)` decimal(3,0) unsigned NOT NULL default '0', + `round(15.4,-1)` decimal(3,0) NOT NULL default '0', `truncate(-5678.123451,-3)` decimal(4,0) NOT NULL default '0', - `abs(-1.1)` decimal(2,1) NOT NULL default '0.0', + `abs(-1.1)` decimal(3,1) NOT NULL default '0.0', `-(-1.1)` decimal(2,1) NOT NULL default '0.0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; @@ -771,7 +771,7 @@ create table t1 as select 0.5; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `0.5` decimal(2,1) unsigned NOT NULL default '0.0' + `0.5` decimal(2,1) NOT NULL default '0.0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; select round(1.5),round(2.5); diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 667d10cd145..4baa56070b7 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -706,7 +706,7 @@ create view v1 as select a from t1; create view v2 as select a from t2 where a in (select a from v1); show create view v2; View Create View -v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t2`.`a` AS `a` from `t2` where `a` in (select `v1`.`a` AS `a` from `v1`) +v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t2`.`a` AS `a` from `t2` where `t2`.`a` in (select `v1`.`a` AS `a` from `v1`) drop view v2, v1; drop table t1, t2; CREATE VIEW `v 1` AS select 5 AS `5`; @@ -2649,3 +2649,14 @@ ldt 2006-01-01 03:00:00 drop view v1, v2; drop table t1; +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, d datetime); +CREATE VIEW v1 AS +SELECT id, date(d) + INTERVAL TIME_TO_SEC(d) SECOND AS t, COUNT(*) +FROM t1 GROUP BY id, t; +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`id` AS `id`,(cast(`t1`.`d` as date) + interval time_to_sec(`t1`.`d`) second) AS `t`,count(0) AS `COUNT(*)` from `t1` group by `t1`.`id`,(cast(`t1`.`d` as date) + interval time_to_sec(`t1`.`d`) second) +SELECT * FROM v1; +id t COUNT(*) +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index 2a3a23c5f96..a38771db233 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -43,3 +43,12 @@ drop table set names latin1; # End of 4.1 tests + + +# +# Bug#15463: EXPLAIN SELECT..INTO hangs the client (QB, command line) +# +select 3 into @v1; +explain select 3 into @v1; + +# End of 5.0 tests. diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index e4c8bf89cca..71b178d0e57 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -2196,3 +2196,16 @@ drop table t2, t1; # --error ER_TABLE_CANT_HANDLE_SPKEYS create table t1 (g geometry not null, spatial gk(g)) engine=innodb; + +####################################################################### +# # +# Please, DO NOT TOUCH this file as well as the innodb.result file. # +# These files are to be modified ONLY BY INNOBASE guys. # +# # +# Use innodb_mysql.[test|result] files instead. # +# # +# If nevertheless you need to make some changes here, please, forward # +# your commit message To: dev@innodb.com Cc: dev-innodb@mysql.com # +# (otherwise your changes may be erased). # +# # +####################################################################### diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index c194213e0c9..7134137a430 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -779,3 +779,29 @@ SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id WHERE t1.name LIKE 'A%' OR FALSE; DROP TABLE t1,t2; + +# +# Bug 19396: LEFT OUTER JOIN over views in curly braces +# +--disable_warnings +DROP VIEW IF EXISTS v1,v2; +DROP TABLE IF EXISTS t1,t2; +--enable_warnings + +CREATE TABLE t1 (a int); +CREATE table t2 (b int); +INSERT INTO t1 VALUES (1), (2), (3), (4), (1), (1), (3); +INSERT INTO t2 VALUES (2), (3); + +CREATE VIEW v1 AS SELECT a FROM t1 JOIN t2 ON t1.a=t2.b; +CREATE VIEW v2 AS SELECT b FROM t2 JOIN t1 ON t2.b=t1.a; + +SELECT v1.a, v2. b + FROM v1 LEFT OUTER JOIN v2 ON (v1.a=v2.b) AND (v1.a >= 3) + GROUP BY v1.a; +SELECT v1.a, v2. b + FROM { OJ v1 LEFT OUTER JOIN v2 ON (v1.a=v2.b) AND (v1.a >= 3) } + GROUP BY v1.a; + +DROP VIEW v1,v2; +DROP TABLE t1,t2; diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 28074fba7e4..d74bb1c3a80 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -122,9 +122,22 @@ select HEX(f) from t3; select HEX(f) from t04; select HEX(f) from t4; +# +# BUG#14157: utf8 encoding in binlog without set character_set_client +# +# BUG: +# This test only works on the MySQL-internal rpl machines. +# Needs to be fixed. Problem is that koi8r is not installed +# on many machines. +# +flush logs; +# --exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table if not exists t5 (a int); set names koi8r; create temporary table `ÑÝÉË` (a int); insert into `ÑÝÉË` values (1); insert into t5 select * from `ÑÝÉË`' +# resulted log is client charset insensitive (latin1 not koi8r) as it must be +# --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000006 | $MYSQL --default-character-set=latin1 +#select * from t5 /* must be (1),(1) */; # clean up drop table t1, t2, t03, t04, t3, t4; -# End of 4.1 tests +# End of 5.0 tests diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 4076fd258e9..4113c136e17 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -1143,3 +1143,19 @@ show create procedure p; drop function f; drop procedure p; +# +# BUG#17201 Spurious 'DROP DATABASE' in output, +# also confusion between tables and views. +# Example code from Markus Popp + +drop database if exists test; +create database test; +use test; +create table t1 (id int); +create view v1 as select * from t1; +insert into t1 values (1232131); +insert into t1 values (4711); +insert into t1 values (3231); +insert into t1 values (0815); +--exec $MYSQL_DUMP --skip-comments --add-drop-database --databases test +drop view v1; diff --git a/mysql-test/t/rename.test b/mysql-test/t/rename.test index 5caecef176e..86e4b6eed0a 100644 --- a/mysql-test/t/rename.test +++ b/mysql-test/t/rename.test @@ -61,9 +61,15 @@ connection con2; sleep 1; show tables; UNLOCK TABLES; -sleep 1; +connection con1; +reap; +connection con2; show tables; drop table t2, t4; +disconnect con2; +disconnect con1; +connection default; + # End of 4.1 tests diff --git a/mysql-test/t/rpl_auto_increment_11932.test b/mysql-test/t/rpl_auto_increment_11932.test new file mode 100644 index 00000000000..d4b7872fb2b --- /dev/null +++ b/mysql-test/t/rpl_auto_increment_11932.test @@ -0,0 +1,63 @@ +# +# Test of auto_increment +# BUG#11932 +# +# Bug reported that master and slave get out of sync after TRUNCATE +# TABLE. +# +# Test supplied by Are Casilla + +source include/master-slave.inc; +--disable_warnings +connection master; +drop database if exists test1; +--enable_warnings +create database test1; +use test1; + +CREATE TABLE `t1` ( + `id` int(10) unsigned NOT NULL auto_increment, + `fname` varchar(100) default NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; + +INSERT INTO `t1` VALUES (1, 'blablabla'); + +CREATE TABLE `t2` ( + `id` int(10) NOT NULL auto_increment, + `comment` varchar(255) NOT NULL default '', + PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=3 ; + +INSERT INTO `t2` VALUES (1, 'testtest 1'); +INSERT INTO `t2` VALUES (2, 'test 2'); + +DELIMITER $; +CREATE PROCEDURE simpleproc3 () + NOT DETERMINISTIC + BEGIN + INSERT INTO t1 (fname) (SELECT t2.comment FROM t2 WHERE t2.id = '1'); + INSERT INTO t1 (fname) VALUES('test'); + END + $ +DELIMITER ;$ + +CALL simpleproc3(); + +select * from t2; + +TRUNCATE TABLE `t1`; +CALL simpleproc3(); + +select * from t1; + +save_master_pos; +connection slave; +sync_with_master; + +use test1; +select * from t1; + +drop database test1; +connection master; +drop database test1; diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index 7d2222ea79a..51a195e3d0e 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -163,24 +163,19 @@ drop table t5; # value was set up at the moment of temp table creation # connection con1; -set @session.pseudo_thread_id=100; +set @@session.pseudo_thread_id=100; create temporary table t101 (id int); create temporary table t102 (id int); -set @session.pseudo_thread_id=200; +set @@session.pseudo_thread_id=200; create temporary table t201 (id int); -create temporary table `#not_user_table_prefixed_with_hash_sign_no_harm` (id int); - -# -# Don't kill our own connection to the server as -# the result code differs depending on platform. -# -# Select the id to kill into a variable of mysqltest -let $con1_id= `select connection_id()`; -# Switch connection to avoid killing our own connection -connection master; ---disable_query_log -eval kill $con1_id; ---enable_query_log +create temporary table `t``201` (id int); +# emulate internal temp table not to come to binlog +create temporary table `#sql_not_user_table202` (id int); +set @@session.pseudo_thread_id=300; +create temporary table t301 (id int); +create temporary table t302 (id int); +create temporary table `#sql_not_user_table303` (id int); +disconnect con1; #now do something to show that slave is ok after DROP temp tables connection master; @@ -194,4 +189,16 @@ select * from t1 /* must be 1 */; connection master; drop table t1; +# +#14157: utf8 encoding in binlog without set character_set_client +# +--exec $MYSQL --character-sets-dir=../sql/share/charsets/ --default-character-set=koi8r test -e 'create table t1 (a int); set names koi8r; create temporary table `ÑÝÉË` (a int); insert into `ÑÝÉË` values (1); insert into t1 select * from `ÑÝÉË`' + +sync_slave_with_master; +#connection slave; +select * from t1; + +connection master; +drop table t1; + # End of 5.0 tests diff --git a/mysql-test/t/rpl_until.test b/mysql-test/t/rpl_until.test index e0ecf981fea..c404ea7e58b 100644 --- a/mysql-test/t/rpl_until.test +++ b/mysql-test/t/rpl_until.test @@ -31,7 +31,7 @@ wait_for_slave_to_stop; select * from t1; --replace_result $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 9 # 11 # 23 # 33 # -show slave status; +--query_vertical SHOW SLAVE STATUS # this should fail right after start start slave until master_log_file='master-no-such-bin.000001', master_log_pos=291; @@ -41,7 +41,7 @@ sleep 2; wait_for_slave_to_stop; --replace_result $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 9 # 11 # 23 # 33 # -show slave status; +--query_vertical SHOW SLAVE STATUS # try replicate all until second insert to t2; start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746; @@ -50,7 +50,7 @@ wait_for_slave_to_stop; select * from t2; --replace_result $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 9 # 11 # 23 # 33 # -show slave status; +--query_vertical SHOW SLAVE STATUS # clean up start slave; @@ -67,7 +67,7 @@ wait_for_slave_to_stop; # here the sql slave thread should be stopped --replace_result $MASTER_MYPORT MASTER_MYPORT bin.000005 bin.000004 bin.000006 bin.000004 bin.000007 bin.000004 --replace_column 1 # 9 # 23 # 33 # -show slave status; +--query_vertical SHOW SLAVE STATUS #testing various error conditions --error 1277 diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 22500bbd280..9995ff5a9ad 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -5773,6 +5773,76 @@ select routine_name,routine_schema from information_schema.routines where routine_schema like 'bug18344%'| +# +# BUG#12472/BUG#15137 'CREATE TABLE ... SELECT ... which explicitly or +# implicitly uses stored function gives "Table not locked" error'. +# +--disable_warnings +drop function if exists bug12472| +--enable_warnings +create function bug12472() returns int return (select count(*) from t1)| +# Check case when function is used directly +create table t3 as select bug12472() as i| +show create table t3| +select * from t3| +drop table t3| +# Check case when function is used indirectly through view +create view v1 as select bug12472() as j| +create table t3 as select * from v1| +show create table t3| +select * from t3| +drop table t3| +drop view v1| +drop function bug12472| + + +# +# BUG#18587: Function that accepts and returns TEXT garbles data if longer than +# 766 chars +# + +# Prepare. + +--disable_warnings +DROP FUNCTION IF EXISTS bug18589_f1| +DROP PROCEDURE IF EXISTS bug18589_p1| +DROP PROCEDURE IF EXISTS bug18589_p2| +--enable_warnings + +CREATE FUNCTION bug18589_f1(arg TEXT) RETURNS TEXT +BEGIN + RETURN CONCAT(arg, ""); +END| + +CREATE PROCEDURE bug18589_p1(arg TEXT, OUT ret TEXT) +BEGIN + SET ret = CONCAT(arg, ""); +END| + +CREATE PROCEDURE bug18589_p2(arg TEXT) +BEGIN + DECLARE v TEXT; + CALL bug18589_p1(arg, v); + SELECT v; +END| + +# Test case. + +SELECT bug18589_f1(REPEAT("a", 767))| + +SET @bug18589_v1 = ""| +CALL bug18589_p1(REPEAT("a", 767), @bug18589_v1)| +SELECT @bug18589_v1| + +CALL bug18589_p2(REPEAT("a", 767))| + +# Cleanup. + +DROP FUNCTION bug18589_f1| +DROP PROCEDURE bug18589_p1| +DROP PROCEDURE bug18589_p2| + + # # BUG#NNNN: New bug synopsis # diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test index b67f1a73db6..2699cb66471 100644 --- a/mysql-test/t/sql_mode.test +++ b/mysql-test/t/sql_mode.test @@ -258,6 +258,9 @@ drop table t1, t2; select @@sql_mode; set sql_mode=2097152; select @@sql_mode; +# BUG#14675 +set sql_mode=4194304; +select @@sql_mode; set sql_mode=16384+(65536*4); select @@sql_mode; --error 1231 diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 1ef80bdd7ac..9f4d89a7e50 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2085,3 +2085,18 @@ create table t2 (a int, b int); insert into t2 values (2, 1), (1, 0); delete from t1 where c <= 1140006215 and (select b from t2 where a = 2) = 1; drop table t1, t2; + +# +# Bug #7549: Missing error message for invalid view selection with subquery +# + +CREATE TABLE t1 (a INT); + +--error 1054 +CREATE VIEW v1 AS SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1); +--error 1054 +CREATE VIEW v2 AS SELECT * FROM t1 WHERE no_such_column = (SELECT 1); +--error 1054 +SELECT * FROM t1 WHERE no_such_column = ANY (SELECT 1); + +DROP TABLE t1; diff --git a/mysql-test/t/trigger-grant.test b/mysql-test/t/trigger-grant.test index 7a3f7a9fa94..12b929898a8 100644 --- a/mysql-test/t/trigger-grant.test +++ b/mysql-test/t/trigger-grant.test @@ -564,3 +564,176 @@ SELECT @mysqltest_var; DROP USER mysqltest_u1@localhost; DROP DATABASE mysqltest_db1; + + +# +# Test for bug #14635 Accept NEW.x as INOUT parameters to stored +# procedures from within triggers +# +# We require UPDATE privilege when NEW.x passed as OUT parameter, and +# SELECT and UPDATE when NEW.x passed as INOUT parameter. +# +DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%'; +DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%'; +FLUSH PRIVILEGES; + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest_db1; +--enable_warnings + +CREATE DATABASE mysqltest_db1; +USE mysqltest_db1; + +CREATE TABLE t1 (i1 INT); +CREATE TABLE t2 (i1 INT); + +CREATE USER mysqltest_dfn@localhost; +CREATE USER mysqltest_inv@localhost; + +GRANT EXECUTE, CREATE ROUTINE, SUPER ON *.* TO mysqltest_dfn@localhost; +GRANT INSERT ON mysqltest_db1.* TO mysqltest_inv@localhost; + +connect (definer,localhost,mysqltest_dfn,,mysqltest_db1); +connect (invoker,localhost,mysqltest_inv,,mysqltest_db1); + +connection definer; +CREATE PROCEDURE p1(OUT i INT) DETERMINISTIC NO SQL SET i = 3; +CREATE PROCEDURE p2(INOUT i INT) DETERMINISTIC NO SQL SET i = i * 5; + +# Check that having no privilege won't work. +connection definer; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW + CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW + CALL p2(NEW.i1); + +connection invoker; +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t1 VALUES (7); +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t2 VALUES (11); + +connection definer; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; + +# Check that having only SELECT privilege is not enough. +connection default; +GRANT SELECT ON mysqltest_db1.* TO mysqltest_dfn@localhost; + +connection definer; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW + CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW + CALL p2(NEW.i1); + +connection invoker; +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t1 VALUES (13); +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t2 VALUES (17); + +connection default; +REVOKE SELECT ON mysqltest_db1.* FROM mysqltest_dfn@localhost; + +connection definer; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; + +# Check that having only UPDATE privilege is enough for OUT parameter, +# but not for INOUT parameter. +connection default; +GRANT UPDATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; + +connection definer; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW + CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW + CALL p2(NEW.i1); + +connection invoker; +INSERT INTO t1 VALUES (19); +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t2 VALUES (23); + +connection default; +REVOKE UPDATE ON mysqltest_db1.* FROM mysqltest_dfn@localhost; + +connection definer; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; + +# Check that having SELECT and UPDATE privileges is enough. +connection default; +GRANT SELECT, UPDATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; + +connection definer; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW + CALL p1(NEW.i1); +CREATE TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW + CALL p2(NEW.i1); + +connection invoker; +INSERT INTO t1 VALUES (29); +INSERT INTO t2 VALUES (31); + +connection default; +REVOKE SELECT, UPDATE ON mysqltest_db1.* FROM mysqltest_dfn@localhost; + +connection definer; +DROP TRIGGER t2_bi; +DROP TRIGGER t1_bi; + +connection default; +DROP PROCEDURE p2; +DROP PROCEDURE p1; + +# Check that late procedure redefining won't open a security hole. +connection default; +GRANT UPDATE ON mysqltest_db1.* TO mysqltest_dfn@localhost; + +connection definer; +CREATE PROCEDURE p1(OUT i INT) DETERMINISTIC NO SQL SET i = 37; +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW + CALL p1(NEW.i1); + +connection invoker; +INSERT INTO t1 VALUES (41); + +connection definer; +DROP PROCEDURE p1; +CREATE PROCEDURE p1(IN i INT) DETERMINISTIC NO SQL SET @v1 = i + 43; + +connection invoker; +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t1 VALUES (47); + +connection definer; +DROP PROCEDURE p1; +CREATE PROCEDURE p1(INOUT i INT) DETERMINISTIC NO SQL SET i = i + 51; + +connection invoker; +--error ER_COLUMNACCESS_DENIED_ERROR +INSERT INTO t1 VALUES (53); + +connection default; +DROP PROCEDURE p1; +REVOKE UPDATE ON mysqltest_db1.* FROM mysqltest_dfn@localhost; + +connection definer; +DROP TRIGGER t1_bi; + +# Cleanup. +disconnect definer; +disconnect invoker; +connection default; +DROP USER mysqltest_inv@localhost; +DROP USER mysqltest_dfn@localhost; +DROP TABLE t2; +DROP TABLE t1; +DROP DATABASE mysqltest_db1; +USE test; + +--echo End of 5.0 tests. diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 00c85a650d1..a5bd2ba0b38 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -1165,4 +1165,126 @@ SELECT * FROM t1 WHERE conn_id != trigger_conn_id; DROP TRIGGER t1_bi; DROP TABLE t1; + +# +# Bug#6951: Triggers/Traditional: SET @ result wrong +# +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (i1 INT); + +SET @save_sql_mode=@@sql_mode; + +SET SQL_MODE=''; + +CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW + SET @x = 5/0; + +SET SQL_MODE='traditional'; + +CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW + SET @x = 5/0; + +SET @x=1; +INSERT INTO t1 VALUES (@x); +SELECT @x; + +SET @x=2; +--error 1365 +UPDATE t1 SET i1 = @x; +SELECT @x; + +SET SQL_MODE=''; + +SET @x=3; +INSERT INTO t1 VALUES (@x); +SELECT @x; + +SET @x=4; +--error 1365 +UPDATE t1 SET i1 = @x; +SELECT @x; + +SET @@sql_mode=@save_sql_mode; + +DROP TRIGGER t1_ai; +DROP TRIGGER t1_au; +DROP TABLE t1; + + +# +# Test for bug #14635 Accept NEW.x as INOUT parameters to stored +# procedures from within triggers +# +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +--enable_warnings + +CREATE TABLE t1 (i1 INT); + +# Check that NEW.x pseudo variable is accepted as INOUT and OUT +# parameter to stored routine. +INSERT INTO t1 VALUES (3); +CREATE PROCEDURE p1(OUT i1 INT) DETERMINISTIC NO SQL SET i1 = 5; +CREATE PROCEDURE p2(INOUT i1 INT) DETERMINISTIC NO SQL SET i1 = i1 * 7; +delimiter //; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW +BEGIN + CALL p1(NEW.i1); + CALL p2(NEW.i1); +END// +delimiter ;// +UPDATE t1 SET i1 = 11 WHERE i1 = 3; +DROP TRIGGER t1_bu; +DROP PROCEDURE p2; +DROP PROCEDURE p1; + +# Check that OLD.x pseudo variable is not accepted as INOUT and OUT +# parameter to stored routine. +INSERT INTO t1 VALUES (13); +CREATE PROCEDURE p1(OUT i1 INT) DETERMINISTIC NO SQL SET @a = 17; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW + CALL p1(OLD.i1); +--error ER_SP_NOT_VAR_ARG +UPDATE t1 SET i1 = 19 WHERE i1 = 13; +DROP TRIGGER t1_bu; +DROP PROCEDURE p1; + +INSERT INTO t1 VALUES (23); +CREATE PROCEDURE p1(INOUT i1 INT) DETERMINISTIC NO SQL SET @a = i1 * 29; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW + CALL p1(OLD.i1); +--error ER_SP_NOT_VAR_ARG +UPDATE t1 SET i1 = 31 WHERE i1 = 23; +DROP TRIGGER t1_bu; +DROP PROCEDURE p1; + +# Check that NEW.x pseudo variable is read-only in the AFTER TRIGGER. +INSERT INTO t1 VALUES (37); +CREATE PROCEDURE p1(OUT i1 INT) DETERMINISTIC NO SQL SET @a = 41; +CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW + CALL p1(NEW.i1); +--error ER_SP_NOT_VAR_ARG +UPDATE t1 SET i1 = 43 WHERE i1 = 37; +DROP TRIGGER t1_au; +DROP PROCEDURE p1; + +INSERT INTO t1 VALUES (47); +CREATE PROCEDURE p1(INOUT i1 INT) DETERMINISTIC NO SQL SET @a = i1 * 49; +CREATE TRIGGER t1_au AFTER UPDATE ON t1 FOR EACH ROW + CALL p1(NEW.i1); +--error ER_SP_NOT_VAR_ARG +UPDATE t1 SET i1 = 51 WHERE i1 = 47; +DROP TRIGGER t1_au; +DROP PROCEDURE p1; + +# Post requisite. +SELECT * FROM t1; + +DROP TABLE t1; + # End of 5.0 tests diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 8f759c2d43e..ea22ada900a 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2512,3 +2512,19 @@ create view v2 as select convert_tz(dt, 'UTC', 'Europe/Moscow') as ldt from v1; select * from v2; drop view v1, v2; drop table t1; + +# +# Bug #19490: usage of view specified by a query with GROUP BY +# an expression containing non-constant interval + +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, d datetime); + +CREATE VIEW v1 AS +SELECT id, date(d) + INTERVAL TIME_TO_SEC(d) SECOND AS t, COUNT(*) + FROM t1 GROUP BY id, t; + +SHOW CREATE VIEW v1; +SELECT * FROM v1; + +DROP VIEW v1; +DROP TABLE t1; diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc index 95f9029f648..90d9d04cd36 100644 --- a/server-tools/instance-manager/manager.cc +++ b/server-tools/instance-manager/manager.cc @@ -35,12 +35,12 @@ #endif -static int create_pid_file(const char *pid_file_name) +int create_pid_file(const char *pid_file_name, int pid) { if (FILE *pid_file= my_fopen(pid_file_name, O_WRONLY | O_CREAT | O_BINARY, MYF(0))) { - fprintf(pid_file, "%d\n", (int) getpid()); + fprintf(pid_file, "%d\n", (int) pid); my_fclose(pid_file, MYF(0)); return 0; } @@ -138,8 +138,13 @@ void manager(const Options &options) if (user_map.load(options.password_file_name)) return; - /* write pid file */ - if (create_pid_file(options.pid_file_name)) + /* write Instance Manager pid file */ + + log_info("IM pid file: '%s'; PID: %d.", + (const char *) options.pid_file_name, + (int) manager_pid); + + if (create_pid_file(options.pid_file_name, manager_pid)) return; sigset_t mask; diff --git a/server-tools/instance-manager/manager.h b/server-tools/instance-manager/manager.h index 12ed6b3b1ff..3ddf292132e 100644 --- a/server-tools/instance-manager/manager.h +++ b/server-tools/instance-manager/manager.h @@ -20,4 +20,6 @@ struct Options; void manager(const Options &options); +int create_pid_file(const char *pid_file_name, int pid); + #endif // INCLUDES_MYSQL_INSTANCE_MANAGER_MANAGER_H diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc index d0b2cf2666c..ef714099de7 100644 --- a/server-tools/instance-manager/mysqlmanager.cc +++ b/server-tools/instance-manager/mysqlmanager.cc @@ -338,6 +338,14 @@ spawn: /* Here we return to main, and fall into manager */ break; default: // parent, success + pid= getpid(); /* Get our pid. */ + + log_info("Angel pid file: '%s'; PID: %d.", + (const char *) options.angel_pid_file_name, + (int) pid); + + create_pid_file(Options::angel_pid_file_name, pid); + while (child_status == CHILD_OK && is_terminated == 0) sigsuspend(&zeromask); diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc index e7d366e7457..a98c0e291be 100644 --- a/server-tools/instance-manager/options.cc +++ b/server-tools/instance-manager/options.cc @@ -44,6 +44,7 @@ const char *Options::user= 0; /* No default value */ const char *default_password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME); const char *default_log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME); const char *Options::config_file= QUOTE(DEFAULT_CONFIG_FILE); +const char *Options::angel_pid_file_name= NULL; #endif const char *Options::log_file_name= default_log_file_name; const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME); @@ -58,6 +59,9 @@ char **Options::saved_argv= NULL; /* Remember if the config file was forced */ bool Options::is_forced_default_file= 0; +static const char * const ANGEL_PID_FILE_SUFFIX= ".angel.pid"; +static const int ANGEL_PID_FILE_SUFFIX_LEN= strlen(ANGEL_PID_FILE_SUFFIX); + /* List of options, accepted by the instance manager. List must be closed with empty option. @@ -72,6 +76,7 @@ enum options { #ifndef __WIN__ OPT_RUN_AS_SERVICE, OPT_USER, + OPT_ANGEL_PID_FILE, #else OPT_INSTALL_SERVICE, OPT_REMOVE_SERVICE, @@ -94,7 +99,14 @@ static struct my_option my_long_options[] = { "pid-file", OPT_PID_FILE, "Pid file to use.", (gptr *) &Options::pid_file_name, (gptr *) &Options::pid_file_name, - 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + +#ifndef __WIN__ + { "angel-pid-file", OPT_ANGEL_PID_FILE, "Pid file for angel process.", + (gptr *) &Options::angel_pid_file_name, + (gptr *) &Options::angel_pid_file_name, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, +#endif { "socket", OPT_SOCKET, "Socket file to use for connection.", (gptr *) &Options::socket_file_name, (gptr *) &Options::socket_file_name, @@ -290,6 +302,46 @@ int Options::load(int argc, char **argv) get_one_option)) != 0) goto err; +#ifndef __WIN__ + if (Options::run_as_service) + { + if (Options::angel_pid_file_name == NULL) + { + /* + Calculate angel pid file on the IM pid file basis: replace the + extension (everything after the last dot) of the pid file basename to + '.angel.pid'. + */ + + char *angel_pid_file_name; + char *base_name_ptr; + char *ext_ptr; + + angel_pid_file_name= (char *) malloc(strlen(Options::pid_file_name) + + ANGEL_PID_FILE_SUFFIX_LEN); + + strcpy(angel_pid_file_name, Options::pid_file_name); + + base_name_ptr= strrchr(angel_pid_file_name, '/'); + + if (!base_name_ptr) + base_name_ptr= angel_pid_file_name + 1; + + ext_ptr= strrchr(base_name_ptr, '.'); + if (ext_ptr) + *ext_ptr= 0; + + strcat(angel_pid_file_name, ANGEL_PID_FILE_SUFFIX); + + Options::angel_pid_file_name= angel_pid_file_name; + } + else + { + Options::angel_pid_file_name= strdup(Options::angel_pid_file_name); + } + } +#endif + return 0; err: @@ -301,6 +353,11 @@ void Options::cleanup() /* free_defaults returns nothing */ if (Options::saved_argv != NULL) free_defaults(Options::saved_argv); + +#ifndef __WIN__ + if (Options::run_as_service) + free((void *) Options::angel_pid_file_name); +#endif } #ifdef __WIN__ diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h index abb094eac93..ad3458869b6 100644 --- a/server-tools/instance-manager/options.h +++ b/server-tools/instance-manager/options.h @@ -35,6 +35,7 @@ struct Options #else static char run_as_service; /* handle_options doesn't support bool */ static const char *user; + static const char *angel_pid_file_name; #endif static bool is_forced_default_file; static const char *log_file_name; diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 895f022624c..4e977c06180 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -642,7 +642,8 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*) void field_conv(Field *to,Field *from) { - if (to->real_type() == from->real_type()) + if (to->real_type() == from->real_type() && + !(to->type() == FIELD_TYPE_BLOB && to->table->copy_blobs)) { if (to->pack_length() == from->pack_length() && !(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) && diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 934437e0c91..28cdfd23b6a 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4048,6 +4048,9 @@ ha_innobase::index_prev( mysql_byte* buf) /* in/out: buffer for previous row in MySQL format */ { + statistic_increment(current_thd->status_var.ha_read_prev_count, + &LOCK_status); + return(general_fetch(buf, ROW_SEL_PREV, 0)); } diff --git a/sql/item.cc b/sql/item.cc index 31fbef0f053..ba378e56cb0 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -958,6 +958,12 @@ void Item_splocal::print(String *str) } +bool Item_splocal::set_value(THD *thd, sp_rcontext *ctx, Item **it) +{ + return ctx->set_variable(thd, get_var_idx(), it); +} + + /***************************************************************************** Item_case_expr methods *****************************************************************************/ @@ -1883,7 +1889,6 @@ Item_decimal::Item_decimal(const char *str_arg, uint length, name= (char*) str_arg; decimals= (uint8) decimal_value.frac; fixed= 1; - unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, decimals, unsigned_flag); } @@ -1893,7 +1898,6 @@ Item_decimal::Item_decimal(longlong val, bool unsig) int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value); decimals= (uint8) decimal_value.frac; fixed= 1; - unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, decimals, unsigned_flag); } @@ -1904,7 +1908,6 @@ Item_decimal::Item_decimal(double val, int precision, int scale) double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value); decimals= (uint8) decimal_value.frac; fixed= 1; - unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, decimals, unsigned_flag); } @@ -1917,7 +1920,6 @@ Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg, name= (char*) str; decimals= (uint8) decimal_par; max_length= length; - unsigned_flag= !decimal_value.sign(); fixed= 1; } @@ -1927,7 +1929,6 @@ Item_decimal::Item_decimal(my_decimal *value_par) my_decimal2decimal(value_par, &decimal_value); decimals= (uint8) decimal_value.frac; fixed= 1; - unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals, decimals, unsigned_flag); } @@ -1939,7 +1940,6 @@ Item_decimal::Item_decimal(const char *bin, int precision, int scale) &decimal_value, precision, scale); decimals= (uint8) decimal_value.frac; fixed= 1; - unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(precision, decimals, unsigned_flag); } @@ -5365,6 +5365,25 @@ bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const } +void Item_trigger_field::set_required_privilege(const bool rw) +{ + /* + Require SELECT and UPDATE privilege if this field will be read and + set, and only UPDATE privilege for setting the field. + */ + want_privilege= (rw ? SELECT_ACL | UPDATE_ACL : UPDATE_ACL); +} + + +bool Item_trigger_field::set_value(THD *thd, sp_rcontext */*ctx*/, Item **it) +{ + Item *item= sp_prepare_func_item(thd, it); + + return (!item || (!fixed && fix_fields(thd, 0)) || + (item->save_in_field(field, 0) < 0)); +} + + bool Item_trigger_field::fix_fields(THD *thd, Item **items) { /* @@ -5387,8 +5406,7 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items) if (table_grants) { - table_grants->want_privilege= - access_type == AT_READ ? SELECT_ACL : UPDATE_ACL; + table_grants->want_privilege= want_privilege; if (check_grant_column(thd, table_grants, triggers->table->s->db, triggers->table->s->table_name, field_name, @@ -5420,6 +5438,7 @@ void Item_trigger_field::print(String *str) void Item_trigger_field::cleanup() { + want_privilege= original_privilege; /* Since special nature of Item_trigger_field we should not do most of things from Item_field::cleanup() or Item_ident::cleanup() here. diff --git a/sql/item.h b/sql/item.h index 24aca4a86d1..cfc2306f15d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -372,6 +372,42 @@ public: /*************************************************************************/ +class sp_rcontext; + + +class Settable_routine_parameter +{ +public: + /* + Set required privileges for accessing the parameter. + + SYNOPSIS + set_required_privilege() + rw if 'rw' is true then we are going to read and set the + parameter, so SELECT and UPDATE privileges might be + required, otherwise we only reading it and SELECT + privilege might be required. + */ + virtual void set_required_privilege(bool rw) {}; + + /* + Set parameter value. + + SYNOPSIS + set_value() + thd thread handle + ctx context to which parameter belongs (if it is local + variable). + it item which represents new value + + RETURN + FALSE if parameter value has been set, + TRUE if error has occured. + */ + virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it)= 0; +}; + + typedef bool (Item::*Item_processor)(byte *arg); typedef Item* (Item::*Item_transformer) (byte *arg); typedef void (*Cond_traverser) (const Item *item, void *arg); @@ -744,6 +780,15 @@ public: } virtual bool is_splocal() { return 0; } /* Needed for error checking */ + + /* + Return Settable_routine_parameter interface of the Item. Return 0 + if this Item is not Settable_routine_parameter. + */ + virtual Settable_routine_parameter *get_settable_routine_parameter() + { + return 0; + } }; @@ -842,7 +887,8 @@ inline bool Item_sp_variable::send(Protocol *protocol, String *str) runtime. *****************************************************************************/ -class Item_splocal :public Item_sp_variable +class Item_splocal :public Item_sp_variable, + private Settable_routine_parameter { uint m_var_idx; @@ -880,6 +926,15 @@ public: inline enum Type type() const; inline Item_result result_type() const; + +private: + bool set_value(THD *thd, sp_rcontext *ctx, Item **it); + +public: + Settable_routine_parameter *get_settable_routine_parameter() + { + return this; + } }; /***************************************************************************** @@ -2100,14 +2155,13 @@ class Table_triggers_list; two Field instances representing either OLD or NEW version of this field. */ -class Item_trigger_field : public Item_field +class Item_trigger_field : public Item_field, + private Settable_routine_parameter { public: /* Is this item represents row from NEW or OLD row ? */ enum row_version_type {OLD_ROW, NEW_ROW}; row_version_type row_version; - /* Is this item used for reading or updating the value? */ - enum access_types { AT_READ = 0x1, AT_UPDATE = 0x2 }; /* Next in list of all Item_trigger_field's in trigger */ Item_trigger_field *next_trg_field; /* Index of the field in the TABLE::field array */ @@ -2118,11 +2172,11 @@ public: Item_trigger_field(Name_resolution_context *context_arg, row_version_type row_ver_arg, const char *field_name_arg, - access_types access_type_arg) + ulong priv, const bool ro) :Item_field(context_arg, (const char *)NULL, (const char *)NULL, field_name_arg), - row_version(row_ver_arg), field_idx((uint)-1), - access_type(access_type_arg), table_grants(NULL) + row_version(row_ver_arg), field_idx((uint)-1), original_privilege(priv), + want_privilege(priv), table_grants(NULL), read_only (ro) {} void setup_field(THD *thd, TABLE *table, GRANT_INFO *table_grant_info); enum Type type() const { return TRIGGER_FIELD_ITEM; } @@ -2133,8 +2187,39 @@ public: void cleanup(); private: - access_types access_type; + void set_required_privilege(const bool rw); + bool set_value(THD *thd, sp_rcontext *ctx, Item **it); + +public: + Settable_routine_parameter *get_settable_routine_parameter() + { + return (read_only ? 0 : this); + } + + bool set_value(THD *thd, Item **it) + { + return set_value(thd, NULL, it); + } + +private: + /* + 'want_privilege' holds privileges required to perform operation on + this trigger field (SELECT_ACL if we are going to read it and + UPDATE_ACL if we are going to update it). It is initialized at + parse time but can be updated later if this trigger field is used + as OUT or INOUT parameter of stored routine (in this case + set_required_privilege() is called to appropriately update + want_privilege and cleanup() is responsible for restoring of + original want_privilege once parameter's value is updated). + */ + ulong original_privilege; + ulong want_privilege; GRANT_INFO *table_grants; + /* + Trigger field is read-only unless it belongs to the NEW row in a + BEFORE INSERT of BEFORE UPDATE trigger. + */ + bool read_only; }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 6ec74560b91..5ef9db6f52b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4120,6 +4120,18 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const } +bool Item_func_get_user_var::set_value(THD *thd, + sp_rcontext */*ctx*/, Item **it) +{ + Item_func_set_user_var *suv= new Item_func_set_user_var(get_name(), *it); + /* + Item_func_set_user_var is not fixed after construction, call + fix_fields(). + */ + return (!suv || suv->fix_fields(thd, it) || suv->check() || suv->update()); +} + + bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); @@ -4752,6 +4764,7 @@ Item_func_sp::sp_result_field(void) const dummy_table->alias = empty_name; dummy_table->maybe_null = maybe_null; dummy_table->in_use= current_thd; + dummy_table->copy_blobs= TRUE; share->table_cache_key = empty_name; share->table_name = empty_name; } diff --git a/sql/item_func.h b/sql/item_func.h index a91d93be8c6..1d8a1bd5e22 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1179,7 +1179,8 @@ public: }; -class Item_func_get_user_var :public Item_func +class Item_func_get_user_var :public Item_func, + private Settable_routine_parameter { user_var_entry *var_entry; @@ -1206,6 +1207,15 @@ public: table_map used_tables() const { return const_item() ? 0 : RAND_TABLE_BIT; } bool eq(const Item *item, bool binary_cmp) const; + +private: + bool set_value(THD *thd, sp_rcontext *ctx, Item **it); + +public: + Settable_routine_parameter *get_settable_routine_parameter() + { + return this; + } }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index d93f6501ebb..4b304725927 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1351,6 +1351,17 @@ void Item_in_subselect::print(String *str) } +bool Item_in_subselect::fix_fields(THD *thd, Item **ref) +{ + bool result = 0; + + if(thd->lex->view_prepare_mode && left_expr && !left_expr->fixed) + result = left_expr->fix_fields(thd, &left_expr); + + return result || Item_subselect::fix_fields(thd, ref); +} + + Item_subselect::trans_res Item_allany_subselect::select_transformer(JOIN *join) { diff --git a/sql/item_subselect.h b/sql/item_subselect.h index a4dac5bda87..293408dc09e 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -258,6 +258,7 @@ public: void top_level_item() { abort_on_null=1; } bool test_limit(st_select_lex_unit *unit); void print(String *str); + bool fix_fields(THD *thd, Item **ref); friend class Item_ref_null_helper; friend class Item_is_not_null_test; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index e997d4ae70c..72c53272e0c 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2144,8 +2144,13 @@ bool Item_date_add_interval::eq(const Item *item, bool binary_cmp) const Item_date_add_interval *other= (Item_date_add_interval*) item; if ((int_type != other->int_type) || - (!args[0]->eq(other->args[0], binary_cmp)) || - (get_interval_value(args[1], int_type, &val, &interval))) + (!args[0]->eq(other->args[0], binary_cmp))) + return FALSE; + + if (!args[1]->const_item() || !other->args[1]->const_item()) + return (args[1]->eq(other->args[1], binary_cmp)); + + if (get_interval_value(args[1], int_type, &val, &interval)) return FALSE; val= other->value; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 1ce9dd78d2c..815876688fb 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -718,12 +718,6 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, List &fields, List &keys, bool tmp_table, uint select_field_count); -TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, - TABLE_LIST *create_table, - List *extra_fields, - List *keys, - List *items, - MYSQL_LOCK **lock); bool mysql_alter_table(THD *thd, char *new_db, char *new_name, HA_CREATE_INFO *create_info, TABLE_LIST *table_list, @@ -1315,10 +1309,11 @@ extern struct st_VioSSLFd * ssl_acceptor_fd; MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags, bool *need_reopen); -/* mysql_lock_tables() flags bits */ +/* mysql_lock_tables() and open_table() flags bits */ #define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001 #define MYSQL_LOCK_IGNORE_FLUSH 0x0002 #define MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN 0x0004 +#define MYSQL_OPEN_IGNORE_LOCKED_TABLES 0x0008 void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); @@ -1582,6 +1577,16 @@ inline int hexchar_to_int(char c) return -1; } +/* + is_user_table() + return true if the table was created explicitly +*/ + +inline bool is_user_table(TABLE * table) +{ + const char *name= table->s->table_name; + return strncmp(name, tmp_file_prefix, tmp_file_prefix_length); +} /* Some functions that are different in the embedded library and the normal diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 2892c5c8b01..4e7b9200d88 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5475,7 +5475,7 @@ ER_SP_DUP_HANDLER 42000 eng "Duplicate handler declared in the same block" ger "Doppelter Handler im selben Block deklariert" ER_SP_NOT_VAR_ARG 42000 - eng "OUT or INOUT argument %d for routine %s is not a variable" + eng "OUT or INOUT argument %d for routine %s is not a variable or NEW pseudo-variable in BEFORE trigger" ger "OUT- oder INOUT-Argument %d für Routine %s ist keine Variable" ER_SP_NO_RETSET 0A000 eng "Not allowed to return a result set from a %s" diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 6a7676c7bf2..174f62c9497 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -310,11 +310,13 @@ sp_prepare_func_item(THD* thd, Item **it_addr) */ bool -sp_eval_expr(THD *thd, Field *result_field, Item *expr_item) +sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) { + Item *expr_item; + DBUG_ENTER("sp_eval_expr"); - if (!(expr_item= sp_prepare_func_item(thd, &expr_item))) + if (!(expr_item= sp_prepare_func_item(thd, expr_item_ptr))) DBUG_RETURN(TRUE); bool err_status= FALSE; @@ -936,6 +938,7 @@ sp_head::execute(THD *thd) bool err_status= FALSE; uint ip= 0; ulong save_sql_mode; + bool save_abort_on_warning; Query_arena *old_arena; /* per-instruction arena */ MEM_ROOT execute_mem_root; @@ -996,6 +999,10 @@ sp_head::execute(THD *thd) thd->derived_tables= 0; save_sql_mode= thd->variables.sql_mode; thd->variables.sql_mode= m_sql_mode; + save_abort_on_warning= thd->abort_on_warning; + thd->abort_on_warning= + (m_sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)); + /* It is also more efficient to save/restore current thd->lex once when do it in each instruction @@ -1128,6 +1135,7 @@ sp_head::execute(THD *thd) DBUG_ASSERT(!thd->derived_tables); thd->derived_tables= old_derived_tables; thd->variables.sql_mode= save_sql_mode; + thd->abort_on_warning= save_abort_on_warning; thd->stmt_arena= old_arena; state= EXECUTED; @@ -1204,130 +1212,144 @@ bool sp_head::execute_function(THD *thd, Item **argp, uint argcount, Field *return_value_fld) { - Item_cache **param_values; ulonglong binlog_save_options; bool need_binlog_call; - uint params; + uint arg_no; sp_rcontext *octx = thd->spcont; sp_rcontext *nctx = NULL; + char buf[STRING_BUFFER_USUAL_SIZE]; + String binlog_buf(buf, sizeof(buf), &my_charset_bin); bool err_status= FALSE; + MEM_ROOT call_mem_root; + Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP); + Query_arena backup_arena; DBUG_ENTER("sp_head::execute_function"); DBUG_PRINT("info", ("function %s", m_name.str)); - params = m_pcont->context_var_count(); - /* Check that the function is called with all specified arguments. If it is not, use my_error() to report an error, or it will not terminate the invoking query properly. */ - - if (argcount != params) + if (argcount != m_pcont->context_var_count()) { /* Need to use my_error here, or it will not terminate the invoking query properly. */ my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), - "FUNCTION", m_qname.str, params, argcount); + "FUNCTION", m_qname.str, m_pcont->context_var_count(), argcount); DBUG_RETURN(TRUE); } - - /* Allocate param_values to be used for dumping the call into binlog. */ - - if (!(param_values= (Item_cache**)thd->alloc(sizeof(Item_cache*)*argcount))) - DBUG_RETURN(TRUE); - - // QQ Should have some error checking here? (types, etc...) + /* + Prepare arena and memroot for objects which lifetime is whole + duration of function call (sp_rcontext, it's tables and items, + sp_cursor and Item_cache holders for case expressions). + We can't use caller's arena/memroot for those objects because + in this case some fixed amount of memory will be consumed for + each function/trigger invocation and so statements which involve + lot of them will hog memory. + TODO: we should create sp_rcontext once per command and reuse + it on subsequent executions of a function/trigger. + */ + init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); + thd->set_n_backup_active_arena(&call_arena, &backup_arena); if (!(nctx= new sp_rcontext(m_pcont, return_value_fld, octx)) || nctx->init(thd)) { - delete nctx; /* Delete nctx if it was init() that failed. */ - DBUG_RETURN(TRUE); + thd->restore_active_arena(&call_arena, &backup_arena); + err_status= TRUE; + goto err_with_cleanup; } + /* + We have to switch temporarily back to callers arena/memroot. + Function arguments belong to the caller and so the may reference + memory which they will allocate during calculation long after + this function call will be finished (e.g. in Item::cleanup()). + */ + thd->restore_active_arena(&call_arena, &backup_arena); + #ifndef DBUG_OFF nctx->sp= this; #endif /* Pass arguments. */ - + for (arg_no= 0; arg_no < argcount; arg_no++) { - uint i; - - for (i= 0 ; i < argcount ; i++) + /* Arguments must be fixed in Item_func_sp::fix_fields */ + DBUG_ASSERT(argp[arg_no]->fixed); + + if ((err_status= nctx->set_variable(thd, arg_no, &(argp[arg_no])))) + goto err_with_cleanup; + } + + need_binlog_call= mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG); + + /* + Remember the original arguments for unrolled replication of functions + before they are changed by execution. + */ + if (need_binlog_call) + { + binlog_buf.length(0); + binlog_buf.append(STRING_WITH_LEN("SELECT ")); + append_identifier(thd, &binlog_buf, m_name.str, m_name.length); + binlog_buf.append('('); + for (arg_no= 0; arg_no < argcount; arg_no++) { - if (!argp[i]->fixed && argp[i]->fix_fields(thd, &argp[i])) - { - err_status= TRUE; - break; - } + String str_value_holder; + String *str_value; - param_values[i]= Item_cache::get_cache(argp[i]->result_type()); - param_values[i]->store(argp[i]); + if (arg_no) + binlog_buf.append(','); - if (nctx->set_variable(thd, i, param_values[i])) - { - err_status= TRUE; - break; - } + str_value= sp_get_item_value(nctx->get_item(arg_no), + &str_value_holder); + + if (str_value) + binlog_buf.append(*str_value); + else + binlog_buf.append(STRING_WITH_LEN("NULL")); } + binlog_buf.append(')'); } - - if (err_status) - { - delete nctx; - DBUG_RETURN(TRUE); - } - thd->spcont= nctx; binlog_save_options= thd->options; - need_binlog_call= mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG); if (need_binlog_call) { reset_dynamic(&thd->user_var_events); mysql_bin_log.start_union_events(thd); } - + + /* + Switch to call arena/mem_root so objects like sp_cursor or + Item_cache holders for case expressions can be allocated on it. + + TODO: In future we should associate call arena/mem_root with + sp_rcontext and allocate all these objects (and sp_rcontext + itself) on it directly rather than juggle with arenas. + */ + thd->set_n_backup_active_arena(&call_arena, &backup_arena); + thd->options&= ~OPTION_BIN_LOG; err_status= execute(thd); thd->options= binlog_save_options; - + + thd->restore_active_arena(&call_arena, &backup_arena); + if (need_binlog_call) mysql_bin_log.stop_union_events(thd); if (need_binlog_call && thd->binlog_evt_union.unioned_events) { - char buf[256]; - String bufstr(buf, sizeof(buf), &my_charset_bin); - bufstr.length(0); - bufstr.append(STRING_WITH_LEN("SELECT ")); - append_identifier(thd, &bufstr, m_name.str, m_name.length); - bufstr.append('('); - for (uint i=0; i < argcount; i++) - { - String str_value_holder; - String *str_value; - - if (i) - bufstr.append(','); - - str_value= sp_get_item_value(param_values[i], &str_value_holder); - - if (str_value) - bufstr.append(*str_value); - else - bufstr.append(STRING_WITH_LEN("NULL")); - } - bufstr.append(')'); - - Query_log_event qinfo(thd, bufstr.ptr(), bufstr.length(), + Query_log_event qinfo(thd, binlog_buf.ptr(), binlog_buf.length(), thd->binlog_evt_union.unioned_events_trans, FALSE); - if (mysql_bin_log.write(&qinfo) && + if (mysql_bin_log.write(&qinfo) && thd->binlog_evt_union.unioned_events_trans) { push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, @@ -1348,27 +1370,19 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, } } + nctx->pop_all_cursors(); // To avoid memory leaks after an error + +err_with_cleanup: delete nctx; + call_arena.free_items(); + free_root(&call_mem_root, MYF(0)); thd->spcont= octx; DBUG_RETURN(err_status); } -static Item_func_get_user_var *item_is_user_var(Item *it) -{ - if (it->type() == Item::FUNC_ITEM) - { - Item_func *fi= static_cast(it); - - if (fi->functype() == Item_func::GUSERVAR_FUNC) - return static_cast(fi); - } - return NULL; -} - - /* Execute a procedure. SYNOPSIS @@ -1444,22 +1458,28 @@ sp_head::execute_procedure(THD *thd, List *args) for (uint i= 0 ; i < params ; i++) { Item *arg_item= it_args++; - sp_variable_t *spvar= m_pcont->find_variable(i); if (!arg_item) break; + sp_variable_t *spvar= m_pcont->find_variable(i); + if (!spvar) continue; if (spvar->mode != sp_param_in) { - if (!arg_item->is_splocal() && !item_is_user_var(arg_item)) + Settable_routine_parameter *srp= + arg_item->get_settable_routine_parameter(); + + if (!srp) { my_error(ER_SP_NOT_VAR_ARG, MYF(0), i+1, m_qname.str); err_status= TRUE; break; } + + srp->set_required_privilege(spvar->mode == sp_param_inout); } if (spvar->mode == sp_param_out) @@ -1467,7 +1487,7 @@ sp_head::execute_procedure(THD *thd, List *args) Item_null *null_item= new Item_null(); if (!null_item || - nctx->set_variable(thd, i, null_item)) + nctx->set_variable(thd, i, (struct Item **)&null_item)) { err_status= TRUE; break; @@ -1475,7 +1495,7 @@ sp_head::execute_procedure(THD *thd, List *args) } else { - if (nctx->set_variable(thd, i, *it_args.ref())) + if (nctx->set_variable(thd, i, it_args.ref())) { err_status= TRUE; break; @@ -1527,36 +1547,16 @@ sp_head::execute_procedure(THD *thd, List *args) if (spvar->mode == sp_param_in) continue; - if (arg_item->is_splocal()) + Settable_routine_parameter *srp= + arg_item->get_settable_routine_parameter(); + + DBUG_ASSERT(srp); + + if (srp->set_value(thd, octx, nctx->get_item_addr(i))) { - if (octx->set_variable(thd, - ((Item_splocal*) arg_item)->get_var_idx(), - nctx->get_item(i))) - { - err_status= TRUE; - break; - } + err_status= TRUE; + break; } - else - { - Item_func_get_user_var *guv= item_is_user_var(arg_item); - - if (guv) - { - Item *item= nctx->get_item(i); - Item_func_set_user_var *suv; - - suv= new Item_func_set_user_var(guv->get_name(), item); - /* - Item_func_set_user_var is not fixed after construction, - call fix_fields(). - */ - if ((err_status= test(!suv || suv->fix_fields(thd, &item) || - suv->check() || suv->update()))) - break; - } - } - } } @@ -2328,7 +2328,7 @@ sp_instr_set::execute(THD *thd, uint *nextp) int sp_instr_set::exec_core(THD *thd, uint *nextp) { - int res= thd->spcont->set_variable(thd, m_offset, m_value); + int res= thd->spcont->set_variable(thd, m_offset, &m_value); if (res && thd->spcont->found_handler_here()) { @@ -2393,12 +2393,7 @@ sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) int sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp) { - int res= 0; - Item *it= sp_prepare_func_item(thd, &value); - if (!it || - !trigger_field->fixed && trigger_field->fix_fields(thd, 0) || - (it->save_in_field(trigger_field->field, 0) < 0)) - res= -1; + const int res= (trigger_field->set_value(thd, &value) ? -1 : 0); *nextp = m_ip+1; return res; } @@ -2603,7 +2598,7 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp) do it in scope of execution the current context/block. */ - return thd->spcont->set_return_value(thd, m_value); + return thd->spcont->set_return_value(thd, &m_value); } void @@ -3047,7 +3042,7 @@ sp_instr_set_case_expr::execute(THD *thd, uint *nextp) int sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp) { - int res= thd->spcont->set_case_expr(thd, m_case_expr_id, m_case_expr); + int res= thd->spcont->set_case_expr(thd, m_case_expr_id, &m_case_expr); if (res && !thd->spcont->get_case_expr(m_case_expr_id) && @@ -3061,7 +3056,7 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp) Item *null_item= new Item_null(); if (!null_item || - thd->spcont->set_case_expr(thd, m_case_expr_id, null_item)) + thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item)) { /* If this also failed, we have to abort. */ diff --git a/sql/sp_head.h b/sql/sp_head.h index 6a9cf97d739..d5f49d8a964 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -1169,6 +1169,6 @@ Item * sp_prepare_func_item(THD* thd, Item **it_addr); bool -sp_eval_expr(THD *thd, Field *result_field, Item *expr_item); +sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr); #endif /* _SP_HEAD_H_ */ diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 38b6de0e75a..3bc27a029d0 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -150,7 +150,7 @@ sp_rcontext::init_var_items() bool -sp_rcontext::set_return_value(THD *thd, Item *return_value_item) +sp_rcontext::set_return_value(THD *thd, Item **return_value_item) { DBUG_ASSERT(m_return_value_fld); @@ -279,14 +279,14 @@ sp_rcontext::pop_cursors(uint count) int -sp_rcontext::set_variable(THD *thd, uint var_idx, Item *value) +sp_rcontext::set_variable(THD *thd, uint var_idx, Item **value) { return set_variable(thd, m_var_table->field[var_idx], value); } int -sp_rcontext::set_variable(THD *thd, Field *field, Item *value) +sp_rcontext::set_variable(THD *thd, Field *field, Item **value) { if (!value) { @@ -478,9 +478,10 @@ sp_rcontext::create_case_expr_holder(THD *thd, Item_result result_type) */ int -sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item *case_expr_item) +sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr) { - if (!(case_expr_item= sp_prepare_func_item(thd, &case_expr_item))) + Item *case_expr_item= sp_prepare_func_item(thd, case_expr_item_ptr); + if (!case_expr_item) return TRUE; if (!m_case_expr_holders[case_expr_id] || @@ -542,7 +543,7 @@ bool Select_fetch_into_spvars::send_data(List &items) */ for (; spvar= spvar_iter++, item= item_iter++; ) { - if (thd->spcont->set_variable(thd, spvar->offset, item)) + if (thd->spcont->set_variable(thd, spvar->offset, &item)) return TRUE; } return FALSE; diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 20aaea3b7c1..30521f6da84 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -91,7 +91,7 @@ class sp_rcontext : public Sql_alloc ~sp_rcontext(); int - set_variable(THD *thd, uint var_idx, Item *value); + set_variable(THD *thd, uint var_idx, Item **value); Item * get_item(uint var_idx); @@ -100,7 +100,7 @@ class sp_rcontext : public Sql_alloc get_item_addr(uint var_idx); bool - set_return_value(THD *thd, Item *return_value_item); + set_return_value(THD *thd, Item **return_value_item); inline bool is_return_value_set() const @@ -200,7 +200,7 @@ class sp_rcontext : public Sql_alloc */ int - set_case_expr(THD *thd, int case_expr_id, Item *case_expr_item); + set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr); Item * get_case_expr(int case_expr_id); @@ -254,7 +254,7 @@ private: Item_cache *create_case_expr_holder(THD *thd, Item_result result_type); - int set_variable(THD *thd, Field *field, Item *value); + int set_variable(THD *thd, Field *field, Item **value); }; // class sp_rcontext : public Sql_alloc diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 482a25acbd2..1f3b9e14631 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -617,118 +617,110 @@ static inline uint tmpkeyval(THD *thd, TABLE *table) void close_temporary_tables(THD *thd) { - TABLE *next, - *prev_table /* prev link is not maintained in TABLE's double-linked list */, - *table; - char *query= (gptr) 0, *end; - uint query_buf_size, max_names_len; - bool found_user_tables; - + TABLE *table; if (!thd->temporary_tables) return; - - LINT_INIT(end); - query_buf_size= 50; // Enough for DROP ... TABLE IF EXISTS - /* - insertion sort of temp tables by pseudo_thread_id to build ordered list + if (!mysql_bin_log.is_open()) + { + for (table= thd->temporary_tables; table; table= table->next) + { + close_temporary(table, 1); + } + thd->temporary_tables= 0; + return; + } + + TABLE *next, + *prev_table /* prev link is not maintained in TABLE's double-linked list */; + bool was_quote_show= true; /* to assume thd->options has OPTION_QUOTE_SHOW_CREATE */ + // Better add "if exists", in case a RESET MASTER has been done + const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS "; + uint stub_len= sizeof(stub) - 1; + char buf[256]; + memcpy(buf, stub, stub_len); + String s_query= String(buf, sizeof(buf), system_charset_info); + bool found_user_tables= false; + LINT_INIT(next); + + /* + insertion sort of temp tables by pseudo_thread_id to build ordered list of sublists of equal pseudo_thread_id */ - for (prev_table= thd->temporary_tables, - table= prev_table->next, - found_user_tables= (prev_table->s->table_name[0] != '#'); + + for (prev_table= thd->temporary_tables, table= prev_table->next; table; prev_table= table, table= table->next) { - TABLE *prev_sorted /* same as for prev_table */, - *sorted; - /* - table not created directly by the user is moved to the tail. - Fixme/todo: nothing (I checked the manual) prevents user to create temp - with `#' - */ - if (table->s->table_name[0] == '#') - continue; - else + TABLE *prev_sorted /* same as for prev_table */, *sorted; + if (is_user_table(table)) { - found_user_tables = 1; - } - for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table; - prev_sorted= sorted, sorted= sorted->next) - { - if (sorted->s->table_name[0] == '#' || tmpkeyval(thd, sorted) > tmpkeyval(thd, table)) + if (!found_user_tables) + found_user_tables= true; + for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table; + prev_sorted= sorted, sorted= sorted->next) { - /* move into the sorted part of the list from the unsorted */ - prev_table->next= table->next; - table->next= sorted; - if (prev_sorted) + if (!is_user_table(sorted) || + tmpkeyval(thd, sorted) > tmpkeyval(thd, table)) { - prev_sorted->next= table; + /* move into the sorted part of the list from the unsorted */ + prev_table->next= table->next; + table->next= sorted; + if (prev_sorted) + { + prev_sorted->next= table; + } + else + { + thd->temporary_tables= table; + } + table= prev_table; + break; } - else - { - thd->temporary_tables= table; - } - table= prev_table; - break; } } - } - /* - calc query_buf_size as max per sublists, one sublist per pseudo thread id. - Also stop at first occurence of `#'-named table that starts - all implicitly created temp tables - */ - for (max_names_len= 0, table=thd->temporary_tables; - table && table->s->table_name[0] != '#'; - table=table->next) - { - uint tmp_names_len; - for (tmp_names_len= table->s->key_length + 1; - table->next && table->s->table_name[0] != '#' && - tmpkeyval(thd, table) == tmpkeyval(thd, table->next); - table=table->next) - { - /* - We are going to add 4 ` around the db/table names, so 1 might not look - enough; indeed it is enough, because table->key_length is greater (by 8, - because of server_id and thread_id) than db||table. - */ - tmp_names_len += table->next->s->key_length + 1; - } - if (tmp_names_len > max_names_len) max_names_len= tmp_names_len; } - - /* allocate */ - if (found_user_tables && mysql_bin_log.is_open() && - (query = alloc_root(thd->mem_root, query_buf_size+= max_names_len))) - // Better add "if exists", in case a RESET MASTER has been done - end= strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS "); + + /* We always quote db,table names though it is slight overkill */ + if (found_user_tables && + !(was_quote_show= (thd->options & OPTION_QUOTE_SHOW_CREATE))) + { + thd->options |= OPTION_QUOTE_SHOW_CREATE; + } /* scan sorted tmps to generate sequence of DROP */ - for (table=thd->temporary_tables; table; table= next) + for (table= thd->temporary_tables; table; table= next) { - if (query // we might be out of memory, but this is not fatal - && table->s->table_name[0] != '#') + if (is_user_table(table)) { - char *end_cur; /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); /* Loop forward through all tables within the sublist of common pseudo_thread_id to create single DROP query */ - for (end_cur= end; - table && table->s->table_name[0] != '#' && + for (s_query.length(stub_len); + table && is_user_table(table) && tmpkeyval(thd, table) == thd->variables.pseudo_thread_id; table= next) { - end_cur= strxmov(end_cur, "`", table->s->db, "`.`", - table->s->table_name, "`,", NullS); + /* + We are going to add 4 ` around the db/table names and possible more + due to special characters in the names + */ + append_identifier(thd, &s_query, table->s->db, strlen(table->s->db)); + s_query.q_append('.'); + append_identifier(thd, &s_query, table->s->table_name, + strlen(table->s->table_name)); + s_query.q_append(','); next= table->next; close_temporary(table, 1); } thd->clear_error(); - /* The -1 is to remove last ',' */ - Query_log_event qinfo(thd, query, (ulong)(end_cur - query) - 1, 0, FALSE); + CHARSET_INFO *cs_save= thd->variables.character_set_client; + thd->variables.character_set_client= system_charset_info; + Query_log_event qinfo(thd, s_query.ptr(), + s_query.length() - 1 /* to remove trailing ',' */, + 0, FALSE); + thd->variables.character_set_client= cs_save; /* Imagine the thread had created a temp table, then was doing a SELECT, and the SELECT was killed. Then it's not clever to mark the statement above as @@ -741,12 +733,14 @@ void close_temporary_tables(THD *thd) qinfo.error_code= 0; mysql_bin_log.write(&qinfo); } - else + else { next= table->next; close_temporary(table, 1); } } + if (!was_quote_show) + thd->options &= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */ thd->temporary_tables=0; } @@ -1160,6 +1154,8 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) MYSQL_LOCK_IGNORE_FLUSH - Open table even if someone has done a flush or namelock on it. No version number checking is done. + MYSQL_OPEN_IGNORE_LOCKED_TABLES - Open table + ignoring set of locked tables and prelocked mode. IMPLEMENTATION Uses a cache of open tables to find a table not in use. @@ -1219,7 +1215,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, } } - if (thd->locked_tables || thd->prelocked_mode) + if (!(flags & MYSQL_OPEN_IGNORE_LOCKED_TABLES) && + (thd->locked_tables || thd->prelocked_mode)) { // Using table locks TABLE *best_table= 0; int best_distance= INT_MIN; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 026c3e0d515..65fd4d3ac19 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1877,7 +1877,7 @@ bool select_dumpvar::send_data(List &items) if ((yy=var_li++)) { if (thd->spcont->set_variable(current_thd, yy->get_var_idx(), - *it.ref())) + it.ref())) DBUG_RETURN(1); } } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 320b8e1df9d..c054499ecd8 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2437,6 +2437,153 @@ bool select_insert::send_eof() CREATE TABLE (SELECT) ... ***************************************************************************/ +/* + Create table from lists of fields and items (or open existing table + with same name). + + SYNOPSIS + create_table_from_items() + thd in Thread object + create_info in Create information (like MAX_ROWS, ENGINE or + temporary table flag) + create_table in Pointer to TABLE_LIST object providing database + and name for table to be created or to be open + extra_fields in/out Initial list of fields for table to be created + keys in List of keys for table to be created + items in List of items which should be used to produce rest + of fields for the table (corresponding fields will + be added to the end of 'extra_fields' list) + lock out Pointer to the MYSQL_LOCK object for table created + (open) will be returned in this parameter. Since + this table is not included in THD::lock caller is + responsible for explicitly unlocking this table. + + NOTES + If 'create_info->options' bitmask has HA_LEX_CREATE_IF_NOT_EXISTS + flag and table with name provided already exists then this function will + simply open existing table. + Also note that create, open and lock sequence in this function is not + atomic and thus contains gap for deadlock and can cause other troubles. + Since this function contains some logic specific to CREATE TABLE ... SELECT + it should be changed before it can be used in other contexts. + + RETURN VALUES + non-zero Pointer to TABLE object for table created or opened + 0 Error +*/ + +static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, + TABLE_LIST *create_table, + List *extra_fields, + List *keys, List *items, + MYSQL_LOCK **lock) +{ + TABLE tmp_table; // Used during 'create_field()' + TABLE *table= 0; + uint select_field_count= items->elements; + /* Add selected items to field list */ + List_iterator_fast it(*items); + Item *item; + Field *tmp_field; + bool not_used; + DBUG_ENTER("create_table_from_items"); + + tmp_table.alias= 0; + tmp_table.timestamp_field= 0; + tmp_table.s= &tmp_table.share_not_to_be_used; + tmp_table.s->db_create_options=0; + tmp_table.s->blob_ptr_size= portable_sizeof_char_ptr; + tmp_table.s->db_low_byte_first= test(create_info->db_type == DB_TYPE_MYISAM || + create_info->db_type == DB_TYPE_HEAP); + tmp_table.null_row=tmp_table.maybe_null=0; + + while ((item=it++)) + { + create_field *cr_field; + Field *field; + if (item->type() == Item::FUNC_ITEM) + field=item->tmp_table_field(&tmp_table); + else + field=create_tmp_field(thd, &tmp_table, item, item->type(), + (Item ***) 0, &tmp_field, 0, 0, 0, 0, 0); + if (!field || + !(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ? + ((Item_field *)item)->field : + (Field*) 0)))) + DBUG_RETURN(0); + if (item->maybe_null) + cr_field->flags &= ~NOT_NULL_FLAG; + extra_fields->push_back(cr_field); + } + /* + create and lock table + + We don't log the statement, it will be logged later. + + If this is a HEAP table, the automatic DELETE FROM which is written to the + binlog when a HEAP table is opened for the first time since startup, must + not be written: 1) it would be wrong (imagine we're in CREATE SELECT: we + don't want to delete from it) 2) it would be written before the CREATE + TABLE, which is a wrong order. So we keep binary logging disabled when we + open_table(). + NOTE: By locking table which we just have created (or for which we just have + have found that it already exists) separately from other tables used by the + statement we create potential window for deadlock. + TODO: create and open should be done atomic ! + */ + { + tmp_disable_binlog(thd); + if (!mysql_create_table(thd, create_table->db, create_table->table_name, + create_info, *extra_fields, *keys, 0, + select_field_count)) + { + /* + If we are here in prelocked mode we either create temporary table + or prelocked mode is caused by the SELECT part of this statement. + */ + DBUG_ASSERT(!thd->prelocked_mode || + create_info->options & HA_LEX_CREATE_TMP_TABLE || + thd->lex->requires_prelocking()); + + /* + NOTE: We don't want to ignore set of locked tables here if we are + under explicit LOCK TABLES since it will open gap for deadlock + too wide (and also is not backward compatible). + */ + if (! (table= open_table(thd, create_table, thd->mem_root, (bool*) 0, + (MYSQL_LOCK_IGNORE_FLUSH | + ((thd->prelocked_mode == PRELOCKED) ? + MYSQL_OPEN_IGNORE_LOCKED_TABLES:0))))) + quick_rm_table(create_info->db_type, create_table->db, + table_case_name(create_info, create_table->table_name)); + } + reenable_binlog(thd); + if (!table) // open failed + DBUG_RETURN(0); + } + + /* + FIXME: What happens if trigger manages to be created while we are + obtaining this lock ? May be it is sensible just to disable + trigger execution in this case ? Or will MYSQL_LOCK_IGNORE_FLUSH + save us from that ? + */ + table->reginfo.lock_type=TL_WRITE; + if (! ((*lock)= mysql_lock_tables(thd, &table, 1, + MYSQL_LOCK_IGNORE_FLUSH, ¬_used))) + { + VOID(pthread_mutex_lock(&LOCK_open)); + hash_delete(&open_cache,(byte*) table); + VOID(pthread_mutex_unlock(&LOCK_open)); + quick_rm_table(create_info->db_type, create_table->db, + table_case_name(create_info, create_table->table_name)); + DBUG_RETURN(0); + } + table->file->extra(HA_EXTRA_WRITE_CACHE); + DBUG_RETURN(table); +} + + int select_create::prepare(List &values, SELECT_LEX_UNIT *u) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a8de7ff0154..7d62e5bb405 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5709,6 +5709,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length) } else { + DBUG_ASSERT(thd->net.report_error); DBUG_PRINT("info",("Command aborted. Fatal_error: %d", thd->is_fatal_error)); query_cache_abort(&thd->net); @@ -7226,7 +7227,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, lex->create_info.merge_list.first)) goto err; if (grant_option && want_priv != CREATE_TMP_ACL && - check_grant(thd, want_priv, create_table, 0, UINT_MAX, 0)) + check_grant(thd, want_priv, create_table, 0, 1, 0)) goto err; if (select_lex->item_list.elements) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9eaadc58cb0..32a86b0f39a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1795,105 +1795,6 @@ make_unique_key_name(const char *field_name,KEY *start,KEY *end) } -/**************************************************************************** -** Create table from a list of fields and items -****************************************************************************/ - -TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, - TABLE_LIST *create_table, - List *extra_fields, - List *keys, - List *items, - MYSQL_LOCK **lock) -{ - TABLE tmp_table; // Used during 'create_field()' - TABLE *table= 0; - uint select_field_count= items->elements; - /* Add selected items to field list */ - List_iterator_fast it(*items); - Item *item; - Field *tmp_field; - bool not_used; - DBUG_ENTER("create_table_from_items"); - - tmp_table.alias= 0; - tmp_table.timestamp_field= 0; - tmp_table.s= &tmp_table.share_not_to_be_used; - tmp_table.s->db_create_options=0; - tmp_table.s->blob_ptr_size= portable_sizeof_char_ptr; - tmp_table.s->db_low_byte_first= test(create_info->db_type == DB_TYPE_MYISAM || - create_info->db_type == DB_TYPE_HEAP); - tmp_table.null_row=tmp_table.maybe_null=0; - - while ((item=it++)) - { - create_field *cr_field; - Field *field; - if (item->type() == Item::FUNC_ITEM) - field=item->tmp_table_field(&tmp_table); - else - field=create_tmp_field(thd, &tmp_table, item, item->type(), - (Item ***) 0, &tmp_field, 0, 0, 0, 0, 0); - if (!field || - !(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ? - ((Item_field *)item)->field : - (Field*) 0)))) - DBUG_RETURN(0); - if (item->maybe_null) - cr_field->flags &= ~NOT_NULL_FLAG; - extra_fields->push_back(cr_field); - } - /* - create and lock table - - We don't log the statement, it will be logged later. - - If this is a HEAP table, the automatic DELETE FROM which is written to the - binlog when a HEAP table is opened for the first time since startup, must - not be written: 1) it would be wrong (imagine we're in CREATE SELECT: we - don't want to delete from it) 2) it would be written before the CREATE - TABLE, which is a wrong order. So we keep binary logging disabled when we - open_table(). - TODO: create and open should be done atomic ! - */ - { - tmp_disable_binlog(thd); - if (!mysql_create_table(thd, create_table->db, create_table->table_name, - create_info, *extra_fields, *keys, 0, - select_field_count)) - { - if (! (table= open_table(thd, create_table, thd->mem_root, (bool*) 0, - MYSQL_LOCK_IGNORE_FLUSH))) - quick_rm_table(create_info->db_type, create_table->db, - table_case_name(create_info, create_table->table_name)); - } - reenable_binlog(thd); - if (!table) // open failed - DBUG_RETURN(0); - } - - /* - FIXME: What happens if trigger manages to be created while we are - obtaining this lock ? May be it is sensible just to disable - trigger execution in this case ? Or will MYSQL_LOCK_IGNORE_FLUSH - save us from that ? - */ - table->reginfo.lock_type=TL_WRITE; - if (! ((*lock)= mysql_lock_tables(thd, &table, 1, - MYSQL_LOCK_IGNORE_FLUSH, ¬_used))) - { - VOID(pthread_mutex_lock(&LOCK_open)); - hash_delete(&open_cache,(byte*) table); - VOID(pthread_mutex_unlock(&LOCK_open)); - quick_rm_table(create_info->db_type, create_table->db, - table_case_name(create_info, create_table->table_name)); - DBUG_RETURN(0); - } - table->file->extra(HA_EXTRA_WRITE_CACHE); - DBUG_RETURN(table); -} - - /**************************************************************************** ** Alter a table definition ****************************************************************************/ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6473163a6ec..b2dbc517fa4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -448,6 +448,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token NUMERIC_SYM %token NVARCHAR_SYM %token OFFSET_SYM +%token OJ_SYM %token OLD_PASSWORD %token ON %token ONE_SHOT_SYM @@ -5246,11 +5247,14 @@ table_factor: } expr '}' { + LEX *lex= Lex; YYERROR_UNLESS($3 && $7); add_join_on($7,$10); Lex->pop_context(); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; + if (!($$= lex->current_select->nest_last_join(lex->thd))) + YYABORT; } | select_derived_init get_select_lex select_derived2 { @@ -5795,7 +5799,11 @@ select_var_ident: if (lex->result) ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($2,0,0,(enum_field_types)0)); else - YYABORT; + /* + The parser won't create select_result instance only + if it's an EXPLAIN. + */ + DBUG_ASSERT(lex->describe); } | ident_or_text { @@ -5807,10 +5815,8 @@ select_var_ident: my_error(ER_SP_UNDECLARED_VAR, MYF(0), $1.str); YYABORT; } - if (! lex->result) - YYABORT; - else - { + if (lex->result) + { my_var *var; ((select_dumpvar *)lex->result)-> var_list.push_back(var= new my_var($1,1,t->offset,t->type)); @@ -5818,6 +5824,14 @@ select_var_ident: if (var) var->sp= lex->sphead; #endif + } + else + { + /* + The parser won't create select_result instance only + if it's an EXPLAIN. + */ + DBUG_ASSERT(lex->describe); } } ; @@ -7206,12 +7220,18 @@ simple_ident_q: YYABORT; } + DBUG_ASSERT(!new_row || + (lex->trg_chistics.event == TRG_EVENT_INSERT || + lex->trg_chistics.event == TRG_EVENT_UPDATE)); + const bool read_only= + !(new_row && lex->trg_chistics.action_time == TRG_ACTION_BEFORE); if (!(trg_fld= new Item_trigger_field(Lex->current_context(), new_row ? Item_trigger_field::NEW_ROW: Item_trigger_field::OLD_ROW, $3.str, - Item_trigger_field::AT_READ))) + SELECT_ACL, + read_only))) YYABORT; /* @@ -7847,11 +7867,13 @@ sys_option_value: it= new Item_null(); } + DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE && + (lex->trg_chistics.event == TRG_EVENT_INSERT || + lex->trg_chistics.event == TRG_EVENT_UPDATE)); if (!(trg_fld= new Item_trigger_field(Lex->current_context(), Item_trigger_field::NEW_ROW, $2.base_name.str, - Item_trigger_field::AT_UPDATE) - ) || + UPDATE_ACL, FALSE)) || !(sp_fld= new sp_instr_set_trigger_field(lex->sphead-> instructions(), lex->spcont,