diff options
272 files changed, 7359 insertions, 3050 deletions
diff --git a/.bzrignore b/.bzrignore index 920522c7592..e9de6662cb2 100644 --- a/.bzrignore +++ b/.bzrignore @@ -420,6 +420,7 @@ libmysqld/sql_unions.cc libmysqld/sql_update.cc libmysqld/sql_yacc.cc libmysqld/stacktrace.c +libmysqld/strfunc.cc libmysqld/table.cc libmysqld/thr_malloc.cc libmysqld/time.cc diff --git a/BUILD/compile-pentium-gcov b/BUILD/compile-pentium-gcov index 05cb0bb0d78..dc4ddcb1090 100755 --- a/BUILD/compile-pentium-gcov +++ b/BUILD/compile-pentium-gcov @@ -3,7 +3,7 @@ path=`dirname $0` . "$path/SETUP.sh" -extra_flags="$pentium_cflags -fprofile-arcs -ftest-coverage" +extra_flags="$pentium_cflags -fprofile-arcs -ftest-coverage -fmessage-length=0 " extra_configs="$pentium_configs $debug_configs --disable-shared $static_link" extra_configs="$extra_configs --with-innodb --with-berkeley-db" diff --git a/BUILD/compile-pentium-valgrind-max b/BUILD/compile-pentium-valgrind-max index f47061b95dd..2e739ce9607 100755 --- a/BUILD/compile-pentium-valgrind-max +++ b/BUILD/compile-pentium-valgrind-max @@ -14,6 +14,7 @@ extra_configs="$extra_configs --with-berkeley-db --with-innodb --without-isam -- if test -z "$just_print" then + set +v +x echo "\ ****************************************************************************** Note that by default BUILD/compile-pentium-valgrind-max calls 'configure' with diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 9fa17da17a1..00084b365f5 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -100,6 +100,7 @@ peter@linux.local peter@mysql.com peterg@mysql.com pgulutzan@linux.local +ram@deer.(none) ram@gw.mysql.r18.ru ram@gw.udmsearch.izhnet.ru ram@mysql.r18.ru diff --git a/BitKeeper/triggers/post-commit b/BitKeeper/triggers/post-commit index a2a0ecb2701..b0d70c85661 100755 --- a/BitKeeper/triggers/post-commit +++ b/BitKeeper/triggers/post-commit @@ -19,7 +19,7 @@ BK_STATUS=$BK_STATUS$BK_COMMIT if [ "$BK_STATUS" = OK ] then -CHANGESET=`bk -R prs -r+ -h -d':I:' ChangeSet` +CHANGESET=`bk -R prs -r+ -h -d':P:::I:' ChangeSet` #++ # dev-public@ diff --git a/VC++Files/libmysqld/libmysqld.dsp b/VC++Files/libmysqld/libmysqld.dsp index 593c53a57ba..953761be297 100644 --- a/VC++Files/libmysqld/libmysqld.dsp +++ b/VC++Files/libmysqld/libmysqld.dsp @@ -446,6 +446,10 @@ SOURCE=..\strings\strcont.c # End Source File # Begin Source File +SOURCE=..\sql\strfunc.cpp +# End Source File +# Begin Source File + SOURCE=..\strings\strinstr.c # End Source File # Begin Source File diff --git a/VC++Files/mysys/mysys.dsp b/VC++Files/mysys/mysys.dsp index 9f7a6bbf2e9..533d4212e2b 100644 --- a/VC++Files/mysys/mysys.dsp +++ b/VC++Files/mysys/mysys.dsp @@ -430,6 +430,10 @@ SOURCE=.\my_symlink2.c # End Source File # Begin Source File +SOURCE=.\my_sync.c +# End Source File +# Begin Source File + SOURCE=.\my_tempnam.c # End Source File # Begin Source File diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp index f8724fb0b06..b8413a9a7ae 100644 --- a/VC++Files/sql/mysqld.dsp +++ b/VC++Files/sql/mysqld.dsp @@ -1253,6 +1253,26 @@ SOURCE=.\sql_yacc.cpp # End Source File # Begin Source File +SOURCE=.\strfunc.cpp + +!IF "$(CFG)" == "mysqld - Win32 Release" + +!ELSEIF "$(CFG)" == "mysqld - Win32 Debug" + +# ADD CPP /G5 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "mysqld - Win32 nt" + +!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt" + +!ELSEIF "$(CFG)" == "mysqld - Win32 Max" + +!ENDIF + +# End Source File +# Begin Source File + SOURCE=.\table.cpp # End Source File # Begin Source File diff --git a/VC++Files/sql/mysqldmax.dsp b/VC++Files/sql/mysqldmax.dsp index 24ea83159d9..a7ed1b918c7 100644 --- a/VC++Files/sql/mysqldmax.dsp +++ b/VC++Files/sql/mysqldmax.dsp @@ -945,6 +945,22 @@ SOURCE=.\sql_yacc.cpp # End Source File # Begin Source File +SOURCE=.\strfunc.cpp + +!IF "$(CFG)" == "mysqldmax - Win32 Release" + +!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug" + +# ADD CPP /G5 +# SUBTRACT CPP /YX /Yc /Yu + +!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt" + +!ENDIF + +# End Source File +# Begin Source File + SOURCE=.\table.cpp # End Source File # Begin Source File diff --git a/VC++Files/strings/strings.dsp b/VC++Files/strings/strings.dsp index 038f460771d..4e43cc875c8 100644 --- a/VC++Files/strings/strings.dsp +++ b/VC++Files/strings/strings.dsp @@ -188,6 +188,10 @@ SOURCE=.\longlong2str.c # End Source File # Begin Source File +SOURCE=.\my_strtoll10.c +# End Source File +# Begin Source File + SOURCE=.\my_vsnprintf.c # End Source File # Begin Source File diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 68b7da78bbf..f870c92cb6d 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -52,7 +52,7 @@ static const char* host = 0; static int port = MYSQL_PORT; static const char* sock= 0; static const char* user = 0; -static const char* pass = ""; +static char* pass = 0; static ulonglong position = 0; static short binlog_flags = 0; static MYSQL* mysql = NULL; @@ -226,7 +226,7 @@ static struct my_option my_long_options[] = {"offset", 'o', "Skip the first N entries.", (gptr*) &offset, (gptr*) &offset, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to connect to remote server.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Use port to connect to the remote server.", (gptr*) &port, (gptr*) &port, 0, GET_INT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, @@ -266,6 +266,11 @@ void sql_print_error(const char *format,...) va_end(args); } +static void cleanup() +{ + my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); +} + static void die(const char* fmt, ...) { va_list args; @@ -274,6 +279,7 @@ static void die(const char* fmt, ...) vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); va_end(args); + cleanup(); exit(1); } @@ -333,6 +339,7 @@ extern "C" my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) { + bool tty_password=0; switch (optid) { #ifndef DBUG_OFF case '#': @@ -343,7 +350,17 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), one_database = 1; break; case 'p': - pass = my_strdup(argument, MYF(0)); + if (argument) + { + my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); + char *start=argument; + pass= my_strdup(argument,MYF(MY_FAE)); + while (*argument) *argument++= 'x'; /* Destroy argument */ + if (*start) + start[1]=0; /* Cut length of argument */ + } + else + tty_password=1; break; case 'r': if (!(result_file = my_fopen(argument, O_WRONLY | O_BINARY, MYF(MY_WME)))) @@ -359,6 +376,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), usage(); exit(0); } + if (tty_password) + pass= get_tty_password(NullS); + return 0; } @@ -707,6 +727,7 @@ int main(int argc, char** argv) my_fclose(result_file, MYF(0)); if (remote_opt) mysql_close(mysql); + cleanup(); free_defaults(defaults_argv); my_end(0); return 0; diff --git a/client/mysqldump.c b/client/mysqldump.c index 84c1c53b313..31305c93e6c 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -68,13 +68,6 @@ /* Size of buffer for dump's select query */ #define QUERY_LENGTH 1536 -#define print_xml_tag(out_file, sbeg, sval, send) \ -{ \ - fputs(sbeg, out_file); \ - print_quoted_xml(out_file, sval, 0); \ - fputs(send, out_file); \ -} - static char *add_load_option(char *ptr, const char *object, const char *statement); static ulong find_set(TYPELIB *lib, const char *x, uint length, @@ -305,7 +298,6 @@ static int init_dumping(char *); static int dump_databases(char **); static int dump_all_databases(); static char *quote_name(const char *name, char *buff, my_bool force); -static void print_quoted_xml(FILE *output, char *str, ulong len); static void print_version(void) { @@ -640,6 +632,7 @@ static my_bool test_if_special_chars(const char *str) } /* test_if_special_chars */ + static char *quote_name(const char *name, char *buff, my_bool force) { char *to= buff; @@ -658,8 +651,98 @@ static char *quote_name(const char *name, char *buff, my_bool force) } /* quote_name */ -void print_xml_row(FILE *xml_file, const char *row_name, MYSQL_RES *tableRes, - MYSQL_ROW *row) +/* + Quote and print a string. + + SYNOPSIS + print_quoted_xml() + output - output file + str - string to print + len - its length + + DESCRIPTION + Quote '<' '>' '&' '\"' singns and print a string to the xml_file. +*/ + +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) { + case '<': + fputs("<", xml_file); + break; + case '>': + fputs(">", xml_file); + break; + case '&': + fputs("&", xml_file); + break; + case '\"': + fputs(""", xml_file); + break; + default: + fputc(*str, xml_file); + break; + } + } +} + + +/* + 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 + + DESCRIPTION + Print tag with one attribute to the xml_file. Format is: + sbeg<stag_atr="sval">send + NOTE + sval MUST be a NULL terminated string. + sval string will be qouted before output. +*/ + +static void print_xml_tag1(FILE * xml_file, const char* sbeg, + const char* stag_atr, const char* sval, + const char* send) +{ + fputs(sbeg, xml_file); + fputs("<", xml_file); + fputs(stag_atr, xml_file); + fputs("\"", xml_file); + print_quoted_xml(xml_file, sval, strlen(sval)); + fputs("\">", xml_file); + fputs(send, xml_file); +} + + +/* + Print xml tag with many attributes. + + SYNOPSIS + print_xml_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<row_name Atr1="Val1" Atr2="Val2"... /> + NOTE + All atributes and values will be quoted before output. +*/ + +static void print_xml_row(FILE *xml_file, const char *row_name, + MYSQL_RES *tableRes, MYSQL_ROW *row) { uint i; MYSQL_FIELD *field; @@ -669,10 +752,10 @@ void print_xml_row(FILE *xml_file, const char *row_name, MYSQL_RES *tableRes, mysql_field_seek(tableRes, 0); for (i= 0; (field= mysql_fetch_field(tableRes)); i++) { - if ((*row)[i] && (*row)[i][0]) + if ((*row)[i]) { fputs(" ", xml_file); - print_quoted_xml(xml_file, field->name, 0); + print_quoted_xml(xml_file, field->name, field->name_length); fputs("=\"", xml_file); print_quoted_xml(xml_file, (*row)[i], lengths[i]); fputs("\"", xml_file); @@ -707,7 +790,8 @@ static uint getTableStructure(char *table, char* db) if (verbose) fprintf(stderr, "-- Retrieving table structure for table %s...\n", table); - sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d", (opt_quoted || opt_keywords)); + sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d", + (opt_quoted || opt_keywords)); result_table= quote_name(table, table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); if (!opt_xml && !mysql_query(sock,insert_pat)) @@ -849,7 +933,7 @@ static uint getTableStructure(char *table, char* db) if (!opt_xml) fprintf(sql_file, "CREATE TABLE %s (\n", result_table); else - print_xml_tag(sql_file, "\t<table_structure name=\"", table, "\">\n"); + print_xml_tag1(sql_file, "\t", "table_structure name=", table, "\n"); } if (cFlag) sprintf(insert_pat, "INSERT %sINTO %s (", delayed, result_table); @@ -959,7 +1043,8 @@ static uint getTableStructure(char *table, char* db) 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)); + fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff, + 0)); } else putc(',', sql_file); @@ -1192,9 +1277,7 @@ static void dumpTable(uint numFields, char *table) rownr=0; init_length=(uint) strlen(insert_pat)+4; if (opt_xml) - { - print_xml_tag(md_result_file, "\t<table_data name=\"", table, "\">\n"); - } + print_xml_tag1(md_result_file, "\t", "table_data name=", table, "\n"); if (opt_autocommit) fprintf(md_result_file, "set autocommit=0;\n"); @@ -1275,8 +1358,8 @@ static void dumpTable(uint numFields, char *table) { if (opt_xml) { - print_xml_tag(md_result_file, "\t\t<field name=\"", field->name, - "\">"); + print_xml_tag1(md_result_file, "\t\t", "field name=", + field->name, ""); print_quoted_xml(md_result_file, row[i], lengths[i]); fputs("</field>\n", md_result_file); } @@ -1289,8 +1372,8 @@ static void dumpTable(uint numFields, char *table) char *ptr = row[i]; if (opt_xml) { - print_xml_tag(md_result_file, "\t\t<field name=\"", field->name, - "\">"); + print_xml_tag1(md_result_file, "\t\t", "field name=", + field->name, ""); fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL", md_result_file); fputs("</field>\n", md_result_file); @@ -1303,10 +1386,8 @@ static void dumpTable(uint numFields, char *table) else { if (opt_xml) - { - print_xml_tag(md_result_file, "\t\t<field name=\"", field->name, - "\">NULL</field>\n"); - } + print_xml_tag1(md_result_file, "\t\t", "field name=", + field->name, "NULL</field>\n"); else fputs("NULL", md_result_file); } @@ -1372,32 +1453,6 @@ static void dumpTable(uint numFields, char *table) } /* dumpTable */ -static void print_quoted_xml(FILE *output, char *str, ulong len) -{ - const char *end= str + (len ? len : strlen(str)); - - for (; str != end; str++) - { - switch (*str) { - case '<': - fputs("<", output); - break; - case '>': - fputs(">", output); - break; - case '&': - fputs("&", output); - break; - case '\"': - fputs(""", output); - break; - default: - fputc(*str, output); - break; - } - } -} - static char *getTableName(int reset) { static MYSQL_RES *res = NULL; @@ -1468,23 +1523,28 @@ static int init_dumping(char *database) { if (opt_databases || opt_alldbs) { - fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", database); + /* + length of table name * 2 (if name contain quotas), 2 quotas and 0 + */ + char quoted_database_buf[64*2+3]; + char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted); + + fprintf(md_result_file,"\n--\n-- Current Database: %s\n--\n", qdatabase); if (!opt_create_db) { - char qbuf[128]; + char qbuf[256]; MYSQL_ROW row; MYSQL_RES *dbinfo; - sprintf(qbuf,"SHOW CREATE DATABASE WITH IF NOT EXISTS %s",database); + sprintf(qbuf,"SHOW CREATE DATABASE WITH IF NOT EXISTS %s", + qdatabase); if (mysql_query(sock, qbuf) || !(dbinfo = mysql_store_result(sock))) { /* Old server version, dump generic CREATE DATABASE */ fprintf(md_result_file, - "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s%s%s;\n", - (opt_quoted ? "`" : ""), - database, - (opt_quoted ? "`" : "")); + "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n", + qdatabase); } else { @@ -1495,18 +1555,16 @@ static int init_dumping(char *database) } } } - fprintf(md_result_file,"\nUSE %s%s%s;\n", (opt_quoted ? "`" : ""), - database, - (opt_quoted ? "`" : "")); + fprintf(md_result_file,"\nUSE %s;\n", qdatabase); } } - if (extended_insert) - if (init_dynamic_string(&extended_row, "", 1024, 1024)) - exit(EX_EOM); + if (extended_insert && init_dynamic_string(&extended_row, "", 1024, 1024)) + exit(EX_EOM); return 0; } /* init_dumping */ + static int dump_all_tables_in_db(char *database) { char *table; @@ -1516,9 +1574,7 @@ static int dump_all_tables_in_db(char *database) if (init_dumping(database)) return 1; if (opt_xml) - { - print_xml_tag(md_result_file, "<database name=\"", database, "\">\n"); - } + print_xml_tag1(md_result_file, "", "database name=", database, "\n"); if (lock_tables) { DYNAMIC_STRING query; @@ -1584,9 +1640,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) /* We shall countinue here, if --force was given */ } if (opt_xml) - { - print_xml_tag(md_result_file, "<database name=\"", db, "\">\n"); - } + print_xml_tag1(md_result_file, "", "database name=", db, "\n"); for (; tables > 0 ; tables-- , table_names++) { numrows = getTableStructure(*table_names, db); diff --git a/configure.in b/configure.in index 207404a89c5..4b930b45f04 100644 --- a/configure.in +++ b/configure.in @@ -731,7 +731,7 @@ AC_CHECK_HEADERS(fcntl.h float.h floatingpoint.h ieeefp.h limits.h \ strings.h string.h synch.h sys/mman.h sys/socket.h netinet/in.h arpa/inet.h \ sys/timeb.h sys/types.h sys/un.h sys/vadvise.h sys/wait.h term.h \ unistd.h utime.h sys/utime.h termio.h termios.h sched.h crypt.h alloca.h \ - sys/ioctl.h) + sys/ioctl.h malloc.h sys/malloc.h) #-------------------------------------------------------------------- # Check for system libraries. Adds the library to $LIBS @@ -1832,7 +1832,7 @@ AC_CHECK_FUNCS(alarm bmove \ pthread_attr_create pthread_getsequence_np pthread_attr_setstacksize \ pthread_attr_getstacksize \ pthread_condattr_create rwlock_init pthread_rwlock_rdlock \ - fchmod getpass getpassphrase initgroups mlockall) + fsync fdatasync fchmod getpass getpassphrase initgroups mlockall) CFLAGS="$ORG_CFLAGS" diff --git a/extra/resolveip.c b/extra/resolveip.c index 12e6977c2ba..f8cff2a976c 100644 --- a/extra/resolveip.c +++ b/extra/resolveip.c @@ -36,10 +36,6 @@ extern int h_errno; #endif -#ifndef HAVE_IN_ADDR_T -#define in_addr_t ulong -#endif - static my_bool silent; static struct my_option my_long_options[] = diff --git a/include/config-win.h b/include/config-win.h index 884b2edfb63..4fdbfbbd02f 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -183,8 +183,8 @@ inline double rint(double nr) } #ifdef _WIN64 -#define ulonglong2double(A) ((double) (A)) -#define my_off_t2double(A) ((double) (A)) +#define ulonglong2double(A) ((double) (ulonglong) (A)) +#define my_off_t2double(A) ((double) (my_off_t) (A)) #else inline double ulonglong2double(ulonglong value) diff --git a/include/m_ctype.h b/include/m_ctype.h index a896afe750a..e2b2f7f1668 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -86,7 +86,7 @@ enum my_lex_states { MY_LEX_START, MY_LEX_CHAR, MY_LEX_IDENT, MY_LEX_IDENT_SEP, MY_LEX_IDENT_START, - MY_LEX_FOUND_IDENT, MY_LEX_REAL, MY_LEX_HEX_NUMBER, + MY_LEX_REAL, MY_LEX_HEX_NUMBER, MY_LEX_CMP_OP, MY_LEX_LONG_CMP_OP, MY_LEX_STRING, MY_LEX_COMMENT, MY_LEX_END, MY_LEX_OPERATOR_OR_IDENT, MY_LEX_NUMBER_IDENT, MY_LEX_INT_OR_REAL, MY_LEX_REAL_OR_POINT, MY_LEX_BOOL, MY_LEX_EOL, MY_LEX_ESCAPE, diff --git a/include/m_string.h b/include/m_string.h index 062d0b4cf65..d72342fb3c1 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -232,6 +232,7 @@ extern char *int2str(long val,char *dst,int radix); extern char *int10_to_str(long val,char *dst,int radix); extern char *str2int(const char *src,int radix,long lower,long upper, long *val); +longlong my_strtoll10(const char *nptr, char **endptr, int *error); #if SIZEOF_LONG == SIZEOF_LONG_LONG #define longlong2str(A,B,C) int2str((A),(B),(C)) #define longlong10_to_str(A,B,C) int10_to_str((A),(B),(C)) diff --git a/include/my_global.h b/include/my_global.h index 73287a2ba2a..43cacf8fa65 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -594,8 +594,8 @@ extern double my_atof(const char*); #define closesocket(A) close(A) #endif #ifndef ulonglong2double -#define ulonglong2double(A) ((double) (A)) -#define my_off_t2double(A) ((double) (A)) +#define ulonglong2double(A) ((double) (ulonglong) (A)) +#define my_off_t2double(A) ((double) (my_off_t) (A)) #endif #endif diff --git a/include/my_net.h b/include/my_net.h index 28d862d8528..7b42afa1f3a 100644 --- a/include/my_net.h +++ b/include/my_net.h @@ -63,6 +63,15 @@ C_MODE_START #define O_NONBLOCK 1 /* For emulation of fcntl() */ #endif +/* + On OSes which don't have the in_addr_t, we guess that using uint32 is the best + possible choice. We guess this from the fact that on HP-UX64bit & FreeBSD64bit + & Solaris64bit, in_addr_t is equivalent to uint32. And on Linux32bit too. +*/ +#ifndef HAVE_IN_ADDR_T +#define in_addr_t uint32 +#endif + /* Thread safe or portable version of some functions */ void my_inet_ntoa(struct in_addr in, char *buf); diff --git a/include/my_pthread.h b/include/my_pthread.h index 424452a9298..a4ea88b20f0 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -645,6 +645,7 @@ struct st_my_thread_var long id; int cmp_length; int volatile abort; + my_bool init; struct st_my_thread_var *next,**prev; void *opt_info; #ifndef DBUG_OFF @@ -669,8 +670,6 @@ extern pthread_t shutdown_th, main_th, signal_th; #define thread_safe_increment(V,L) atomic_add(1,(atomic_t*) &V); #define thread_safe_add(V,C,L) atomic_add((C),(atomic_t*) &V); #define thread_safe_sub(V,C,L) atomic_sub((C),(atomic_t*) &V); -#define statistic_increment(V,L) thread_safe_increment((V),(L)) -#define statistic_add(V,C,L) thread_safe_add((V),(C),(L)) #else #define thread_safe_increment(V,L) \ pthread_mutex_lock((L)); (V)++; pthread_mutex_unlock((L)); @@ -678,6 +677,7 @@ extern pthread_t shutdown_th, main_th, signal_th; pthread_mutex_lock((L)); (V)+=(C); pthread_mutex_unlock((L)); #define thread_safe_sub(V,C,L) \ pthread_mutex_lock((L)); (V)-=(C); pthread_mutex_unlock((L)); +#endif /* HAVE_ATOMIC_ADD */ #ifdef SAFE_STATISTICS #define statistic_increment(V,L) thread_safe_increment((V),(L)) #define statistic_add(V,C,L) thread_safe_add((V),(C),(L)) @@ -685,7 +685,6 @@ extern pthread_t shutdown_th, main_th, signal_th; #define statistic_increment(V,L) (V)++ #define statistic_add(V,C,L) (V)+=(C) #endif /* SAFE_STATISTICS */ -#endif /* HAVE_ATOMIC_ADD */ #endif /* thread_safe_increment */ #ifdef __cplusplus diff --git a/include/my_sys.h b/include/my_sys.h index c404e54c2a9..6082b988822 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -614,6 +614,7 @@ extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags); extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags); extern int my_fclose(FILE *fd,myf MyFlags); extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags); +extern int my_sync(File fd, myf my_flags); extern int my_error _VARARGS((int nr,myf MyFlags, ...)); extern int my_printf_error _VARARGS((uint my_err, const char *format, myf MyFlags, ...) diff --git a/include/mysql_com.h b/include/mysql_com.h index be8db185737..f4b6114c8d4 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -33,7 +33,7 @@ #if defined(__WIN__) && !defined( _CUSTOMCONFIG_) #define MYSQL_NAMEDPIPE "MySQL" -#define MYSQL_SERVICENAME "MySql" +#define MYSQL_SERVICENAME "MySQL" #endif /* __WIN__ */ enum enum_server_command diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 60204349de2..91b10ab578a 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -295,7 +295,12 @@ #define ER_BAD_SLAVE_UNTIL_COND 1276 #define ER_MISSING_SKIP_SLAVE 1277 #define ER_UNTIL_COND_IGNORED 1278 -#define ER_WRONG_INDEX_NAME 1279 -#define ER_WARN_QC_RESIZE 1280 -#define ER_BAD_FT_COLUMN 1281 -#define ER_ERROR_MESSAGES 282 +#define ER_WRONG_NAME 1279 +#define ER_TABLE 1280 +#define ER_DATABASE 1281 +#define ER_COLUMN 1282 +#define ER_INDEX 1283 +#define ER_CATALOG 1284 +#define ER_WARN_QC_RESIZE 1285 +#define ER_BAD_FT_COLUMN 1286 +#define ER_ERROR_MESSAGES 287 diff --git a/include/mysys_err.h b/include/mysys_err.h index a86765c74fd..0ee89e91ee4 100644 --- a/include/mysys_err.h +++ b/include/mysys_err.h @@ -21,7 +21,7 @@ extern "C" { #endif #define GLOB 0 /* Error maps */ -#define GLOBERRS 27 /* Max number of error messages in map's */ +#define GLOBERRS 28 /* Max number of error messages in map's */ #define EE(X) globerrs[ X ] /* Defines to add error to right map */ extern const char * NEAR globerrs[]; /* my_error_messages is here */ @@ -53,6 +53,7 @@ extern const char * NEAR globerrs[]; /* my_error_messages is here */ #define EE_CANT_READLINK 24 #define EE_CANT_SYMLINK 25 #define EE_REALPATH 26 +#define EE_SYNC 27 /* exit codes for all MySQL programs */ diff --git a/include/sql_state.h b/include/sql_state.h index 222636d3bec..d55fb137e27 100644 --- a/include/sql_state.h +++ b/include/sql_state.h @@ -159,4 +159,4 @@ ER_WARN_TOO_MANY_RECORDS, "01000", "", ER_WARN_NULL_TO_NOTNULL, "01000", "", ER_WARN_DATA_OUT_OF_RANGE, "01000", "", ER_WARN_DATA_TRUNCATED, "01000", "", -ER_WRONG_INDEX_NAME, "42000", "", +ER_WRONG_NAME, "42000", "", diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index b403cc4df0d..946020acd11 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -297,8 +297,9 @@ buf_page_is_corrupted( ulint old_checksum; ulint checksum_field; ulint old_checksum_field; +#ifndef UNIV_HOTBACKUP dulint current_lsn; - +#endif if (mach_read_from_4(read_buf + FIL_PAGE_LSN + 4) != mach_read_from_4(read_buf + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) { diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c index 9d1ec53645d..a5077252c6a 100644 --- a/innobase/dict/dict0crea.c +++ b/innobase/dict/dict0crea.c @@ -301,9 +301,12 @@ dict_build_table_def_step( - page 2 is the first inode page, - page 3 will contain the root of the clustered index of the table we create here. */ + + table->space = 0; /* reset to zero for the call below */ error = fil_create_new_single_table_tablespace( - &(table->space), table->name, 4); + &(table->space), table->name, + FIL_IBD_FILE_INITIAL_SIZE); if (error != DB_SUCCESS) { return(error); @@ -311,7 +314,7 @@ dict_build_table_def_step( mtr_start(&mtr); - fsp_header_init(table->space, 4, &mtr); + fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr); mtr_commit(&mtr); } diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 9056c974f02..0ae36eec6dc 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -2580,7 +2580,7 @@ dict_create_foreign_constraints_low( sprintf(buf + strlen(buf), " Error in foreign key constraint of table %.500s.\n" "Cannot find the table from the internal data dictionary of InnoDB.\n" -"Create table statement:\n%.2000\n", name, sql_string); +"Create table statement:\n%.2000s\n", name, sql_string); ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); mutex_exit(&dict_foreign_err_mutex); diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index 3b729938ea7..a9ae59fbd50 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -23,7 +23,10 @@ Created 10/25/1995 Heikki Tuuri #include "fsp0fsp.h" #include "srv0srv.h" #include "srv0start.h" +#include "mtr0mtr.h" +#include "mtr0log.h" + /* IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE ============================================= @@ -80,6 +83,10 @@ out of the LRU-list and keep a count of pending operations. When an operation completes, we decrement the count and return the file node to the LRU-list if the count drops to zero. */ +/* When mysqld is run, the default directory "." is the mysqld datadir, +but in ibbackup we must set it explicitly */ +char* fil_path_to_mysql_datadir = (char*)"."; + ulint fil_n_pending_log_flushes = 0; ulint fil_n_pending_tablespace_flushes = 0; @@ -257,6 +264,17 @@ fil_node_complete_io( ulint type); /* in: OS_FILE_WRITE or OS_FILE_READ; marks the node as modified if type == OS_FILE_WRITE */ +/*********************************************************************** +Checks if a single-table tablespace for a given table name exists in the +tablespace memory cache. */ +static +ulint +fil_get_space_id_for_table( +/*=======================*/ + /* out: space id, ULINT_UNDEFINED if not + found */ + char* name); /* in: table name in the standard + 'databasename/tablename' format */ /*********************************************************************** @@ -474,15 +492,18 @@ fil_node_open_file( system->n_open++; if (node->size == 0) { + os_file_get_size(node->handle, &size_low, &size_high); + + size_bytes = (((ib_longlong)size_high) << 32) + + (ib_longlong)size_low; +#ifdef UNIV_HOTBACKUP + node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE); + +#else /* It must be a single-table tablespace and we do not know the size of the file yet */ ut_a(space->id != 0); - - os_file_get_size(node->handle, &size_low, &size_high); - - size_bytes = (((ib_longlong)size_high) << 32) - + (ib_longlong)size_low; if (size_bytes >= FSP_EXTENT_SIZE * UNIV_PAGE_SIZE) { node->size = (ulint) ((size_bytes / (1024 * 1024)) @@ -490,8 +511,8 @@ fil_node_open_file( } else { node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE); } - - space->size = node->size; +#endif + space->size += node->size; } if (space->purpose == FIL_TABLESPACE && space->id != 0) { @@ -516,6 +537,7 @@ fil_node_close_file( ut_a(node->open); ut_a(node->n_pending == 0); ut_a(node->n_pending_flushes == 0); + ut_a(node->modification_counter == node->flush_counter); ret = os_file_close(node->handle); ut_a(ret); @@ -690,12 +712,13 @@ close_more: mutex_exit(&(system->mutex)); +#ifndef UNIV_HOTBACKUP /* Wake the i/o-handler threads to make sure pending i/o's are performed */ os_aio_simulated_wake_handler_threads(); os_thread_sleep(20000); - +#endif /* Flush tablespaces so that we can close modified files in the LRU list */ @@ -722,6 +745,11 @@ fil_node_free( ut_a(node->n_pending == 0); if (node->open) { + /* We fool the assertion in fil_node_close_file() to think + there are no unflushed modifications in the file */ + + node->modification_counter = node->flush_counter; + fil_node_close_file(node, system); } @@ -854,8 +882,7 @@ try_again: space->id = id; system->tablespace_version++; - space->tablespace_version = - system->tablespace_version; + space->tablespace_version = system->tablespace_version; space->mark = FALSE; if (purpose == FIL_TABLESPACE && id > system->max_assigned_id) { @@ -1005,6 +1032,29 @@ fil_space_free( return(TRUE); } +#ifdef UNIV_HOTBACKUP +/*********************************************************************** +Returns the tablespace object for a given id, or NULL if not found from the +tablespace memory cache. */ +static +fil_space_t* +fil_get_space_for_id_low( +/*=====================*/ + /* out: tablespace object or NULL; NOTE that you must + own &(fil_system->mutex) to call this function! */ + ulint id) /* in: space id */ +{ + fil_system_t* system = fil_system; + fil_space_t* space; + + ut_ad(system); + + HASH_SEARCH(hash, system->spaces, id, space, space->id == id); + + return(space); +} +#endif + /*********************************************************************** Returns the size of the space in pages. The tablespace must be cached in the memory cache. */ @@ -1456,6 +1506,225 @@ fil_decr_pending_ibuf_merges( mutex_exit(&(system->mutex)); } +/************************************************************ +Creates the database directory for a table if it does not exist yet. */ +static +void +fil_create_directory_for_tablename( +/*===============================*/ + char* name) /* in: name in the standard 'databasename/tablename' + format */ +{ + char* ptr; + char path[OS_FILE_MAX_PATH]; + + sprintf(path, "%s/%s", fil_path_to_mysql_datadir, name); + + ptr = path + ut_strlen(path); + + while (*ptr != '/') { + ptr--; + + ut_a(ptr >= path); + } + + *ptr = '\0'; + + srv_normalize_path_for_win(path); + + ut_a(os_file_create_directory(path, FALSE)); +} + +#ifndef UNIV_HOTBACKUP +/************************************************************ +Writes a log record about an .ibd file create/rename/delete. */ +static +void +fil_op_write_log( +/*=============*/ + ulint type, /* in: MLOG_FILE_CREATE, MLOG_FILE_DELETE, or + MLOG_FILE_RENAME */ + ulint space_id, /* in: space id */ + char* name, /* in: table name in the familiar + 'databasename/tablename' format, or the file + path in the case of MLOG_FILE_DELETE */ + char* new_name, /* in: if type is MLOG_FILE_RENAME, the new + table name in the 'databasename/tablename' + format */ + mtr_t* mtr) /* in: mini-transaction handle */ +{ + byte* log_ptr; + + log_ptr = mlog_open(mtr, 30); + + log_ptr = mlog_write_initial_log_record_for_file_op(type, space_id, 0, + log_ptr, mtr); + /* Let us store the strings as null-terminated for easier readability + and handling */ + + mach_write_to_2(log_ptr, ut_strlen(name) + 1); + log_ptr += 2; + + mlog_close(mtr, log_ptr); + + mlog_catenate_string(mtr, name, ut_strlen(name) + 1); + + if (type == MLOG_FILE_RENAME) { + log_ptr = mlog_open(mtr, 30); + mach_write_to_2(log_ptr, ut_strlen(new_name) + 1); + log_ptr += 2; + + mlog_close(mtr, log_ptr); + + mlog_catenate_string(mtr, new_name, ut_strlen(new_name) + 1); + } +} +#endif + +/*********************************************************************** +Parses the body of a log record written about an .ibd file operation. That is, +the log record part after the standard (type, space id, page no) header of the +log record. + +If desired, also replays the delete or rename operation if the .ibd file +exists and the space id in it matches. Replays the create operation if a file +at that path does not exist yet. If the database directory for the file to be +created does not exist, then we create the directory, too. + +Note that ibbackup --apply-log sets fil_path_to_mysql_datadir to point to the +datadir that we should use in replaying the file operations. */ + +byte* +fil_op_log_parse_or_replay( +/*=======================*/ + /* out: end of log record, or NULL if the + record was not completely contained between + ptr and end_ptr */ + byte* ptr, /* in: buffer containing the log record body, + or an initial segment of it, if the record does + not fir completely between ptr and end_ptr */ + byte* end_ptr, /* in: buffer end */ + ulint type, /* in: the type of this log record */ + ibool do_replay, /* in: TRUE if we want to replay the + operation, and not just parse the log record */ + ulint space_id) /* in: if do_replay is TRUE, the space id of + the tablespace in question; otherwise + ignored */ +{ + ulint name_len; + ulint new_name_len; + char* name; + char* new_name = NULL; + + if (end_ptr < ptr + 2) { + + return(NULL); + } + + name_len = mach_read_from_2(ptr); + + ptr += 2; + + if (end_ptr < ptr + name_len) { + + return(NULL); + } + + name = ptr; + + ptr += name_len; + + if (type == MLOG_FILE_RENAME) { + if (end_ptr < ptr + 2) { + + return(NULL); + } + + new_name_len = mach_read_from_2(ptr); + + ptr += 2; + + if (end_ptr < ptr + new_name_len) { + + return(NULL); + } + + new_name = ptr; + + ptr += new_name_len; + } + + /* We managed to parse a full log record body */ +/* + printf("Parsed log rec of type %lu space %lu\n" + "name %s\n", type, space_id, name); + + if (type == MLOG_FILE_RENAME) { + printf("new name %s\n", new_name); + } +*/ + if (do_replay == FALSE) { + + return(ptr); + } + + /* Let us try to perform the file operation, if sensible. Note that + ibbackup has at this stage already read in all space id info to the + fil0fil.c data structures. + + NOTE that our algorithm is not guaranteed to work correctly if there + were renames of tables during the backup. See ibbackup code for more + on the problem. */ + + if (type == MLOG_FILE_DELETE) { + if (fil_tablespace_exists_in_mem(space_id)) { + ut_a(fil_delete_tablespace(space_id)); + } + } else if (type == MLOG_FILE_RENAME) { + /* We do the rename based on space id, not old file name; + this should guarantee that after the log replay each .ibd file + has the correct name for the latest log sequence number; the + proof is left as an exercise :) */ + + if (fil_tablespace_exists_in_mem(space_id)) { + /* Create the database directory for the new name, if + it does not exist yet */ + fil_create_directory_for_tablename(new_name); + + /* Rename the table if there is not yet a tablespace + with the same name */ + + if (fil_get_space_id_for_table(new_name) + == ULINT_UNDEFINED) { + ut_a(fil_rename_tablespace(name, space_id, + new_name)); + } + } + } else { + ut_a(type == MLOG_FILE_CREATE); + + if (fil_tablespace_exists_in_mem(space_id)) { + /* Do nothing */ + } else if (fil_get_space_id_for_table(name) != + ULINT_UNDEFINED) { + /* Do nothing */ + } else { + /* Create the database directory for name, if it does + not exist yet */ + fil_create_directory_for_tablename(name); + + ut_a(space_id != 0); + + ut_a(DB_SUCCESS == + fil_create_new_single_table_tablespace( + &space_id, name, + FIL_IBD_FILE_INITIAL_SIZE)); + } + } + + return(ptr); +} + /*********************************************************************** Deletes a single-table tablespace. The tablespace must be cached in the memory cache. */ @@ -1554,7 +1823,7 @@ try_again: } mutex_exit(&(system->mutex)); - +#ifndef UNIV_HOTBACKUP /* Invalidate in the buffer pool all pages belonging to the tablespace. Since we have set space->is_being_deleted = TRUE, readahead or ibuf merge can no longer read more pages of this tablespace to the @@ -1563,6 +1832,8 @@ try_again: fil_flush() from being applied to this tablespace. */ buf_LRU_invalidate_tablespace(id); +#endif + /* printf("Deleting tablespace %s id %lu\n", space->name, id); */ success = fil_space_free(id); @@ -1570,7 +1841,23 @@ try_again: success = os_file_delete(path); if (success) { - + /* Write a log record about the deletion of the .ibd + file, so that ibbackup can replay it in the + --apply-log phase. We use a dummy mtr and the familiar + log write mechanism. */ +#ifndef UNIV_HOTBACKUP + { + mtr_t mtr; + + /* When replaying the operation in ibbackup, do not try + to write any log record */ + mtr_start(&mtr); + + fil_op_write_log(MLOG_FILE_DELETE, id, path, + NULL, &mtr); + mtr_commit(&mtr); + } +#endif return(TRUE); } } @@ -1679,8 +1966,8 @@ fil_rename_tablespace( fil_space_t* space; fil_node_t* node; ulint count = 0; + char* path = NULL; char old_path[OS_FILE_MAX_PATH]; - char path[OS_FILE_MAX_PATH]; ut_a(id != 0); retry: @@ -1752,9 +2039,10 @@ retry: /* Check that the old name in the space is right */ - ut_a(strlen(old_name) < OS_FILE_MAX_PATH - 10); + ut_a(strlen(old_name) + strlen(fil_path_to_mysql_datadir) + < OS_FILE_MAX_PATH - 10); - sprintf(old_path, "./%s.ibd", old_name); + sprintf(old_path, "%s/%s.ibd", fil_path_to_mysql_datadir, old_name); srv_normalize_path_for_win(old_path); @@ -1763,9 +2051,11 @@ retry: /* Rename the tablespace and the node in the memory cache */ - ut_a(strlen(new_name) < OS_FILE_MAX_PATH - 10); + ut_a(strlen(new_name) + strlen(fil_path_to_mysql_datadir) + < OS_FILE_MAX_PATH - 10); + path = mem_alloc(OS_FILE_MAX_PATH); - sprintf(path, "./%s.ibd", new_name); + sprintf(path, "%s/%s.ibd", fil_path_to_mysql_datadir, new_name); srv_normalize_path_for_win(path); @@ -1776,6 +2066,8 @@ retry: goto func_exit; } + /* printf("Renaming tablespace %s to %s id %lu\n", path, old_path, id); + */ success = os_file_rename(old_path, path); if (!success) { @@ -1784,11 +2076,26 @@ retry: ut_a(fil_rename_tablespace_in_mem(space, node, old_path)); } + func_exit: + if (path) { + mem_free(path); + } space->stop_ios = FALSE; mutex_exit(&(system->mutex)); +#ifndef UNIV_HOTBACKUP + if (success) { + mtr_t mtr; + + mtr_start(&mtr); + + fil_op_write_log(MLOG_FILE_RENAME, id, old_name, new_name, + &mtr); + mtr_commit(&mtr); + } +#endif return(success); } @@ -1802,11 +2109,14 @@ ulint fil_create_new_single_table_tablespace( /*===================================*/ /* out: DB_SUCCESS or error code */ - ulint* space_id, /* out: space id */ + ulint* space_id, /* in/out: space id; if this is != 0, then + this is an input parameter, otherwise + output */ char* tablename, /* in: the table name in the usual databasename/tablename format of InnoDB */ ulint size) /* in: the initial size of the tablespace file - in pages, must be > 0 */ + in pages, must be >= FIL_IBD_FILE_INITIAL_SIZE + */ { os_file_t file; ibool ret; @@ -1815,9 +2125,11 @@ fil_create_new_single_table_tablespace( ibool success; char path[OS_FILE_MAX_PATH]; - ut_a(strlen(tablename) < OS_FILE_MAX_PATH - 10); + ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE); - sprintf(path, "./%s.ibd", tablename); + ut_a(strlen(tablename) + strlen(fil_path_to_mysql_datadir) + < OS_FILE_MAX_PATH - 10); + sprintf(path, "%s/%s.ibd", fil_path_to_mysql_datadir, tablename); srv_normalize_path_for_win(path); @@ -1865,7 +2177,11 @@ fil_create_new_single_table_tablespace( return(DB_OUT_OF_FILE_SPACE); } - *space_id = fil_assign_new_space_id(); + if (*space_id == 0) { + *space_id = fil_assign_new_space_id(); + } + + /* printf("Creating tablespace %s id %lu\n", path, *space_id); */ if (*space_id == ULINT_UNDEFINED) { ut_free(page); @@ -1934,6 +2250,17 @@ fil_create_new_single_table_tablespace( fil_node_create(path, size, *space_id, FALSE); +#ifndef UNIV_HOTBACKUP + { + mtr_t mtr; + + mtr_start(&mtr); + + fil_op_write_log(MLOG_FILE_CREATE, *space_id, tablename, NULL, &mtr); + + mtr_commit(&mtr); + } +#endif return(DB_SUCCESS); } @@ -1971,7 +2298,7 @@ fil_reset_too_high_lsns( ut_a(strlen(name) < OS_FILE_MAX_PATH - 10); - sprintf(filepath, "./%s.ibd", name); + sprintf(filepath, "%s/%s.ibd", fil_path_to_mysql_datadir, name); srv_normalize_path_for_win(filepath); @@ -2106,7 +2433,7 @@ fil_open_single_table_tablespace( ut_a(strlen(name) < OS_FILE_MAX_PATH - 10); - sprintf(filepath, "./%s.ibd", name); + sprintf(filepath, "%s/%s.ibd", fil_path_to_mysql_datadir, name); srv_normalize_path_for_win(filepath); @@ -2196,13 +2523,16 @@ fil_load_single_table_tablespace( ulint size_low; ulint size_high; ib_longlong size; - +#ifdef UNIV_HOTBACKUP + fil_space_t* space; +#endif filepath = ut_malloc(OS_FILE_MAX_PATH); - ut_a(strlen(dbname) + strlen(filename) < OS_FILE_MAX_PATH - 10); + ut_a(strlen(dbname) + strlen(filename) + + strlen(fil_path_to_mysql_datadir) < OS_FILE_MAX_PATH - 100); - sprintf(filepath, "./%s/%s", dbname, filename); - + sprintf(filepath, "%s/%s/%s", fil_path_to_mysql_datadir, dbname, + filename); srv_normalize_path_for_win(filepath); file = os_file_create_simple_no_error_handling(filepath, OS_FILE_OPEN, @@ -2236,9 +2566,12 @@ fil_load_single_table_tablespace( return; } - size = (((ib_longlong)size_high) << 32) + (ib_longlong)size_low; + /* Every .ibd file is created >= 4 pages in size. Smaller files + cannot be ok. */ - if (size < 4 * UNIV_PAGE_SIZE) { + size = (((ib_longlong)size_high) << 32) + (ib_longlong)size_low; +#ifndef UNIV_HOTBACKUP + if (size < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) { fprintf(stderr, "InnoDB: Error: the size of single-table tablespace file %s\n" "InnoDB: is only %lu %lu, should be at least %lu!", filepath, size_high, @@ -2248,24 +2581,95 @@ fil_load_single_table_tablespace( return; } - - /* Read the first page of the tablespace */ +#endif + /* Read the first page of the tablespace if the size big enough */ page = ut_malloc(UNIV_PAGE_SIZE); - success = os_file_read(file, page, 0, 0, UNIV_PAGE_SIZE); + if (size >= FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) { + success = os_file_read(file, page, 0, 0, UNIV_PAGE_SIZE); - /* We have to read the tablespace id from the file */ + /* We have to read the tablespace id from the file */ - space_id = fsp_header_get_space_id(page); + space_id = fsp_header_get_space_id(page); + } else { + space_id = ULINT_UNDEFINED; + } +#ifndef UNIV_HOTBACKUP if (space_id == ULINT_UNDEFINED || space_id == 0) { fprintf(stderr, "InnoDB: Error: tablespace id %lu in file %s is not sensible\n", space_id, filepath); goto func_exit; } +#else + if (space_id == ULINT_UNDEFINED || space_id == 0) { + char* new_path; + + fprintf(stderr, +"InnoDB: Renaming tablespace %s of id %lu,\n" +"InnoDB: to %s_ibbackup_old_vers_<timestamp>\n" +"InnoDB: because its size %lld is too small (< 4 pages 16 kB each),\n" +"InnoDB: or the space id in the file header is not sensible.\n" +"InnoDB: This can happen in an ibbackup run, and is not dangerous.\n", + filepath, space_id, filepath, size); + os_file_close(file); + + new_path = ut_malloc(OS_FILE_MAX_PATH); + sprintf(new_path, "%s_ibbackup_old_vers_", filepath); + ut_sprintf_timestamp_without_extra_chars( + new_path + ut_strlen(new_path)); + ut_a(os_file_rename(filepath, new_path)); + + ut_free(page); + ut_free(filepath); + ut_free(new_path); + + return; + } + + /* A backup may contain the same space several times, if the space got + renamed at a sensitive time. Since it is enough to have one version of + the space, we rename the file if a space with the same space id + already exists in the tablespace memory cache. We rather rename the + file than delete it, because if there is a bug, we do not want to + destroy valuable data. */ + + mutex_enter(&(fil_system->mutex)); + + space = fil_get_space_for_id_low(space_id); + + if (space) { + char* new_path; + + fprintf(stderr, +"InnoDB: Renaming tablespace %s of id %lu,\n" +"InnoDB: to %s_ibbackup_old_vers_<timestamp>\n" +"InnoDB: because space %s with the same id\n" +"InnoDB: was scanned earlier. This can happen if you have renamed tables\n" +"InnoDB: during an ibbackup run.\n", filepath, space_id, filepath, + space->name); + os_file_close(file); + + new_path = ut_malloc(OS_FILE_MAX_PATH); + + sprintf(new_path, "%s_ibbackup_old_vers_", filepath); + ut_sprintf_timestamp_without_extra_chars( + new_path + ut_strlen(new_path)); + mutex_exit(&(fil_system->mutex)); + + ut_a(os_file_rename(filepath, new_path)); + + ut_free(page); + ut_free(filepath); + ut_free(new_path); + + return; + } + mutex_exit(&(fil_system->mutex)); +#endif success = fil_space_create(filepath, space_id, FIL_TABLESPACE); if (!success) { @@ -2305,7 +2709,7 @@ fil_load_single_table_tablespaces(void) /* The datadir of MySQL is always the default directory of mysqld */ - dir = os_file_opendir((char*)".", TRUE); + dir = os_file_opendir(fil_path_to_mysql_datadir, TRUE); if (dir == NULL) { @@ -2317,8 +2721,8 @@ fil_load_single_table_tablespaces(void) /* Scan all directories under the datadir. They are the database directories of MySQL. */ - ret = os_file_readdir_next_file((char*)".", dir, &dbinfo); - + ret = os_file_readdir_next_file(fil_path_to_mysql_datadir, dir, + &dbinfo); while (ret == 0) { /* printf("Looking at %s in datadir\n", dbinfo.name); */ @@ -2333,8 +2737,8 @@ fil_load_single_table_tablespaces(void) ut_a(strlen(dbinfo.name) < OS_FILE_MAX_PATH - 10); - sprintf(dbpath, "./%s", dbinfo.name); - + sprintf(dbpath, "%s/%s", fil_path_to_mysql_datadir, + dbinfo.name); srv_normalize_path_for_win(dbpath); dbdir = os_file_opendir(dbpath, FALSE); @@ -2378,7 +2782,8 @@ next_file_item: } next_datadir_item: - ret = os_file_readdir_next_file((char*)".", dir, &dbinfo); + ret = os_file_readdir_next_file(fil_path_to_mysql_datadir, + dir, &dbinfo); } ut_free(dbpath); @@ -2427,11 +2832,10 @@ fil_print_orphaned_tablespaces(void) && !space->mark) { fprintf(stderr, "InnoDB: Warning: tablespace %s of id %lu has no matching table in\n" -"InnoDB: the InnoDB data dixtionary.\n", space->name, space->id); +"InnoDB: the InnoDB data dictionary.\n", space->name, space->id); } space = UT_LIST_GET_NEXT(space_list, space); - } mutex_exit(&(system->mutex)); @@ -2515,8 +2919,8 @@ there may be many tablespaces which are not yet in the memory cache. */ ibool fil_space_for_table_exists_in_mem( /*==============================*/ - /* out: TRUE if a matching tablespace - exists in the memory cache */ + /* out: TRUE if a matching tablespace exists + in the memory cache */ ulint id, /* in: space id */ char* name, /* in: table name in the standard 'databasename/tablename' format */ @@ -2539,7 +2943,7 @@ fil_space_for_table_exists_in_mem( mutex_enter(&(system->mutex)); - sprintf(path, "./%s.ibd", name); + sprintf(path, "%s/%s.ibd", fil_path_to_mysql_datadir, name); srv_normalize_path_for_win(path); /* Look if there is a space with the same id */ @@ -2552,16 +2956,19 @@ fil_space_for_table_exists_in_mem( HASH_SEARCH(name_hash, system->name_hash, ut_fold_string(path), namespace, 0 == strcmp(namespace->name, path)); - if (!print_error_if_does_not_exist) { - if (space && space == namespace) { - if (mark_space) { - space->mark = TRUE; - } + if (space && space == namespace) { + /* Found */ + + if (mark_space) { + space->mark = TRUE; + } - mutex_exit(&(system->mutex)); + mutex_exit(&(system->mutex)); - return(TRUE); - } + return(TRUE); + } + + if (!print_error_if_does_not_exist) { mutex_exit(&(system->mutex)); @@ -2602,7 +3009,8 @@ fil_space_for_table_exists_in_mem( " InnoDB: Error: table %s\n" "InnoDB: in InnoDB data dictionary has tablespace id %lu,\n" "InnoDB: but tablespace with that id has name %s.\n" -"InnoDB: Have you deleted or moved .ibd files?", name, id, space->name); +"InnoDB: Have you deleted or moved .ibd files?\n", name, id, space->name); + if (namespace != NULL) { fprintf(stderr, "InnoDB: There is a tablespace with the right name\n" @@ -2618,182 +3026,228 @@ fil_space_for_table_exists_in_mem( return(FALSE); } - ut_a(space == namespace); + mutex_exit(&(system->mutex)); - if (mark_space) { - space->mark = TRUE; - } + return(FALSE); +} + +/*********************************************************************** +Checks if a single-table tablespace for a given table name exists in the +tablespace memory cache. */ +static +ulint +fil_get_space_id_for_table( +/*=======================*/ + /* out: space id, ULINT_UNDEFINED if not + found */ + char* name) /* in: table name in the standard + 'databasename/tablename' format */ +{ + fil_system_t* system = fil_system; + fil_space_t* namespace; + ulint id = ULINT_UNDEFINED; + char path[OS_FILE_MAX_PATH]; + + ut_ad(system); + + mutex_enter(&(system->mutex)); + + sprintf(path, "%s/%s.ibd", fil_path_to_mysql_datadir, name); + srv_normalize_path_for_win(path); + + /* Look if there is a space with the same name; the name is the + directory path to the file */ + + HASH_SEARCH(name_hash, system->name_hash, + ut_fold_string(path), namespace, + 0 == strcmp(namespace->name, path)); + if (namespace) { + id = namespace->id; + } mutex_exit(&(system->mutex)); - return(TRUE); + return(id); } /************************************************************************** -Tries to extend a data file by the number of pages given. Fractions of 1 MB -are ignored. The tablespace must be cached in the memory cache. */ +Tries to extend a data file so that it would accommodate the number of pages +given. The tablespace must be cached in the memory cache. If the space is big +enough already, does nothing. */ ibool -fil_extend_last_data_file( -/*======================*/ - /* out: TRUE if success, also if we run - out of disk space we may return TRUE */ - ulint* actual_increase,/* out: number of pages we were able to - extend, here the original size of the file and - the resulting size of the file are rounded - downwards to a full megabyte, and the - difference expressed in pages is returned */ - ulint space_id, /* in: space id */ - ulint size, /* in: current size of the space in pages, as - stored in the fsp header */ - ulint size_increase) /* in: try to extend this many pages */ +fil_extend_space_to_desired_size( +/*=============================*/ + /* out: TRUE if success */ + ulint* actual_size, /* out: size of the space after extension; + if we ran out of disk space this may be lower + than the desired size */ + ulint space_id, /* in: space id, must be != 0 */ + ulint size_after_extend)/* in: desired size in pages after the + extension; if the current space size is bigger + than this already, the function does nothing */ { fil_system_t* system = fil_system; fil_node_t* node; fil_space_t* space; byte* buf2; byte* buf; - ibool success; - ulint i; + ulint start_page_no; + ulint file_start_page_no; + ulint n_pages; + ulint offset_high; + ulint offset_low; + ibool success = TRUE; fil_mutex_enter_and_prepare_for_io(space_id); HASH_SEARCH(hash, system->spaces, space_id, space, space->id == space_id); ut_a(space); + + if (space->size >= size_after_extend) { + /* Space already big enough */ + + *actual_size = space->size; + + mutex_exit(&(system->mutex)); + + return(TRUE); + } node = UT_LIST_GET_LAST(space->chain); fil_node_prepare_for_io(node, system, space); - if (UT_LIST_GET_LEN(space->chain) == 1 && node->size < size) { - ut_print_timestamp(stderr); - fprintf(stderr, -"InnoDB: Fatal error: space %s id %lu size stored in header is %lu pages\n" -"InnoDB: but actual size is only %lu pages (possibly rounded downwards)!\n" -"InnoDB: Cannot continue operation!\n", space->name, space->id, size, - node->size); - exit(1); - } + /* Extend 1 MB at a time */ buf2 = mem_alloc(1024 * 1024 + UNIV_PAGE_SIZE); buf = ut_align(buf2, UNIV_PAGE_SIZE); memset(buf, '\0', 1024 * 1024); - for (i = 0; i < size_increase / ((1024 * 1024) / UNIV_PAGE_SIZE); - i++) { - /* If we use native Windows aio, then we use it also in this - write */ + start_page_no = space->size; + file_start_page_no = space->size - node->size; + + while (start_page_no < size_after_extend) { + n_pages = size_after_extend - start_page_no; + + if (n_pages > (1024 * 1024) / UNIV_PAGE_SIZE) { + n_pages = (1024 * 1024) / UNIV_PAGE_SIZE; + } + offset_high = (start_page_no - file_start_page_no) + / (4096 * ((1024 * 1024) / UNIV_PAGE_SIZE)); + offset_low = ((start_page_no - file_start_page_no) + % (4096 * ((1024 * 1024) / UNIV_PAGE_SIZE))) + * UNIV_PAGE_SIZE; +#ifdef UNIV_HOTBACKUP + success = os_file_write(node->name, node->handle, buf, + offset_low, offset_high, + UNIV_PAGE_SIZE * n_pages); +#else success = os_aio(OS_FILE_WRITE, OS_AIO_SYNC, node->name, node->handle, buf, - (node->size << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFFUL, - node->size >> (32 - UNIV_PAGE_SIZE_SHIFT), - 1024 * 1024, NULL, NULL); + offset_low, offset_high, + UNIV_PAGE_SIZE * n_pages, + NULL, NULL); +#endif + if (success) { + node->size += n_pages; + space->size += n_pages; + + os_has_said_disk_full = FALSE; + } else { + /* Let us measure the size of the file to determine + how much we were able to extend it */ + + n_pages = ((ulint) + (os_file_get_size_as_iblonglong(node->handle) + / UNIV_PAGE_SIZE)) - node->size; + + node->size += n_pages; + space->size += n_pages; - if (!success) { break; } - node->size += ((1024 * 1024) / UNIV_PAGE_SIZE); - space->size += ((1024 * 1024) / UNIV_PAGE_SIZE); - - os_has_said_disk_full = FALSE; + start_page_no += n_pages; } mem_free(buf2); fil_node_complete_io(node, system, OS_FILE_WRITE); + *actual_size = space->size; + /* + printf("Extended %s to %lu, actual size %lu pages\n", space->name, + size_after_extend, *actual_size); */ mutex_exit(&(system->mutex)); - *actual_increase = i * ((1024 * 1024) / UNIV_PAGE_SIZE); - fil_flush(space_id); - if (space_id == 0) { - srv_data_file_sizes[srv_n_data_files - 1] += *actual_increase; - } - - return(TRUE); + return(success); } -/************************************************************************** -Tries to extend a data file so that it would accommodate the number of pages -given. The tablespace must be cached in the memory cache. */ +#ifdef UNIV_HOTBACKUP +/************************************************************************ +Extends all tablespaces to the size stored in the space header. During the +ibbackup --apply-log phase we extended the spaces on-demand so that log records +could be appllied, but that may have left spaces still too small compared to +the size stored in the space header. */ -ibool -fil_extend_data_file_with_pages( -/*============================*/ - /* out: TRUE if success */ - ulint space_id, /* in: space id, must be != 0 */ - ulint size, /* in: current size of the space in pages, as - stored in the fsp header */ - ulint size_after_extend)/* in: desired size in pages after the - extension, should be less than 4 GB (this - function is primarily intended for increasing - the data file size from < 64 pages to up to - 64 pages) */ +void +fil_extend_tablespaces_to_stored_len(void) +/*======================================*/ { - fil_system_t* system = fil_system; - fil_node_t* node; + fil_system_t* system = fil_system; fil_space_t* space; - byte* buf2; byte* buf; + ulint actual_size; + ulint size_in_header; + ulint error; ibool success; - ut_a(space_id != 0); - ut_a(size_after_extend < 64 * 4096); - ut_a(size_after_extend >= size); + buf = mem_alloc(UNIV_PAGE_SIZE); - fil_mutex_enter_and_prepare_for_io(space_id); + mutex_enter(&(system->mutex)); - HASH_SEARCH(hash, system->spaces, space_id, space, - space->id == space_id); - ut_a(space); - - node = UT_LIST_GET_LAST(space->chain); + space = UT_LIST_GET_FIRST(system->space_list); - fil_node_prepare_for_io(node, system, space); + while (space) { + ut_a(space->purpose == FIL_TABLESPACE); - if (UT_LIST_GET_LEN(space->chain) == 1 && node->size < size) { - ut_print_timestamp(stderr); - fprintf(stderr, -"InnoDB: Fatal error: space %s id %lu size stored in header is %lu pages\n" -"InnoDB: but actual size is only %lu pages (possibly rounded downwards)!\n" -"InnoDB: Cannot continue operation!\n", space->name, space_id, size, - node->size); - exit(1); - } + mutex_exit(&(system->mutex)); /* no need to protect with a + mutex, because this is a single- + threaded operation */ + error = fil_read(TRUE, space->id, 0, 0, UNIV_PAGE_SIZE, buf, + NULL); + ut_a(error == DB_SUCCESS); - buf2 = mem_alloc((1 + size_after_extend - size) * UNIV_PAGE_SIZE); - buf = ut_align(buf2, UNIV_PAGE_SIZE); + size_in_header = fsp_get_size_low(buf); - memset(buf, '\0', (size_after_extend - size) * UNIV_PAGE_SIZE); + success = fil_extend_space_to_desired_size(&actual_size, + space->id, size_in_header); + if (!success) { + fprintf(stderr, +"InnoDB: Error: could not extend the tablespace of %s\n" +"InnoDB: to the size stored in header, %lu pages;\n" +"InnoDB: size after extension %lu pages\n" +"InnoDB: Check that you have free disk space and retry!\n", space->name, + size_in_header, actual_size); + exit(1); + } - success = os_aio(OS_FILE_WRITE, OS_AIO_SYNC, - node->name, node->handle, buf, - UNIV_PAGE_SIZE * size, 0, - UNIV_PAGE_SIZE * (size_after_extend - size), - NULL, NULL); - if (success) { - node->size = size_after_extend; - space->size = size_after_extend; + mutex_enter(&(system->mutex)); - os_has_said_disk_full = FALSE; + space = UT_LIST_GET_NEXT(space_list, space); } - mem_free(buf2); - - fil_node_complete_io(node, system, OS_FILE_WRITE); - - mutex_exit(&(system->mutex)); - - fil_flush(space_id); + mutex_exit(&(system->mutex)); - return(success); + mem_free(buf); } +#endif /*========== RESERVE FREE EXTENTS (for a B-tree split, for example) ===*/ @@ -3123,12 +3577,23 @@ fil_io( /* Do aio */ - ut_anp(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0); - ut_anp((len % OS_FILE_LOG_BLOCK_SIZE) == 0); + ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0); +#ifdef UNIV_HOTBACKUP + /* In ibbackup do normal i/o, not aio */ + if (type == OS_FILE_READ) { + ret = os_file_read(node->handle, buf, offset_low, offset_high, + len); + } else { + ret = os_file_write(node->name, node->handle, buf, + offset_low, offset_high, len); + } +#else /* Queue the aio request */ ret = os_aio(type, mode | wake_later, node->name, node->handle, buf, offset_low, offset_high, len, node, message); +#endif ut_a(ret); if (mode == OS_AIO_SYNC) { diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c index 7c4d691ea13..8ceea03f34a 100644 --- a/innobase/fsp/fsp0fsp.c +++ b/innobase/fsp/fsp0fsp.c @@ -27,6 +27,10 @@ Created 11/29/1995 Heikki Tuuri #include "dict0mem.h" #include "log0log.h" + +#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header + within a file page */ + /* The data structures in files are defined just as byte strings in C */ typedef byte fsp_header_t; typedef byte xdes_t; @@ -38,8 +42,6 @@ File space header data structure: this data structure is contained in the first page of a space. The space for this header is reserved in every extent descriptor page, but used only in the first. */ -#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header - within a file page */ /*-------------------------------------*/ #define FSP_SPACE_ID 0 /* space id */ #define FSP_NOT_USED 4 /* this field contained a value up to @@ -90,7 +92,6 @@ descriptor page, but used only in the first. */ #define FSP_FREE_ADD 4 /* this many free extents are added to the free list from above FSP_FREE_LIMIT at a time */ - /* FILE SEGMENT INODE ================== @@ -298,6 +299,19 @@ fseg_alloc_free_page_low( FSP_UP, FSP_NO_DIR */ mtr_t* mtr); /* in: mtr handle */ + +/************************************************************************** +Reads the file space size stored in the header page. */ + +ulint +fsp_get_size_low( +/*=============*/ + /* out: tablespace size stored in the space header */ + page_t* page) /* in: header page (page 0 in the tablespace) */ +{ + return(mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SIZE)); +} + /************************************************************************** Gets a pointer to the space header and x-locks its page. */ UNIV_INLINE @@ -1034,8 +1048,9 @@ fsp_try_extend_data_file_with_pages( fsp_header_t* header, /* in: space header */ mtr_t* mtr) /* in: mtr */ { - ulint size; ibool success; + ulint actual_size; + ulint size; ut_a(space != 0); @@ -1043,12 +1058,12 @@ fsp_try_extend_data_file_with_pages( ut_a(page_no >= size); - success = fil_extend_data_file_with_pages(space, size, page_no + 1); - - if (success) { - mlog_write_ulint(header + FSP_SIZE, page_no + 1, MLOG_4BYTES, - mtr); - } + success = fil_extend_space_to_desired_size(&actual_size, space, + page_no + 1); + /* actual_size now has the space size in pages; it may be less than + we wanted if we ran out of disk space */ + + mlog_write_ulint(header + FSP_SIZE, actual_size, MLOG_4BYTES, mtr); return(success); } @@ -1060,13 +1075,20 @@ ibool fsp_try_extend_data_file( /*=====================*/ /* out: FALSE if not auto-extending */ - ulint* actual_increase,/* out: actual increase in pages */ + ulint* actual_increase,/* out: actual increase in pages, where + we measure the tablespace size from + what the header field says; it may be + the actual file size rounded down to + megabyte */ ulint space, /* in: space */ fsp_header_t* header, /* in: space header */ mtr_t* mtr) /* in: mtr */ { ulint size; + ulint new_size; + ulint old_size; ulint size_increase; + ulint actual_size; ibool success; *actual_increase = 0; @@ -1078,6 +1100,8 @@ fsp_try_extend_data_file( size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr); + old_size = size; + if (space == 0 && srv_last_file_size_max != 0) { if (srv_last_file_size_max < srv_data_file_sizes[srv_n_data_files - 1]) { @@ -1107,8 +1131,12 @@ fsp_try_extend_data_file( success = fsp_try_extend_data_file_with_pages( space, FSP_EXTENT_SIZE - 1, header, mtr); - if (!success) { + new_size = mtr_read_ulint( + header + FSP_SIZE, MLOG_4BYTES, mtr); + + *actual_increase = new_size - old_size; + return(FALSE); } @@ -1118,7 +1146,10 @@ fsp_try_extend_data_file( if (size < 32 * FSP_EXTENT_SIZE) { size_increase = FSP_EXTENT_SIZE; } else { - size_increase = 8 * FSP_EXTENT_SIZE; + /* Below in fsp_fill_free_list() we assume + that we add at most FSP_FREE_ADD extents at + a time */ + size_increase = FSP_FREE_ADD * FSP_EXTENT_SIZE; } } } @@ -1128,18 +1159,17 @@ fsp_try_extend_data_file( return(TRUE); } - /* Extend the data file. If we are not able to extend the full - requested length, the function tells how many pages we were able to - extend so that the size of the tablespace would be divisible by 1 MB - (we possibly managed to extend more, but we only take into account - full megabytes). */ - - success = fil_extend_last_data_file(actual_increase, space, size, - size_increase); - if (success) { - mlog_write_ulint(header + FSP_SIZE, size + *actual_increase, + success = fil_extend_space_to_desired_size(&actual_size, space, + size + size_increase); + /* We ignore any fragments of a full megabyte when storing the size + to the space header */ + + mlog_write_ulint(header + FSP_SIZE, + ut_calc_align_down(actual_size, (1024 * 1024) / UNIV_PAGE_SIZE), MLOG_4BYTES, mtr); - } + new_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr); + + *actual_increase = new_size - old_size; return(TRUE); } @@ -1186,8 +1216,10 @@ fsp_fill_free_list( size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr); } - if (space != 0 && !init_space) { - /* Try to increase the data file size */ + if (space != 0 && !init_space + && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) { + + /* Try to increase the .ibd file size */ fsp_try_extend_data_file(&actual_increase, space, header, mtr); size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr); } @@ -1222,7 +1254,7 @@ fsp_fill_free_list( fsp_init_file_page(descr_page, mtr); } - /* Initialize the ibuf page in a separate + /* Initialize the ibuf bitmap page in a separate mini-transaction because it is low in the latching order, and we must be able to release its latch before returning from the fsp routine */ @@ -1797,7 +1829,7 @@ fsp_free_seg_inode( flst_remove(space_header + FSP_SEG_INODES_FREE, page + FSEG_INODE_PAGE_NODE, mtr); - fsp_free_page(space, buf_frame_get_page_no(page), mtr); + fsp_free_page(space, buf_frame_get_page_no(page), mtr); } } @@ -3157,7 +3189,7 @@ fseg_free_step( freed yet */ ut_a(descr); - ut_anp(xdes_get_bit(descr, XDES_FREE_BIT, buf_frame_get_page_no(header) + ut_a(xdes_get_bit(descr, XDES_FREE_BIT, buf_frame_get_page_no(header) % FSP_EXTENT_SIZE, mtr) == FALSE); inode = fseg_inode_get(header, mtr); diff --git a/innobase/include/fil0fil.h b/innobase/include/fil0fil.h index 506bc6c1870..0ed012c489a 100644 --- a/innobase/include/fil0fil.h +++ b/innobase/include/fil0fil.h @@ -16,6 +16,14 @@ Created 10/25/1995 Heikki Tuuri #include "ut0byte.h" #include "os0file.h" +/* When mysqld is run, the default directory "." is the mysqld datadir, but in +ibbackup we must set it explicitly; the patgh must NOT contain the trailing +'/' or '\' */ +extern char* fil_path_to_mysql_datadir; + +/* Initial size of a single-table tablespace in pages */ +#define FIL_IBD_FILE_INITIAL_SIZE 4 + /* 'null' (undefined) page offset in the context of file spaces */ #define FIL_NULL ULINT32_UNDEFINED @@ -261,6 +269,35 @@ fil_decr_pending_ibuf_merges( /*========================*/ ulint id); /* in: space id */ /*********************************************************************** +Parses the body of a log record written about an .ibd file operation. That is, +the log record part after the standard (type, space id, page no) header of the +log record. + +If desired, also replays the delete or rename operation if the .ibd file +exists and the space id in it matches. Replays the create operation if a file +at that path does not exist yet. If the database directory for the file to be +created does not exist, then we create the directory, too. + +Note that ibbackup --apply-log sets fil_path_to_mysql_datadir to point to the +datadir that we should use in replaying the file operations. */ + +byte* +fil_op_log_parse_or_replay( +/*=======================*/ + /* out: end of log record, or NULL if the + record was not completely contained between + ptr and end_ptr */ + byte* ptr, /* in: buffer containing the log record body, + or an initial segment of it, if the record does + not fir completely between ptr and end_ptr */ + byte* end_ptr, /* in: buffer end */ + ulint type, /* in: the type of this log record */ + ibool do_replay, /* in: TRUE if we want to replay the + operation, and not just parse the log record */ + ulint space_id); /* in: if do_replay is TRUE, the space id of + the tablespace in question; otherwise + ignored */ +/*********************************************************************** Deletes a single-table tablespace. The tablespace must be cached in the memory cache. */ @@ -306,16 +343,18 @@ ulint fil_create_new_single_table_tablespace( /*===================================*/ /* out: DB_SUCCESS or error code */ - ulint* space_id, /* out: space id */ + ulint* space_id, /* in/out: space id; if this is != 0, then + this is an input parameter, otherwise + output */ char* tablename, /* in: the table name in the usual databasename/tablename format of InnoDB */ ulint size); /* in: the initial size of the tablespace file - in pages */ + in pages, must be > 0 */ /************************************************************************ Tries to open a single-table tablespace and checks the space id is right in it. If does not succeed, prints an error message to the .err log. This function is used to open the tablespace when we load a table definition -to the dictionarky cache. NOTE that we assume this operation is used under the +to the dictionary cache. NOTE that we assume this operation is used under the protection of the dictionary mutex, so that two users cannot race here. */ ibool @@ -410,39 +449,32 @@ fil_space_for_table_exists_in_mem( the .err log if a matching tablespace is not found from memory */ /************************************************************************** -Tries to extend a data file by the number of pages given. Fractions of 1 MB -are ignored. The tablespace must be cached in the memory cache. */ - -ibool -fil_extend_last_data_file( -/*======================*/ - /* out: TRUE if success, also if we run - out of disk space we may return TRUE */ - ulint* actual_increase,/* out: number of pages we were able to - extend, here the original size of the file and - the resulting size of the file are rounded - downwards to a full megabyte, and the - difference expressed in pages is returned */ - ulint space_id, /* in: space id */ - ulint size, /* in: current size of the space in pages, as - stored in the fsp header */ - ulint size_increase); /* in: try to extend this many pages */ -/************************************************************************** Tries to extend a data file so that it would accommodate the number of pages -given. The tablespace must be cached in the memory cache. */ +given. The tablespace must be cached in the memory cache. If the space is big +enough already, does nothing. */ ibool -fil_extend_data_file_with_pages( -/*============================*/ +fil_extend_space_to_desired_size( +/*=============================*/ /* out: TRUE if success */ + ulint* actual_size, /* out: size of the space after extension; + if we ran out of disk space this may be lower + than the desired size */ ulint space_id, /* in: space id, must be != 0 */ - ulint size, /* in: current size of the space in pages, as - stored in the fsp header */ ulint size_after_extend);/* in: desired size in pages after the - extension, should be less than 4 GB (this - function is primarily intended for increasing - the data file size from < 64 pages to up to - 64 pages) */ + extension; if the current space size is bigger + than this already, the function does nothing */ +#ifdef UNIV_HOTBACKUP +/************************************************************************ +Extends all tablespaces to the size stored in the space header. During the +ibbackup --apply-log phase we extended the spaces on-demand so that log records +could be appllied, but that may have left spaces still too small compared to +the size stored in the space header. */ + +void +fil_extend_tablespaces_to_stored_len(void); +/*======================================*/ +#endif /*********************************************************************** Tries to reserve free extents in a file space. */ diff --git a/innobase/include/fsp0fsp.h b/innobase/include/fsp0fsp.h index 127e01ef59f..2fcde882df7 100644 --- a/innobase/include/fsp0fsp.h +++ b/innobase/include/fsp0fsp.h @@ -67,6 +67,14 @@ fsp_header_get_tablespace_size( /* out: size in pages */ ulint space); /* in: space id, must be 0 */ /************************************************************************** +Reads the file space size stored in the header page. */ + +ulint +fsp_get_size_low( +/*=============*/ + /* out: tablespace size stored in the space header */ + page_t* page); /* in: header page (page 0 in the tablespace) */ +/************************************************************************** Reads the space id from the first page of a tablespace. */ ulint diff --git a/innobase/include/ha0ha.ic b/innobase/include/ha0ha.ic index 22da7107659..77064cdf9da 100644 --- a/innobase/include/ha0ha.ic +++ b/innobase/include/ha0ha.ic @@ -51,8 +51,6 @@ ha_chain_get_next( /* out: next node, NULL if none */ ha_node_t* node) /* in: hash chain node */ { - ut_ad(table); - return(node->next); } @@ -144,8 +142,6 @@ ha_next( fold = node->fold; - ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold))); - node = ha_chain_get_next(node); while (node) { diff --git a/innobase/include/log0recv.h b/innobase/include/log0recv.h index 0a4f56816a1..5991960e8ae 100644 --- a/innobase/include/log0recv.h +++ b/innobase/include/log0recv.h @@ -175,17 +175,14 @@ recv_apply_hashed_log_recs( disk and invalidated in buffer pool: this alternative means that no new log records can be generated during the application */ +#ifdef UNIV_HOTBACKUP /*********************************************************************** Applies log records in the hash table to a backup. */ void -recv_apply_log_recs_for_backup( -/*===========================*/ - ulint n_data_files, /* in: number of data files */ - char** data_files, /* in: array containing the paths to the - data files */ - ulint* file_sizes); /* in: sizes of the data files in database - pages */ +recv_apply_log_recs_for_backup(void); +/*================================*/ +#endif /************************************************************ Recovers from archived log files, and also from log files, if they exist. */ diff --git a/innobase/include/mtr0log.h b/innobase/include/mtr0log.h index acbf87df447..da942dd45d7 100644 --- a/innobase/include/mtr0log.h +++ b/innobase/include/mtr0log.h @@ -58,6 +58,19 @@ mlog_write_initial_log_record( byte type, /* in: log item type: MLOG_1BYTE, ... */ mtr_t* mtr); /* in: mini-transaction handle */ /************************************************************ +Writes a log record about an .ibd file create/delete/rename. */ +UNIV_INLINE +byte* +mlog_write_initial_log_record_for_file_op( +/*======================================*/ + /* out: new value of log_ptr */ + ulint type, /* in: MLOG_FILE_CREATE, MLOG_FILE_DELETE, or + MLOG_FILE_RENAME */ + ulint space_id,/* in: space id, if applicable */ + ulint page_no,/* in: page number (not relevant currently) */ + byte* log_ptr,/* in: pointer to mtr log which has been opened */ + mtr_t* mtr); /* in: mtr */ +/************************************************************ Catenates 1 - 4 bytes to the mtr log. */ UNIV_INLINE void diff --git a/innobase/include/mtr0log.ic b/innobase/include/mtr0log.ic index c2150660794..60a5b390be9 100644 --- a/innobase/include/mtr0log.ic +++ b/innobase/include/mtr0log.ic @@ -185,3 +185,31 @@ mlog_write_initial_log_record_fast( #endif return(log_ptr); } + +/************************************************************ +Writes a log record about an .ibd file create/delete/rename. */ +UNIV_INLINE +byte* +mlog_write_initial_log_record_for_file_op( +/*======================================*/ + /* out: new value of log_ptr */ + ulint type, /* in: MLOG_FILE_CREATE, MLOG_FILE_DELETE, or + MLOG_FILE_RENAME */ + ulint space_id,/* in: space id, if applicable */ + ulint page_no,/* in: page number (not relevant currently) */ + byte* log_ptr,/* in: pointer to mtr log which has been opened */ + mtr_t* mtr) /* in: mtr */ +{ + ut_ad(log_ptr); + + mach_write_to_1(log_ptr, type); + log_ptr++; + + /* We write dummy space id and page number */ + log_ptr += mach_write_compressed(log_ptr, space_id); + log_ptr += mach_write_compressed(log_ptr, page_no); + + mtr->n_log_recs++; + + return(log_ptr); +} diff --git a/innobase/include/mtr0mtr.h b/innobase/include/mtr0mtr.h index 0ef25b3d1ee..c47fb54a6f8 100644 --- a/innobase/include/mtr0mtr.h +++ b/innobase/include/mtr0mtr.h @@ -96,7 +96,13 @@ flag value must give the length also! */ sequence of these records */ #define MLOG_DUMMY_RECORD ((byte)32) /* dummy log record used to pad a log block full */ -#define MLOG_BIGGEST_TYPE ((byte)32) /* biggest value (used in +#define MLOG_FILE_CREATE ((byte)33) /* log record about an .ibd + file creation */ +#define MLOG_FILE_RENAME ((byte)34) /* log record about an .ibd + file rename */ +#define MLOG_FILE_DELETE ((byte)35) /* log record about an .ibd + file deletion */ +#define MLOG_BIGGEST_TYPE ((byte)35) /* biggest value (used in asserts) */ /******************************************************************* diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index d1dc9dea18b..4a9fae90f07 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -63,6 +63,7 @@ log. */ #define OS_FILE_READ_ONLY 333 #define OS_FILE_READ_WRITE 444 +#define OS_FILE_READ_ALLOW_DELETE 555 /* for ibbackup */ /* Options for file_create */ #define OS_FILE_AIO 61 @@ -199,6 +200,21 @@ os_file_readdir_next_file( char* dirname,/* in: directory name or path */ os_file_dir_t dir, /* in: directory stream */ os_file_stat_t* info); /* in/out: buffer where the info is returned */ +/********************************************************************* +This function attempts to create a directory named pathname. The new directory +gets default permissions. On Unix, the permissions are (0770 & ~umask). If the +directory exists already, nothing is done and the call succeeds, unless the +fail_if_exists arguments is true. */ + +ibool +os_file_create_directory( +/*=====================*/ + /* out: TRUE if call succeeds, FALSE on + error */ + char* pathname, /* in: directory name as null-terminated + string */ + ibool fail_if_exists);/* in: if TRUE, pre-existing directory is + treated as an error. */ /******************************************************************** A simple function to open or create a file. */ @@ -206,7 +222,8 @@ os_file_t os_file_create_simple( /*==================*/ /* out, own: handle to the file, not defined if error, - error number can be retrieved with os_get_last_error */ + error number can be retrieved with + os_file_get_last_error */ char* name, /* in: name of the file or path as a null-terminated string */ ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened @@ -221,13 +238,16 @@ os_file_t os_file_create_simple_no_error_handling( /*====================================*/ /* out, own: handle to the file, not defined if error, - error number can be retrieved with os_get_last_error */ + error number can be retrieved with + os_file_get_last_error */ char* name, /* in: name of the file or path as a null-terminated string */ ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened (if does not exist, error), or OS_FILE_CREATE if a new file is created (if exists, error) */ - ulint access_type,/* in: OS_FILE_READ_ONLY or OS_FILE_READ_WRITE */ + ulint access_type,/* in: OS_FILE_READ_ONLY, OS_FILE_READ_WRITE, or + OS_FILE_READ_ALLOW_DELETE; the last option is used by + a backup program reading the file */ ibool* success);/* out: TRUE if succeed, FALSE if error */ /******************************************************************** Opens an existing file or creates a new. */ @@ -236,7 +256,8 @@ os_file_t os_file_create( /*===========*/ /* out, own: handle to the file, not defined if error, - error number can be retrieved with os_get_last_error */ + error number can be retrieved with + os_file_get_last_error */ char* name, /* in: name of the file or path as a null-terminated string */ ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened diff --git a/innobase/include/ut0dbg.h b/innobase/include/ut0dbg.h index 802557099fc..9b07d5da488 100644 --- a/innobase/include/ut0dbg.h +++ b/innobase/include/ut0dbg.h @@ -20,81 +20,34 @@ extern ibool ut_dbg_stop_threads; extern ulint* ut_dbg_null_ptr; +extern const char* ut_dbg_msg_assert_fail; +extern const char* ut_dbg_msg_trap; +extern const char* ut_dbg_msg_stop; + #define ut_a(EXPR)\ -{\ - ulint dbg_i;\ -\ - if (!((ulint)(EXPR) + ut_dbg_zero)) {\ - ut_print_timestamp(stderr);\ - fprintf(stderr,\ - " InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ - os_thread_pf(os_thread_get_curr_id()), IB__FILE__,\ - (ulint)__LINE__);\ - fprintf(stderr,\ - "InnoDB: Failing assertion: " #EXPR);\ - fprintf(stderr,\ - "\nInnoDB: We intentionally generate a memory trap.\n");\ - fprintf(stderr,\ - "InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n");\ - ut_dbg_stop_threads = TRUE;\ - dbg_i = *(ut_dbg_null_ptr);\ - if (dbg_i) {\ - ut_dbg_null_ptr = NULL;\ - }\ - }\ - if (ut_dbg_stop_threads) {\ - fprintf(stderr,\ - "InnoDB: Thread %lu stopped in file %s line %lu\n",\ - os_thread_pf(os_thread_get_curr_id()), IB__FILE__, (ulint)__LINE__);\ - os_thread_sleep(1000000000);\ - }\ -} - -/* This can be used if there are % characters in the assertion formula: -if we try to printf the formula gcc would complain of illegal print -format characters */ -#define ut_anp(EXPR)\ -{\ - ulint dbg_i;\ -\ if (!((ulint)(EXPR) + ut_dbg_zero)) {\ ut_print_timestamp(stderr);\ - fprintf(stderr,\ - " InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ + fprintf(stderr, ut_dbg_msg_assert_fail,\ os_thread_pf(os_thread_get_curr_id()), IB__FILE__,\ (ulint)__LINE__);\ - fprintf(stderr,\ - "\nInnoDB: We intentionally generate a memory trap.\n");\ - fprintf(stderr,\ - "InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n");\ + fputs("InnoDB: Failing assertion: " #EXPR "\n", stderr);\ + fputs(ut_dbg_msg_trap, stderr);\ ut_dbg_stop_threads = TRUE;\ - dbg_i = *(ut_dbg_null_ptr);\ - if (dbg_i) {\ - ut_dbg_null_ptr = NULL;\ - }\ + (*ut_dbg_null_ptr)++;\ }\ if (ut_dbg_stop_threads) {\ - fprintf(stderr,\ - "InnoDB: Thread %lu stopped in file %s line %lu\n",\ + fprintf(stderr, ut_dbg_msg_stop,\ os_thread_pf(os_thread_get_curr_id()), IB__FILE__, (ulint)__LINE__);\ os_thread_sleep(1000000000);\ - }\ -} - -#define ut_error {\ - ulint dbg_i;\ - ut_print_timestamp(stderr);\ - fprintf(stderr,\ - " InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ - os_thread_pf(os_thread_get_curr_id()), IB__FILE__, (ulint)__LINE__);\ - fprintf(stderr,\ - "InnoDB: We intentionally generate a memory trap.\n");\ - fprintf(stderr,\ - "InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n");\ - ut_dbg_stop_threads = TRUE;\ - dbg_i = *(ut_dbg_null_ptr);\ - printf("%lu", dbg_i);\ -} + } + +#define ut_error\ + ut_print_timestamp(stderr);\ + fprintf(stderr, ut_dbg_msg_assert_fail,\ + os_thread_pf(os_thread_get_curr_id()), IB__FILE__, (ulint)__LINE__);\ + fprintf(stderr, ut_dbg_msg_trap);\ + ut_dbg_stop_threads = TRUE;\ + (*ut_dbg_null_ptr)++; #ifdef UNIV_DEBUG #define ut_ad(EXPR) ut_a(EXPR) diff --git a/innobase/include/ut0ut.h b/innobase/include/ut0ut.h index 8ec23b23dcd..6a45d438a7f 100644 --- a/innobase/include/ut0ut.h +++ b/innobase/include/ut0ut.h @@ -139,7 +139,7 @@ void ut_ulint_sort(ulint* arr, ulint* aux_arr, ulint low, ulint high); /*============================================================*/ /************************************************************ -The following function returns a clock time in milliseconds. */ +The following function returns elapsed CPU time in milliseconds. */ ulint ut_clock(void); @@ -174,6 +174,14 @@ ut_sprintf_timestamp( /*=================*/ char* buf); /* in: buffer where to sprintf */ /************************************************************** +Sprintfs a timestamp to a buffer with no spaces and with ':' characters +replaced by '_'. */ + +void +ut_sprintf_timestamp_without_extra_chars( +/*=====================================*/ + char* buf); /* in: buffer where to sprintf */ +/************************************************************** Returns current year, month, day. */ void diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index 62c1dea0d41..d3309815998 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -95,14 +95,6 @@ static void log_io_complete_archive(void); /*=========================*/ -/******************************************************************** -Tries to establish a big enough margin of free space in the log groups, such -that a new log entry can be catenated without an immediate need for a -archiving. */ -static -void -log_archive_margin(void); -/*====================*/ /******************************************************************** Sets the global variable log_fsp_current_free_limit. Also makes a checkpoint, @@ -407,7 +399,7 @@ log_pad_current_log_block(void) log_close(); log_release(); - ut_anp((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE) + ut_a((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE) == LOG_BLOCK_HDR_SIZE); } @@ -745,7 +737,8 @@ log_init(void) memset(log_sys->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE); /*----------------------------*/ - log_sys->archiving_state = LOG_ARCH_ON; + /* Under MySQL, log archiving is always off */ + log_sys->archiving_state = LOG_ARCH_OFF; log_sys->archived_lsn = log_sys->lsn; log_sys->next_archived_lsn = ut_dulint_zero; @@ -754,13 +747,15 @@ log_init(void) rw_lock_create(&(log_sys->archive_lock)); rw_lock_set_level(&(log_sys->archive_lock), SYNC_NO_ORDER_CHECK); - log_sys->archive_buf = ut_align( + log_sys->archive_buf = NULL; + + /* ut_align( ut_malloc(LOG_ARCHIVE_BUF_SIZE + OS_FILE_LOG_BLOCK_SIZE), - OS_FILE_LOG_BLOCK_SIZE); - log_sys->archive_buf_size = LOG_ARCHIVE_BUF_SIZE; + OS_FILE_LOG_BLOCK_SIZE); */ + log_sys->archive_buf_size = 0; - memset(log_sys->archive_buf, '\0', LOG_ARCHIVE_BUF_SIZE); + /* memset(log_sys->archive_buf, '\0', LOG_ARCHIVE_BUF_SIZE); */ log_sys->archiving_on = os_event_create(NULL); @@ -1107,8 +1102,8 @@ log_group_write_buf( ulint i; ut_ad(mutex_own(&(log_sys->mutex))); - ut_anp(len % OS_FILE_LOG_BLOCK_SIZE == 0); - ut_anp(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_a(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); if (new_data_offset == 0) { write_header = TRUE; @@ -2080,6 +2075,8 @@ log_archived_file_name_gen( ulint id, /* in: group id */ ulint file_no)/* in: file number */ { + ut_a(0); + UT_NOT_USED(id); /* Currently we only archive the first group */ sprintf(buf, "%sib_arch_log_%010lu", srv_arch_dir, file_no); @@ -2101,6 +2098,8 @@ log_group_archive_file_header_write( byte* buf; ulint dest_offset; + ut_a(0); + ut_ad(mutex_own(&(log_sys->mutex))); ut_a(nth_file < group->n_files); @@ -2138,6 +2137,8 @@ log_group_archive_completed_header_write( byte* buf; ulint dest_offset; + ut_a(0); + ut_ad(mutex_own(&(log_sys->mutex))); ut_a(nth_file < group->n_files); @@ -2177,15 +2178,17 @@ log_group_archive( ulint n_files; ulint open_mode; + ut_a(0); + ut_ad(mutex_own(&(log_sys->mutex))); start_lsn = log_sys->archived_lsn; - ut_anp(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_a(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); end_lsn = log_sys->next_archived_lsn; - ut_anp(ut_dulint_get_low(end_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_a(ut_dulint_get_low(end_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); buf = log_sys->archive_buf; @@ -2289,7 +2292,7 @@ loop: group->next_archived_file_no = group->archived_file_no + n_files; group->next_archived_offset = next_offset % group->file_size; - ut_anp(group->next_archived_offset % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_a(group->next_archived_offset % OS_FILE_LOG_BLOCK_SIZE == 0); } /********************************************************* @@ -2302,6 +2305,8 @@ log_archive_groups(void) { log_group_t* group; + ut_a(0); + ut_ad(mutex_own(&(log_sys->mutex))); group = UT_LIST_GET_FIRST(log_sys->log_groups); @@ -2325,6 +2330,8 @@ log_archive_write_complete_groups(void) dulint end_lsn; ulint i; + ut_a(0); + ut_ad(mutex_own(&(log_sys->mutex))); group = UT_LIST_GET_FIRST(log_sys->log_groups); @@ -2387,6 +2394,8 @@ void log_archive_check_completion_low(void) /*==================================*/ { + ut_a(0); + ut_ad(mutex_own(&(log_sys->mutex))); if (log_sys->n_pending_archive_ios == 0 @@ -2423,6 +2432,8 @@ log_io_complete_archive(void) { log_group_t* group; + ut_a(0); + mutex_enter(&(log_sys->mutex)); group = UT_LIST_GET_FIRST(log_sys->log_groups); @@ -2458,6 +2469,8 @@ log_archive_do( dulint start_lsn; dulint limit_lsn; + ut_a(0); + calc_new_limit = TRUE; loop: mutex_enter(&(log_sys->mutex)); @@ -2484,7 +2497,7 @@ loop: start_lsn = log_sys->archived_lsn; if (calc_new_limit) { - ut_anp(log_sys->archive_buf_size % OS_FILE_LOG_BLOCK_SIZE + ut_a(log_sys->archive_buf_size % OS_FILE_LOG_BLOCK_SIZE == 0); limit_lsn = ut_dulint_add(start_lsn, log_sys->archive_buf_size); @@ -2584,6 +2597,8 @@ log_archive_all(void) return; } + ut_a(0); + present_lsn = log_sys->lsn; mutex_exit(&(log_sys->mutex)); @@ -2621,11 +2636,17 @@ log_archive_close_groups( ut_ad(mutex_own(&(log_sys->mutex))); + if (log_sys->archiving_state == LOG_ARCH_OFF) { + + return; + } + + ut_a(0); + group = UT_LIST_GET_FIRST(log_sys->log_groups); trunc_len = UNIV_PAGE_SIZE * fil_space_get_size(group->archive_space_id); - if (trunc_len > 0) { ut_a(trunc_len == group->file_size); @@ -2653,17 +2674,18 @@ log_archive_close_groups( /******************************************************************** Writes the log contents to the archive up to the lsn when this function was called, and stops the archiving. When archiving is started again, the archived -log file numbers start from 2 higher, so that the archiving will -not write again to the archived log files which exist when this function -returns. */ +log file numbers start from 2 higher, so that the archiving will not write +again to the archived log files which exist when this function returns. */ ulint log_archive_stop(void) /*==================*/ - /* out: DB_SUCCESS or DB_ERROR */ + /* out: DB_SUCCESS or DB_ERROR */ { ibool success; + ut_a(0); + mutex_enter(&(log_sys->mutex)); if (log_sys->archiving_state != LOG_ARCH_ON) { @@ -2676,7 +2698,7 @@ log_archive_stop(void) log_sys->archiving_state = LOG_ARCH_STOPPING; mutex_exit(&(log_sys->mutex)); - + log_archive_all(); mutex_enter(&(log_sys->mutex)); @@ -2697,7 +2719,7 @@ log_archive_stop(void) if appropriate */ log_archive_close_groups(TRUE); - + mutex_exit(&(log_sys->mutex)); /* Make a checkpoint, so that if recovery is needed, the file numbers @@ -2726,6 +2748,8 @@ log_archive_start(void) /*===================*/ /* out: DB_SUCCESS or DB_ERROR */ { + ut_a(0); + mutex_enter(&(log_sys->mutex)); if (log_sys->archiving_state != LOG_ARCH_STOPPED) { @@ -2752,6 +2776,7 @@ log_archive_noarchivelog(void) /*==========================*/ /* out: DB_SUCCESS or DB_ERROR */ { + ut_a(0); loop: mutex_enter(&(log_sys->mutex)); @@ -2784,6 +2809,7 @@ log_archive_archivelog(void) /*========================*/ /* out: DB_SUCCESS or DB_ERROR */ { + ut_a(0); mutex_enter(&(log_sys->mutex)); if (log_sys->archiving_state == LOG_ARCH_OFF) { @@ -2791,7 +2817,7 @@ log_archive_archivelog(void) log_sys->archiving_state = LOG_ARCH_ON; log_sys->archived_lsn = ut_dulint_align_down(log_sys->lsn, - OS_FILE_LOG_BLOCK_SIZE); + OS_FILE_LOG_BLOCK_SIZE); mutex_exit(&(log_sys->mutex)); return(DB_SUCCESS); @@ -2802,6 +2828,7 @@ log_archive_archivelog(void) return(DB_ERROR); } +#ifdef notdefined /******************************************************************** Tries to establish a big enough margin of free space in the log groups, such that a new log entry can be catenated without an immediate need for @@ -2855,6 +2882,7 @@ loop: goto loop; } } +#endif /************************************************************************ Checks that there is enough free space in the log to start a new query step. @@ -2871,7 +2899,7 @@ loop: log_checkpoint_margin(); - log_archive_margin(); + /* log_archive_margin(); */ mutex_enter(&(log_sys->mutex)); @@ -3009,7 +3037,7 @@ loop: goto loop; } - log_archive_all(); + /* log_archive_all(); */ log_make_checkpoint_at(ut_dulint_max, TRUE); mutex_enter(&(log_sys->mutex)); @@ -3027,15 +3055,16 @@ loop: goto loop; } - arch_log_no = + arch_log_no = 0; +/* UT_LIST_GET_FIRST(log_sys->log_groups)->archived_file_no; if (0 == UT_LIST_GET_FIRST(log_sys->log_groups)->archived_offset) { arch_log_no--; } - - log_archive_close_groups(TRUE); +*/ + /* log_archive_close_groups(TRUE); */ mutex_exit(&(log_sys->mutex)); diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index cf9e3c89559..942dde78e35 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -721,7 +721,7 @@ recv_scan_log_seg_for_backup( /*********************************************************************** Tries to parse a single log record body and also applies it to a page if -specified. */ +specified. File ops are parsed, but not applied in this function. */ static byte* recv_parse_or_apply_log_rec_body( @@ -798,8 +798,14 @@ recv_parse_or_apply_log_rec_body( } else if (type == MLOG_INIT_FILE_PAGE) { new_ptr = fsp_parse_init_file_page(ptr, end_ptr, page); - } else if (type <= MLOG_WRITE_STRING) { + } else if (type == MLOG_WRITE_STRING) { new_ptr = mlog_parse_string(ptr, end_ptr, page); + + } else if (type == MLOG_FILE_CREATE + || type == MLOG_FILE_RENAME + || type == MLOG_FILE_DELETE) { + new_ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, FALSE, + ULINT_UNDEFINED); } else { new_ptr = NULL; @@ -1322,7 +1328,6 @@ loop: fprintf(stderr, "%lu ", (i * 100) / hash_get_n_cells(recv_sys->addr_hash)); - } } @@ -1376,130 +1381,132 @@ loop: } #ifdef UNIV_HOTBACKUP +/* This page is allocated from the buffer pool and used in the function +below */ +page_t* recv_backup_application_page = NULL; + /*********************************************************************** Applies log records in the hash table to a backup. */ void -recv_apply_log_recs_for_backup( -/*===========================*/ - ulint n_data_files, /* in: number of data files */ - char** data_files, /* in: array containing the paths to the - data files */ - ulint* file_sizes) /* in: sizes of the data files in database - pages */ +recv_apply_log_recs_for_backup(void) +/*================================*/ { recv_addr_t* recv_addr; - os_file_t data_file; - ulint n_pages_total = 0; - ulint nth_file = 0; - ulint nth_page_in_file= 0; + ulint n_hash_cells; byte* page; + ulint actual_size; ibool success; + ulint error; ulint i; recv_sys->apply_log_recs = TRUE; recv_sys->apply_batch_on = TRUE; - page = buf_pool->frame_zero; - - for (i = 0; i < n_data_files; i++) { - n_pages_total += file_sizes[i]; + if (recv_backup_application_page == NULL) { + recv_backup_application_page = buf_frame_alloc(); } - if (recv_max_parsed_page_no >= n_pages_total) { - printf( -"InnoDB: Error: tablespace size %lu pages, but a log record on page %lu!\n" -"InnoDB: Are you sure you have specified all the ibdata files right in\n" -"InnoDB: the my.cnf file you gave as the argument to ibbackup --restore?\n", - n_pages_total, recv_max_parsed_page_no); - } + page = recv_backup_application_page; printf( "InnoDB: Starting an apply batch of log records to the database...\n" "InnoDB: Progress in percents: "); - for (i = 0; i < n_pages_total; i++) { + n_hash_cells = hash_get_n_cells(recv_sys->addr_hash); - if (i == 0 || nth_page_in_file == file_sizes[nth_file]) { - if (i != 0) { - nth_file++; - nth_page_in_file = 0; - os_file_flush(data_file); - os_file_close(data_file); - } + for (i = 0; i < n_hash_cells; i++) { + /* The address hash table is externally chained */ + recv_addr = hash_get_nth_cell(recv_sys->addr_hash, i)->node; - data_file = os_file_create_simple(data_files[nth_file], - OS_FILE_OPEN, - OS_FILE_READ_WRITE, - &success); - if (!success) { + while (recv_addr != NULL) { + + if (!fil_tablespace_exists_in_mem(recv_addr->space)) { +/* printf( -"InnoDB: Error: cannot open %lu'th data file\n", nth_file); +"InnoDB: Warning: cannot apply log record to tablespace %lu page %lu,\n" +"InnoDB: because tablespace with that id does not exist.\n", + recv_addr->space, recv_addr->page_no); +*/ + recv_addr->state = RECV_PROCESSED; - exit(1); + ut_a(recv_sys->n_addrs); + recv_sys->n_addrs--; + + goto skip_this_recv_addr; } - } - - recv_addr = recv_get_fil_addr_struct(0, i); - - if (recv_addr != NULL) { - success = os_file_read(data_file, page, - (nth_page_in_file << UNIV_PAGE_SIZE_SHIFT) - & 0xFFFFFFFFUL, - nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT), - UNIV_PAGE_SIZE); + + /* We simulate a page read made by the buffer pool, to + make sure the recovery apparatus works ok, for + example, the buf_frame_align() function. We must init + the block corresponding to buf_pool->frame_zero + (== page). */ + + buf_page_init_for_backup_restore(recv_addr->space, + recv_addr->page_no, + buf_block_align(page)); + + /* Extend the tablespace's last file if the page_no + does not fall inside its bounds; we assume the last + file is auto-extending, and ibbackup copied the file + when it still was smaller */ + + success = fil_extend_space_to_desired_size( + &actual_size, + recv_addr->space, + recv_addr->page_no + 1); if (!success) { printf( -"InnoDB: Error: cannot read page no %lu from %lu'th data file\n", - nth_page_in_file, nth_file); +"InnoDB: Fatal error: cannot extend tablespace %lu to hold %lu pages\n", + recv_addr->space, recv_addr->page_no); + + exit(1); + } + /* Read the page from the tablespace file using the + fil0fil.c routines */ + + error = fil_io(OS_FILE_READ, TRUE, recv_addr->space, + recv_addr->page_no, 0, UNIV_PAGE_SIZE, + page, NULL); + if (error != DB_SUCCESS) { + printf( +"InnoDB: Fatal error: cannot read from tablespace %lu page number %lu\n", + recv_addr->space, recv_addr->page_no); + exit(1); } - - /* We simulate a page read made by the buffer pool, - to make sure recovery works ok. We must init the - block corresponding to buf_pool->frame_zero - (== page) */ - buf_page_init_for_backup_restore(0, i, - buf_block_align(page)); + /* Apply the log records to this page */ + recv_recover_page(TRUE, FALSE, page, recv_addr->space, + recv_addr->page_no); - recv_recover_page(TRUE, FALSE, page, 0, i); + /* Write the page back to the tablespace file using the + fil0fil.c routines */ buf_flush_init_for_writing(page, mach_read_from_8(page + FIL_PAGE_LSN), - 0, i); - - success = os_file_write(data_files[nth_file], - data_file, page, - (nth_page_in_file << UNIV_PAGE_SIZE_SHIFT) - & 0xFFFFFFFF, - nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT), - UNIV_PAGE_SIZE); - if (!success) { - printf( -"InnoDB: Error: cannot write page no %lu to %lu'th data file\n", - nth_page_in_file, nth_file); + recv_addr->space, recv_addr->page_no); - exit(1); - } + error = fil_io(OS_FILE_WRITE, TRUE, recv_addr->space, + recv_addr->page_no, 0, UNIV_PAGE_SIZE, + page, NULL); +skip_this_recv_addr: + recv_addr = HASH_GET_NEXT(addr_hash, recv_addr); } - if ((100 * i) / n_pages_total - != (100 * (i + 1)) / n_pages_total) { - printf("%lu ", (100 * i) / n_pages_total); + if ((100 * i) / n_hash_cells + != (100 * (i + 1)) / n_hash_cells) { + printf("%lu ", (100 * i) / n_hash_cells); fflush(stdout); } - - nth_page_in_file++; } - - os_file_flush(data_file); - os_file_close(data_file); recv_sys_empty_hash(); } +#endif +#ifdef notdefined /*********************************************************************** In the debug version, updates the replica of a file page, based on a log record. */ @@ -1737,7 +1744,7 @@ recv_parse_log_rec( return(0); } - /* Check that space id and page_no are sensible */ + /* Check that page_no is sensible */ if (*page_no > 0x8FFFFFFFUL) { @@ -1911,12 +1918,16 @@ loop: single_rec = (ulint)*ptr & MLOG_SINGLE_REC_FLAG; if (single_rec || *ptr == MLOG_DUMMY_RECORD) { - /* The mtr only modified a single page */ + /* The mtr only modified a single page, or this is a file op */ old_lsn = recv_sys->recovered_lsn; + /* Try to parse a log record, fetching its type, space id, + page no, and a pointer to the body of the log record */ + len = recv_parse_log_rec(ptr, end_ptr, &type, &space, &page_no, &body); + if (len == 0 || recv_sys->found_corrupt_log) { if (recv_sys->found_corrupt_log) { @@ -1954,6 +1965,26 @@ loop: if (type == MLOG_DUMMY_RECORD) { /* Do nothing */ + } else if (store_to_hash && (type == MLOG_FILE_CREATE + || type == MLOG_FILE_RENAME + || type == MLOG_FILE_DELETE)) { +#ifdef UNIV_HOTBACKUP + /* In ibbackup --apply-log, replay an .ibd file + operation, if possible; note that + fil_path_to_mysql_datadir is set in ibbackup to + point to the datadir we should use there */ + + if (NULL == fil_op_log_parse_or_replay(body, end_ptr, + type, TRUE, space)) { + fprintf(stderr, +"InnoDB: Error: file op log record of type %lu space %lu not complete in\n" +"InnoDB: the replay phase. Path %s\n", (ulint)type, space, (char*)(body + 2)); + + ut_a(0); + } +#endif + /* In normal mysqld crash recovery we do not try to + replay file operations */ } else if (store_to_hash) { recv_add_to_hash_table(type, space, page_no, body, ptr + len, old_lsn, @@ -2915,6 +2946,8 @@ recv_reset_log_files_for_backup( buf = ut_malloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE); + memset(buf, LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE, '\0'); + for (i = 0; i < n_log_files; i++) { sprintf(name, "%sib_logfile%lu", log_dir, i); @@ -2954,7 +2987,7 @@ recv_reset_log_files_for_backup( log_block_init_in_old_format(buf + LOG_FILE_HDR_SIZE, lsn); log_block_set_first_rec_group(buf + LOG_FILE_HDR_SIZE, LOG_BLOCK_HDR_SIZE); - sprintf(name, "%sib_logfile%lu", log_dir, 0); + sprintf(name, "%sib_logfile%lu", log_dir, 0UL); log_file = os_file_create_simple(name, OS_FILE_OPEN, OS_FILE_READ_WRITE, &success); @@ -2996,6 +3029,8 @@ log_group_recover_from_archive_file( int input_char; char name[10000]; + ut_a(0); + try_open_again: buf = log_sys->buf; @@ -3173,6 +3208,8 @@ recv_recovery_from_archive_start( ibool ret; ulint err; + ut_a(0); + recv_sys_create(); recv_sys_init(FALSE, buf_pool_get_curr_size()); @@ -3271,6 +3308,8 @@ void recv_recovery_from_archive_finish(void) /*===================================*/ { + ut_a(0); + recv_recovery_from_checkpoint_finish(); recv_recovery_from_backup_on = FALSE; diff --git a/innobase/mem/mem0pool.c b/innobase/mem/mem0pool.c index 9b1aea089d1..274daae1d4e 100644 --- a/innobase/mem/mem0pool.c +++ b/innobase/mem/mem0pool.c @@ -603,7 +603,7 @@ mem_pool_validate( } } - ut_anp(free + pool->reserved == pool->size); + ut_a(free + pool->reserved == pool->size); mutex_exit(&(pool->mutex)); diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 4b9289d2b93..b6d4eba9f9b 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -595,6 +595,51 @@ next_file: #endif } +/********************************************************************* +This function attempts to create a directory named pathname. The new directory +gets default permissions. On Unix the permissions are (0770 & ~umask). If the +directory exists already, nothing is done and the call succeeds, unless the +fail_if_exists arguments is true. */ + +ibool +os_file_create_directory( +/*=====================*/ + /* out: TRUE if call succeeds, FALSE on + error */ + char* pathname, /* in: directory name as null-terminated + string */ + ibool fail_if_exists) /* in: if TRUE, pre-existing directory is + treated as an error. */ +{ +#ifdef __WIN__ + BOOL rcode; + + rcode = CreateDirectory(pathname, NULL); + if (!(rcode != 0 || + (GetLastError() == ERROR_FILE_EXISTS && !fail_if_exists))) { + /* failure */ + os_file_handle_error(NULL, pathname, "CreateDirectory"); + + return(FALSE); + } + + return (TRUE); +#else + int rcode; + + rcode = mkdir(pathname, 0770); + + if (!(rcode == 0 || (errno == EEXIST && !fail_if_exists))) { + /* failure */ + os_file_handle_error(0, pathname, "mkdir"); + + return(FALSE); + } + + return (TRUE); +#endif +} + /******************************************************************** A simple function to open or create a file. */ @@ -602,7 +647,8 @@ os_file_t os_file_create_simple( /*==================*/ /* out, own: handle to the file, not defined if error, - error number can be retrieved with os_get_last_error */ + error number can be retrieved with + os_file_get_last_error */ char* name, /* in: name of the file or path as a null-terminated string */ ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened @@ -714,13 +760,16 @@ os_file_t os_file_create_simple_no_error_handling( /*====================================*/ /* out, own: handle to the file, not defined if error, - error number can be retrieved with os_get_last_error */ + error number can be retrieved with + os_file_get_last_error */ char* name, /* in: name of the file or path as a null-terminated string */ ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened (if does not exist, error), or OS_FILE_CREATE if a new file is created (if exists, error) */ - ulint access_type,/* in: OS_FILE_READ_ONLY or OS_FILE_READ_WRITE */ + ulint access_type,/* in: OS_FILE_READ_ONLY, OS_FILE_READ_WRITE, or + OS_FILE_READ_ALLOW_DELETE; the last option is used by + a backup program reading the file */ ibool* success)/* out: TRUE if succeed, FALSE if error */ { #ifdef __WIN__ @@ -728,6 +777,7 @@ os_file_create_simple_no_error_handling( DWORD create_flag; DWORD access; DWORD attributes = 0; + DWORD share_mode = FILE_SHARE_READ; ut_a(name); @@ -744,6 +794,13 @@ os_file_create_simple_no_error_handling( access = GENERIC_READ; } else if (access_type == OS_FILE_READ_WRITE) { access = GENERIC_READ | GENERIC_WRITE; + } else if (access_type == OS_FILE_READ_ALLOW_DELETE) { + access = GENERIC_READ; + share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ + | FILE_SHARE_WRITE; /* A backup program has to give + mysqld the maximum freedom to + do what it likes with the + file */ } else { access = 0; ut_error; @@ -751,8 +808,7 @@ os_file_create_simple_no_error_handling( file = CreateFile(name, access, - FILE_SHARE_READ,/* file can be read also by other - processes */ + share_mode, NULL, /* default security attributes */ create_flag, attributes, @@ -808,7 +864,8 @@ os_file_t os_file_create( /*===========*/ /* out, own: handle to the file, not defined if error, - error number can be retrieved with os_get_last_error */ + error number can be retrieved with + os_file_get_last_error */ char* name, /* in: name of the file or path as a null-terminated string */ ulint create_mode, /* in: OS_FILE_OPEN if an existing file is opened @@ -896,7 +953,7 @@ try_again: start 2 instances of mysqld on the SAME files, that could cause severe database corruption! When opening - raw disk partitions Microsoft manuals + raw disk partitions, Microsoft manuals say that we must give also the write permission. */ NULL, /* default security attributes */ @@ -1017,6 +1074,10 @@ os_file_delete( { #ifdef __WIN__ BOOL ret; + ulint count = 0; +loop: + /* In Windows, deleting an .ibd file may fail if ibbackup is copying + it */ ret = DeleteFile((LPCTSTR)name); @@ -1024,9 +1085,31 @@ os_file_delete( return(TRUE); } - os_file_handle_error(NULL, name, "delete"); + if (GetLastError() == ERROR_PATH_NOT_FOUND) { + /* If the file does not exist, we classify this as a 'mild' + error and return */ - return(FALSE); + return(FALSE); + } + + count++; + + if (count > 100 && 0 == (count % 10)) { + fprintf(stderr, +"InnoDB: Warning: cannot delete file %s\n" +"InnoDB: Are you running ibbackup to back up the file?\n", name); + + os_file_get_last_error(TRUE); /* print error information */ + } + + os_thread_sleep(1000000); /* sleep for a second */ + + if (count > 2000) { + + return(FALSE); + } + + goto loop; #else int ret; @@ -1103,6 +1186,7 @@ os_file_close( } os_file_handle_error(file, NULL, "close"); + return(FALSE); #else int ret; @@ -1111,6 +1195,7 @@ os_file_close( if (ret == -1) { os_file_handle_error(file, NULL, "close"); + return(FALSE); } @@ -3010,7 +3095,15 @@ consecutive_loop: /* Do the i/o with ordinary, synchronous i/o functions: */ if (slot->type == OS_FILE_WRITE) { if (array == os_aio_write_array) { - + if ((total_len % UNIV_PAGE_SIZE != 0) + || (slot->offset % UNIV_PAGE_SIZE != 0)) { + fprintf(stderr, +"InnoDB: Error: trying a displaced write to %s %lu %lu, len %lu\n", + slot->name, slot->offset_high, + slot->offset, total_len); + ut_a(0); + } + /* Do a 'last millisecond' check that the page end is sensible; reported page checksum errors from Linux seem to wipe over the page end */ diff --git a/innobase/pars/lexyy.c b/innobase/pars/lexyy.c index 71507ccd868..7c6711d2f97 100644 --- a/innobase/pars/lexyy.c +++ b/innobase/pars/lexyy.c @@ -1,7 +1,7 @@ /* A lexical scanner generated by flex */ /* Scanner skeleton version: - * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ + * $Header: /home/heikki/cvsroot/ib/pars/lexyy.c,v 1.2 2003/10/30 20:27:19 heikki Exp $ */ #define FLEX_SCANNER diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 661aec3d9a9..61bb41fe3e6 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -2346,8 +2346,13 @@ row_drop_table_for_mysql( /* Do not drop possible .ibd tablespace if something went wrong: we do not want to delete valuable data of the user */ - if (err == DB_SUCCESS && space_id != 0 - && fil_tablespace_exists_in_mem(space_id)) { + if (err == DB_SUCCESS && space_id > 0) { + if (!fil_space_for_table_exists_in_mem(space_id, name, + FALSE, TRUE)) { + err = DB_ERROR; + + goto funct_exit; + } success = fil_delete_tablespace(space_id); diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index e6022abe105..f41574b2855 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -3287,8 +3287,14 @@ rec_loop: latest version of the record */ } else if (index == clust_index) { - - if (!lock_clust_rec_cons_read_sees(rec, index, + + /* Fetch a previous version of the row if the current + one is not visible in the snapshot; if we have a very + high force recovery level set, we try to avoid crashes + by skipping this lookup */ + + if (srv_force_recovery < 5 + && !lock_clust_rec_cons_read_sees(rec, index, trx->read_view)) { err = row_sel_build_prev_vers_for_mysql( diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 2f3502f99ad..9987804f03e 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -102,7 +102,7 @@ char** srv_log_group_home_dirs = NULL; ulint srv_n_log_groups = ULINT_MAX; ulint srv_n_log_files = ULINT_MAX; ulint srv_log_file_size = ULINT_MAX; /* size in database pages */ -ibool srv_log_archive_on = TRUE; +ibool srv_log_archive_on = FALSE; ulint srv_log_buffer_size = ULINT_MAX; /* size in database pages */ ulint srv_flush_log_at_trx_commit = 1; @@ -1717,7 +1717,7 @@ srv_init(void) os_fast_mutex_init(&srv_conc_mutex); UT_LIST_INIT(srv_conc_queue); - + srv_conc_slots = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_conc_slot_t)); for (i = 0; i < OS_THREAD_MAX_N; i++) { @@ -3209,11 +3209,13 @@ flush_loop: goto loop; } mutex_exit(&kernel_mutex); - +/* srv_main_thread_op_info = (char*)"archiving log (if log archive is on)"; log_archive_do(FALSE, &n_bytes_archived); +*/ + n_bytes_archived = 0; /* Keep looping in the background loop if still work to do */ diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 83cde6e6589..067aec36627 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -553,7 +553,6 @@ open_or_create_log_file( ulint i) /* in: log file number in group */ { ibool ret; - ulint arch_space_id; ulint size; ulint size_high; char name[10000]; @@ -649,9 +648,10 @@ open_or_create_log_file( fil_node_create(name, srv_log_file_size, 2 * k + SRV_LOG_SPACE_FIRST_ID, FALSE); - +#ifdef notdefined /* If this is the first log group, create the file space object - for archived logs */ + for archived logs. + Under MySQL, no archiving ever done. */ if (k == 0 && i == 0) { arch_space_id = 2 * k + 1 + SRV_LOG_SPACE_FIRST_ID; @@ -661,12 +661,13 @@ open_or_create_log_file( } else { arch_space_id = ULINT_UNDEFINED; } - +#endif if (i == 0) { log_group_init(k, srv_n_log_files, srv_log_file_size * UNIV_PAGE_SIZE, 2 * k + SRV_LOG_SPACE_FIRST_ID, - arch_space_id); + SRV_LOG_SPACE_FIRST_ID + 1); /* dummy arch + space id */ } return(DB_SUCCESS); @@ -1000,7 +1001,6 @@ innobase_start_or_create_for_mysql(void) dulint max_flushed_lsn; ulint min_arch_log_no; ulint max_arch_log_no; - ibool start_archive; ulint sum_of_new_sizes; ulint sum_of_data_file_sizes; ulint tablespace_size_in_header; @@ -1156,7 +1156,7 @@ NetWare. */ assume fewer threads. */ srv_max_n_threads = 10000; } else { - srv_max_n_threads = 1000; /* saves several MB of memory, + srv_max_n_threads = 1000; /* saves several MB of memory, especially in 64-bit computers */ } @@ -1164,6 +1164,28 @@ NetWare. */ /* Note that the call srv_boot() also changes the values of srv_pool_size etc. to the units used by InnoDB internally */ + /* Set the maximum number of threads which can wait for a semaphore + inside InnoDB */ +#if defined(__WIN__) || defined(__NETWARE__) + +/* Create less event semaphores because Win 98/ME had difficulty creating +40000 event semaphores. +Comment from Novell, Inc.: also, these just take a lot of memory on +NetWare. */ + srv_max_n_threads = 1000; +#else + if (srv_pool_size >= 8 * 1024 * 1024) { + /* Here we still have srv_pool_size counted + in bytes, srv_boot converts the value to + pages; if buffer pool is less than 8 MB, + assume fewer threads. */ + srv_max_n_threads = 10000; + } else { + srv_max_n_threads = 1000; /* saves several MB of memory, + especially in 64-bit + computers */ + } +#endif err = srv_boot(); if (err != DB_SUCCESS) { @@ -1341,7 +1363,9 @@ NetWare. */ mutex_enter(&(log_sys->mutex)); - recv_reset_logs(max_flushed_lsn, max_arch_log_no + 1, TRUE); + /* Do not + 1 arch_log_no because we do not use log + archiving */ + recv_reset_logs(max_flushed_lsn, max_arch_log_no, TRUE); mutex_exit(&(log_sys->mutex)); } @@ -1430,6 +1454,8 @@ NetWare. */ log_make_checkpoint_at(ut_dulint_max, TRUE); +#ifdef notdefined + /* Archiving is always off under MySQL */ if (!srv_log_archive_on) { ut_a(DB_SUCCESS == log_archive_noarchivelog()); } else { @@ -1447,7 +1473,7 @@ NetWare. */ ut_a(DB_SUCCESS == log_archive_archivelog()); } } - +#endif if (!create_new_db && srv_force_recovery == 0) { /* After a crash recovery we only check that the info in data dictionary is consistent with what we already know about space diff --git a/innobase/ut/ut0dbg.c b/innobase/ut/ut0dbg.c index 970dd501fad..6cd0ed62454 100644 --- a/innobase/ut/ut0dbg.c +++ b/innobase/ut/ut0dbg.c @@ -19,9 +19,10 @@ ibool ut_dbg_stop_threads = FALSE; ulint* ut_dbg_null_ptr = NULL; -/* Dummy function to prevent gcc from ignoring this file */ -void -ut_dummy(void) -{ - printf("Hello world\n"); -} +const char* ut_dbg_msg_assert_fail = +"InnoDB: Assertion failure in thread %lu in file %s line %lu\n"; +const char* ut_dbg_msg_trap = +"InnoDB: We intentionally generate a memory trap.\n" +"InnoDB: Send a detailed bug report to mysql@lists.mysql.com.\n"; +const char* ut_dbg_msg_stop = +"InnoDB: Thread %lu stopped in file %s line %lu\n"; diff --git a/innobase/ut/ut0rnd.c b/innobase/ut/ut0rnd.c index 3335861384f..85d2e6094c3 100644 --- a/innobase/ut/ut0rnd.c +++ b/innobase/ut/ut0rnd.c @@ -71,9 +71,8 @@ ut_find_prime( /* Found a prime */ break; - next_n: ; +next_n: ; } return(n); } - diff --git a/innobase/ut/ut0ut.c b/innobase/ut/ut0ut.c index be311764261..f3be1a082a2 100644 --- a/innobase/ut/ut0ut.c +++ b/innobase/ut/ut0ut.c @@ -63,7 +63,7 @@ ut_get_high32( } /************************************************************ -The following function returns a clock time in milliseconds. */ +The following function returns elapsed CPU time in milliseconds. */ ulint ut_clock(void) @@ -182,6 +182,50 @@ ut_sprintf_timestamp( } /************************************************************** +Sprintfs a timestamp to a buffer with no spaces and with ':' characters +replaced by '_'. */ + +void +ut_sprintf_timestamp_without_extra_chars( +/*=====================================*/ + char* buf) /* in: buffer where to sprintf */ +{ +#ifdef __WIN__ + SYSTEMTIME cal_tm; + + GetLocalTime(&cal_tm); + + sprintf(buf, "%02d%02d%02d_%2d_%02d_%02d", + (int)cal_tm.wYear % 100, + (int)cal_tm.wMonth, + (int)cal_tm.wDay, + (int)cal_tm.wHour, + (int)cal_tm.wMinute, + (int)cal_tm.wSecond); +#else + struct tm cal_tm; + struct tm* cal_tm_ptr; + time_t tm; + + time(&tm); + +#ifdef HAVE_LOCALTIME_R + localtime_r(&tm, &cal_tm); + cal_tm_ptr = &cal_tm; +#else + cal_tm_ptr = localtime(&tm); +#endif + sprintf(buf, "%02d%02d%02d_%2d_%02d_%02d", + cal_tm_ptr->tm_year % 100, + cal_tm_ptr->tm_mon + 1, + cal_tm_ptr->tm_mday, + cal_tm_ptr->tm_hour, + cal_tm_ptr->tm_min, + cal_tm_ptr->tm_sec); +#endif +} + +/************************************************************** Returns current year, month, day. */ void diff --git a/isam/extra.c b/isam/extra.c index e2f13532ddf..3bf1dd012ed 100644 --- a/isam/extra.c +++ b/isam/extra.c @@ -250,17 +250,15 @@ int nisam_extra(N_INFO *info, enum ha_extra_function function) pthread_mutex_unlock(&THR_LOCK_isam); break; case HA_EXTRA_FLUSH: -#ifdef __WIN__ if (info->s->not_flushed) { info->s->not_flushed=0; - if (_commit(info->s->kfile)) - error=errno; - if (_commit(info->dfile)) - error=errno; + if (my_sync(info->s->kfile, MYF(0))) + error= my_errno; + if (my_sync(info->dfile, MYF(0))) + error= my_errno; } break; -#endif case HA_EXTRA_NORMAL: /* Theese isn't in use */ case HA_EXTRA_QUICK: case HA_EXTRA_KEY_CACHE: diff --git a/libmysql/manager.c b/libmysql/manager.c index 1354b98d1c9..ddf9b6c1010 100644 --- a/libmysql/manager.c +++ b/libmysql/manager.c @@ -90,7 +90,7 @@ MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con, { my_socket sock; struct sockaddr_in sock_addr; - uint32 ip_addr; + in_addr_t ip_addr; char msg_buf[MAX_MYSQL_MANAGER_MSG]; int msg_len; Vio* vio; diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 09b03bce79a..95cbd4ec826 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -38,7 +38,7 @@ libmysqlsources = errmsg.c get_password.c libmysql.c client.c pack.c noinst_HEADERS = embedded_priv.h -sqlsources = derror.cc field.cc field_conv.cc filesort.cc \ +sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ ha_innodb.cc ha_berkeley.cc ha_heap.cc ha_isam.cc ha_isammrg.cc \ ha_myisam.cc ha_myisammrg.cc handler.cc sql_handler.cc \ hostname.cc init.cc password.c \ @@ -92,10 +92,10 @@ libmysqld.a: libmysqld_int.a $(INC_LIB) ar x $$file; \ for obj in *.o ; do mv $$obj $${bfile}_$$obj ; done ; \ ar q ../libmysqld_int2.a *.o ; \ - rm *.o ; \ + rm -f *.o ; \ done mv libmysqld_int2.a libmysqld.a - rm tmp/* + rm -f tmp/* $(RANLIB) libmysqld.a ## XXX: any time the client interface changes, we'll need to bump diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 95d0149c67d..f3b593f7341 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -362,7 +362,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, Hack: instead of init_queue, we'll use reinit queue to be able to alloc queue with alloc_root() */ - res=ftb->queue.max_elements=1+query_len/(ft_min_word_len+1); + res=ftb->queue.max_elements=1+query_len/(min(ft_min_word_len,2)+1); ftb->queue.root=(byte **)alloc_root(&ftb->mem_root, (res+1)*sizeof(void*)); reinit_queue(& ftb->queue, res, 0, 0, (int (*)(void*,byte*,byte*))FTB_WORD_cmp, 0); diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index 1d57e0c0e18..8c7515550e7 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -336,22 +336,10 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) if (share->not_flushed) { share->not_flushed=0; -#if defined(__WIN__) - if (_commit(share->kfile)) - error=errno; - if (_commit(info->dfile)) - error=errno; -#elif defined(HAVE_FDATASYNC) - if (fdatasync(share->kfile)) - error=errno; - if (fdatasync(share->dfile)) - error=errno; -#elif defined(HAVE_FSYNC) - if ( fsync(share->kfile)) - error=errno; - if (fsync(share->dfile)) - error=errno; -#endif + if (my_sync(share->kfile, MYF(0))) + error= my_errno; + if (my_sync(info->dfile, MYF(0))) + error= my_errno; if (error) { share->changed=1; diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index 785979235ce..6f996ab5abd 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -98,22 +98,10 @@ int mi_lock_database(MI_INFO *info, int lock_type) share->changed=0; if (myisam_flush) { -#if defined(__WIN__) - if (_commit(share->kfile)) - error=errno; - if (_commit(info->dfile)) - error=errno; -#elif defined(HAVE_FDATASYNC) - if (fdatasync(share->kfile)) - error=errno; - if (fdatasync(share->dfile)) - error=errno; -#elif defined(HAVE_FSYNC) - if (fsync(share->kfile)) - error=errno; - if (fsync(share->dfile)) - error=errno; -#endif + if (my_sync(share->kfile, MYF(0))) + error= my_errno; + if (my_sync(info->dfile, MYF(0))) + error= my_errno; } else share->not_flushed=1; diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 744bb9bb3b6..0b4e8681bdd 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -508,6 +508,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) &info.buff,(share->base.max_key_block_length*2+ share->base.max_key_length), &info.lastkey,share->base.max_key_length*3+1, + &info.first_mbr_key, share->base.max_key_length, &info.filename,strlen(org_name)+1, &info.rtree_recursion_state,have_rtree ? 1024 : 0, NullS)) diff --git a/myisam/mi_rnext_same.c b/myisam/mi_rnext_same.c index 200e715bddc..19190a60246 100644 --- a/myisam/mi_rnext_same.c +++ b/myisam/mi_rnext_same.c @@ -41,17 +41,20 @@ int mi_rnext_same(MI_INFO *info, byte *buf) if (info->s->concurrent_insert) rw_rdlock(&info->s->key_root_lock[inx]); - switch(keyinfo->key_alg) + switch (keyinfo->key_alg) { case HA_KEY_ALG_RTREE: - if((error=rtree_find_next(info,inx,myisam_read_vec[info->last_key_func]))) - { - /* FIXME: What to do?*/ - } + if ((error=rtree_find_next(info,inx, + myisam_read_vec[info->last_key_func]))) + { + error=1; + my_errno=HA_ERR_END_OF_FILE; + info->lastpos= HA_OFFSET_ERROR; + break; + } break; case HA_KEY_ALG_BTREE: default: - memcpy(info->lastkey2,info->lastkey,info->last_rkey_length); for (;;) { diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 5a3768c9932..59cc26b198b 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -411,6 +411,8 @@ static void usage(void) -q, --quick Faster repair by not modifying the data file.\n\ One can give a second '-q' to force myisamchk to\n\ modify the original datafile in case of duplicate keys.\n\ + NOTE: Tables where the data file is currupted can't be\n\ + fixed with this option.\n\ -u, --unpack Unpack file packed with myisampack.\n\ "); @@ -1109,7 +1111,7 @@ end2: filename)); if (param->testflag & T_REP_ANY) VOID(fprintf(stderr, - "Try fixing it by using the --safe-recover (-o) or the --force (-f) option\n")); + "Try fixing it by using the --safe-recover (-o), the --force (-f) option or by not using the --quick (-q) flag\n")); } else if (!(param->error_printed & 2) && !(param->testflag & T_FORCE_CREATE)) diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 3b1dd1fbf92..c23959d995c 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -229,6 +229,7 @@ struct st_myisam_info { char *filename; /* parameter to open filename */ uchar *buff, /* Temp area for key */ *lastkey,*lastkey2; /* Last used search key */ + uchar *first_mbr_key; /* Searhed spatial key */ byte *rec_buff; /* Tempbuff for recordpack */ uchar *int_keypos, /* Save position for next/previous */ *int_maxpos; /* -""- */ diff --git a/myisam/rt_index.c b/myisam/rt_index.c index 8b877d2e65c..30146b9fd67 100644 --- a/myisam/rt_index.c +++ b/myisam/rt_index.c @@ -36,16 +36,21 @@ typedef struct st_page_list stPageLevel *pages; } stPageList; + /* -Find next key in r-tree according to search_flag recursively -Used in rtree_find_first() and rtree_find_next() -Result values: --1 - error - 0 - found - 1 - not found + Find next key in r-tree according to search_flag recursively + + NOTES + Used in rtree_find_first() and rtree_find_next() + + RETURN + -1 Error + 0 Found + 1 Not found */ -static int rtree_find_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint search_flag, uint nod_cmp_flag, - my_off_t page, int level) + +static int rtree_find_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint search_flag, + uint nod_cmp_flag, my_off_t page, int level) { uchar *k; uchar *last; @@ -81,7 +86,7 @@ static int rtree_find_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint search_flag, u if (nod_flag) { /* this is an internal node in the tree */ - if (!(res = rtree_key_cmp(keyinfo->seg, info->lastkey2, k, + if (!(res = rtree_key_cmp(keyinfo->seg, info->first_mbr_key, k, info->last_rkey_length, nod_cmp_flag))) { switch ((res = rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, @@ -102,7 +107,7 @@ static int rtree_find_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint search_flag, u else { /* this is a leaf */ - if (!rtree_key_cmp(keyinfo->seg, info->lastkey2, k, + if (!rtree_key_cmp(keyinfo->seg, info->first_mbr_key, k, info->last_rkey_length, search_flag)) { uchar *after_key = rt_PAGE_NEXT_KEY(k, k_len, nod_flag); @@ -143,13 +148,24 @@ err1: return -1; } + /* -Find first key in r-tree according to search_flag condition -Result values: --1 - error - 0 - found - 1 - not found + Find first key in r-tree according to search_flag condition + + SYNOPSIS + rtree_find_first() + info Handler to MyISAM file + uint keynr Key number to use + key Key to search for + key_length Length of 'key' + search_flag Bitmap of flags how to do the search + + RETURN + -1 Error + 0 Found + 1 Not found */ + int rtree_find_first(MI_INFO *info, uint keynr, uchar *key, uint key_length, uint search_flag) { @@ -164,7 +180,8 @@ int rtree_find_first(MI_INFO *info, uint keynr, uchar *key, uint key_length, } /* Save searched key */ - memcpy(info->lastkey2, key, keyinfo->keylength - info->s->base.rec_reflength); + memcpy(info->first_mbr_key, key, keyinfo->keylength - + info->s->base.rec_reflength); info->last_rkey_length = key_length; info->rtree_recursion_depth = -1; @@ -175,13 +192,22 @@ int rtree_find_first(MI_INFO *info, uint keynr, uchar *key, uint key_length, return rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, root, 0); } + /* -Find next key in r-tree according to search_flag condition -Result values: --1 - error - 0 - found - 1 - not found + Find next key in r-tree according to search_flag condition + + SYNOPSIS + rtree_find_next() + info Handler to MyISAM file + uint keynr Key number to use + search_flag Bitmap of flags how to do the search + + RETURN + -1 Error + 0 Found + 1 Not found */ + int rtree_find_next(MI_INFO *info, uint keynr, uint search_flag) { my_off_t root; @@ -189,40 +215,30 @@ int rtree_find_next(MI_INFO *info, uint keynr, uint search_flag) MI_KEYDEF *keyinfo = info->s->keyinfo + keynr; if (info->update & HA_STATE_DELETED) - { return rtree_find_first(info, keynr, info->lastkey, info->lastkey_length, search_flag); - } - + if (!info->buff_used) { - uchar *key = info->int_keypos; + uchar *key= info->int_keypos; while (key < info->int_maxpos) { - if (!rtree_key_cmp(keyinfo->seg, info->lastkey2, key, + if (!rtree_key_cmp(keyinfo->seg, info->first_mbr_key, key, info->last_rkey_length, search_flag)) { uchar *after_key = key + keyinfo->keylength; - info->lastpos = _mi_dpos(info, 0, after_key); + info->lastpos= _mi_dpos(info, 0, after_key); memcpy(info->lastkey, key, info->lastkey_length); if (after_key < info->int_maxpos) - { - info->int_keypos = after_key; - } + info->int_keypos= after_key; else - { - info->buff_used = 1; - } - + info->buff_used= 1; return 0; } - else - { - key += keyinfo->keylength; - } + key+= keyinfo->keylength; } } if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) @@ -236,14 +252,19 @@ int rtree_find_next(MI_INFO *info, uint keynr, uint search_flag) return rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, root, 0); } + /* -Get next key in r-tree recursively -Used in rtree_get_first() and rtree_get_next() -Result values: --1 - error - 0 - found - 1 - not found + Get next key in r-tree recursively + + NOTES + Used in rtree_get_first() and rtree_get_next() + + RETURN + -1 Error + 0 Found + 1 Not found */ + static int rtree_get_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint key_length, my_off_t page, int level) { @@ -339,13 +360,16 @@ err1: return -1; } + /* -Get first key in r-tree -Result values: --1 - error - 0 - found - 1 - not found + Get first key in r-tree + + RETURN + -1 Error + 0 Found + 1 Not found */ + int rtree_get_first(MI_INFO *info, uint keynr, uint key_length) { my_off_t root; @@ -363,12 +387,16 @@ int rtree_get_first(MI_INFO *info, uint keynr, uint key_length) return rtree_get_req(info, &keyinfo[keynr], key_length, root, 0); } -/* Get next key in r-tree -Result values: --1 - error - 0 - found - 1 - not found + +/* + Get next key in r-tree + + RETURN + -1 Error + 0 Found + 1 Not found */ + int rtree_get_next(MI_INFO *info, uint keynr, uint key_length) { my_off_t root; @@ -407,13 +435,16 @@ int rtree_get_next(MI_INFO *info, uint keynr, uint key_length) } } + /* -Go down and insert key into tree -Result values: --1 - error - 0 - child was not split - 1 - child was split + Go down and insert key into tree + + RETURN + -1 Error + 0 Child was not split + 1 Child was split */ + static int rtree_insert_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, uint key_length, my_off_t page, my_off_t *new_page, int ins_level, int level) @@ -490,13 +521,16 @@ err1: return -1; } + /* -Insert key into the tree -Result values: --1 - error - 0 - root was not split - 1 - root was split + Insert key into the tree + + RETURN + -1 Error + 0 Root was not split + 1 Root was split */ + static int rtree_insert_level(MI_INFO *info, uint keynr, uchar *key, uint key_length, int ins_level) { @@ -580,20 +614,29 @@ err1: return res; } + /* -Insert key into the tree - interface function -Result values: --1 - error - 0 - OK + Insert key into the tree - interface function + + RETURN + -1 Error + 0 OK */ + int rtree_insert(MI_INFO *info, uint keynr, uchar *key, uint key_length) { return (rtree_insert_level(info, keynr, key, key_length, -1) == -1) ? -1 : 0; } + /* -Fill reinsert page buffer + Fill reinsert page buffer + + RETURN + -1 Error + 0 OK */ + static int rtree_fill_reinsert_list(stPageList *ReinsertList, my_off_t page, int level) { @@ -614,14 +657,17 @@ err1: return -1; } + /* -Go down and delete key from the tree -Result values: --1 - error - 0 - deleted - 1 - not found - 2 - empty leaf + Go down and delete key from the tree + + RETURN + -1 Error + 0 Deleted + 1 Not found + 2 Empty leaf */ + static int rtree_delete_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, uint key_length, my_off_t page, uint *page_size, stPageList *ReinsertList, int level) @@ -740,12 +786,15 @@ err1: return -1; } + /* -Delete key - interface function -Result values: --1 - error - 0 - deleted + Delete key - interface function + + RETURN + -1 Error + 0 Deleted */ + int rtree_delete(MI_INFO *info, uint keynr, uchar *key, uint key_length) { uint page_size; @@ -846,9 +895,14 @@ err1: } } + /* -Estimate number of suitable keys in the tree + Estimate number of suitable keys in the tree + + RETURN + estimated value */ + ha_rows rtree_estimate(MI_INFO *info, uint keynr, uchar *key, uint key_length, uint flag) { diff --git a/myisam/rt_split.c b/myisam/rt_split.c index 41d6f8f8ccd..62b8ea6a65b 100644 --- a/myisam/rt_split.c +++ b/myisam/rt_split.c @@ -326,7 +326,8 @@ int rtree_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key, cur2 = rt_PAGE_NEXT_KEY(cur2, key_length, nod_flag); ++n2; } - memcpy(to - nod_flag, cur->key - nod_flag, full_length); + if (to != cur->key) + memcpy(to - nod_flag, cur->key - nod_flag, full_length); } mi_putint(page, 2 + n1 * full_length, nod_flag); diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 94affe6b2f7..46d6819b819 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -337,13 +337,23 @@ while test $# -gt 0; do EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --gdb" EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --gdb" ;; - --valgrind) - VALGRIND="valgrind --alignment=8 --leak-check=yes --num-callers=16" + --valgrind | --valgrind-all) + VALGRIND=`which valgrind` # this will print an error if not found + # Give good warning to the user and stop + if [ -z "$VALGRIND" ] ; then + $ECHO "You need to have the 'valgrind' program in your PATH to run mysql-test-run with option --valgrind. Valgrind's home page is http://developer.kde.org/~sewardj ." + exit 1 + fi + VALGRIND="$VALGRIND --alignment=8 --leak-check=yes --num-callers=16" EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-safemalloc --skip-bdb" EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-safemalloc --skip-bdb" SLEEP_TIME_AFTER_RESTART=10 SLEEP_TIME_FOR_DELETE=60 USE_RUNNING_SERVER="" + if test "$1" = "--valgrind-all" + then + VALGRIND="$VALGRIND -v --show-reachable=yes" + fi ;; --valgrind-options=*) TMP=`$ECHO "$1" | $SED -e "s;--valgrind-options=;;"` @@ -394,7 +404,7 @@ SLAVE_MYLOG="$MYSQL_TEST_DIR/var/log/slave.log" SLAVE_MYERR="$MYSQL_TEST_DIR/var/log/slave.err" CURRENT_TEST="$MYSQL_TEST_DIR/var/log/current_test" -SMALL_SERVER="-O key_buffer_size=1M -O sort_buffer=256K -O max_heap_table_size=1M" +SMALL_SERVER="--key_buffer_size=1M --sort_buffer=256K --max_heap_table_size=1M" export MASTER_MYPORT export SLAVE_MYPORT @@ -795,13 +805,13 @@ manager_launch() ident=$1 shift if [ $USE_MANAGER = 0 ] ; then - $@ >> $CUR_MYERR 2>&1 & + $@ >> $CUR_MYERR 2>&1 & sleep 2 #hack return fi $MYSQL_MANAGER_CLIENT $MANAGER_QUIET_OPT --user=$MYSQL_MANAGER_USER \ --password=$MYSQL_MANAGER_PW --port=$MYSQL_MANAGER_PORT <<EOF -def_exec $ident $@ +def_exec $ident "$@" set_exec_stdout $ident $CUR_MYERR set_exec_stderr $ident $CUR_MYERR set_exec_con $ident root localhost $CUR_MYSOCK @@ -1163,7 +1173,7 @@ run_testcase () echo $tname > $CURRENT_TEST SKIP_SLAVE=`$EXPR \( $tname : rpl \) = 0` if [ $USE_MANAGER = 1 ] ; then - many_slaves=`$EXPR \( $tname : rpl_failsafe \) != 0` + many_slaves=`$EXPR \( \( $tname : rpl_failsafe \) != 0 \) \| \( \( $tname : rpl_chain_temp_table \) != 0 \)` fi if [ -n "$SKIP_TEST" ] ; then diff --git a/mysql-test/r/auto_increment.result b/mysql-test/r/auto_increment.result index 8c898bae699..113c2930977 100644 --- a/mysql-test/r/auto_increment.result +++ b/mysql-test/r/auto_increment.result @@ -112,6 +112,11 @@ insert into t1 set i = null; select last_insert_id(); last_insert_id() 255 +explain extended select last_insert_id(); +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 +Warnings: +Note 1003 select high_priority no_cache 255 AS `last_insert_id()` insert into t1 set i = 254; ERROR 23000: Duplicate entry '254' for key 1 select last_insert_id(); diff --git a/mysql-test/r/bench_count_distinct.result b/mysql-test/r/bench_count_distinct.result index d414e8e466e..2b4701389db 100644 --- a/mysql-test/r/bench_count_distinct.result +++ b/mysql-test/r/bench_count_distinct.result @@ -3,4 +3,9 @@ create table t1(n int not null, key(n)) delay_key_write = 1; select count(distinct n) from t1; count(distinct n) 100 +explain extended select count(distinct n) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL n 4 NULL 200 Using index +Warnings: +Note 1003 select high_priority count(distinct test.t1.n) AS `count(distinct n)` from test.t1 drop table t1; diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index 08f148f94c0..4aab3defa2b 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -23,6 +23,11 @@ false select CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END; CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END one +explain extended select CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END; +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 +Warnings: +Note 1003 select high_priority (case 1 when 1 then _latin1'one' when 2 then _latin1'two' else _latin1'more' end) AS `CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END` select CASE 2.0 when 1 then "one" WHEN 2.0 then "two" ELSE "more" END; CASE 2.0 when 1 then "one" WHEN 2.0 then "two" ELSE "more" END two @@ -57,6 +62,11 @@ fcase count(*) 0 2 2 1 3 1 +explain extended select case a when 1 then 2 when 2 then 3 else 0 end as fcase, count(*) from t1 group by fcase; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort +Warnings: +Note 1003 select high_priority (case test.t1.a when 1 then 2 when 2 then 3 else 0 end) AS `fcase`,count(0) AS `count(*)` from test.t1 group by (case test.t1.a when 1 then 2 when 2 then 3 else 0 end) select case a when 1 then "one" when 2 then "two" else "nothing" end as fcase, count(*) from t1 group by fcase; fcase count(*) nothing 2 @@ -122,6 +132,14 @@ CREATE TABLE t1 SELECT COALESCE(1), COALESCE(1.0),COALESCE('a'), COALESCE(1,1.0), COALESCE(1,'1'),COALESCE(1.1,'1'), COALESCE('a' COLLATE latin1_bin,'b'); +explain extended SELECT +COALESCE(1), COALESCE(1.0),COALESCE('a'), +COALESCE(1,1.0), COALESCE(1,'1'),COALESCE(1.1,'1'), +COALESCE('a' COLLATE latin1_bin,'b'); +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 +Warnings: +Note 1003 select high_priority coalesce(1) AS `COALESCE(1)`,coalesce(1.0) AS `COALESCE(1.0)`,coalesce(_latin1'a') AS `COALESCE('a')`,coalesce(1,1.0) AS `COALESCE(1,1.0)`,coalesce(1,_latin1'1') AS `COALESCE(1,'1')`,coalesce(1.1,_latin1'1') AS `COALESCE(1.1,'1')`,coalesce((_latin1'a' collate _latin1'latin1_bin'),_latin1'b') AS `COALESCE('a' COLLATE latin1_bin,'b')` SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index d604a17d270..974a79580ae 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -16,6 +16,11 @@ cast(-5 as unsigned) -1 cast(-5 as unsigned) + 1 select ~5, cast(~5 as signed); ~5 cast(~5 as signed) 18446744073709551610 -6 +explain extended select ~5, cast(~5 as signed); +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 +Warnings: +Note 1003 select high_priority ~(5) AS `~5`,cast(~(5) as signed) AS `cast(~5 as signed)` select cast(5 as unsigned) -6.0; cast(5 as unsigned) -6.0 -1.0 diff --git a/mysql-test/r/ctype_collate.result b/mysql-test/r/ctype_collate.result index b865084b409..6a9da97042b 100644 --- a/mysql-test/r/ctype_collate.result +++ b/mysql-test/r/ctype_collate.result @@ -521,6 +521,11 @@ character_set_client latin1 SELECT charset('a'),collation('a'),coercibility('a'),'a'='A'; charset('a') collation('a') coercibility('a') 'a'='A' latin1 latin1_swedish_ci 3 1 +explain extended SELECT charset('a'),collation('a'),coercibility('a'),'a'='A'; +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 +Warnings: +Note 1003 select high_priority charset(_latin1'a') AS `charset('a')`,collation(_latin1'a') AS `collation('a')`,coercibility(_latin1'a') AS `coercibility('a')`,(_latin1'a' = _latin1'A') AS `'a'='A'` SET CHARACTER SET koi8r; SHOW VARIABLES LIKE 'collation_client'; Variable_name Value diff --git a/mysql-test/r/ctype_latin1_de.result b/mysql-test/r/ctype_latin1_de.result index 3db2f3d5519..07ea97258d9 100644 --- a/mysql-test/r/ctype_latin1_de.result +++ b/mysql-test/r/ctype_latin1_de.result @@ -219,6 +219,13 @@ a test drop table t1; create table t1 (word varchar(255) not null, word2 varchar(255) not null, index(word)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `word` varchar(255) collate latin1_german2_ci NOT NULL default '', + `word2` varchar(255) collate latin1_german2_ci NOT NULL default '', + KEY `word` (`word`) +) TYPE=MyISAM CHARSET=latin1 COLLATE=latin1_german2_ci insert into t1 (word) values ('ss'),(0xDF),(0xE4),('ae'); update t1 set word2=word; select word, word=binary 0xdf as t from t1 having t > 0; @@ -273,6 +280,11 @@ drop table t1; CREATE TABLE t1 ( s1 CHAR(5) CHARACTER SET latin1 COLLATE latin1_german2_ci ); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` char(5) collate latin1_german2_ci default NULL +) TYPE=MyISAM CHARSET=latin1 COLLATE=latin1_german2_ci INSERT INTO t1 VALUES ('Ü'); INSERT INTO t1 VALUES ('ue'); SELECT DISTINCT s1 FROM t1; diff --git a/mysql-test/r/ctype_many.result b/mysql-test/r/ctype_many.result index ebc84db7115..c465655473d 100644 --- a/mysql-test/r/ctype_many.result +++ b/mysql-test/r/ctype_many.result @@ -340,6 +340,129 @@ CYR CAPIT SOFT SIGN ø ø CYR CAPIT E ü ü CYR CAPIT YU à à CYR CAPIT YA ñ ñ +select CONVERT(koi8_ru_f, 'cp1251_general_ci', 'utf8_general_ci'), comment from t1; +CONVERT(koi8_ru_f, 'cp1251_general_ci', 'utf8_general_ci') comment +a LAT SMALL A +b LAT SMALL B +c LAT SMALL C +d LAT SMALL D +e LAT SMALL E +f LAT SMALL F +g LAT SMALL G +h LAT SMALL H +i LAT SMALL I +j LAT SMALL J +k LAT SMALL K +l LAT SMALL L +m LAT SMALL M +n LAT SMALL N +o LAT SMALL O +p LAT SMALL P +q LAT SMALL Q +r LAT SMALL R +s LAT SMALL S +t LAT SMALL T +u LAT SMALL U +v LAT SMALL V +w LAT SMALL W +x LAT SMALL X +y LAT SMALL Y +z LAT SMALL Z +A LAT CAPIT A +B LAT CAPIT B +C LAT CAPIT C +D LAT CAPIT D +E LAT CAPIT E +F LAT CAPIT F +G LAT CAPIT G +H LAT CAPIT H +I LAT CAPIT I +J LAT CAPIT J +K LAT CAPIT K +L LAT CAPIT L +M LAT CAPIT M +N LAT CAPIT N +O LAT CAPIT O +P LAT CAPIT P +Q LAT CAPIT Q +R LAT CAPIT R +S LAT CAPIT S +T LAT CAPIT T +U LAT CAPIT U +V LAT CAPIT V +W LAT CAPIT W +X LAT CAPIT X +Y LAT CAPIT Y +Z LAT CAPIT Z +â CYR SMALL A +÷ CYR SMALL BE +þ CYR SMALL VE +ú CYR SMALL GE +ä CYR SMALL DE +å CYR SMALL IE +? CYR SMALL IO +ã CYR SMALL ZHE +ÿ CYR SMALL ZE +ê CYR SMALL I +ì CYR SMALL KA +í CYR SMALL EL +î CYR SMALL EM +ï CYR SMALL EN +ð CYR SMALL O +ò CYR SMALL PE +ô CYR SMALL ER +õ CYR SMALL ES +æ CYR SMALL TE +è CYR SMALL U +ö CYR SMALL EF +é CYR SMALL HA +ç CYR SMALL TSE +à CYR SMALL CHE +ù CYR SMALL SHA +ü CYR SMALL SCHA +ñ CYR SMALL HARD SIGN +ý CYR SMALL YERU +û CYR SMALL SOFT SIGN +ø CYR SMALL E +á CYR SMALL YU +ó CYR SMALL YA + CYR CAPIT A +× CYR CAPIT BE +Þ CYR CAPIT VE +Ú CYR CAPIT GE +Ä CYR CAPIT DE +Å CYR CAPIT IE +? CYR CAPIT IO +à CYR CAPIT ZHE +ß CYR CAPIT ZE +Ê CYR CAPIT I +Ì CYR CAPIT KA +Í CYR CAPIT EL +Î CYR CAPIT EM +Ï CYR CAPIT EN +Ð CYR CAPIT O +Ò CYR CAPIT PE +Ô CYR CAPIT ER +Õ CYR CAPIT ES +Æ CYR CAPIT TE +È CYR CAPIT U +Ö CYR CAPIT EF +É CYR CAPIT HA +Ç CYR CAPIT TSE +À CYR CAPIT CHE +Ù CYR CAPIT SHA +Ü CYR CAPIT SCHA +Ñ CYR CAPIT HARD SIGN +Ý CYR CAPIT YERU +Û CYR CAPIT SOFT SIGN +Ø CYR CAPIT E +Á CYR CAPIT YU +Ó CYR CAPIT YA +explain extended select CONVERT(koi8_ru_f, 'cp1251_general_ci', 'utf8_general_ci'), comment from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 116 +Warnings: +Note 1003 select high_priority convert(test.t1.koi8_ru_f,_latin1'utf8_general_ci',_latin1'cp1251_general_ci') AS `CONVERT(koi8_ru_f, 'cp1251_general_ci', 'utf8_general_ci')`,test.t1.comment AS `comment` from test.t1 ALTER TABLE t1 ADD bin_f CHAR(32) BYTE NOT NULL; UPDATE t1 SET bin_f=koi8_ru_f; SELECT COUNT(DISTINCT bin_f),COUNT(DISTINCT koi8_ru_f),COUNT(DISTINCT utf8_f) FROM t1; diff --git a/mysql-test/r/ctype_recoding.result b/mysql-test/r/ctype_recoding.result index 5a53c1db2e1..1fe07692290 100644 --- a/mysql-test/r/ctype_recoding.result +++ b/mysql-test/r/ctype_recoding.result @@ -1,5 +1,5 @@ SET CHARACTER SET koi8r; -DROP TABLE IF EXISTS ÔÁÂÌÉÃÁ; +DROP TABLE IF EXISTS ÔÁÂÌÉÃÁ, t1; SET CHARACTER SET koi8r; CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp1251) SELECT _koi8r'ÐÒÏÂÁ' AS a; SHOW CREATE TABLE t1; @@ -14,7 +14,7 @@ SELECT HEX(a) FROM t1; HEX(a) EFF0EEE1E0 DROP TABLE t1; -CREATE TABLE ÔÁÂÌÉÃÁ +CREATE TABLE `ÔÁÂÌÉÃÁ` ( ÐÏÌÅ CHAR(32) CHARACTER SET koi8r NOT NULL COMMENT "ËÏÍÍÅÎÔÁÒÉÊ ÐÏÌÑ" ) COMMENT "ËÏÍÍÅÎÔÁÒÉÊ ÔÁÂÌÉÃÙ"; diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 1f07de17b14..1aef43cd570 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -47,6 +47,9 @@ locate(_utf8 0xD091, _utf8 0xD0B0D0B1D0B2 collate utf8_bin) select locate(_utf8 0xD0B1, _utf8 0xD0B0D091D0B2 collate utf8_bin); locate(_utf8 0xD0B1, _utf8 0xD0B0D091D0B2 collate utf8_bin) 0 +select length(_utf8 0xD0B1), bit_length(_utf8 0xD0B1), char_length(_utf8 0xD0B1); +length(_utf8 0xD0B1) bit_length(_utf8 0xD0B1) char_length(_utf8 0xD0B1) +2 16 1 select 'a' like 'a'; 'a' like 'a' 1 diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result index 590a1d6904b..346d086f34c 100644 --- a/mysql-test/r/date_formats.result +++ b/mysql-test/r/date_formats.result @@ -1,151 +1,315 @@ +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' SHOW GLOBAL VARIABLES LIKE "%_format%"; Variable_name Value date_format %d.%m.%Y -datetime_format %Y/%d/%m-%H:%i:%s +datetime_format %Y-%m-%d %H:%i:%s default_week_format 0 time_format %H.%i.%s SHOW SESSION VARIABLES LIKE "%_format%"; Variable_name Value date_format %d.%m.%Y -datetime_format %Y/%d/%m-%H:%i:%s +datetime_format %Y-%m-%d %H:%i:%s default_week_format 0 time_format %H.%i.%s -SET date_format="%d.%m.%Y"; -select CAST("01.01.2001" as DATE) as a; -a -01.01.2001 -SET datetime_format="%d.%m.%Y %H.%i.%s"; -select CAST("01.01.2001 05.12.06" as DATETIME) as a; -a -01.01.2001 05.12.06 -SET time_format="%H.%i.%s"; -select CAST("05.12.06" as TIME) as a; -a -05.12.06 -SET datetime_format="%d.%m.%Y %h:%i:%s %p"; -select CAST("01.01.2001 05:12:06AM" as DATETIME) as a; -a -01.01.2001 05:12:06 AM -select CAST("01.01.2001 05:12:06 PM" as DATETIME) as a; -a -01.01.2001 05:12:06 PM -SET time_format="%h:%i:%s %p"; -select CAST("05:12:06 AM" as TIME) as a; -a -05:12:06 AM -select CAST("05:12:06.1234PM" as TIME) as a; -a -05:12:06.001234 PM -SET time_format="%h.%i.%s %p"; -SET date_format='%d.%m.%y'; -SET datetime_format="%d.%m.%y %h.%i.%s %p"; -select CAST("12-12-06" as DATE) as a; -a -12.12.06 -select adddate("01.01.97 11.59.59.000001 PM", 10); -adddate("01.01.97 11.59.59.000001 PM", 10) -11.01.97 11.59.59.000001 PM -select datediff("31.12.97 11.59:59.000001 PM","01.01.98"); -datediff("31.12.97 11.59:59.000001 PM","01.01.98") --1 -select weekofyear("31.11.97 11:59:59.000001 PM"); -weekofyear("31.11.97 11:59:59.000001 PM") -49 -select makedate(1997,1); -makedate(1997,1) -01.01.97 -select addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"); -addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002") -02.01.98 01.01.01.000001 AM -select maketime(23,11,12); -maketime(23,11,12) -11.11.12 PM -select timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM"); -timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM") -8795.59.59.999999 PM -SET time_format="%H%i%s"; -SET time_format="%h%i%s"; -ERROR HY000: Unknown error +SET time_format='%H%i%s'; +SET time_format='%H:%i:%s.%f'; +SET time_format='%h-%i-%s.%f%p'; +SET time_format='%h:%i:%s.%f %p'; +SET time_format='%h:%i:%s%p'; +SET date_format='%Y%m%d'; +SET date_format='%Y.%m.%d'; +SET date_format='%d.%m.%Y'; +SET date_format='%m-%d-%Y'; +set datetime_format= '%Y%m%d%H%i%s'; +set datetime_format= '%Y-%m-%d %H:%i:%s'; +set datetime_format= '%m-%d-%y %H:%i:%s.%f'; +set datetime_format= '%d-%m-%Y %h:%i:%s%p'; +set datetime_format= '%H:%i:%s %Y-%m-%d'; +set datetime_format= '%H:%i:%s.%f %m-%d-%Y'; +set datetime_format= '%h:%i:%s %p %Y-%m-%d'; +set datetime_format= '%h:%i:%s.%f %p %Y-%m-%d'; +SHOW SESSION VARIABLES LIKE "%format"; +Variable_name Value +date_format %m-%d-%Y +datetime_format %h:%i:%s.%f %p %Y-%m-%d +default_week_format 0 +time_format %h:%i:%s%p +SET time_format='%h:%i:%s'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%h:%i:%s' +SET time_format='%H %i:%s'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H %i:%s' +SET time_format='%H::%i:%s'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H::%i:%s' +SET time_format='%H:%i:%s%f'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H:%i:%s%f' +SET time_format='%H:%i.%f:%s'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H:%i.%f:%s' +SET time_format='%H:%i:%s%p'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H:%i:%s%p' +SET time_format='%h:%i:%s.%f %p %Y-%m-%d'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%h:%i:%s.%f %p %Y-%m-%d' +SET time_format='%H%i%s.%f'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H%i%s.%f' +SET time_format='%H:%i-%s.%f'; +ERROR 42000: Variable 'time_format' can't be set to the value of '%H:%i-%s.%f' SET date_format='%d.%m.%d'; -ERROR HY000: Unknown error -SET datetime_format="%d.%m.%y %h.%i.%s"; -ERROR HY000: Unknown error +ERROR 42000: Variable 'date_format' can't be set to the value of '%d.%m.%d' +SET datetime_format='%h.%m.%y %d.%i.%s'; +ERROR 42000: Variable 'datetime_format' can't be set to the value of '%h.%m.%y %d.%i.%s' +set datetime_format= '%H:%i:%s.%f %p %Y-%m-%d'; +ERROR 42000: Variable 'datetime_format' can't be set to the value of '%H:%i:%s.%f %p %Y-%m-%d' +set GLOBAL datetime_format= '%H:%i:%s %Y-%m-%d'; +SET SESSION datetime_format=default; +select @@global.datetime_format, @@session.datetime_format; +@@global.datetime_format @@session.datetime_format +%H:%i:%s %Y-%m-%d %H:%i:%s %Y-%m-%d +SET GLOBAL datetime_format=default; +SET SESSION datetime_format=default; +select @@global.datetime_format, @@session.datetime_format; +@@global.datetime_format @@session.datetime_format +%Y-%m-%d %H:%i:%s %Y-%m-%d %H:%i:%s SET GLOBAL date_format=default; -SHOW GLOBAL VARIABLES LIKE "date_format%"; -Variable_name Value -date_format %d.%m.%Y SET GLOBAL time_format=default; -SHOW GLOBAL VARIABLES LIKE "time_format%"; -Variable_name Value -time_format %H.%i.%s SET GLOBAL datetime_format=default; -SHOW GLOBAL VARIABLES LIKE "datetime_format%"; -Variable_name Value -datetime_format %Y/%d/%m-%H:%i:%s -SET date_format=default; -SHOW SESSION VARIABLES LIKE "date_format%"; -Variable_name Value -date_format %d.%m.%Y SET time_format=default; -SHOW SESSION VARIABLES LIKE "time_format%"; -Variable_name Value -time_format %H.%i.%s +SET date_format=default; SET datetime_format=default; -SHOW SESSION VARIABLES LIKE "datetime_format%"; -Variable_name Value -datetime_format %Y/%d/%m-%H:%i:%s -SET time_format='%i:%s:%H'; -select cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME); -cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME) -59:59:12 -SET GLOBAL date_format='%Y-%m-%d'; -SET GLOBAL time_format='%H:%i:%s'; -SET GLOBAL datetime_format='%Y-%m-%d %H:%i:%s'; -SET date_format='%Y-%m-%d'; -SET time_format='%H:%i:%s'; -SET datetime_format='%Y-%m-%d %H:%i:%s'; -select str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S"); -str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") -2001-01-15 12:59:59 -select str_to_date("15 September 2001", "%d %M %Y"); -str_to_date("15 September 2001", "%d %M %Y") -2001-09-15 00:00:00 -select str_to_date("15 Septembeb 2001", "%d %M %Y"); -str_to_date("15 Septembeb 2001", "%d %M %Y") -NULL -select str_to_date("15 MAY 2001", "%d %b %Y"); -str_to_date("15 MAY 2001", "%d %b %Y") -2001-05-15 00:00:00 -select str_to_date("Sunday 15 MAY 2001", "%W %d %b %Y"); -str_to_date("Sunday 15 MAY 2001", "%W %d %b %Y") -2001-05-15 00:00:00 -select str_to_date("Sundai 15 MAY 2001", "%W %d %b %Y"); -str_to_date("Sundai 15 MAY 2001", "%W %d %b %Y") -NULL -select str_to_date("Sundai 15 MA", "%W %d %b %Y"); -str_to_date("Sundai 15 MA", "%W %d %b %Y") -NULL -select str_to_date("Tuesday 52 2001", "%W %V %X"); -str_to_date("Tuesday 52 2001", "%W %V %X") -NULL -select str_to_date("Sunday 01 2001", "%W %V %X"); -str_to_date("Sunday 01 2001", "%W %V %X") -NULL -select str_to_date("Tuesday 00 2002", "%W %U %Y"); -str_to_date("Tuesday 00 2002", "%W %U %Y") -2002-01-01 00:00:00 -select str_to_date("Thursday 53 1998", "%W %u %Y"); -str_to_date("Thursday 53 1998", "%W %u %Y") -1998-12-31 00:00:00 -select str_to_date("15-01-2001", "%d-%m-%Y %H:%i:%S"); -str_to_date("15-01-2001", "%d-%m-%Y %H:%i:%S") -2001-01-15 00:00:00 -select str_to_date("15-01-20", "%d-%m-%Y"); -str_to_date("15-01-20", "%d-%m-%Y") -NULL -select str_to_date("15-2001-1", "%d-%Y-%c"); -str_to_date("15-2001-1", "%d-%Y-%c") -2001-01-15 00:00:00 +select str_to_date(concat('15-01-2001',' 2:59:58.999'), +concat('%d-%m-%Y',' ','%H:%i:%s.%f')); +str_to_date(concat('15-01-2001',' 2:59:58.999'), +concat('%d-%m-%Y',' ','%H:%i:%s.%f')) +2001-01-15 02:59:58.000999 +create table t1 (date char(30), format char(30) not null); +insert into t1 values +('2003-01-02 10:11:12', '%Y-%m-%d %H:%i:%S'), +('03-01-02 8:11:2.123456', '%y-%m-%d %H:%i:%S'), +('2003-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'), +('2003-01-02 01:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f%p'), +('2003-01-02 02:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f %p'), +('2003-01-02 12:11:12.12345 am', '%Y-%m-%d %h:%i:%S.%f%p'), +('2003-01-02 11:11:12Pm', '%Y-%m-%d %h:%i:%S%p'), +('10:20:10', '%H:%i:%s'), +('10:20:10', '%h:%i:%s.%f'), +('10:20:10AM', '%h:%i:%s%p'), +('10:20:10.44AM', '%h:%i:%s.%f%p'), +('15-01-2001 12:59:58', '%d-%m-%Y %H:%i:%S'), +('15 September 2001', '%d %M %Y'), +('15 SEPTEMB 2001', '%d %M %Y'), +('15 MAY 2001', '%d %b %Y'), +('Sunday 15 MAY 2001', '%W %d %b %Y'), +('Sund 15 MAY 2001', '%W %d %b %Y'), +('Tuesday 00 2002', '%W %U %Y'), +('Thursday 53 1998', '%W %u %Y'), +('15-01-2001', '%d-%m-%Y %H:%i:%S'), +('15-01-20', '%d-%m-%y'), +('15-2001-1', '%d-%Y-%c'); +select date,format,str_to_date(date, format) as str_to_date from t1; +date format str_to_date +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 2003-01-02 08:11:02 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12 +2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.012345 +2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.012345 +2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.012345 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12 +10:20:10 %H:%i:%s 0000-00-00 10:20:10 +10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10 +10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10 +10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.000044 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58 +15 September 2001 %d %M %Y 2001-09-15 00:00:00 +15 SEPTEMB 2001 %d %M %Y 2001-01-15 00:00:00 +15 MAY 2001 %d %b %Y 2001-05-15 00:00:00 +Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 +Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 +Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00 +Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00 +15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00 +15-01-20 %d-%m-%y 2020-01-15 00:00:00 +15-2001-1 %d-%Y-%c 2001-01-15 00:00:00 +select date,format,concat('',str_to_date(date, format)) as con from t1; +date format con +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 2003-01-02 08:11:02 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12 +2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.012345 +2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.012345 +2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.012345 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12 +10:20:10 %H:%i:%s 0000-00-00 10:20:10 +10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10 +10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10 +10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.000044 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58 +15 September 2001 %d %M %Y 2001-09-15 00:00:00 +15 SEPTEMB 2001 %d %M %Y 2001-01-15 00:00:00 +15 MAY 2001 %d %b %Y 2001-05-15 00:00:00 +Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 +Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 +Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00 +Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00 +15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00 +15-01-20 %d-%m-%y 2020-01-15 00:00:00 +15-2001-1 %d-%Y-%c 2001-01-15 00:00:00 +select date,format,cast(str_to_date(date, format) as datetime) as datetime from t1; +date format datetime +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 2003-01-02 08:11:02 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12 +2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.012345 +2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.012345 +2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.012345 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12 +10:20:10 %H:%i:%s 0000-00-00 10:20:10 +10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10 +10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10 +10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.000044 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58 +15 September 2001 %d %M %Y 2001-09-15 00:00:00 +15 SEPTEMB 2001 %d %M %Y 2001-01-15 00:00:00 +15 MAY 2001 %d %b %Y 2001-05-15 00:00:00 +Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 +Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00 +Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00 +Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00 +15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00 +15-01-20 %d-%m-%y 2020-01-15 00:00:00 +15-2001-1 %d-%Y-%c 2001-01-15 00:00:00 +select date,format,DATE(str_to_date(date, format)) as date2 from t1; +date format date2 +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 2003-01-02 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 +2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 +2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 +2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 +10:20:10 %H:%i:%s 0000-00-00 +10:20:10 %h:%i:%s.%f 0000-00-00 +10:20:10AM %h:%i:%s%p 0000-00-00 +10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 +15 September 2001 %d %M %Y 2001-09-15 +15 SEPTEMB 2001 %d %M %Y 2001-01-15 +15 MAY 2001 %d %b %Y 2001-05-15 +Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 +Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 +Tuesday 00 2002 %W %U %Y 2002-01-01 +Thursday 53 1998 %W %u %Y 1998-12-31 +15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 +15-01-20 %d-%m-%y 2020-01-15 +15-2001-1 %d-%Y-%c 2001-01-15 +select date,format,TIME(str_to_date(date, format)) as time from t1; +date format time +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 10:11:12 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 08:11:02 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 22:11:12 +2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 01:11:12.012345 +2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 02:11:12.012345 +2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 00:11:12.012345 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 23:11:12 +10:20:10 %H:%i:%s 10:20:10 +10:20:10 %h:%i:%s.%f 10:20:10 +10:20:10AM %h:%i:%s%p 10:20:10 +10:20:10.44AM %h:%i:%s.%f%p 10:20:10.000044 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 12:59:58 +15 September 2001 %d %M %Y 00:00:00 +15 SEPTEMB 2001 %d %M %Y 00:00:00 +15 MAY 2001 %d %b %Y 00:00:00 +Sunday 15 MAY 2001 %W %d %b %Y 00:00:00 +Sund 15 MAY 2001 %W %d %b %Y 00:00:00 +Tuesday 00 2002 %W %U %Y 00:00:00 +Thursday 53 1998 %W %u %Y 00:00:00 +15-01-2001 %d-%m-%Y %H:%i:%S 00:00:00 +15-01-20 %d-%m-%y 00:00:00 +15-2001-1 %d-%Y-%c 00:00:00 +select date,format,concat(TIME(str_to_date(date, format))) as time2 from t1; +date format time2 +2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 10:11:12 +03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 08:11:02 +2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 22:11:12 +2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 01:11:12.012345 +2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 02:11:12.012345 +2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 00:11:12.012345 +2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 23:11:12 +10:20:10 %H:%i:%s 10:20:10 +10:20:10 %h:%i:%s.%f 10:20:10 +10:20:10AM %h:%i:%s%p 10:20:10 +10:20:10.44AM %h:%i:%s.%f%p 10:20:10.000044 +15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 12:59:58 +15 September 2001 %d %M %Y 00:00:00 +15 SEPTEMB 2001 %d %M %Y 00:00:00 +15 MAY 2001 %d %b %Y 00:00:00 +Sunday 15 MAY 2001 %W %d %b %Y 00:00:00 +Sund 15 MAY 2001 %W %d %b %Y 00:00:00 +Tuesday 00 2002 %W %U %Y 00:00:00 +Thursday 53 1998 %W %u %Y 00:00:00 +15-01-2001 %d-%m-%Y %H:%i:%S 00:00:00 +15-01-20 %d-%m-%y 00:00:00 +15-2001-1 %d-%Y-%c 00:00:00 +truncate table t1; +insert into t1 values +('2003-01-02 10:11:12 PM', '%Y-%m-%d %H:%i:%S %p'), +('2003-01-02 10:11:12.123456', '%Y-%m-%d %h:%i:%S %p'), +('2003-01-02 10:11:12AM', '%Y-%m-%d %h:%i:%S.%f %p'), +('2003-01-02 10:11:12AN', '%Y-%m-%d %h:%i:%S%p'), +('2003-01-02 10:11:12 PM', '%y-%m-%d %H:%i:%S %p'), +('10:20:10AM', '%H:%i:%s%p'), +('15 Septembei 2001', '%d %M %Y'), +('15 Ju 2001', '%d %M %Y'), +('Sund 15 MA', '%W %d %b %Y'), +('Sunday 01 2001', '%W %V %X'), +('Thursdai 12 1998', '%W %u %Y'), +(NULL, get_format(DATE,'USA')), +('Tuesday 52 2001', '%W %V %X'); +select date,format,str_to_date(date, format) as str_to_date from t1; +date format str_to_date +2003-01-02 10:11:12 PM %Y-%m-%d %H:%i:%S %p NULL +2003-01-02 10:11:12.123456 %Y-%m-%d %h:%i:%S %p NULL +2003-01-02 10:11:12AM %Y-%m-%d %h:%i:%S.%f %p NULL +2003-01-02 10:11:12AN %Y-%m-%d %h:%i:%S%p NULL +2003-01-02 10:11:12 PM %y-%m-%d %H:%i:%S %p NULL +10:20:10AM %H:%i:%s%p NULL +15 Septembei 2001 %d %M %Y NULL +15 Ju 2001 %d %M %Y NULL +Sund 15 MA %W %d %b %Y NULL +Sunday 01 2001 %W %V %X NULL +Thursdai 12 1998 %W %u %Y NULL +NULL %m.%d.%Y NULL +Tuesday 52 2001 %W %V %X NULL +select date,format,concat(str_to_date(date, format),'') as con from t1; +date format con +2003-01-02 10:11:12 PM %Y-%m-%d %H:%i:%S %p NULL +2003-01-02 10:11:12.123456 %Y-%m-%d %h:%i:%S %p NULL +2003-01-02 10:11:12AM %Y-%m-%d %h:%i:%S.%f %p NULL +2003-01-02 10:11:12AN %Y-%m-%d %h:%i:%S%p NULL +2003-01-02 10:11:12 PM %y-%m-%d %H:%i:%S %p NULL +10:20:10AM %H:%i:%s%p NULL +15 Septembei 2001 %d %M %Y NULL +15 Ju 2001 %d %M %Y NULL +Sund 15 MA %W %d %b %Y NULL +Sunday 01 2001 %W %V %X NULL +Thursdai 12 1998 %W %u %Y NULL +NULL %m.%d.%Y NULL +Tuesday 52 2001 %W %V %X NULL +truncate table t1; +insert into t1 values +('10:20:10AM', '%h:%i:%s'), +('2003-01-02 10:11:12', '%Y-%m-%d %h:%i:%S'), +('03-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'); +select date,format,str_to_date(date, format) as str_to_date from t1; +date format str_to_date +10:20:10AM %h:%i:%s 0000-00-00 10:20:10 +2003-01-02 10:11:12 %Y-%m-%d %h:%i:%S 2003-01-02 10:11:12 +03-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 0003-01-02 22:11:12 +select date,format,concat(str_to_date(date, format),'') as con from t1; +date format con +10:20:10AM %h:%i:%s 0000-00-00 10:20:10 +2003-01-02 10:11:12 %Y-%m-%d %h:%i:%S 2003-01-02 10:11:12 +03-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 0003-01-02 22:11:12 +drop table t1; select get_format(DATE, 'USA') as a; a %m.%d.%Y @@ -154,4 +318,15 @@ a %H%i%s select get_format(DATETIME, 'eur') as a; a -%Y-%m-%d-%H.%i.%s +%Y-%m-%d %H.%i.%s +select get_format(DATE, 'TEST') as a; +a +NULL +select str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA')); +str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA')) +NULL +explain extended select makedate(1997,1), addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"),subtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"),timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM"),cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME), maketime(23,11,12),microsecond("1997-12-31 23:59:59.000001"); +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 +Warnings: +Note 1003 select high_priority makedate(1997,1) AS `makedate(1997,1)`,addtime(_latin1'31.12.97 11.59.59.999999 PM',_latin1'31.12.97 11.59.59.999999 PM') AS `addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002")`,subtime(_latin1'31.12.97 11.59.59.999999 PM',_latin1'31.12.97 11.59.59.999999 PM') AS `subtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002")`,timediff(_latin1'01.01.97 11:59:59.000001 PM',_latin1'31.12.95 11:59:59.000002 PM') AS `timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM")`,cast(str_to_date(_latin1'15-01-2001 12:59:59',_latin1'%d-%m-%Y %H:%i:%S') as time) AS `cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME)`,maketime(23,11,12) AS `maketime(23,11,12)`,microsecond(_latin1'1997-12-31 23:59:59.000001') AS `microsecond("1997-12-31 23:59:59.000001")` diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index 12d8bbaf8ae..37742893c2b 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -227,6 +227,4 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 THEMAX.E2 1 Using where 2 DERIVED t1 ALL NULL NULL NULL NULL 2 Using where 3 DEPENDENT SUBQUERY B ALL NULL NULL NULL NULL 2 Using where -Warnings: -Note 1275 Field or reference 'A.E2' of SELECT #3 was resolved in SELECT #2 drop table t1; diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 3dacb9cc124..385e2d52fb5 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -9,6 +9,11 @@ select * from t1 where MATCH(a,b) AGAINST ("collections"); a b Only MyISAM tables support collections Full-text indexes are called collections +explain extended select * from t1 where MATCH(a,b) AGAINST ("collections"); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 fulltext a a 0 1 Using where +Warnings: +Note 1003 select high_priority test.t1.a AS `a`,test.t1.b AS `b` from test.t1 where (match test.t1.a,test.t1.b against (_latin1'collections')) select * from t1 where MATCH(a,b) AGAINST ("indexes"); a b Full-text indexes are called collections @@ -65,6 +70,11 @@ id select_type table type possible_keys key key_len ref rows Extra select * from t1 where MATCH(a,b) AGAINST("support -collections" IN BOOLEAN MODE); a b MySQL has now support for full-text search +explain extended select * from t1 where MATCH(a,b) AGAINST("support -collections" IN BOOLEAN MODE); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 fulltext a a 0 1 Using where +Warnings: +Note 1003 select high_priority test.t1.a AS `a`,test.t1.b AS `b` from test.t1 where (match test.t1.a,test.t1.b against (_latin1'support -collections' in boolean mode)) select * from t1 where MATCH(a,b) AGAINST("support collections" IN BOOLEAN MODE); a b MySQL has now support for full-text search @@ -287,6 +297,8 @@ insert into t2 values (3, 1, 'xxbuz'); select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against('xxfoo' in boolean mode); t1_id name t2_id t1_id name 1 data1 1 1 xxfoo +select * from t2 where match name against ('a* b* c* d* e* f*' in boolean mode); +t2_id t1_id name drop table t1,t2; SET NAMES latin1; CREATE TABLE t1 (t text character set utf8 not null, fulltext(t)); diff --git a/mysql-test/r/func_compress.result b/mysql-test/r/func_compress.result index 85842f28e64..461fc1018c1 100644 --- a/mysql-test/r/func_compress.result +++ b/mysql-test/r/func_compress.result @@ -7,9 +7,19 @@ length(@test_compress_string) select uncompress(compress(@test_compress_string)); uncompress(compress(@test_compress_string)) string for test compress function aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +explain extended select uncompress(compress(@test_compress_string)); +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 +Warnings: +Note 1003 select high_priority no_cache uncompress(compress((@test_compress_string))) AS `uncompress(compress(@test_compress_string))` select uncompressed_length(compress(@test_compress_string))=length(@test_compress_string); uncompressed_length(compress(@test_compress_string))=length(@test_compress_string) 1 +explain extended select uncompressed_length(compress(@test_compress_string))=length(@test_compress_string); +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 +Warnings: +Note 1003 select high_priority no_cache (uncompressed_length(compress((@test_compress_string))) = length((@test_compress_string))) AS `uncompressed_length(compress(@test_compress_string))=length(@test_compress_string)` select uncompressed_length(compress(@test_compress_string)); uncompressed_length(compress(@test_compress_string)) 117 @@ -55,6 +65,6 @@ NULL 50000 NULL Warnings: -Error 1258 Z_DATA_ERROR: Input data was corrupted for zlib +Error 1258 ZLIB: Input data was corrupted for zlib Error 1255 Too big size of uncompressed data. The maximum size is 1048576. (probably, length of uncompressed data was corrupted) drop table t1; diff --git a/mysql-test/r/func_crypt.result b/mysql-test/r/func_crypt.result index 5ee0f0f3e93..70ebcf216fb 100644 --- a/mysql-test/r/func_crypt.result +++ b/mysql-test/r/func_crypt.result @@ -1,6 +1,16 @@ +drop table if exists t1; select length(encrypt('foo', 'ff')) <> 0; length(encrypt('foo', 'ff')) <> 0 1 +create table t1 (name varchar(50), pw varchar(64)); +insert into t1 values ('tom', password('my_pass')); +set @pass='my_pass'; +select name from t1 where name='tom' and pw=password(@pass); +name +tom +select name from t1 where name='tom' and pw=password(@undefined); +name +drop table t1; select password('abc'); password('abc') *0D3CED9BEC10A777AEC23CCC353A8C08A633045E @@ -77,3 +87,8 @@ old_password('idkfa') select old_password(' i d k f a '); old_password(' i d k f a ') 5c078dc54ca0fcca +explain extended select password('idkfa '), old_password('idkfa'); +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 +Warnings: +Note 1003 select high_priority password(_latin1'idkfa ') AS `password('idkfa ')`,old_password(_latin1'idkfa') AS `old_password('idkfa')` diff --git a/mysql-test/r/func_default.result b/mysql-test/r/func_default.result new file mode 100644 index 00000000000..fe3f5b9473a --- /dev/null +++ b/mysql-test/r/func_default.result @@ -0,0 +1,18 @@ +drop table if exists t1,t2; +create table t1(str varchar(10) default 'def',strnull varchar(10),intg int default '10',rel double default '3.14'); +insert into t1 values ('','',0,0.0); +select default(str), default(strnull), default(intg), default(rel) from t1; +default(str) default(strnull) default(intg) default(rel) +def NULL 10 3.14 +explain extended select default(str), default(strnull), default(intg), default(rel) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 +Warnings: +Note 1003 select high_priority default(test.t1.str) AS `default(str)`,default(test.t1.strnull) AS `default(strnull)`,default(test.t1.intg) AS `default(intg)`,default(test.t1.rel) AS `default(rel)` from test.t1 +select * from t1 where str <> default(str); +str strnull intg rel + 0 0 +explain select * from t1 where str <> default(str); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 +drop table t1; diff --git a/mysql-test/r/func_encrypt.result b/mysql-test/r/func_encrypt.result index 39c734999b2..abdfda0423f 100644 --- a/mysql-test/r/func_encrypt.result +++ b/mysql-test/r/func_encrypt.result @@ -134,3 +134,8 @@ NULL select hex(des_decrypt(des_encrypt("hello","hidden"))); hex(des_decrypt(des_encrypt("hello","hidden"))) NULL +explain extended select des_decrypt(des_encrypt("hello",4),'password2'), des_decrypt(des_encrypt("hello","hidden")); +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 +Warnings: +Note 1003 select high_priority des_decrypt(des_encrypt(_latin1'hello',4),_latin1'password2') AS `des_decrypt(des_encrypt("hello",4),'password2')`,des_decrypt(des_encrypt(_latin1'hello',_latin1'hidden')) AS `des_decrypt(des_encrypt("hello","hidden"))` diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 5eae6b4b871..af6f7956fe3 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -14,6 +14,11 @@ grp group_concat(c) 1 a 2 b,c 3 E,C,D,d,d,D +explain extended select grp,group_concat(c) from t1 group by grp; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 9 Using filesort +Warnings: +Note 1003 select high_priority test.t1.grp AS `grp`,group_concat(test.t1.c seperator ',') AS `group_concat(c)` from test.t1 group by test.t1.grp select grp,group_concat(a,c) from t1 group by grp; grp group_concat(a,c) 1 1a @@ -79,6 +84,11 @@ grp group_concat(distinct c order by c desc) 1 a 2 c,b 3 E,D,C +explain extended select grp,group_concat(distinct c order by c desc) from t1 group by grp; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 9 Using filesort +Warnings: +Note 1003 select high_priority test.t1.grp AS `grp`,group_concat(distinct test.t1.c order by test.t1.c seperator ',') AS `group_concat(distinct c order by c desc)` from test.t1 group by test.t1.grp select grp,group_concat(c order by c separator ",") from t1 group by grp; grp group_concat(c order by c separator ",") 1 a @@ -94,6 +104,11 @@ grp group_concat(distinct c order by c separator ",") 1 a 2 b,c 3 C,D,E +explain extended select grp,group_concat(distinct c order by c separator ",") from t1 group by grp; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 9 Using filesort +Warnings: +Note 1003 select high_priority test.t1.grp AS `grp`,group_concat(distinct test.t1.c order by test.t1.c seperator ',') AS `group_concat(distinct c order by c separator ",")` from test.t1 group by test.t1.grp select grp,group_concat(distinct c order by c desc separator ",") from t1 group by grp; grp group_concat(distinct c order by c desc separator ",") 1 a diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 2fb38ffe592..7ae3bbb0608 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -559,8 +559,8 @@ id select_type table type possible_keys key key_len ref rows Extra explain select concat(min(t1.a1),min(t2.a4)) from t1, t2 where t2.a4 <> 'AME'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 3 NULL 14 Using index 1 SIMPLE t2 range k2 k2 4 NULL 6 Using where; Using index +1 SIMPLE t1 index NULL PRIMARY 3 NULL 14 Using index drop table t1, t2; CREATE TABLE t1 (a int, b int); select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1; @@ -597,11 +597,16 @@ a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) 1 0 NULL NULL NULL NULL NULL 0 0 2 1 1 1.0000 0.0000 1 1 0 1 3 1 1 1.0000 0.0000 1 1 1 1 -select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) -1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 -2 1 1 1.0000 0.0000 1 1 1 1 -3 1 1 1.0000 0.0000 1 1 1 1 +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) bit_xor(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 0 +2 1 1 1.0000 0.0000 1 1 1 1 1 +3 1 1 1.0000 0.0000 1 1 1 1 1 +explain extended select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort +Warnings: +Note 1003 select high_priority big_result test.t1.a AS `a`,count(test.t1.b) AS `count(b)`,sum(test.t1.b) AS `sum(b)`,avg(test.t1.b) AS `avg(b)`,std(test.t1.b) AS `std(b)`,min(test.t1.b) AS `min(b)`,max(test.t1.b) AS `max(b)`,bit_and(test.t1.b) AS `bit_and(b)`,bit_or(test.t1.b) AS `bit_or(b)`,bit_xor(test.t1.b) AS `bit_xor(b)` from test.t1 group by test.t1.a drop table t1; create table t1 (USR_ID integer not null, MAX_REQ integer not null, constraint PK_SEA_USER primary key (USR_ID)) type=InnoDB; insert into t1 values (1, 3); diff --git a/mysql-test/r/func_if.result b/mysql-test/r/func_if.result index 0ab41258091..64070179395 100644 --- a/mysql-test/r/func_if.result +++ b/mysql-test/r/func_if.result @@ -39,6 +39,25 @@ a a aa aaa +explain extended select if(u=1,st,binary st) s from t1 where st like "%a%" order by s; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 7 Using where; Using filesort +Warnings: +Note 1003 select high_priority if((test.t1.u = 1),test.t1.st,(test.t1.st collate _latin1'BINARY')) AS `s` from test.t1 where (test.t1.st like _latin1'%a%') order by if((test.t1.u = 1),test.t1.st,(test.t1.st collate _latin1'BINARY')) +select nullif(u=0, 'test') from t1; +nullif(u=0, 'test') +NULL +NULL +NULL +NULL +NULL +1 +1 +explain extended select nullif(u=0, 'test') from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 7 +Warnings: +Note 1003 select high_priority nullif((test.t1.u = 0),_latin1'test') AS `nullif(u=0, 'test')` from test.t1 drop table t1; create table t1 (num double(12,2)); insert into t1 values (144.54); diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index a197371b345..04b6fc038b0 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -142,6 +142,11 @@ a c c select * from t1 where 'a' in (a,b,c collate latin1_bin); a b c a c c +explain extended select * from t1 where 'a' in (a,b,c collate latin1_bin); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +Warnings: +Note 1003 select high_priority test.t1.a AS `a`,test.t1.b AS `b`,test.t1.c AS `c` from test.t1 where (_latin1'a' in (test.t1.a,test.t1.b,(test.t1.c collate _latin1'latin1_bin'))) drop table t1; select '1.0' in (1,2); '1.0' in (1,2) diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index d6596e51db4..151a2902423 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -1,43 +1,108 @@ select floor(5.5),floor(-5.5); floor(5.5) floor(-5.5) 5 -6 +explain extended select floor(5.5),floor(-5.5); +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 +Warnings: +Note 1003 select high_priority floor(5.5) AS `floor(5.5)`,floor(-(5.5)) AS `floor(-5.5)` select ceiling(5.5),ceiling(-5.5); ceiling(5.5) ceiling(-5.5) 6 -5 +explain extended select ceiling(5.5),ceiling(-5.5); +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 +Warnings: +Note 1003 select high_priority ceiling(5.5) AS `ceiling(5.5)`,ceiling(-(5.5)) AS `ceiling(-5.5)` select truncate(52.64,1),truncate(52.64,2),truncate(52.64,-1),truncate(52.64,-2), truncate(-52.64,1),truncate(-52.64,-1); truncate(52.64,1) truncate(52.64,2) truncate(52.64,-1) truncate(52.64,-2) truncate(-52.64,1) truncate(-52.64,-1) 52.6 52.64 50 0 -52.6 -50 +explain extended select truncate(52.64,1),truncate(52.64,2),truncate(52.64,-1),truncate(52.64,-2), truncate(-52.64,1),truncate(-52.64,-1); +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 +Warnings: +Note 1003 select high_priority truncate(52.64,1) AS `truncate(52.64,1)`,truncate(52.64,2) AS `truncate(52.64,2)`,truncate(52.64,-(1)) AS `truncate(52.64,-1)`,truncate(52.64,-(2)) AS `truncate(52.64,-2)`,truncate(-(52.64),1) AS `truncate(-52.64,1)`,truncate(-(52.64),-(1)) AS `truncate(-52.64,-1)` select round(5.5),round(-5.5); round(5.5) round(-5.5) 6 -6 +explain extended select round(5.5),round(-5.5); +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 +Warnings: +Note 1003 select high_priority round(5.5,0) AS `round(5.5)`,round(-(5.5),0) AS `round(-5.5)` select round(5.64,1),round(5.64,2),round(5.64,-1),round(5.64,-2); round(5.64,1) round(5.64,2) round(5.64,-1) round(5.64,-2) 5.6 5.64 10 0 select abs(-10), sign(-5), sign(5), sign(0); abs(-10) sign(-5) sign(5) sign(0) 10 -1 1 0 +explain extended select abs(-10), sign(-5), sign(5), sign(0); +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 +Warnings: +Note 1003 select high_priority abs(-(10)) AS `abs(-10)`,sign(-(5)) AS `sign(-5)`,sign(5) AS `sign(5)`,sign(0) AS `sign(0)` select log(exp(10)),exp(log(sqrt(10))*2),log(-1),log(NULL),log(1,1),log(3,9),log(-1,2),log(NULL,2); log(exp(10)) exp(log(sqrt(10))*2) log(-1) log(NULL) log(1,1) log(3,9) log(-1,2) log(NULL,2) 10.000000 10.000000 NULL NULL NULL 2.000000 NULL NULL +explain extended select log(exp(10)),exp(log(sqrt(10))*2),log(-1),log(NULL),log(1,1),log(3,9),log(-1,2),log(NULL,2); +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 +Warnings: +Note 1003 select high_priority log(exp(10)) AS `log(exp(10))`,exp((log(sqrt(10)) * 2)) AS `exp(log(sqrt(10))*2)`,log(-(1)) AS `log(-1)`,log(NULL) AS `log(NULL)`,log(1,1) AS `log(1,1)`,log(3,9) AS `log(3,9)`,log(-(1),2) AS `log(-1,2)`,log(NULL,2) AS `log(NULL,2)` select ln(exp(10)),exp(ln(sqrt(10))*2),ln(-1),ln(0),ln(NULL); ln(exp(10)) exp(ln(sqrt(10))*2) ln(-1) ln(0) ln(NULL) 10.000000 10.000000 NULL NULL NULL +explain extended select ln(exp(10)),exp(ln(sqrt(10))*2),ln(-1),ln(0),ln(NULL); +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 +Warnings: +Note 1003 select high_priority ln(exp(10)) AS `ln(exp(10))`,exp((ln(sqrt(10)) * 2)) AS `exp(ln(sqrt(10))*2)`,ln(-(1)) AS `ln(-1)`,ln(0) AS `ln(0)`,ln(NULL) AS `ln(NULL)` select log2(8),log2(15),log2(-2),log2(0),log2(NULL); log2(8) log2(15) log2(-2) log2(0) log2(NULL) 3.000000 3.906891 NULL NULL NULL +explain extended select log2(8),log2(15),log2(-2),log2(0),log2(NULL); +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 +Warnings: +Note 1003 select high_priority log2(8) AS `log2(8)`,log2(15) AS `log2(15)`,log2(-(2)) AS `log2(-2)`,log2(0) AS `log2(0)`,log2(NULL) AS `log2(NULL)` select log10(100),log10(18),log10(-4),log10(0),log10(NULL); log10(100) log10(18) log10(-4) log10(0) log10(NULL) 2.000000 1.255273 NULL NULL NULL +explain extended select log10(100),log10(18),log10(-4),log10(0),log10(NULL); +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 +Warnings: +Note 1003 select high_priority log10(100) AS `log10(100)`,log10(18) AS `log10(18)`,log10(-(4)) AS `log10(-4)`,log10(0) AS `log10(0)`,log10(NULL) AS `log10(NULL)` select pow(10,log10(10)),power(2,4); pow(10,log10(10)) power(2,4) 10.000000 16.000000 +explain extended select pow(10,log10(10)),power(2,4); +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 +Warnings: +Note 1003 select high_priority pow(10,log10(10)) AS `pow(10,log10(10))`,pow(2,4) AS `power(2,4)` set @@rand_seed1=10000000,@@rand_seed2=1000000; select rand(999999),rand(); rand(999999) rand() 0.014231365187309 0.028870999839968 +explain extended select rand(999999),rand(); +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 +Warnings: +Note 1003 select high_priority no_cache rand(999999) AS `rand(999999)`,rand() AS `rand()` select pi(),sin(pi()/2),cos(pi()/2),abs(tan(pi())),cot(1),asin(1),acos(0),atan(1); pi() sin(pi()/2) cos(pi()/2) abs(tan(pi())) cot(1) asin(1) acos(0) atan(1) 3.141593 1.000000 0.000000 0.000000 0.64209262 1.570796 1.570796 0.785398 +explain extended select pi(),sin(pi()/2),cos(pi()/2),abs(tan(pi())),cot(1),asin(1),acos(0),atan(1); +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 +Warnings: +Note 1003 select high_priority pi() AS `pi()`,sin((pi() / 2)) AS `sin(pi()/2)`,cos((pi() / 2)) AS `cos(pi()/2)`,abs(tan(pi())) AS `abs(tan(pi()))`,(1 / tan(1)) AS `cot(1)`,asin(1) AS `asin(1)`,acos(0) AS `acos(0)`,atan(1) AS `atan(1)` select degrees(pi()),radians(360); degrees(pi()) radians(360) 180 6.2831853071796 +explain extended select degrees(pi()),radians(360); +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 +Warnings: +Note 1003 select high_priority degrees(pi()) AS `degrees(pi())`,radians(360) AS `radians(360)` diff --git a/mysql-test/r/func_op.result b/mysql-test/r/func_op.result index 9f49b5809df..25a7ac20b66 100644 --- a/mysql-test/r/func_op.result +++ b/mysql-test/r/func_op.result @@ -1,9 +1,19 @@ select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; 1+1 1-1 1+1*2 8/5 8%5 mod(8,5) mod(8,5)|0 -(1+1)*-2 2 0 3 1.60 3 3 3 4 +explain extended select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; +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 +Warnings: +Note 1003 select high_priority (1 + 1) AS `1+1`,(1 - 1) AS `1-1`,(1 + (1 * 2)) AS `1+1*2`,(8 / 5) AS `8/5`,(8 % 5) AS `8%5`,(8 % 5) AS `mod(8,5)`,((8 % 5) | 0) AS `mod(8,5)|0`,(-((1 + 1)) * -(2)) AS `-(1+1)*-2` select 1 | (1+1),5 & 3,bit_count(7) ; 1 | (1+1) 5 & 3 bit_count(7) 3 1 3 +explain extended select 1 | (1+1),5 & 3,bit_count(7) ; +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 +Warnings: +Note 1003 select high_priority (1 | (1 + 1)) AS `1 | (1+1)`,(5 & 3) AS `5 & 3`,bit_count(7) AS `bit_count(7)` select 1 << 32,1 << 63, 1 << 64, 4 >> 2, 4 >> 63, 1<< 63 >> 60; 1 << 32 1 << 63 1 << 64 4 >> 2 4 >> 63 1<< 63 >> 60 4294967296 9223372036854775808 0 1 0 8 diff --git a/mysql-test/r/func_regexp.result b/mysql-test/r/func_regexp.result index 35742136ee6..323642cab8c 100644 --- a/mysql-test/r/func_regexp.result +++ b/mysql-test/r/func_regexp.result @@ -36,6 +36,11 @@ insert into t1 (xxx) values('this is a test of some long text to see what happen select * from t1 where xxx regexp('is a test of some long text to'); xxx this is a test of some long text to see what happens +explain extended select * from t1 where xxx regexp('is a test of some long text to'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 +Warnings: +Note 1003 select high_priority test.t1.xxx AS `xxx` from test.t1 where (test.t1.xxx regexp _latin1'is a test of some long text to') select * from t1 where xxx regexp('is a test of some long text to '); xxx this is a test of some long text to see what happens diff --git a/mysql-test/r/func_set.result b/mysql-test/r/func_set.result index 86608e7c247..2a3631140b0 100644 --- a/mysql-test/r/func_set.result +++ b/mysql-test/r/func_set.result @@ -1,6 +1,11 @@ select interval(55,10,20,30,40,50,60,70,80,90,100),interval(3,1,1+1,1+1+1+1),field("IBM","NCA","ICL","SUN","IBM","DIGITAL"),field("A","B","C"),elt(2,"ONE","TWO","THREE"),interval(0,1,2,3,4),elt(1,1,2,3)|0,elt(1,1.1,1.2,1.3)+0; interval(55,10,20,30,40,50,60,70,80,90,100) interval(3,1,1+1,1+1+1+1) field("IBM","NCA","ICL","SUN","IBM","DIGITAL") field("A","B","C") elt(2,"ONE","TWO","THREE") interval(0,1,2,3,4) elt(1,1,2,3)|0 elt(1,1.1,1.2,1.3)+0 5 2 4 0 TWO 0 1 1.1 +explain extended select INTERVAL(55,10,20,30,40,50,60,70,80,90,100),interval(3,1,1+1,1+1+1+1),field("IBM","NCA","ICL","SUN","IBM","DIGITAL"),field("A","B","C"),elt(2,"ONE","TWO","THREE"),interval(0,1,2,3,4),elt(1,1,2,3)|0,elt(1,1.1,1.2,1.3)+0; +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 +Warnings: +Note 1003 select high_priority interval((55,10,20,30,40,50,60,70,80,90,100)) AS `INTERVAL(55,10,20,30,40,50,60,70,80,90,100)`,interval((3,1,(1 + 1),(((1 + 1) + 1) + 1))) AS `interval(3,1,1+1,1+1+1+1)`,field(_latin1'IBM',_latin1'NCA',_latin1'ICL',_latin1'SUN',_latin1'IBM',_latin1'DIGITAL') AS `field("IBM","NCA","ICL","SUN","IBM","DIGITAL")`,field(_latin1'A',_latin1'B',_latin1'C') AS `field("A","B","C")`,elt(2,_latin1'ONE',_latin1'TWO',_latin1'THREE') AS `elt(2,"ONE","TWO","THREE")`,interval((0,1,2,3,4)) AS `interval(0,1,2,3,4)`,(elt(1,1,2,3) | 0) AS `elt(1,1,2,3)|0`,(elt(1,1.1,1.2,1.3) + 0) AS `elt(1,1.1,1.2,1.3)+0` select find_in_set("b","a,b,c"),find_in_set("c","a,b,c"),find_in_set("dd","a,bbb,dd"),find_in_set("bbb","a,bbb,dd"); find_in_set("b","a,b,c") find_in_set("c","a,b,c") find_in_set("dd","a,bbb,dd") find_in_set("bbb","a,bbb,dd") 2 3 3 2 diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index ac25277351c..e43f9a9119e 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -12,9 +12,15 @@ length('\n\t\r\b\0\_\%\\') select bit_length('\n\t\r\b\0\_\%\\'); bit_length('\n\t\r\b\0\_\%\\') 80 -select concat('monty',' was here ','again'),length('hello'),char(ascii('h')); -concat('monty',' was here ','again') length('hello') char(ascii('h')) -monty was here again 5 h +select char_length('\n\t\r\b\0\_\%\\'); +char_length('\n\t\r\b\0\_\%\\') +10 +select length(_latin1'\n\t\n\b\0\\_\\%\\'); +length(_latin1'\n\t\n\b\0\\_\\%\\') +10 +select concat('monty',' was here ','again'),length('hello'),char(ascii('h')),ord('h'); +concat('monty',' was here ','again') length('hello') char(ascii('h')) ord('h') +monty was here again 5 h 104 select locate('he','hello'),locate('he','hello',2),locate('lo','hello',2) ; locate('he','hello') locate('he','hello',2) locate('lo','hello',2) 1 0 4 @@ -99,6 +105,9 @@ NULL select md5('hello'); md5('hello') 5d41402abc4b2a76b9719d911017c592 +select crc32("123"); +crc32("123") +2286445522 select sha('abc'); sha('abc') a9993e364706816aba3e25717850c26c9cd0d89d @@ -579,3 +588,11 @@ CONCAT("</a>",RPAD("",(55 - LENGTH(title)),".")) NULL </a>.......................... DROP TABLE t1; +select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2); +substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2) substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2) +1abcd;2abcd 3abcd;4abcd +explain extended select md5('hello'), sha('abc'), sha1('abc'), soundex(''), 'mood' sounds like 'mud', aes_decrypt(aes_encrypt('abc','1'),'1'),concat('*',space(5),'*'), reverse('abc'), rpad('a',4,'1'), lpad('a',4,'1'), concat_ws(',','',NULL,'a'),make_set(255,_latin2'a',_latin2'b',_latin2'c'),elt(2,1),locate("a","b",2),format(130,10),char(0),conv(130,16,10),hex(130),binary 'HE', export_set(255,_latin2'y',_latin2'n',_latin2' '),FIELD('b' COLLATE latin1_bin,'A','B'),FIND_IN_SET(_latin1'B',_latin1'a,b,c,d'),collation(conv(130,16,10)), coercibility(conv(130,16,10)),length('\n\t\r\b\0\_\%\\'),bit_length('\n\t\r\b\0\_\%\\'),bit_length('\n\t\r\b\0\_\%\\'),concat('monty',' was here ','again'),length('hello'),char(ascii('h')),ord('h'),quote(1/0),crc32("123"),replace('aaaa','a','b'),insert('txs',2,1,'hi'),left(_latin2'a',1),right(_latin2'a',1),lcase(_latin2'a'),ucase(_latin2'a'),SUBSTR('abcdefg',3,2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),trim(_latin2' a '),ltrim(_latin2' a '),rtrim(_latin2' a '), decode(encode(repeat("a",100000),"monty"),"monty"); +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 +Warnings: +Note 1003 select high_priority md5(_latin1'hello') AS `md5('hello')`,sha(_latin1'abc') AS `sha('abc')`,sha(_latin1'abc') AS `sha1('abc')`,soundex(_latin1'') AS `soundex('')`,(soundex(_latin1'mood') = soundex(_latin1'mud')) AS `'mood' sounds like 'mud'`,aes_decrypt(aes_encrypt(_latin1'abc',_latin1'1'),_latin1'1') AS `aes_decrypt(aes_encrypt('abc','1'),'1')`,concat(_latin1'*',repeat(_latin1' ',5),_latin1'*') AS `concat('*',space(5),'*')`,reverse(_latin1'abc') AS `reverse('abc')`,rpad(_latin1'a',4,_latin1'1') AS `rpad('a',4,'1')`,lpad(_latin1'a',4,_latin1'1') AS `lpad('a',4,'1')`,concat_ws(_latin1',',_latin1'',NULL,_latin1'a') AS `concat_ws(',','',NULL,'a')`,make_set(255,_latin2'a',_latin2'b',_latin2'c') AS `make_set(255,_latin2'a',_latin2'b',_latin2'c')`,elt(2,1) AS `elt(2,1)`,locate(_latin1'a',_latin1'b',2) AS `locate("a","b",2)`,format(130,10) AS `format(130,10)`,char(0) AS `char(0)`,conv(130,16,10) AS `conv(130,16,10)`,hex(130) AS `hex(130)`,(_latin1'HE' collate _latin1'BINARY') AS `binary 'HE'`,export_set(255,_latin2'y',_latin2'n',_latin2' ') AS `export_set(255,_latin2'y',_latin2'n',_latin2' ')`,field((_latin1'b' collate _latin1'latin1_bin'),_latin1'A',_latin1'B') AS `FIELD('b' COLLATE latin1_bin,'A','B')`,find_in_set(_latin1'B',_latin1'a,b,c,d') AS `FIND_IN_SET(_latin1'B',_latin1'a,b,c,d')`,collation(conv(130,16,10)) AS `collation(conv(130,16,10))`,coercibility(conv(130,16,10)) AS `coercibility(conv(130,16,10))`,length(_latin1'\n \r\0\\_\\%\\') AS `length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,bit_length(_latin1'\n \r\0\\_\\%\\') AS `bit_length('\n\t\r\b\0\_\%\\')`,concat(_latin1'monty',_latin1' was here ',_latin1'again') AS `concat('monty',' was here ','again')`,length(_latin1'hello') AS `length('hello')`,char(ascii(_latin1'h')) AS `char(ascii('h'))`,ord(_latin1'h') AS `ord('h')`,quote((1 / 0)) AS `quote(1/0)`,crc32(_latin1'123') AS `crc32("123")`,replace(_latin1'aaaa',_latin1'a',_latin1'b') AS `replace('aaaa','a','b')`,insert(_latin1'txs',2,1,_latin1'hi') AS `insert('txs',2,1,'hi')`,left(_latin2'a',1) AS `left(_latin2'a',1)`,right(_latin2'a',1) AS `right(_latin2'a',1)`,lcase(_latin2'a') AS `lcase(_latin2'a')`,ucase(_latin2'a') AS `ucase(_latin2'a')`,substr(_latin1'abcdefg',3,2) AS `SUBSTR('abcdefg',3,2)`,substr_index(_latin1'1abcd;2abcd;3abcd;4abcd',_latin1';',2) AS `substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2)`,trim(_latin2' a ') AS `trim(_latin2' a ')`,ltrim(_latin2' a ') AS `ltrim(_latin2' a ')`,rtrim(_latin2' a ') AS `rtrim(_latin2' a ')`,decode(encode(repeat(_latin1'a',100000))) AS `decode(encode(repeat("a",100000),"monty"),"monty")` diff --git a/mysql-test/r/func_system.result b/mysql-test/r/func_system.result index a52d5613c04..9d370b43099 100644 --- a/mysql-test/r/func_system.result +++ b/mysql-test/r/func_system.result @@ -37,6 +37,11 @@ version()>=_latin1"3.23.29" select charset(version()); charset(version()) utf8 +explain extended select database(), user(); +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 +Warnings: +Note 1003 select high_priority no_cache database() AS `database()`,user() AS `user()` create table t1 (version char(40)) select database(), user(), version() as 'version'; show create table t1; Table Create Table diff --git a/mysql-test/r/func_test.result b/mysql-test/r/func_test.result index 851c308ba3e..4951d954abb 100644 --- a/mysql-test/r/func_test.result +++ b/mysql-test/r/func_test.result @@ -44,19 +44,47 @@ select -1.49 or -1.49,0.6 or 0.6; select 3 ^ 11, 1 ^ 1, 1 ^ 0, 1 ^ NULL, NULL ^ 1; 3 ^ 11 1 ^ 1 1 ^ 0 1 ^ NULL NULL ^ 1 8 0 1 NULL NULL +explain extended select 3 ^ 11, 1 ^ 1, 1 ^ 0, 1 ^ NULL, NULL ^ 1; +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 +Warnings: +Note 1003 select high_priority (3 ^ 11) AS `3 ^ 11`,(1 ^ 1) AS `1 ^ 1`,(1 ^ 0) AS `1 ^ 0`,(1 ^ NULL) AS `1 ^ NULL`,(NULL ^ 1) AS `NULL ^ 1` select 1 XOR 1, 1 XOR 0, 0 XOR 1, 0 XOR 0, NULL XOR 1, 1 XOR NULL, 0 XOR NULL; 1 XOR 1 1 XOR 0 0 XOR 1 0 XOR 0 NULL XOR 1 1 XOR NULL 0 XOR NULL 0 1 1 0 NULL NULL NULL select 10 % 7, 10 mod 7, 10 div 3; 10 % 7 10 mod 7 10 div 3 3 3 3 +explain extended select 10 % 7, 10 mod 7, 10 div 3; +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 +Warnings: +Note 1003 select high_priority (10 % 7) AS `10 % 7`,(10 % 7) AS `10 mod 7`,(10 DIV 3) AS `10 div 3` select (1 << 64)-1, ((1 << 64)-1) DIV 1, ((1 << 64)-1) DIV 2; (1 << 64)-1 ((1 << 64)-1) DIV 1 ((1 << 64)-1) DIV 2 18446744073709551615 18446744073709551615 9223372036854775807 +explain extended select (1 << 64)-1, ((1 << 64)-1) DIV 1, ((1 << 64)-1) DIV 2; +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 +Warnings: +Note 1003 select high_priority ((1 << 64) - 1) AS `(1 << 64)-1`,(((1 << 64) - 1) DIV 1) AS `((1 << 64)-1) DIV 1`,(((1 << 64) - 1) DIV 2) AS `((1 << 64)-1) DIV 2` create table t1 (a int); insert t1 values (1); select * from t1 where 1 xor 1; a +explain extended select * from t1 where 1 xor 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select high_priority test.t1.a AS `a` from test.t1 where (1 xor 1) +select - a from t1; +- a +-1 +explain extended select - a from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 +Warnings: +Note 1003 select high_priority -(test.t1.a) AS `- a` from test.t1 drop table t1; select 5 between 0 and 10 between 0 and 1,(5 between 0 and 10) between 0 and 1; 5 between 0 and 10 between 0 and 1 (5 between 0 and 10) between 0 and 1 @@ -73,6 +101,11 @@ _koi8r'a' = _koi8r'A' select _koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci; _koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci 1 +explain extended select _koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci; +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 +Warnings: +Note 1003 select high_priority (_koi8r'a' = (_koi8r'A' collate _latin1'koi8r_general_ci')) AS `_koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci` select _koi8r'a' = _koi8r'A' COLLATE koi8r_bin; _koi8r'a' = _koi8r'A' COLLATE koi8r_bin 0 diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index b8709487c6d..9d38083f48a 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -486,3 +486,8 @@ strcmp(date_format(utc_timestamp(),"%Y-%m-%d"), utc_date())=0 select strcmp(concat(utc_date(),' ',utc_time()),utc_timestamp())=0; strcmp(concat(utc_date(),' ',utc_time()),utc_timestamp())=0 1 +explain extended select period_add("9602",-12),period_diff(199505,"9404"),from_days(to_days("960101")),dayofmonth("1997-01-02"), month("1997-01-02"), monthname("1972-03-04"),dayofyear("0000-00-00"),HOUR("1997-03-03 23:03:22"),MINUTE("23:03:22"),SECOND(230322),QUARTER(980303),WEEK("1998-03-03"),yearweek("2000-01-01",1),week(19950101,1),year("98-02-03"),weekday(curdate())-weekday(now()),dayname("1962-03-03"),unix_timestamp(),sec_to_time(time_to_sec("0:30:47")/6.21),curtime(),utc_time(),curdate(),utc_date(),utc_timestamp(),date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w"),from_unixtime(unix_timestamp("1994-03-02 10:11:12")),"1997-12-31 23:59:59" + INTERVAL 1 SECOND,"1998-01-01 00:00:00" - INTERVAL 1 SECOND,INTERVAL 1 DAY + "1997-12-31", extract(YEAR FROM "1999-01-02 10:11:12"),date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND); +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 +Warnings: +Note 1003 select high_priority no_cache period_add(_latin1'9602',-(12)) AS `period_add("9602",-12)`,period_diff(199505,_latin1'9404') AS `period_diff(199505,"9404")`,from_days(to_days(_latin1'960101')) AS `from_days(to_days("960101"))`,dayofmonth(_latin1'1997-01-02') AS `dayofmonth("1997-01-02")`,month(_latin1'1997-01-02') AS `month("1997-01-02")`,monthname(_latin1'1972-03-04') AS `monthname("1972-03-04")`,dayofyear(_latin1'0000-00-00') AS `dayofyear("0000-00-00")`,hour(_latin1'1997-03-03 23:03:22') AS `HOUR("1997-03-03 23:03:22")`,minute(_latin1'23:03:22') AS `MINUTE("23:03:22")`,second(230322) AS `SECOND(230322)`,quarter(980303) AS `QUARTER(980303)`,week(_latin1'1998-03-03',0) AS `WEEK("1998-03-03")`,yearweek(_latin1'2000-01-01',1) AS `yearweek("2000-01-01",1)`,week(19950101,1) AS `week(19950101,1)`,year(_latin1'98-02-03') AS `year("98-02-03")`,(weekday(to_days(curdate())) - weekday(to_days(now()))) AS `weekday(curdate())-weekday(now())`,dayname(to_days(_latin1'1962-03-03')) AS `dayname("1962-03-03")`,unix_timestamp() AS `unix_timestamp()`,sec_to_time((time_to_sec(_latin1'0:30:47') / 6.21)) AS `sec_to_time(time_to_sec("0:30:47")/6.21)`,curtime() AS `curtime()`,utc_time() AS `utc_time()`,curdate() AS `curdate()`,utc_date() AS `utc_date()`,utc_timestamp() AS `utc_timestamp()`,date_format(_latin1'1997-01-02 03:04:05',_latin1'%M %W %D %Y %y %m %d %h %i %s %w') AS `date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w")`,from_unixtime(unix_timestamp(_latin1'1994-03-02 10:11:12')) AS `from_unixtime(unix_timestamp("1994-03-02 10:11:12"))`,(_latin1'1997-12-31 23:59:59' + interval 1 second) AS `"1997-12-31 23:59:59" + INTERVAL 1 SECOND`,(_latin1'1998-01-01 00:00:00' - interval 1 second) AS `"1998-01-01 00:00:00" - INTERVAL 1 SECOND`,(_latin1'1997-12-31' + interval 1 day) AS `INTERVAL 1 DAY + "1997-12-31"`,extract(year from _latin1'1999-01-02 10:11:12') AS `extract(YEAR FROM "1999-01-02 10:11:12")`,(_latin1'1997-12-31 23:59:59' + interval 1 second) AS `date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND)` diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 4317daea0b3..7ee16d54724 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -224,6 +224,11 @@ fid AsText(Envelope(g)) 119 POLYGON((0 0,3 0,3 3,0 3,0 0)) 120 POLYGON((0 0,10 0,10 10,0 10,0 0)) 121 POLYGON((3 6,44 6,44 9,3 9,3 6)) +explain extended select Dimension(g), GeometryType(g), IsEmpty(g), AsText(Envelope(g)) from geo; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE geo ALL NULL NULL NULL NULL 21 +Warnings: +Note 1003 select high_priority dimension(test.geo.g) AS `Dimension(g)`,geometrytype(test.geo.g) AS `GeometryType(g)`,isempty(test.geo.g) AS `IsEmpty(g)`,astext(envelope(test.geo.g)) AS `AsText(Envelope(g))` from test.geo SELECT fid, X(g) FROM pt; fid X(g) 101 10 @@ -236,6 +241,11 @@ fid Y(g) 102 10 103 20 104 20 +explain extended select X(g),Y(g) FROM pt; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE pt ALL NULL NULL NULL NULL 4 +Warnings: +Note 1003 select high_priority x(test.pt.g) AS `X(g)`,y(test.pt.g) AS `Y(g)` from test.pt SELECT fid, AsText(StartPoint(g)) FROM ls; fid AsText(StartPoint(g)) 105 POINT(0 0) @@ -266,6 +276,11 @@ fid IsClosed(g) 105 0 106 1 107 0 +explain extended select AsText(StartPoint(g)),AsText(EndPoint(g)),GLength(g),NumPoints(g),AsText(PointN(g, 2)),IsClosed(g) FROM ls; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE ls ALL NULL NULL NULL NULL 3 +Warnings: +Note 1003 select high_priority astext(startpoint(test.ls.g)) AS `AsText(StartPoint(g))`,astext(endpoint(test.ls.g)) AS `AsText(EndPoint(g))`,glength(test.ls.g) AS `GLength(g)`,numpoints(test.ls.g) AS `NumPoints(g)`,astext(pointn(test.ls.g,2)) AS `AsText(PointN(g, 2))`,isclosed(test.ls.g) AS `IsClosed(g)` from test.ls SELECT fid, AsText(Centroid(g)) FROM p; fid AsText(Centroid(g)) 108 POINT(15 15) @@ -291,6 +306,11 @@ fid AsText(InteriorRingN(g, 1)) 108 NULL 109 LINESTRING(10 10,20 10,20 20,10 20,10 10) 110 NULL +explain extended select AsText(Centroid(g)),Area(g),AsText(ExteriorRing(g)),NumInteriorRings(g),AsText(InteriorRingN(g, 1)) FROM p; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE p ALL NULL NULL NULL NULL 3 +Warnings: +Note 1003 select high_priority astext(centroid(test.p.g)) AS `AsText(Centroid(g))`,area(test.p.g) AS `Area(g)`,astext(exteriorring(test.p.g)) AS `AsText(ExteriorRing(g))`,numinteriorrings(test.p.g) AS `NumInteriorRings(g)`,astext(interiorringn(test.p.g,1)) AS `AsText(InteriorRingN(g, 1))` from test.p SELECT fid, IsClosed(g) FROM mls; fid IsClosed(g) 114 0 @@ -325,6 +345,11 @@ SELECT fid, NumGeometries(g) from gc; fid NumGeometries(g) 120 2 121 2 +explain extended SELECT fid, NumGeometries(g) from mpt; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE mpt ALL NULL NULL NULL NULL 3 +Warnings: +Note 1003 select high_priority test.mpt.fid AS `fid`,numgeometries(test.mpt.g) AS `NumGeometries(g)` from test.mpt SELECT fid, AsText(GeometryN(g, 2)) from mpt; fid AsText(GeometryN(g, 2)) 111 POINT(10 10) @@ -344,6 +369,11 @@ SELECT fid, AsText(GeometryN(g, 2)) from gc; fid AsText(GeometryN(g, 2)) 120 LINESTRING(0 0,10 10) 121 LINESTRING(3 6,7 9) +explain extended SELECT fid, AsText(GeometryN(g, 2)) from mpt; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE mpt ALL NULL NULL NULL NULL 3 +Warnings: +Note 1003 select high_priority test.mpt.fid AS `fid`,astext(geometryn(test.mpt.g,2)) AS `AsText(GeometryN(g, 2))` from test.mpt SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, @@ -354,6 +384,16 @@ first second w c o e d t i r 120 121 0 0 0 0 0 0 1 0 121 120 0 0 1 0 0 0 1 0 121 121 1 1 0 1 0 0 1 0 +explain extended SELECT g1.fid as first, g2.fid as second, +Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, +Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, +Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r +FROM gc g1, gc g2 ORDER BY first, second; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE g1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort +1 SIMPLE g2 ALL NULL NULL NULL NULL 2 +Warnings: +Note 1003 select high_priority test.g1.fid AS `first`,test.g2.fid AS `second`,within(test.g1.g,test.g2.g) AS `w`,contains(test.g1.g,test.g2.g) AS `c`,overlaps(test.g1.g,test.g2.g) AS `o`,equals(test.g1.g,test.g2.g) AS `e`,disjoint(test.g1.g,test.g2.g) AS `d`,touches(test.g1.g,test.g2.g) AS `t`,intersects(test.g1.g,test.g2.g) AS `i`,crosses(test.g1.g,test.g2.g) AS `r` from test.gc g1 join test.gc g2 order by test.g1.fid,test.g2.fid DROP TABLE pt, ls, p, mpt, mls, mp, gc, geo; CREATE TABLE g1 ( pt point, @@ -391,3 +431,26 @@ DROP TABLE g1; SELECT AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4)')))); AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4)')))) POINT(1 4) +explain extended SELECT AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4)')))); +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 +Warnings: +Note 1003 select high_priority astext(geometryfromwkb(aswkb(geometryfromtext(_latin1'POINT(1 4)')))) AS `AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4)'))))` +explain extended SELECT AsText(GeometryFromWKB(AsWKB(PointFromText('POINT(1 4)')))); +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 +Warnings: +Note 1003 select high_priority astext(geometryfromwkb(aswkb(geometryfromtext(_latin1'POINT(1 4)')))) AS `AsText(GeometryFromWKB(AsWKB(PointFromText('POINT(1 4)'))))` +SELECT SRID(GeomFromText('LineString(1 1,2 2)',101)); +SRID(GeomFromText('LineString(1 1,2 2)',101)) +101 +explain extended SELECT SRID(GeomFromText('LineString(1 1,2 2)',101)); +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 +Warnings: +Note 1003 select high_priority srid(geometryfromtext(_latin1'LineString(1 1,2 2)',101)) AS `SRID(GeomFromText('LineString(1 1,2 2)',101))` +explain extended select issimple(MultiPoint(Point(3, 6), Point(4, 10))), issimple(Point(3, 6)); +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 +Warnings: +Note 1003 select high_priority issimple(multipoint(point(3,6),point(4,10))) AS `issimple(MultiPoint(Point(3, 6), Point(4, 10)))`,issimple(point(3,6)) AS `issimple(Point(3, 6))` diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index c286b4d8fc4..b9eaa81ba2a 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -284,9 +284,11 @@ select spid,count(*) from t1 where spid between 1 and 2 group by spid desc; spid count(*) 2 2 1 1 -explain select sql_big_result spid,sum(userid) from t1 group by spid desc; +explain extended select sql_big_result spid,sum(userid) from t1 group by spid desc; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using filesort +Warnings: +Note 1003 select high_priority big_result test.t1.spID AS `spid`,sum(test.t1.userID) AS `sum(userid)` from test.t1 group by test.t1.spID desc explain select sql_big_result spid,sum(userid) from t1 group by spid desc order by null; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 8 diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result index fc0b3c652ef..7c88776579b 100644 --- a/mysql-test/r/having.result +++ b/mysql-test/r/having.result @@ -8,6 +8,11 @@ b select count(a) as b from t1 where a=0 having b >=0; b 0 +explain extended select count(a) as b from t1 where a=0 having b >=0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select high_priority count(test.t1.a) AS `b` from test.t1 where (test.t1.a = 0) having (count(test.t1.a) >= 0) drop table t1; CREATE TABLE t1 ( raw_id int(10) NOT NULL default '0', diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index 4ef25781331..3a7679ce1e3 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -56,4 +56,14 @@ a b c VALUES(a) 5 0 30 NULL 8 9 60 NULL 2 1 11 NULL +explain extended SELECT *, VALUES(a) FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 +Warnings: +Note 1003 select high_priority test.t1.a AS `a`,test.t1.b AS `b`,test.t1.c AS `c`,values(test.t1.a) AS `VALUES(a)` from test.t1 +explain extended select * from t1 where values(a); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +Warnings: +Note 1003 select high_priority test.t1.a AS `a`,test.t1.b AS `b`,test.t1.c AS `c` from test.t1 DROP TABLE t1; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index fa9658c0202..4025a01bc93 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -5,7 +5,7 @@ INSERT INTO t1 VALUES (1), (2); <mysqldump> <database name="test"> <table_structure name="t1"> - <field Field="a" Type="int(11)" Null="YES" /> + <field Field="a" Type="int(11)" Null="YES" Key="" Extra="" /> </table_structure> <table_data name="t1"> <row> @@ -18,15 +18,40 @@ INSERT INTO t1 VALUES (1), (2); </database> </mysqldump> DROP TABLE t1; -CREATE TABLE `"t"1` (`a"b"` char(2)); -INSERT INTO `"t"1` VALUES ("1\""), ("\"2"); +CREATE TABLE t1(a int, b text, c varchar(3)); +INSERT INTO t1 VALUES (1, "test", "tes"), (2, "TEST", "TES"); <?xml version="1.0"?> <mysqldump> <database name="test"> - <table_structure name=""t"1"> - <field Field="a"b"" Type="char(2)" Null="YES" /> + <table_structure name="t1"> + <field Field="a" Type="int(11)" Null="YES" Key="" Extra="" /> + <field Field="b" Type="text" Null="YES" Key="" Extra="" /> + <field Field="c" Type="char(3)" Null="YES" Key="" Extra="" /> </table_structure> - <table_data name=""t"1"> + <table_data name="t1"> + <row> + <field name="a">1</field> + <field name="b">test</field> + <field name="c">tes</field> + </row> + <row> + <field name="a">2</field> + <field name="b">TEST</field> + <field name="c">TES</field> + </row> + </table_data> +</database> +</mysqldump> +DROP TABLE t1; +CREATE TABLE t1 (`a"b"` char(2)); +INSERT INTO t1 VALUES ("1\""), ("\"2"); +<?xml version="1.0"?> +<mysqldump> +<database name="test"> + <table_structure name="t1"> + <field Field="a"b"" Type="char(2)" Null="YES" Key="" Extra="" /> + </table_structure> + <table_data name="t1"> <row> <field name="a"b"">1"</field> </row> @@ -36,4 +61,4 @@ INSERT INTO `"t"1` VALUES ("1\""), ("\"2"); </table_data> </database> </mysqldump> -DROP TABLE `"t"1`; +DROP TABLE t1; diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result index 2ef1f0c86f9..9de9fdce2db 100644 --- a/mysql-test/r/null.result +++ b/mysql-test/r/null.result @@ -2,6 +2,11 @@ drop table if exists t1; select null,\N,isnull(null),isnull(1/0),isnull(1/0 = null),ifnull(null,1),ifnull(null,"TRUE"),ifnull("TRUE","ERROR"),1/0 is null,1 is not null; NULL NULL isnull(null) isnull(1/0) isnull(1/0 = null) ifnull(null,1) ifnull(null,"TRUE") ifnull("TRUE","ERROR") 1/0 is null 1 is not null NULL NULL 1 1 1 1 TRUE TRUE 1 1 +explain extended select null,\N,isnull(null),isnull(1/0),isnull(1/0 = null),ifnull(null,1),ifnull(null,"TRUE"),ifnull("TRUE","ERROR"),1/0 is null,1 is not null; +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 +Warnings: +Note 1003 select high_priority NULL AS `NULL`,NULL AS `NULL`,isnull(NULL) AS `isnull(null)`,isnull((1 / 0)) AS `isnull(1/0)`,isnull(((1 / 0) = NULL)) AS `isnull(1/0 = null)`,ifnull(NULL,1) AS `ifnull(null,1)`,ifnull(NULL,_latin1'TRUE') AS `ifnull(null,"TRUE")`,ifnull(_latin1'TRUE',_latin1'ERROR') AS `ifnull("TRUE","ERROR")`,isnull((1 / 0)) AS `1/0 is null`,(1 is not null) AS `1 is not null` select 1 | NULL,1 & NULL,1+NULL,1-NULL; 1 | NULL 1 & NULL 1+NULL 1-NULL NULL NULL NULL NULL @@ -23,6 +28,11 @@ field(NULL,"a","b","c") select 2 between null and 1,2 between 3 AND NULL,NULL between 1 and 2,2 between NULL and 3, 2 between 1 AND null; 2 between null and 1 2 between 3 AND NULL NULL between 1 and 2 2 between NULL and 3 2 between 1 AND null 0 0 NULL NULL NULL +explain extended select 2 between null and 1,2 between 3 AND NULL,NULL between 1 and 2,2 between NULL and 3, 2 between 1 AND null; +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 +Warnings: +Note 1003 select high_priority (2 between NULL and 1) AS `2 between null and 1`,(2 between 3 and NULL) AS `2 between 3 AND NULL`,(NULL between 1 and 2) AS `NULL between 1 and 2`,(2 between NULL and 3) AS `2 between NULL and 3`,(2 between 1 and NULL) AS `2 between 1 AND null` SELECT NULL AND NULL, 1 AND NULL, NULL AND 1, NULL OR NULL, 0 OR NULL, NULL OR 0; NULL AND NULL 1 AND NULL NULL AND 1 NULL OR NULL 0 OR NULL NULL OR 0 NULL NULL NULL NULL NULL NULL @@ -35,6 +45,11 @@ NULL AND 0 0 and NULL select inet_ntoa(null),inet_aton(null),inet_aton("122.256"),inet_aton("122.226."),inet_aton(""); inet_ntoa(null) inet_aton(null) inet_aton("122.256") inet_aton("122.226.") inet_aton("") NULL NULL NULL NULL NULL +explain extended select inet_ntoa(null),inet_aton(null),inet_aton("122.256"),inet_aton("122.226."),inet_aton(""); +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 +Warnings: +Note 1003 select high_priority inet_ntoa(NULL) AS `inet_ntoa(null)`,inet_aton(NULL) AS `inet_aton(null)`,inet_aton(_latin1'122.256') AS `inet_aton("122.256")`,inet_aton(_latin1'122.226.') AS `inet_aton("122.226.")`,inet_aton(_latin1'') AS `inet_aton("")` create table t1 (x int); insert into t1 values (null); select * from t1 where x != 0; diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result index bacd95d852e..9aaea0d800b 100644 --- a/mysql-test/r/null_key.result +++ b/mysql-test/r/null_key.result @@ -153,12 +153,12 @@ a b 7 NULL explain select * from t1 where (a = 7 or a is null) and (b=7 or b is null); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref_or_null a,b a 5 const 4 Using where; Using index +1 SIMPLE t1 range a,b a 10 NULL 3 Using where; Using index select * from t1 where (a = 7 or a is null) and (b=7 or b is null); a b +NULL 7 7 NULL 7 7 -NULL 7 explain select * from t1 where (a = 7 or a is null) and (a = 7 or a is null); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref_or_null a a 5 const 5 Using where; Using index diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 84e37bf56a9..37e68d8b13e 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -81,9 +81,11 @@ TV 2 2000 200 TV 2 NULL 200 TV NULL NULL 600 NULL NULL NULL 7785 -explain select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; +explain extended select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 15 Using temporary; Using filesort +Warnings: +Note 1003 select high_priority test.t1.product AS `product`,test.t1.country_id AS `country_id`,test.t1.year AS `year`,sum(test.t1.profit) AS `sum(profit)` from test.t1 group by test.t1.product,test.t1.country_id,test.t1.year with rollup select product, country_id , sum(profit) from t1 group by product desc, country_id with rollup; product country_id sum(profit) TV 1 400 diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 1a1eec1f915..e91153cae15 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1,8 +1,9 @@ +set GLOBAL query_cache_size=1355776; flush query cache; flush query cache; reset query cache; flush status; -drop table if exists t1,t2,t3; +drop table if exists t1,t2,t3,t4,t11,t21; drop database if exists mysqltest; create table t1 (a int not null); insert into t1 values (1),(2),(3); @@ -300,6 +301,11 @@ select USER() from t1; USER() select benchmark(1,1) from t1; benchmark(1,1) +explain extended select benchmark(1,1) from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found +Warnings: +Note 1003 select high_priority no_cache benchmark(1,1) AS `benchmark(1,1)` from test.t1 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 @@ -580,7 +586,7 @@ select * from t1; a set GLOBAL query_cache_size=1024; Warnings: -Warning 1280 Query cache failed to set size 1024, new query cache size is 0 +Warning 1285 Query cache failed to set size 1024, new query cache size is 0 show global variables like "query_cache_size"; Variable_name Value query_cache_size 0 @@ -588,7 +594,7 @@ select * from t1; a set GLOBAL query_cache_size=10240; Warnings: -Warning 1280 Query cache failed to set size 10240, new query cache size is 0 +Warning 1285 Query cache failed to set size 10240, new query cache size is 0 show global variables like "query_cache_size"; Variable_name Value query_cache_size 0 @@ -596,7 +602,7 @@ select * from t1; a set GLOBAL query_cache_size=20480; Warnings: -Warning 1280 Query cache failed to set size 20480, new query cache size is 0 +Warning 1285 Query cache failed to set size 20480, new query cache size is 0 show global variables like "query_cache_size"; Variable_name Value query_cache_size 0 @@ -604,7 +610,7 @@ select * from t1; a set GLOBAL query_cache_size=40960; Warnings: -Warning 1280 Query cache failed to set size 40960, new query cache size is 0 +Warning 1285 Query cache failed to set size 40960, new query cache size is 0 show global variables like "query_cache_size"; Variable_name Value query_cache_size 0 @@ -717,6 +723,45 @@ Variable_name Value Qcache_queries_in_cache 2 SET OPTION SQL_SELECT_LIMIT=DEFAULT; drop table t1; +flush query cache; +reset query cache; +flush status; +set GLOBAL query_cache_size=1048576; +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +create table t2 (a text not null); +create table t3 (a text not null); +insert into t3 values("1111111111111111111111111111111111111111111111111111"); +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +drop table t2; +create table t2 (a int not null); +insert into t2 values (1),(2),(3); +create table t4 (a int not null); +insert into t4 values (1),(2),(3); +select * from t4; +select * from t2; +select * from t1 as tt, t1 as ttt where tt.a=1 and ttt.a=2; +select * from t2; +select * from t4; +select * from t1 as tt, t1 as ttt where tt.a=1 and ttt.a=2; +select * from t2; +select * from t4; +select * from t1 as tt, t1 as ttt where tt.a=1 and ttt.a=2; +delete from t2 where a=1; +flush query cache; +select * from t3; +delete from t4 where a=1; +flush query cache; +drop table t1,t2,t3,t4; SET NAMES koi8r; CREATE TABLE t1 (a char(1) character set koi8r); INSERT INTO t1 VALUES (_koi8r'á'),(_koi8r'Á'); @@ -726,7 +771,7 @@ a  'â'='Â' Á  1 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 12 +Qcache_hits 6 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 1 @@ -737,7 +782,7 @@ a  'â'='Â' Á  0 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 12 +Qcache_hits 6 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 2 @@ -748,7 +793,7 @@ a ÷ '×'='÷' Á ÷ 0 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 12 +Qcache_hits 6 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 3 @@ -759,8 +804,9 @@ a  'â'='Â' à  0 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 12 +Qcache_hits 6 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 4 DROP TABLE t1; +SET GLOBAL query_cache_size=0; diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 38d3d9b2b7d..1b66f442a9a 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -262,6 +262,23 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ref j1 j1 4 const 1 Using where; Using index 1 SIMPLE t1 ALL i2 NULL NULL NULL 4 Range checked for each record (index map: 0x2) DROP TABLE t1,t2; +CREATE TABLE t1 ( +a int(11) default NULL, +b int(11) default NULL, +KEY a (a), +KEY b (b) +) TYPE=MyISAM; +INSERT INTO t1 VALUES +(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,2),(10,2), +(13,2),(14,2),(15,2),(16,2),(17,3),(17,3),(16,3),(17,3),(19,3),(20,3), +(21,4),(22,5),(23,5),(24,5),(25,5),(26,5),(30,5),(31,5),(32,5),(33,5), +(33,5),(33,5),(33,5),(33,5),(34,5),(35,5); +EXPLAIN SELECT * FROM t1 WHERE a IN(1,2) AND b=5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a,b a 5 NULL 2 Using where +SELECT * FROM t1 WHERE a IN(1,2) AND b=5; +a b +DROP TABLE t1; create table t1 (id int(10) primary key); insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9); select id from t1 where id in (2,5,9) ; diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result index ab60f714d82..37d4f1d9b26 100644 --- a/mysql-test/r/row.result +++ b/mysql-test/r/row.result @@ -40,6 +40,11 @@ ERROR 21000: Operand should contain 2 column(s) select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))); row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))) NULL +explain extended select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))); +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 +Warnings: +Note 1003 select high_priority ((1,2,(3,4)) in ((3,2,(3,4)),(1,2,(3,NULL)))) AS `row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL)))` SELECT (1,2,3)=(0,NULL,3); (1,2,3)=(0,NULL,3) 0 diff --git a/mysql-test/r/rpl000001.result b/mysql-test/r/rpl000001.result index 79438f8fa40..b8071b16c2e 100644 --- a/mysql-test/r/rpl000001.result +++ b/mysql-test/r/rpl000001.result @@ -40,10 +40,20 @@ create table t1(n int); select get_lock("hold_slave",10); get_lock("hold_slave",10) 1 +explain extended select get_lock("hold_slave",10); +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 +Warnings: +Note 1003 select high_priority no_cache get_lock(_latin1'hold_slave',10) AS `get_lock("hold_slave",10)` start slave; select release_lock("hold_slave"); release_lock("hold_slave") 1 +explain extended select release_lock("hold_slave"); +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 +Warnings: +Note 1003 select high_priority no_cache release_lock(_latin1'hold_slave') AS `release_lock("hold_slave")` unlock tables; create table t2(id int); insert into t2 values(connection_id()); diff --git a/mysql-test/r/rpl_chain_temp_table.result b/mysql-test/r/rpl_chain_temp_table.result new file mode 100644 index 00000000000..5ece80565c7 --- /dev/null +++ b/mysql-test/r/rpl_chain_temp_table.result @@ -0,0 +1,30 @@ +slave stop; +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; +slave start; +reset master; +change master to master_host='127.0.0.1',master_port=9307, master_user='root'; +start slave; +create temporary table t1 (a int); +create temporary table t1 (a int); +show status like 'slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 2 +create temporary table t1 (a int); +create temporary table t1 (a int); +show status like 'slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 4 +stop slave; +insert into t1 values(1); +create table t2 as select * from t1; +start slave; +show status like 'slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 4 +select * from t2; +a +1 +drop table t2; diff --git a/mysql-test/r/rpl_get_lock.result b/mysql-test/r/rpl_get_lock.result index 369fde7ef8f..8e3e335b2d0 100644 --- a/mysql-test/r/rpl_get_lock.result +++ b/mysql-test/r/rpl_get_lock.result @@ -18,9 +18,14 @@ get_lock("lock",3) select * from t1; n 1 -select is_free_lock("lock"); -is_free_lock("lock") -0 +select is_free_lock("lock"), is_used_lock("lock"); +is_free_lock("lock") is_used_lock("lock") +0 6 +explain extended select is_free_lock("lock"), is_used_lock("lock"); +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 +Warnings: +Note 1003 select high_priority no_cache is_free_lock(_latin1'lock') AS `is_free_lock("lock")`,is_used_lock(_latin1'lock') AS `is_used_lock("lock")` select is_free_lock("lock2"); is_free_lock("lock2") 1 diff --git a/mysql-test/r/rpl_master_pos_wait.result b/mysql-test/r/rpl_master_pos_wait.result index bbd125a98d6..ea917805560 100644 --- a/mysql-test/r/rpl_master_pos_wait.result +++ b/mysql-test/r/rpl_master_pos_wait.result @@ -7,6 +7,11 @@ start slave; select master_pos_wait('master-bin.999999',0,2); master_pos_wait('master-bin.999999',0,2) -1 +explain extended select master_pos_wait('master-bin.999999',0,2); +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 +Warnings: +Note 1003 select high_priority no_cache master_pos_wait(_latin1'master-bin.999999',0,2) AS `master_pos_wait('master-bin.999999',0,2)` select master_pos_wait('master-bin.999999',0); stop slave sql_thread; master_pos_wait('master-bin.999999',0) diff --git a/mysql-test/r/rpl_reset_slave.result b/mysql-test/r/rpl_reset_slave.result index 8887462389d..e1fbf12786d 100644 --- a/mysql-test/r/rpl_reset_slave.result +++ b/mysql-test/r/rpl_reset_slave.result @@ -20,3 +20,13 @@ start slave; 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_PORT 1 master-bin.000001 79 slave-relay-bin.000002 123 master-bin.000001 Yes Yes 0 0 79 123 None 0 No # +stop slave; +reset slave; +start slave; +create temporary table t1 (a int); +stop slave; +reset slave; +start slave; +show status like 'slave_open_temp_tables'; +Variable_name Value +Slave_open_temp_tables 1 diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result index cf2b8814047..e7b64066c37 100644 --- a/mysql-test/r/rpl_temporary.result +++ b/mysql-test/r/rpl_temporary.result @@ -74,3 +74,4 @@ f 5 7 drop table t1,t2; +create temporary table t3 (f int); diff --git a/mysql-test/r/rpl_trunc_binlog.result b/mysql-test/r/rpl_trunc_binlog.result index 1cd9cdf08a0..caca15ab4ef 100644 --- a/mysql-test/r/rpl_trunc_binlog.result +++ b/mysql-test/r/rpl_trunc_binlog.result @@ -11,4 +11,3 @@ start slave; 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_PORT 1 master-bin.000002 4 slave-relay-bin.000002 123 master-bin.000001 Yes No 0 Rolling back unfinished transaction (no COMMIT or ROLLBACK) from relay log. Probably cause is that the master died while writing the transaction to it's binary log. 0 79 326 None 0 No # -reset master; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index fca4a0549d3..8edd0182dec 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -1466,6 +1466,11 @@ companynr count(*) select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 where companynr = 34 and fld4<>""; count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1) variance(fld1) 70 absentee vest 17788966 254128.0857 3272.5940 10709871.3069 +explain extended select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 where companynr = 34 and fld4<>""; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 Using where +Warnings: +Note 1003 select high_priority count(0) AS `count(*)`,min(test.t2.fld4) AS `min(fld4)`,max(test.t2.fld4) AS `max(fld4)`,sum(test.t2.fld1) AS `sum(fld1)`,avg(test.t2.fld1) AS `avg(fld1)`,std(test.t2.fld1) AS `std(fld1)`,variance(test.t2.fld1) AS `variance(fld1)` from test.t2 where ((test.t2.companynr = 34) and (test.t2.fld4 <> _latin1'')) select companynr,count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 group by companynr limit 3; companynr count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1) variance(fld1) 00 82 Anthony windmills 10355753 126289.6707 115550.9757 13352027981.7087 @@ -2145,10 +2150,10 @@ a a a select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 on t1.a>1; a a a 1 1 2 -2 2 2 -3 3 2 1 1 3 +2 2 2 2 2 3 +3 3 2 3 3 3 select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1; a a a diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 29bba54b55a..31b5ff84365 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2,32 +2,35 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12; select (select 2); (select 2) 2 -explain select (select 2); +explain extended select (select 2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: Note 1248 Select 2 was reduced during optimisation +Note 1003 select high_priority 2 AS `(select 2)` SELECT (SELECT 1) UNION SELECT (SELECT 2); (SELECT 1) 1 2 -explain SELECT (SELECT 1) UNION SELECT (SELECT 2); +explain extended SELECT (SELECT 1) UNION SELECT (SELECT 2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used 3 UNION NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: Note 1248 Select 2 was reduced during optimisation Note 1248 Select 4 was reduced during optimisation +Note 1003 select high_priority 1 AS `(SELECT 1)` union select 2 AS `(SELECT 2)` SELECT (SELECT (SELECT 0 UNION SELECT 0)); (SELECT (SELECT 0 UNION SELECT 0)) 0 -explain SELECT (SELECT (SELECT 0 UNION SELECT 0)); +explain extended SELECT (SELECT (SELECT 0 UNION SELECT 0)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used 3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used 4 UNION NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: Note 1248 Select 2 was reduced during optimisation +Note 1003 select high_priority (select 0 AS `0` union select 0 AS `0`) AS `(SELECT (SELECT 0 UNION SELECT 0))` SELECT (SELECT 1 FROM (SELECT 1) as b HAVING a=1) as a; ERROR 42S22: Reference 'a' not supported (forward reference in item list) SELECT (SELECT 1 FROM (SELECT 1) as b HAVING b=1) as a,(SELECT 1 FROM (SELECT 1) as c HAVING a=1) as b; @@ -37,7 +40,7 @@ SELECT (SELECT 1),MAX(1) FROM (SELECT 1) as a; 1 1 SELECT (SELECT a) as a; ERROR 42S22: Reference 'a' not supported (forward reference in item list) -EXPLAIN SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; +EXPLAIN EXTENDED SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived2> system NULL NULL NULL NULL 1 3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used @@ -45,6 +48,7 @@ id select_type table type possible_keys key key_len ref rows Extra Warnings: Note 1275 Field or reference 'a' of SELECT #3 was resolved in SELECT #1 Note 1275 Field or reference 'b.a' of SELECT #3 was resolved in SELECT #1 +Note 1003 select high_priority 1 AS `1` from (select 1 AS `a`) b having ((select b.a AS `a`) = 1) SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; 1 1 @@ -172,12 +176,14 @@ a b 2 7 3 8 4 8 -explain (select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); +explain extended (select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where 2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 Using filesort 3 UNION t4 ALL NULL NULL NULL NULL 3 Using where; Using filesort 4 SUBQUERY t2 ALL NULL NULL NULL NULL 2 +Warnings: +Note 1003 (select high_priority test.t2.a AS `a`,test.t2.b AS `b` from test.t2 where (test.t2.b = (select test.t3.a AS `a` from test.t3 order by test.t3.a desc limit 1))) union (select test.t4.a AS `a`,test.t4.b AS `b` from test.t4 where (test.t4.b = (select (max(test.t2.a) * 4) AS `max(t2.a)*4` from test.t2)) order by test.t4.a) select (select a from t3 where a<t2.a*4 order by 1 desc limit 1), a from t2; (select a from t3 where a<t2.a*4 order by 1 desc limit 1) a 3 1 @@ -186,12 +192,14 @@ select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; (select t3.a from t3 where a<8 order by 1 desc limit 1) a 7 2 -explain select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from +explain extended select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived3> system NULL NULL NULL NULL 1 3 DERIVED t2 ALL NULL NULL NULL NULL 2 Using where 2 SUBQUERY t3 ALL NULL NULL NULL NULL 3 Using where; Using filesort +Warnings: +Note 1003 select high_priority (select test.t3.a AS `a` from test.t3 where (test.t3.a < 8) order by test.t3.a desc limit 1) AS `(select t3.a from t3 where a<8 order by 1 desc limit 1)`,tt.a AS `a` from (select test.t2.a AS `a`,test.t2.b AS `b` from test.t2 where (test.t2.a > 1)) tt select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); a 2 @@ -205,13 +213,14 @@ b (select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) 8 7.5000 8 4.5000 9 7.5000 -explain select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; +explain extended select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t4 ALL NULL NULL NULL NULL 3 2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 3 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 3 Using where Warnings: Note 1275 Field or reference 't4.a' of SELECT #3 was resolved in SELECT #1 +Note 1003 select high_priority test.t4.b AS `b`,(select avg((test.t2.a + (select min(test.t3.a) AS `min(t3.a)` from test.t3 where (test.t3.a >= test.t4.a)))) AS `avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a))` from test.t2) AS `(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2)` from test.t4 select * from t3 where exists (select * from t2 where t2.b=t3.a); a 7 @@ -252,10 +261,12 @@ select * from t3 where a >= any (select b from t2); a 6 7 -explain select * from t3 where a >= any (select b from t2); +explain extended select * from t3 where a >= any (select b from t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 +Warnings: +Note 1003 select high_priority test.t3.a AS `a` from test.t3 where (test.t3.a >= (select min(test.t2.b) from test.t2 limit 1)) select * from t3 where a >= all (select b from t2); a 7 @@ -290,7 +301,7 @@ select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a) (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a) a NULL 1 2 2 -explain select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; +explain extended select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 2 DEPENDENT SUBQUERY t1 system NULL NULL NULL NULL 1 @@ -298,6 +309,7 @@ id select_type table type possible_keys key key_len ref rows Extra Warnings: Note 1275 Field or reference 't2.a' of SELECT #2 was resolved in SELECT #1 Note 1275 Field or reference 't2.a' of SELECT #3 was resolved in SELECT #1 +Note 1003 select high_priority (select test.t1.a AS `a` from test.t1 where (test.t1.a = test.t2.a) union select test.t5.a AS `a` from test.t5 where (test.t5.a = test.t2.a)) AS `(select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a)`,test.t2.a AS `a` from test.t2 select (select a from t1 where t1.a=t2.a union all select a from t5 where t5.a=t2.a), a from t2; ERROR 21000: Subquery returns more than 1 row create table t6 (patient_uq int, clinic_uq int, index i1 (clinic_uq)); @@ -309,12 +321,13 @@ patient_uq clinic_uq 1 1 1 2 2 2 -explain select * from t6 where exists (select * from t7 where uq = clinic_uq); +explain extended select * from t6 where exists (select * from t7 where uq = clinic_uq); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t6 ALL NULL NULL NULL NULL 4 Using where 2 DEPENDENT SUBQUERY t7 eq_ref PRIMARY PRIMARY 4 test.t6.clinic_uq 1 Warnings: Note 1275 Field or reference 'clinic_uq' of SELECT #2 was resolved in SELECT #1 +Note 1003 select high_priority test.t6.patient_uq AS `patient_uq`,test.t6.clinic_uq AS `clinic_uq` from test.t6 where exists(select test.t7.uq AS `uq`,test.t7.name AS `name` from test.t7 where (test.t7.uq = test.t6.clinic_uq) limit 1) select * from t1 where a= (select a from t2,t4 where t2.b=t4.b); ERROR 23000: Column: 'a' in field list is ambiguous drop table if exists t1,t2,t3; @@ -342,12 +355,14 @@ UNIQUE KEY `email` (`email`) INSERT INTO t8 (pseudo,email) VALUES ('joce','test'); INSERT INTO t8 (pseudo,email) VALUES ('joce1','test1'); INSERT INTO t8 (pseudo,email) VALUES ('2joce1','2test1'); -EXPLAIN SELECT pseudo,(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce')) FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'); +EXPLAIN EXTENDED SELECT pseudo,(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce')) FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t8 const PRIMARY PRIMARY 35 const 1 4 SUBQUERY t8 const PRIMARY PRIMARY 35 1 2 SUBQUERY t8 const PRIMARY PRIMARY 35 const 1 3 SUBQUERY t8 const PRIMARY PRIMARY 35 1 +Warnings: +Note 1003 select high_priority test.t8.pseudo AS `pseudo`,(select test.t8.email AS `email` from test.t8 where (test.t8.pseudo = (select test.t8.pseudo AS `pseudo` from test.t8 where (test.t8.pseudo = _latin1'joce')))) AS `(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'))` from test.t8 where (test.t8.pseudo = (select test.t8.pseudo AS `pseudo` from test.t8 where (test.t8.pseudo = _latin1'joce'))) SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo,email FROM t8 WHERE pseudo='joce'); ERROR 21000: Operand should contain 1 column(s) @@ -369,13 +384,17 @@ KEY `topic` (`topic`) ) TYPE=MyISAM ROW_FORMAT=DYNAMIC; INSERT INTO t1 (topic,date,pseudo) VALUES ('43506','2002-10-02','joce'),('40143','2002-08-03','joce'); -EXPLAIN SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; +EXPLAIN EXTENDED SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL PRIMARY 41 NULL 2 Using where; Using index -EXPLAIN SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'); +Warnings: +Note 1003 select high_priority distinct test.t1.date AS `date` from test.t1 where (test.t1.date = 20020803) +EXPLAIN EXTENDED SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used 2 SUBQUERY t1 index NULL PRIMARY 41 NULL 2 Using where; Using index +Warnings: +Note 1003 select high_priority (select distinct test.t1.date AS `date` from test.t1 where (test.t1.date = 20020803)) AS `(SELECT DISTINCT date FROM t1 WHERE date='2002-08-03')` SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; date 2002-08-03 @@ -389,11 +408,13 @@ SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1) UNION ALL SELECT 1; 1 SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION ALL SELECT 1) UNION SELECT 1; ERROR 21000: Subquery returns more than 1 row -EXPLAIN SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1); +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL topic 3 NULL 2 Using index 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used 3 UNION NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select high_priority 1 AS `1` from test.t1 drop table t1; CREATE TABLE `t1` ( `numeropost` mediumint(8) unsigned NOT NULL auto_increment, @@ -507,15 +528,19 @@ ERROR 42S22: Unknown column 'a' in 'having clause' SELECT numreponse, (SELECT numeropost FROM t1 HAVING numreponse=1) FROM (SELECT * FROM t1) as a; numreponse (SELECT numeropost FROM t1 HAVING numreponse=1) INSERT INTO t1 (numeropost,numreponse,pseudo) VALUES (1,1,'joce'),(1,2,'joce'),(1,3,'test'); -EXPLAIN SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT 1 FROM t1 WHERE numeropost='1'); +EXPLAIN EXTENDED SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT 1 FROM t1 WHERE numeropost='1'); ERROR 21000: Subquery returns more than 1 row -EXPLAIN SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'; +EXPLAIN EXTENDED SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away -EXPLAIN SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'); +Warnings: +Note 1003 select high_priority max(test.t1.numreponse) AS `MAX(numreponse)` from test.t1 where (test.t1.numeropost = _latin1'1') +EXPLAIN EXTENDED SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 const PRIMARY,numreponse PRIMARY 7 const,const 1 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +Warnings: +Note 1003 select high_priority test.t1.numreponse AS `numreponse` from test.t1 where ((test.t1.numeropost = _latin1'1') and (test.t1.numreponse = 3)) drop table t1; CREATE TABLE t1 (a int(1)); INSERT INTO t1 VALUES (1); @@ -678,28 +703,32 @@ INSERT INTO t2 VALUES (1),(2); SELECT * FROM t2 WHERE id IN (SELECT 1); id 1 -EXPLAIN SELECT * FROM t2 WHERE id IN (SELECT 1); +EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ref id id 5 const 1 Using where; Using index Warnings: Note 1248 Select 2 was reduced during optimisation +Note 1003 select high_priority test.t2.id AS `id` from test.t2 where (test.t2.id = 1) SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3); id 1 SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1)); id 2 -EXPLAIN SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1)); +EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ref id id 5 const 1 Using where; Using index Warnings: Note 1248 Select 3 was reduced during optimisation Note 1248 Select 2 was reduced during optimisation -EXPLAIN SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3); +Note 1003 select high_priority test.t2.id AS `id` from test.t2 where (test.t2.id = (1 + 1)) +EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL id 5 NULL 2 Using where; Using index 2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used 3 DEPENDENT UNION NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select high_priority test.t2.id AS `id` from test.t2 where <in_optimizer>(test.t2.id,<exists>(select 1 AS `Not_used` having (<cache>(test.t2.id) = <null_helper>(1)) limit 1 union select 1 AS `Not_used` having (<cache>(test.t2.id) = <null_helper>(3)) limit 1)) SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 3); id SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2); @@ -819,12 +848,13 @@ NULL select 10.5 > ANY (SELECT * from t1); 10.5 > ANY (SELECT * from t1) 1 -explain select (select a+1) from t1; +explain extended select (select a+1) from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Warnings: Note 1275 Field or reference 'a' of SELECT #2 was resolved in SELECT #1 Note 1248 Select 2 was reduced during optimisation +Note 1003 select high_priority (test.t1.a + 1) AS `(select a+1)` from test.t1 select (select a+1) from t1; (select a+1) 2.5 @@ -841,10 +871,12 @@ a t1.a in (select t2.a from t2) 2 1 3 1 4 0 -explain SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; +explain extended SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 Using index 2 DEPENDENT SUBQUERY t2 index_subquery a a 5 func 2 Using index +Warnings: +Note 1003 select high_priority test.t1.a AS `a`,<in_optimizer>(test.t1.a,<exists>(<index_lookup>(<cache>(test.t1.a) in t2 on a chicking NULL))) AS `t1.a in (select t2.a from t2)` from test.t1 CREATE TABLE t3 (a int(11) default '0'); INSERT INTO t3 VALUES (1),(2),(3); SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; @@ -853,11 +885,13 @@ a t1.a in (select t2.a from t2,t3 where t3.a=t2.a) 2 1 3 1 4 0 -explain SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; +explain extended SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 Using index 2 DEPENDENT SUBQUERY t2 ref_or_null a a 5 func 2 Using where; Using index 2 DEPENDENT SUBQUERY t3 ALL NULL NULL NULL NULL 3 Using where +Warnings: +Note 1003 select high_priority test.t1.a AS `a`,<in_optimizer>(test.t1.a,<exists>(select 1 AS `Not_used` from test.t2 join test.t3 where ((test.t3.a = test.t2.a) and ((<cache>(test.t1.a) = test.t2.a) or isnull(test.t2.a))) having <is_not_null_test>(test.t2.a) limit 1)) AS `t1.a in (select t2.a from t2,t3 where t3.a=t2.a)` from test.t1 drop table t1,t2,t3; create table t1 (a float); select 10.5 IN (SELECT * from t1 LIMIT 1); @@ -962,18 +996,24 @@ UPDATE t1 SET i=i+1 WHERE i=(SELECT MAX(i)); ERROR HY000: Invalid use of group function drop table t1; CREATE TABLE t1 (a int(1)); -EXPLAIN SELECT (SELECT RAND() FROM t1) FROM t1; +EXPLAIN EXTENDED SELECT (SELECT RAND() FROM t1) FROM t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found 2 UNCACHEABLE SUBQUERY t1 system NULL NULL NULL NULL 0 const row not found -EXPLAIN SELECT (SELECT ENCRYPT('test') FROM t1) FROM t1; +Warnings: +Note 1003 select high_priority no_cache (select no_cache rand() AS `RAND()` from test.t1) AS `(SELECT RAND() FROM t1)` from test.t1 +EXPLAIN EXTENDED SELECT (SELECT ENCRYPT('test') FROM t1) FROM t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found 2 UNCACHEABLE SUBQUERY t1 system NULL NULL NULL NULL 0 const row not found -EXPLAIN SELECT (SELECT BENCHMARK(1,1) FROM t1) FROM t1; +Warnings: +Note 1003 select high_priority no_cache (select no_cache ecrypt(_latin1'test') AS `ENCRYPT('test')` from test.t1) AS `(SELECT ENCRYPT('test') FROM t1)` from test.t1 +EXPLAIN EXTENDED SELECT (SELECT BENCHMARK(1,1) FROM t1) FROM t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found 2 UNCACHEABLE SUBQUERY t1 system NULL NULL NULL NULL 0 const row not found +Warnings: +Note 1003 select high_priority no_cache (select no_cache benchmark(1,1) AS `BENCHMARK(1,1)` from test.t1) AS `(SELECT BENCHMARK(1,1) FROM t1)` from test.t1 drop table t1; CREATE TABLE `t1` ( `mot` varchar(30) character set latin1 NOT NULL default '', @@ -1061,12 +1101,14 @@ t1 CREATE TABLE `t1` ( drop table t1; create table t1 (a int); insert into t1 values (1), (2), (3); -explain select a,(select (select rand() from t1 limit 1) from t1 limit 1) +explain extended select a,(select (select rand() from t1 limit 1) from t1 limit 1) from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 2 UNCACHEABLE SUBQUERY t1 ALL NULL NULL NULL NULL 3 3 UNCACHEABLE SUBQUERY t1 ALL NULL NULL NULL NULL 3 +Warnings: +Note 1003 select high_priority no_cache test.t1.a AS `a`,(select no_cache (select no_cache rand() AS `rand()` from test.t1 limit 1) AS `(select rand() from t1 limit 1)` from test.t1 limit 1) AS `(select (select rand() from t1 limit 1) from t1 limit 1)` from test.t1 drop table t1; select t1.Continent, t2.Name, t2.Population from t1 LEFT JOIN t2 ON t1.Code = t2.Country where t2.Population IN (select max(t2.Population) AS Population from t2, t1 where t2.Country = t1.Code group by Continent); ERROR 42S02: Table 'test.t1' doesn't exist @@ -1115,18 +1157,22 @@ INSERT INTO t1 (pseudo) VALUES ('test'); SELECT 0 IN (SELECT 1 FROM t1 a); 0 IN (SELECT 1 FROM t1 a) 0 -EXPLAIN SELECT 0 IN (SELECT 1 FROM t1 a); +EXPLAIN EXTENDED SELECT 0 IN (SELECT 1 FROM t1 a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used 2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select high_priority <in_optimizer>(0,<exists>(select 1 AS `Not_used` from test.t1 a where isnull(1) having <is_not_null_test>(1) limit 1)) AS `0 IN (SELECT 1 FROM t1 a)` INSERT INTO t1 (pseudo) VALUES ('test1'); SELECT 0 IN (SELECT 1 FROM t1 a); 0 IN (SELECT 1 FROM t1 a) 0 -EXPLAIN SELECT 0 IN (SELECT 1 FROM t1 a); +EXPLAIN EXTENDED SELECT 0 IN (SELECT 1 FROM t1 a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used 2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1003 select high_priority <in_optimizer>(0,<exists>(select 1 AS `Not_used` from test.t1 a where isnull(1) having <is_not_null_test>(1) limit 1)) AS `0 IN (SELECT 1 FROM t1 a)` drop table t1; CREATE TABLE `t1` ( `i` int(11) NOT NULL default '0', @@ -1165,10 +1211,12 @@ NULL drop table t1; create table t1 (id int not null auto_increment primary key, salary int, key(salary)); insert into t1 (salary) values (100),(1000),(10000),(10),(500),(5000),(50000); -explain SELECT id FROM t1 where salary = (SELECT MAX(salary) FROM t1); +explain extended SELECT id FROM t1 where salary = (SELECT MAX(salary) FROM t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ref salary salary 5 const 1 Using where 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +Warnings: +Note 1003 select high_priority test.t1.id AS `id` from test.t1 where (test.t1.salary = (select max(test.t1.salary) AS `MAX(salary)` from test.t1)) drop table t1; CREATE TABLE t1 ( ID int(10) unsigned NOT NULL auto_increment, @@ -1230,27 +1278,33 @@ a 2 3 4 -explain select * from t2 where t2.a in (select a from t1); +explain extended select * from t2 where t2.a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 Using where; Using index 2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 Using index +Warnings: +Note 1003 select high_priority test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(<primary_index_lookup>(<cache>(test.t2.a) in t1 on PRIMARY))) select * from t2 where t2.a in (select a from t1 where t1.b <> 30); a 2 4 -explain select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 Using where; Using index 2 DEPENDENT SUBQUERY t1 unique_subquery PRIMARY PRIMARY 4 func 1 Using index; Using where +Warnings: +Note 1003 select high_priority test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(<primary_index_lookup>(<cache>(test.t2.a) in t1 on PRIMARY where (test.t1.b <> 30)))) select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); a 2 3 -explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 Using where; Using index 2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where 2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 Using where; Using index +Warnings: +Note 1003 select high_priority test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(select 1 AS `Not_used` from test.t1 join test.t3 where ((test.t1.b = test.t3.a) and (<cache>(test.t2.a) = test.t1.a)) limit 1)) drop table t1, t2, t3; create table t1 (a int, b int, index a (a,b)); create table t2 (a int, index a (a)); @@ -1263,27 +1317,33 @@ a 2 3 4 -explain select * from t2 where t2.a in (select a from t1); +explain extended select * from t2 where t2.a in (select a from t1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index 2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 1001 Using index +Warnings: +Note 1003 select high_priority test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(<index_lookup>(<cache>(test.t2.a) in t1 on a))) select * from t2 where t2.a in (select a from t1 where t1.b <> 30); a 2 4 -explain select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index 2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 1001 Using index; Using where +Warnings: +Note 1003 select high_priority test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(<index_lookup>(<cache>(test.t2.a) in t1 on a where (test.t1.b <> 30)))) select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); a 2 3 -explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index 2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t1 ref a a 10 func,test.t3.a 1000 Using where; Using index +Warnings: +Note 1003 select high_priority test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(select 1 AS `Not_used` from test.t1 join test.t3 where ((test.t1.b = test.t3.a) and (<cache>(test.t2.a) = test.t1.a)) limit 1)) insert into t1 values (3,31); select * from t2 where t2.a in (select a from t1 where t1.b <> 30); a @@ -1294,10 +1354,12 @@ select * from t2 where t2.a in (select a from t1 where t1.b <> 30 and t1.b <> 31 a 2 4 -explain select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index 2 DEPENDENT SUBQUERY t1 index_subquery a a 5 func 1001 Using index; Using where +Warnings: +Note 1003 select high_priority test.t2.a AS `a` from test.t2 where <in_optimizer>(test.t2.a,<exists>(<index_lookup>(<cache>(test.t2.a) in t1 on a where (test.t1.b <> 30)))) drop table t1, t2, t3; create table t1 (a int, b int); create table t2 (a int, b int); @@ -1350,9 +1412,11 @@ insert into t1 values ('tttt'); select * from t1 where ('a','b')=(select 'a','b' from t1 union select 'a','b' from t1); s1 tttt -explain (select * from t1); +explain extended (select * from t1); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 system NULL NULL NULL NULL 1 +Warnings: +Note 1003 (select high_priority test.t1.s1 AS `s1` from test.t1) (select * from t1); s1 tttt @@ -1381,22 +1445,30 @@ s1 s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') a1 0 a2 1 a3 1 -explain select s1, s1 NOT IN (SELECT s1 FROM t2) from t1; +explain extended select s1, s1 NOT IN (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL s1 6 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index -explain select s1, s1 = ANY (SELECT s1 FROM t2) from t1; +Warnings: +Note 1003 select high_priority test.t1.s1 AS `s1`,not(<in_optimizer>(test.t1.s1,<exists>(<index_lookup>(<cache>(test.t1.s1) in t2 on s1 chicking NULL)))) AS `s1 NOT IN (SELECT s1 FROM t2)` from test.t1 +explain extended select s1, s1 = ANY (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL s1 6 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index -explain select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; +Warnings: +Note 1003 select high_priority test.t1.s1 AS `s1`,<in_optimizer>(test.t1.s1,<exists>(<index_lookup>(<cache>(test.t1.s1) in t2 on s1 chicking NULL))) AS `s1 = ANY (SELECT s1 FROM t2)` from test.t1 +explain extended select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL s1 6 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index -explain select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; +Warnings: +Note 1003 select high_priority test.t1.s1 AS `s1`,not(<in_optimizer>(test.t1.s1,<exists>(<index_lookup>(<cache>(test.t1.s1) in t2 on s1 chicking NULL)))) AS `s1 <> ALL (SELECT s1 FROM t2)` from test.t1 +explain extended select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL s1 6 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 1 Using index; Using where +Warnings: +Note 1003 select high_priority test.t1.s1 AS `s1`,not(<in_optimizer>(test.t1.s1,<exists>(<index_lookup>(<cache>(test.t1.s1) in t2 on s1 chicking NULL where (test.t2.s1 < _latin1'a2'))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from test.t1 drop table t1,t2; create table t2 (a int, b int); create table t3 (a int); @@ -1406,19 +1478,23 @@ a 6 7 3 -explain select * from t3 where a >= all (select b from t2); +explain extended select * from t3 where a >= all (select b from t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 const row not found +Warnings: +Note 1003 select high_priority test.t3.a AS `a` from test.t3 where <not>((test.t3.a < (select max(test.t2.b) from test.t2 limit 1))) insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); a 6 7 -explain select * from t3 where a > all (select max(b) from t2 group by a); +explain extended select * from t3 where a > all (select max(b) from t2 group by a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort +Warnings: +Note 1003 select high_priority test.t3.a AS `a` from test.t3 where <not>((test.t3.a <= <max>(select max(test.t2.b) AS `max(b)` from test.t2 group by test.t2.a))) drop table t2, t3; CREATE TABLE `t1` ( `id` mediumint(9) NOT NULL auto_increment, `taskid` bigint(20) NOT NULL default '0', `dbid` int(11) NOT NULL default '0', `create_date` datetime NOT NULL default '0000-00-00 00:00:00', `last_update` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`id`)) TYPE=MyISAM CHARSET=latin1 AUTO_INCREMENT=3 ; INSERT INTO `t1` (`id`, `taskid`, `dbid`, `create_date`,`last_update`) VALUES (1, 1, 15, '2003-09-29 10:31:36', '2003-09-29 10:31:36'), (2, 1, 21, now(), now()); diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index f12be1d363c..82aefa78bb2 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -492,6 +492,14 @@ collation(load_file('../../std_data/words.dat')), coercibility(load_file('../../std_data/words.dat')); charset(load_file('../../std_data/words.dat')) collation(load_file('../../std_data/words.dat')) coercibility(load_file('../../std_data/words.dat')) binary binary 3 +explain extended select +charset(load_file('../../std_data/words.dat')), +collation(load_file('../../std_data/words.dat')), +coercibility(load_file('../../std_data/words.dat')); +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 +Warnings: +Note 1003 select high_priority no_cache charset(load_file(_latin1'../../std_data/words.dat')) AS `charset(load_file('../../std_data/words.dat'))`,collation(load_file(_latin1'../../std_data/words.dat')) AS `collation(load_file('../../std_data/words.dat'))`,coercibility(load_file(_latin1'../../std_data/words.dat')) AS `coercibility(load_file('../../std_data/words.dat'))` update t1 set imagem=load_file('../../std_data/words.dat') where id=1; select if(imagem is null, "ERROR", "OK"),length(imagem) from t1 where id = 1; if(imagem is null, "ERROR", "OK") length(imagem) diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index bf47e6ad430..5729d3b32ee 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -86,10 +86,12 @@ a b 1 a (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by t1.b; ERROR 42000: Table 't1' from one of SELECT's can not be used in global ORDER clause -explain (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; +explain extended (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 2 UNION t2 ALL NULL NULL NULL NULL 4 Using filesort +Warnings: +Note 1003 (select high_priority test.t1.a AS `a`,test.t1.b AS `b` from test.t1 limit 2) union all (select test.t2.a AS `a`,test.t2.b AS `b` from test.t2 order by test.t2.a limit 1) order by b desc (select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2; a b 1 a @@ -463,10 +465,12 @@ create table t1 (a int not null primary key auto_increment, b int, key(b)); create table t2 (a int not null primary key auto_increment, b int); insert into t1 (b) values (1),(2),(2),(3); insert into t2 (b) values (10),(11),(12),(13); -explain (select * from t1 where a=1) union (select * from t2 where a=1); +explain extended (select * from t1 where a=1) union (select * from t2 where a=1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 2 UNION t2 const PRIMARY PRIMARY 4 const 1 +Warnings: +Note 1003 (select high_priority test.t1.a AS `a`,test.t1.b AS `b` from test.t1 where (test.t1.a = 1)) union (select test.t2.a AS `a`,test.t2.b AS `b` from test.t2 where (test.t2.a = 1)) (select * from t1 where a=5) union (select * from t2 where a=1); a b 1 10 diff --git a/mysql-test/r/varbinary.result b/mysql-test/r/varbinary.result index 5464d741f70..cf001158ae2 100644 --- a/mysql-test/r/varbinary.result +++ b/mysql-test/r/varbinary.result @@ -11,9 +11,11 @@ x'31' X'ffff'+0 create table t1 (ID int(8) unsigned zerofill not null auto_increment,UNIQ bigint(21) unsigned zerofill not null,primary key (ID),unique (UNIQ) ); insert into t1 set UNIQ=0x38afba1d73e6a18a; insert into t1 set UNIQ=123; -explain select * from t1 where UNIQ=0x38afba1d73e6a18a; +explain extended select * from t1 where UNIQ=0x38afba1d73e6a18a; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 const UNIQ UNIQ 8 const 1 +Warnings: +Note 1003 select high_priority test.t1.ID AS `ID`,test.t1.UNIQ AS `UNIQ` from test.t1 where (test.t1.UNIQ = 4084688022709641610) drop table t1; select x'hello'; ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'x'hello'' at line 1 diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 52ea28e6076..90654bece2e 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -22,6 +22,11 @@ NULL NULL NULL NULL select @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3; @t1:=(@t2:=1)+@t3:=4 @t1 @t2 @t3 5 5 1 4 +explain extended select @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3; +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 +Warnings: +Note 1003 select high_priority no_cache (@t1:=((@t2:=1) + (@t3:=4))) AS `@t1:=(@t2:=1)+@t3:=4`,(@t1) AS `@t1`,(@t2) AS `@t2`,(@t3) AS `@t3` select @t5; @t5 1.23456 @@ -76,9 +81,19 @@ select @@VERSION=version(); select last_insert_id(345); last_insert_id(345) 345 +explain extended select last_insert_id(345); +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 +Warnings: +Note 1003 select high_priority no_cache last_insert_id(345) AS `last_insert_id(345)` select @@IDENTITY,last_insert_id(), @@identity; @@IDENTITY last_insert_id() @@identity 345 345 345 +explain extended select @@IDENTITY,last_insert_id(), @@identity; +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 +Warnings: +Note 1003 select high_priority no_cache 345 AS `@@IDENTITY`,345 AS `last_insert_id()`,345 AS `@@identity` set big_tables=OFF, big_tables=ON, big_tables=0, big_tables=1, big_tables="OFF", big_tables="ON"; set global concurrent_insert=ON; show variables like 'concurrent_insert'; diff --git a/mysql-test/t/auto_increment.test b/mysql-test/t/auto_increment.test index a036121f297..d02850f6745 100644 --- a/mysql-test/t/auto_increment.test +++ b/mysql-test/t/auto_increment.test @@ -80,6 +80,7 @@ create table t1 (i tinyint unsigned not null auto_increment primary key); insert into t1 set i = 254; insert into t1 set i = null; select last_insert_id(); +explain extended select last_insert_id(); --error 1062 insert into t1 set i = 254; select last_insert_id(); diff --git a/mysql-test/t/bench_count_distinct.test b/mysql-test/t/bench_count_distinct.test index c1adeab2c44..3ffb95a69c2 100644 --- a/mysql-test/t/bench_count_distinct.test +++ b/mysql-test/t/bench_count_distinct.test @@ -16,4 +16,5 @@ while ($1) } enable_query_log; select count(distinct n) from t1; +explain extended select count(distinct n) from t1; drop table t1; diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index 4d4ceb062e4..9a1b6b6bbfe 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -14,6 +14,7 @@ select CASE "b" when "a" then 1 when binary "B" then 2 WHEN "b" then "ok" END; select CASE concat("a","b") when concat("ab","") then "a" when "b" then "b" end; select CASE when 1=0 then "true" else "false" END; select CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END; +explain extended select CASE 1 when 1 then "one" WHEN 2 then "two" ELSE "more" END; select CASE 2.0 when 1 then "one" WHEN 2.0 then "two" ELSE "more" END; select (CASE "two" when "one" then "1" WHEN "two" then "2" END) | 0; select (CASE "two" when "one" then 1.00 WHEN "two" then 2.00 END) +0.0; @@ -30,6 +31,7 @@ select case when 1<0 then "TRUE" else "FALSE" END; create table t1 (a int); insert into t1 values(1),(2),(3),(4); select case a when 1 then 2 when 2 then 3 else 0 end as fcase, count(*) from t1 group by fcase; +explain extended select case a when 1 then 2 when 2 then 3 else 0 end as fcase, count(*) from t1 group by fcase; select case a when 1 then "one" when 2 then "two" else "nothing" end as fcase, count(*) from t1 group by fcase; drop table t1; @@ -98,5 +100,9 @@ CREATE TABLE t1 SELECT COALESCE(1), COALESCE(1.0),COALESCE('a'), COALESCE(1,1.0), COALESCE(1,'1'),COALESCE(1.1,'1'), COALESCE('a' COLLATE latin1_bin,'b'); +explain extended SELECT + COALESCE(1), COALESCE(1.0),COALESCE('a'), + COALESCE(1,1.0), COALESCE(1,'1'),COALESCE(1.1,'1'), + COALESCE('a' COLLATE latin1_bin,'b'); SHOW CREATE TABLE t1; DROP TABLE t1; diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index b3ae8981671..dd17904effb 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -8,6 +8,7 @@ select CONVERT('-1',UNSIGNED); select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1; select cast(-5 as unsigned) -1, cast(-5 as unsigned) + 1; select ~5, cast(~5 as signed); +explain extended select ~5, cast(~5 as signed); select cast(5 as unsigned) -6.0; select cast("A" as binary) = "a", cast(BINARY "a" as CHAR) = "A"; select cast("2001-1-1" as DATE), cast("2001-1-1" as DATETIME); diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 059808161a3..cec7dd17e6d 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -40,9 +40,9 @@ create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null -- error 1044,1 create table not_existing_database.test (a int); ---error 1103 +--error 1279 create table `a/a` (a int); ---error 1103 +--error 1279 create table `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa int); --error 1059 create table a (`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` int); @@ -66,11 +66,11 @@ create table test_$1.test2$ (a int); drop table test_$1.test2$; drop database test_$1; ---error 1103 +--error 1279 create table `` (a int); ---error 1103 +--error 1279 drop table if exists ``; ---error 1166 +--error 1279 create table t1 (`` int); --error 1279 create table t1 (i int, index `` (i)); @@ -254,12 +254,16 @@ create table t2 like t3; show create table t2; select * from t2; create table t3 like t1; -!$1050 create table t3 like test_$1.t3; +--error 1050 +create table t3 like test_$1.t3; --error 1044,1 create table non_existing_database.t1 like t1; -!$1051 create table t3 like non_existing_table; -!$1050 create temporary table t3 like t1; -!$1103 create table t3 like `a/a`; +--error 1051 +create table t3 like non_existing_table; +--error 1050 +create temporary table t3 like t1; +--error 1279 +create table t3 like `a/a`; drop table t1, t2, t3; drop table t3; drop database test_$1; diff --git a/mysql-test/t/ctype_collate.test b/mysql-test/t/ctype_collate.test index d42696e693b..2d9a4be5b36 100644 --- a/mysql-test/t/ctype_collate.test +++ b/mysql-test/t/ctype_collate.test @@ -139,6 +139,7 @@ SHOW FIELDS FROM t1; SET CHARACTER SET 'latin1'; SHOW VARIABLES LIKE 'character_set_client'; SELECT charset('a'),collation('a'),coercibility('a'),'a'='A'; +explain extended SELECT charset('a'),collation('a'),coercibility('a'),'a'='A'; SET CHARACTER SET koi8r; SHOW VARIABLES LIKE 'collation_client'; diff --git a/mysql-test/t/ctype_latin1_de.test b/mysql-test/t/ctype_latin1_de.test index 52ee227b011..a5d0c29baf6 100644 --- a/mysql-test/t/ctype_latin1_de.test +++ b/mysql-test/t/ctype_latin1_de.test @@ -64,6 +64,7 @@ drop table t1; # The below checks both binary and character comparisons. # create table t1 (word varchar(255) not null, word2 varchar(255) not null, index(word)); +show create table t1; insert into t1 (word) values ('ss'),(0xDF),(0xE4),('ae'); update t1 set word2=word; select word, word=binary 0xdf as t from t1 having t > 0; @@ -85,6 +86,7 @@ drop table t1; CREATE TABLE t1 ( s1 CHAR(5) CHARACTER SET latin1 COLLATE latin1_german2_ci ); +show create table t1; INSERT INTO t1 VALUES ('Ü'); INSERT INTO t1 VALUES ('ue'); SELECT DISTINCT s1 FROM t1; diff --git a/mysql-test/t/ctype_many.test b/mysql-test/t/ctype_many.test index 66732520f4d..a1549f952e5 100644 --- a/mysql-test/t/ctype_many.test +++ b/mysql-test/t/ctype_many.test @@ -147,6 +147,12 @@ UPDATE t1 SET utf8_f=CONVERT(koi8_ru_f USING utf8); SET CHARACTER SET koi8r; SELECT * FROM t1; +# +# codecovarage for Item_func_conv_charset3 +# +select CONVERT(koi8_ru_f, 'cp1251_general_ci', 'utf8_general_ci'), comment from t1; +explain extended select CONVERT(koi8_ru_f, 'cp1251_general_ci', 'utf8_general_ci'), comment from t1; + ALTER TABLE t1 ADD bin_f CHAR(32) BYTE NOT NULL; UPDATE t1 SET bin_f=koi8_ru_f; SELECT COUNT(DISTINCT bin_f),COUNT(DISTINCT koi8_ru_f),COUNT(DISTINCT utf8_f) FROM t1; diff --git a/mysql-test/t/ctype_recoding.test b/mysql-test/t/ctype_recoding.test index 325a8f075ed..2f08e021df2 100644 --- a/mysql-test/t/ctype_recoding.test +++ b/mysql-test/t/ctype_recoding.test @@ -1,7 +1,7 @@ SET CHARACTER SET koi8r; --disable_warnings -DROP TABLE IF EXISTS ÔÁÂÌÉÃÁ; +DROP TABLE IF EXISTS ÔÁÂÌÉÃÁ, t1; --enable_warnings SET CHARACTER SET koi8r; @@ -11,7 +11,7 @@ SELECT a FROM t1; SELECT HEX(a) FROM t1; DROP TABLE t1; -CREATE TABLE ÔÁÂÌÉÃÁ +CREATE TABLE `ÔÁÂÌÉÃÁ` ( ÐÏÌÅ CHAR(32) CHARACTER SET koi8r NOT NULL COMMENT "ËÏÍÍÅÎÔÁÒÉÊ ÐÏÌÑ" ) COMMENT "ËÏÍÍÅÎÔÁÒÉÊ ÔÁÂÌÉÃÙ"; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 46359e84f1d..54d934b66db 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -23,6 +23,8 @@ select locate(_utf8 0xD0B1, _utf8 0xD0B0D091D0B2); select locate(_utf8 0xD091, _utf8 0xD0B0D0B1D0B2 collate utf8_bin); select locate(_utf8 0xD0B1, _utf8 0xD0B0D091D0B2 collate utf8_bin); +select length(_utf8 0xD0B1), bit_length(_utf8 0xD0B1), char_length(_utf8 0xD0B1); + select 'a' like 'a'; select 'A' like 'a'; select 'A' like 'a' collate utf8_bin; diff --git a/mysql-test/t/date_formats-master.opt b/mysql-test/t/date_formats-master.opt index 7977a601dd7..ab243fe729c 100644 --- a/mysql-test/t/date_formats-master.opt +++ b/mysql-test/t/date_formats-master.opt @@ -1 +1 @@ ---date_format=%d.%m.%Y --time_format=%H.%i.%s --datetime_format=%Y/%d/%m-%H:%i:%s +--date-format=%d.%m.%Y --time-format=%H.%i.%s diff --git a/mysql-test/t/date_formats.test b/mysql-test/t/date_formats.test index 9551efaa648..d9219d3ac2e 100644 --- a/mysql-test/t/date_formats.test +++ b/mysql-test/t/date_formats.test @@ -1,82 +1,202 @@ +# +# Test of date format functions +# + +--disable-warnings +drop table if exists t1; +--enable-warnings + SHOW GLOBAL VARIABLES LIKE "%_format%"; SHOW SESSION VARIABLES LIKE "%_format%"; -SET date_format="%d.%m.%Y"; -select CAST("01.01.2001" as DATE) as a; -SET datetime_format="%d.%m.%Y %H.%i.%s"; -select CAST("01.01.2001 05.12.06" as DATETIME) as a; -SET time_format="%H.%i.%s"; -select CAST("05.12.06" as TIME) as a; - -SET datetime_format="%d.%m.%Y %h:%i:%s %p"; -select CAST("01.01.2001 05:12:06AM" as DATETIME) as a; -select CAST("01.01.2001 05:12:06 PM" as DATETIME) as a; - -SET time_format="%h:%i:%s %p"; -select CAST("05:12:06 AM" as TIME) as a; -select CAST("05:12:06.1234PM" as TIME) as a; - -SET time_format="%h.%i.%s %p"; -SET date_format='%d.%m.%y'; -SET datetime_format="%d.%m.%y %h.%i.%s %p"; -select CAST("12-12-06" as DATE) as a; - -select adddate("01.01.97 11.59.59.000001 PM", 10); -select datediff("31.12.97 11.59:59.000001 PM","01.01.98"); -select weekofyear("31.11.97 11:59:59.000001 PM"); -select makedate(1997,1); -select addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"); -select maketime(23,11,12); -select timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM"); - -SET time_format="%H%i%s"; ---error 1105 -SET time_format="%h%i%s"; ---error 1105 +# +# Test setting a lot of different formats to see which formats are accepted and +# which aren't +# + +SET time_format='%H%i%s'; +SET time_format='%H:%i:%s.%f'; +SET time_format='%h-%i-%s.%f%p'; +SET time_format='%h:%i:%s.%f %p'; +SET time_format='%h:%i:%s%p'; + +SET date_format='%Y%m%d'; +SET date_format='%Y.%m.%d'; +SET date_format='%d.%m.%Y'; +SET date_format='%m-%d-%Y'; + +set datetime_format= '%Y%m%d%H%i%s'; +set datetime_format= '%Y-%m-%d %H:%i:%s'; +set datetime_format= '%m-%d-%y %H:%i:%s.%f'; +set datetime_format= '%d-%m-%Y %h:%i:%s%p'; +set datetime_format= '%H:%i:%s %Y-%m-%d'; +set datetime_format= '%H:%i:%s.%f %m-%d-%Y'; +set datetime_format= '%h:%i:%s %p %Y-%m-%d'; +set datetime_format= '%h:%i:%s.%f %p %Y-%m-%d'; + +SHOW SESSION VARIABLES LIKE "%format"; + +--error 1231 +SET time_format='%h:%i:%s'; +--error 1231 +SET time_format='%H %i:%s'; +--error 1231 +SET time_format='%H::%i:%s'; +--error 1231 +SET time_format='%H:%i:%s%f'; +--error 1231 +SET time_format='%H:%i.%f:%s'; +--error 1231 +SET time_format='%H:%i:%s%p'; +--error 1231 +SET time_format='%h:%i:%s.%f %p %Y-%m-%d'; +--error 1231 +SET time_format='%H%i%s.%f'; +--error 1231 +SET time_format='%H:%i-%s.%f'; +--error 1231 SET date_format='%d.%m.%d'; ---error 1105 -SET datetime_format="%d.%m.%y %h.%i.%s"; +--error 1231 +SET datetime_format='%h.%m.%y %d.%i.%s'; +--error 1231 +set datetime_format= '%H:%i:%s.%f %p %Y-%m-%d'; + +# +# Test GLOBAL values + +set GLOBAL datetime_format= '%H:%i:%s %Y-%m-%d'; +SET SESSION datetime_format=default; +select @@global.datetime_format, @@session.datetime_format; +SET GLOBAL datetime_format=default; +SET SESSION datetime_format=default; +select @@global.datetime_format, @@session.datetime_format; SET GLOBAL date_format=default; -SHOW GLOBAL VARIABLES LIKE "date_format%"; SET GLOBAL time_format=default; -SHOW GLOBAL VARIABLES LIKE "time_format%"; SET GLOBAL datetime_format=default; -SHOW GLOBAL VARIABLES LIKE "datetime_format%"; - -SET date_format=default; -SHOW SESSION VARIABLES LIKE "date_format%"; SET time_format=default; -SHOW SESSION VARIABLES LIKE "time_format%"; +SET date_format=default; SET datetime_format=default; -SHOW SESSION VARIABLES LIKE "datetime_format%"; - -SET time_format='%i:%s:%H'; -select cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME); - -SET GLOBAL date_format='%Y-%m-%d'; -SET GLOBAL time_format='%H:%i:%s'; -SET GLOBAL datetime_format='%Y-%m-%d %H:%i:%s'; -SET date_format='%Y-%m-%d'; -SET time_format='%H:%i:%s'; -SET datetime_format='%Y-%m-%d %H:%i:%s'; - -select str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S"); -select str_to_date("15 September 2001", "%d %M %Y"); -select str_to_date("15 Septembeb 2001", "%d %M %Y"); -select str_to_date("15 MAY 2001", "%d %b %Y"); -select str_to_date("Sunday 15 MAY 2001", "%W %d %b %Y"); -select str_to_date("Sundai 15 MAY 2001", "%W %d %b %Y"); -select str_to_date("Sundai 15 MA", "%W %d %b %Y"); -select str_to_date("Tuesday 52 2001", "%W %V %X"); -select str_to_date("Sunday 01 2001", "%W %V %X"); -select str_to_date("Tuesday 00 2002", "%W %U %Y"); -select str_to_date("Thursday 53 1998", "%W %u %Y"); -select str_to_date("15-01-2001", "%d-%m-%Y %H:%i:%S"); -select str_to_date("15-01-20", "%d-%m-%Y"); -select str_to_date("15-2001-1", "%d-%Y-%c"); + +# +# The following tests will work only when we at some point will enable +# dynamic changing of formats +# + +# SET date_format='%d.%m.%Y'; +# select CAST('01.01.2001' as DATE) as a; +# SET datetime_format='%d.%m.%Y %H.%i.%s'; +# select CAST('01.01.2001 05.12.06' as DATETIME) as a; +# SET time_format='%H.%i.%s'; +# select CAST('05.12.06' as TIME) as a; +# +# SET datetime_format='%d.%m.%Y %h:%i:%s %p'; +# select CAST('01.01.2001 05:12:06AM' as DATETIME) as a; +# select CAST('01.01.2001 05:12:06 PM' as DATETIME) as a; +# +# SET time_format='%h:%i:%s %p'; +# select CAST('05:12:06 AM' as TIME) as a; +# select CAST('05:12:06.1234PM' as TIME) as a; +# +# SET time_format='%h.%i.%s %p'; +# SET date_format='%d.%m.%y'; +# SET datetime_format='%d.%m.%y %h.%i.%s %p'; +# select CAST('12-12-06' as DATE) as a; +# +# select adddate('01.01.97 11.59.59.000001 PM', 10); +# select datediff('31.12.97 11.59:59.000001 PM','01.01.98'); +# select weekofyear('31.11.97 11:59:59.000001 PM'); +# select makedate(1997,1); +# select addtime('31.12.97 11.59.59.999999 PM', '1 1.1.1.000002'); +# select maketime(23,11,12); +# select timediff('01.01.97 11:59:59.000001 PM','31.12.95 11:59:59.000002 PM'); +# +# SET time_format='%i:%s:%H'; +# select cast(str_to_date('15-01-2001 12:59:59', '%d-%m-%Y %H:%i:%S') as TIME); + +# +# Test of str_to_date +# + +select str_to_date(concat('15-01-2001',' 2:59:58.999'), + concat('%d-%m-%Y',' ','%H:%i:%s.%f')); + +create table t1 (date char(30), format char(30) not null); +insert into t1 values +('2003-01-02 10:11:12', '%Y-%m-%d %H:%i:%S'), +('03-01-02 8:11:2.123456', '%y-%m-%d %H:%i:%S'), +('2003-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'), +('2003-01-02 01:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f%p'), +('2003-01-02 02:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f %p'), +('2003-01-02 12:11:12.12345 am', '%Y-%m-%d %h:%i:%S.%f%p'), +('2003-01-02 11:11:12Pm', '%Y-%m-%d %h:%i:%S%p'), +('10:20:10', '%H:%i:%s'), +('10:20:10', '%h:%i:%s.%f'), +('10:20:10AM', '%h:%i:%s%p'), +('10:20:10.44AM', '%h:%i:%s.%f%p'), +('15-01-2001 12:59:58', '%d-%m-%Y %H:%i:%S'), +('15 September 2001', '%d %M %Y'), +('15 SEPTEMB 2001', '%d %M %Y'), +('15 MAY 2001', '%d %b %Y'), +('Sunday 15 MAY 2001', '%W %d %b %Y'), +('Sund 15 MAY 2001', '%W %d %b %Y'), +('Tuesday 00 2002', '%W %U %Y'), +('Thursday 53 1998', '%W %u %Y'), +('15-01-2001', '%d-%m-%Y %H:%i:%S'), +('15-01-20', '%d-%m-%y'), +('15-2001-1', '%d-%Y-%c'); + +# Use through protocol functions +select date,format,str_to_date(date, format) as str_to_date from t1; +# Use as a string +select date,format,concat('',str_to_date(date, format)) as con from t1; +# Use as datetime +select date,format,cast(str_to_date(date, format) as datetime) as datetime from t1; +select date,format,DATE(str_to_date(date, format)) as date2 from t1; +select date,format,TIME(str_to_date(date, format)) as time from t1; +select date,format,concat(TIME(str_to_date(date, format))) as time2 from t1; + +# Test wrong dates + +truncate table t1; +insert into t1 values +('2003-01-02 10:11:12 PM', '%Y-%m-%d %H:%i:%S %p'), +('2003-01-02 10:11:12.123456', '%Y-%m-%d %h:%i:%S %p'), +('2003-01-02 10:11:12AM', '%Y-%m-%d %h:%i:%S.%f %p'), +('2003-01-02 10:11:12AN', '%Y-%m-%d %h:%i:%S%p'), +('2003-01-02 10:11:12 PM', '%y-%m-%d %H:%i:%S %p'), +('10:20:10AM', '%H:%i:%s%p'), +('15 Septembei 2001', '%d %M %Y'), +('15 Ju 2001', '%d %M %Y'), +('Sund 15 MA', '%W %d %b %Y'), +('Sunday 01 2001', '%W %V %X'), +('Thursdai 12 1998', '%W %u %Y'), +(NULL, get_format(DATE,'USA')), +('Tuesday 52 2001', '%W %V %X'); +select date,format,str_to_date(date, format) as str_to_date from t1; +select date,format,concat(str_to_date(date, format),'') as con from t1; + +# Test 'maybe' date formats and 'strange but correct' results + +truncate table t1; +insert into t1 values +('10:20:10AM', '%h:%i:%s'), +('2003-01-02 10:11:12', '%Y-%m-%d %h:%i:%S'), +('03-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'); + +select date,format,str_to_date(date, format) as str_to_date from t1; +select date,format,concat(str_to_date(date, format),'') as con from t1; + +drop table t1; + +# +# Test of get_format +# select get_format(DATE, 'USA') as a; select get_format(TIME, 'internal') as a; select get_format(DATETIME, 'eur') as a; +select get_format(DATE, 'TEST') as a; +select str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA')); +explain extended select makedate(1997,1), addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"),subtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002"),timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM"),cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME), maketime(23,11,12),microsecond("1997-12-31 23:59:59.000001"); diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 422ca23de90..3aace91447d 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -16,6 +16,7 @@ INSERT INTO t1 VALUES('MySQL has now support', 'for full-text search'), # nl search select * from t1 where MATCH(a,b) AGAINST ("collections"); +explain extended select * from t1 where MATCH(a,b) AGAINST ("collections"); select * from t1 where MATCH(a,b) AGAINST ("indexes"); select * from t1 where MATCH(a,b) AGAINST ("indexes collections"); select * from t1 where MATCH(a,b) AGAINST ("only"); @@ -42,6 +43,7 @@ explain select * from t1 where MATCH(a,b) AGAINST ("collections")>0 and a like ' # boolean search select * from t1 where MATCH(a,b) AGAINST("support -collections" IN BOOLEAN MODE); +explain extended select * from t1 where MATCH(a,b) AGAINST("support -collections" IN BOOLEAN MODE); select * from t1 where MATCH(a,b) AGAINST("support collections" IN BOOLEAN MODE); select * from t1 where MATCH(a,b) AGAINST("support +collections" IN BOOLEAN MODE); select * from t1 where MATCH(a,b) AGAINST("sear*" IN BOOLEAN MODE); @@ -131,9 +133,9 @@ select * from t2 having MATCH inhalt AGAINST ('foobar'); # check of fulltext errors # ---error 1281 +--error 1286 CREATE TABLE t3 (t int(11),i text,fulltext tix (t,i)); ---error 1281 +--error 1286 CREATE TABLE t3 (t int(11),i text, j varchar(200) CHARACTER SET latin2, fulltext tix (i,j)); @@ -226,6 +228,12 @@ insert into t2 values (1, 1, 'xxfoo'); insert into t2 values (2, 1, 'xxbar'); insert into t2 values (3, 1, 'xxbuz'); select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against('xxfoo' in boolean mode); + +# +# bug with many short (< ft_min_word_len) words in boolean search +# +select * from t2 where match name against ('a* b* c* d* e* f*' in boolean mode); + drop table t1,t2; # diff --git a/mysql-test/t/func_compress.test b/mysql-test/t/func_compress.test index 069fbed8562..06ebb388517 100644 --- a/mysql-test/t/func_compress.test +++ b/mysql-test/t/func_compress.test @@ -7,7 +7,9 @@ select @test_compress_string:='string for test compress function aaaaaaaaaaaaaaa select length(@test_compress_string); select uncompress(compress(@test_compress_string)); +explain extended select uncompress(compress(@test_compress_string)); select uncompressed_length(compress(@test_compress_string))=length(@test_compress_string); +explain extended select uncompressed_length(compress(@test_compress_string))=length(@test_compress_string); select uncompressed_length(compress(@test_compress_string)); select length(compress(@test_compress_string))<length(@test_compress_string); diff --git a/mysql-test/t/func_crypt.test b/mysql-test/t/func_crypt.test index c1c7090cab3..f352a98e3cd 100644 --- a/mysql-test/t/func_crypt.test +++ b/mysql-test/t/func_crypt.test @@ -1,9 +1,21 @@ -- source include/have_crypt.inc +--disable_warnings +drop table if exists t1; +--enable_warnings + select length(encrypt('foo', 'ff')) <> 0; --replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l. +create table t1 (name varchar(50), pw varchar(64)); +insert into t1 values ('tom', password('my_pass')); +set @pass='my_pass'; +select name from t1 where name='tom' and pw=password(@pass); +select name from t1 where name='tom' and pw=password(@undefined); +drop table t1; + # Test new and old password handling functions + select password('abc'); select password(''); select old_password('abc'); @@ -34,3 +46,5 @@ select password('idkfa'); select password(' idkfa'); select old_password('idkfa'); select old_password(' i d k f a '); + +explain extended select password('idkfa '), old_password('idkfa'); diff --git a/mysql-test/t/func_default.test b/mysql-test/t/func_default.test new file mode 100644 index 00000000000..6ae9f088f92 --- /dev/null +++ b/mysql-test/t/func_default.test @@ -0,0 +1,19 @@ +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + + +create table t1(str varchar(10) default 'def',strnull varchar(10),intg int default '10',rel double default '3.14'); + +insert into t1 values ('','',0,0.0); +select default(str), default(strnull), default(intg), default(rel) from t1; +explain extended select default(str), default(strnull), default(intg), default(rel) from t1; +select * from t1 where str <> default(str); +explain select * from t1 where str <> default(str); + +#TODO: uncomment when bug will be fixed +#create table t2 select default(str), default(strnull), default(intg), default(rel) from t1; +#show create table from t1; +#insert into t2 select select default(str), default(strnull), default(intg), default(rel) from t1; + +drop table t1;
\ No newline at end of file diff --git a/mysql-test/t/func_encrypt.test b/mysql-test/t/func_encrypt.test index fbb71f850e2..fe81a814dda 100644 --- a/mysql-test/t/func_encrypt.test +++ b/mysql-test/t/func_encrypt.test @@ -68,3 +68,5 @@ select @a = des_decrypt(des_encrypt("hello")); select hex("hello"); select hex(des_decrypt(des_encrypt("hello",4),'password2')); select hex(des_decrypt(des_encrypt("hello","hidden"))); + +explain extended select des_decrypt(des_encrypt("hello",4),'password2'), des_decrypt(des_encrypt("hello","hidden")); diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 041225bdaf5..d004c81f14e 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -18,6 +18,7 @@ insert into t1 values (3,9,"D","c"); # Test of MySQL simple request select grp,group_concat(c) from t1 group by grp; +explain extended select grp,group_concat(c) from t1 group by grp; select grp,group_concat(a,c) from t1 group by grp; select grp,group_concat("(",a,":",c,")") from t1 group by grp; @@ -33,9 +34,11 @@ select grp,group_concat(c order by 1) from t1 group by grp; select grp,group_concat(c order by "c") from t1 group by grp; select grp,group_concat(distinct c order by c) from t1 group by grp; select grp,group_concat(distinct c order by c desc) from t1 group by grp; +explain extended select grp,group_concat(distinct c order by c desc) from t1 group by grp; select grp,group_concat(c order by c separator ",") from t1 group by grp; select grp,group_concat(c order by c desc separator ",") from t1 group by grp; select grp,group_concat(distinct c order by c separator ",") from t1 group by grp; +explain extended select grp,group_concat(distinct c order by c separator ",") from t1 group by grp; select grp,group_concat(distinct c order by c desc separator ",") from t1 group by grp; # Test of SQL_LIST objects diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index ac3a1986d93..9e0184d35ce 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -346,7 +346,8 @@ select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; insert into t1 values (3,1); select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; -select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; +explain extended select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b), bit_xor(b) from t1 group by a; drop table t1; --disable_warnings create table t1 (USR_ID integer not null, MAX_REQ integer not null, constraint PK_SEA_USER primary key (USR_ID)) type=InnoDB; diff --git a/mysql-test/t/func_if.test b/mysql-test/t/func_if.test index 21e5836c781..7842df4fd0a 100644 --- a/mysql-test/t/func_if.test +++ b/mysql-test/t/func_if.test @@ -20,6 +20,13 @@ select if(1,st,st) s from t1 order by s; select if(u=1,st,st) s from t1 order by s; select if(u=1,binary st,st) s from t1 order by s; select if(u=1,st,binary st) s from t1 where st like "%a%" order by s; +explain extended select if(u=1,st,binary st) s from t1 where st like "%a%" order by s; + +# +# NULLIF test +# +select nullif(u=0, 'test') from t1; +explain extended select nullif(u=0, 'test') from t1; drop table t1; # diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index 689b061f88d..9ff768ec76b 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -72,6 +72,7 @@ select * from t1 where a in ('a'); select * from t1 where 'a' collate latin1_general_ci in (a,b,c); select * from t1 where 'a' collate latin1_bin in (a,b,c); select * from t1 where 'a' in (a,b,c collate latin1_bin); +explain extended select * from t1 where 'a' in (a,b,c collate latin1_bin); drop table t1; select '1.0' in (1,2); diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index bd125dafd53..b6e2d3bd725 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -3,17 +3,30 @@ # select floor(5.5),floor(-5.5); +explain extended select floor(5.5),floor(-5.5); select ceiling(5.5),ceiling(-5.5); +explain extended select ceiling(5.5),ceiling(-5.5); select truncate(52.64,1),truncate(52.64,2),truncate(52.64,-1),truncate(52.64,-2), truncate(-52.64,1),truncate(-52.64,-1); +explain extended select truncate(52.64,1),truncate(52.64,2),truncate(52.64,-1),truncate(52.64,-2), truncate(-52.64,1),truncate(-52.64,-1); select round(5.5),round(-5.5); +explain extended select round(5.5),round(-5.5); select round(5.64,1),round(5.64,2),round(5.64,-1),round(5.64,-2); select abs(-10), sign(-5), sign(5), sign(0); +explain extended select abs(-10), sign(-5), sign(5), sign(0); select log(exp(10)),exp(log(sqrt(10))*2),log(-1),log(NULL),log(1,1),log(3,9),log(-1,2),log(NULL,2); +explain extended select log(exp(10)),exp(log(sqrt(10))*2),log(-1),log(NULL),log(1,1),log(3,9),log(-1,2),log(NULL,2); select ln(exp(10)),exp(ln(sqrt(10))*2),ln(-1),ln(0),ln(NULL); +explain extended select ln(exp(10)),exp(ln(sqrt(10))*2),ln(-1),ln(0),ln(NULL); select log2(8),log2(15),log2(-2),log2(0),log2(NULL); +explain extended select log2(8),log2(15),log2(-2),log2(0),log2(NULL); select log10(100),log10(18),log10(-4),log10(0),log10(NULL); +explain extended select log10(100),log10(18),log10(-4),log10(0),log10(NULL); select pow(10,log10(10)),power(2,4); +explain extended select pow(10,log10(10)),power(2,4); set @@rand_seed1=10000000,@@rand_seed2=1000000; select rand(999999),rand(); +explain extended select rand(999999),rand(); select pi(),sin(pi()/2),cos(pi()/2),abs(tan(pi())),cot(1),asin(1),acos(0),atan(1); +explain extended select pi(),sin(pi()/2),cos(pi()/2),abs(tan(pi())),cot(1),asin(1),acos(0),atan(1); select degrees(pi()),radians(360); +explain extended select degrees(pi()),radians(360); diff --git a/mysql-test/t/func_op.test b/mysql-test/t/func_op.test index 778c8406b8d..cb6ca58f193 100644 --- a/mysql-test/t/func_op.test +++ b/mysql-test/t/func_op.test @@ -3,5 +3,7 @@ # Simple operands and arithmetic grouping select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; +explain extended select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; select 1 | (1+1),5 & 3,bit_count(7) ; +explain extended select 1 | (1+1),5 & 3,bit_count(7) ; select 1 << 32,1 << 63, 1 << 64, 4 >> 2, 4 >> 63, 1<< 63 >> 60; diff --git a/mysql-test/t/func_regexp.test b/mysql-test/t/func_regexp.test index 6ecb56ef9c4..edfa9afcfa6 100644 --- a/mysql-test/t/func_regexp.test +++ b/mysql-test/t/func_regexp.test @@ -36,6 +36,7 @@ drop table t1; create table t1 (xxx char(128)); insert into t1 (xxx) values('this is a test of some long text to see what happens'); select * from t1 where xxx regexp('is a test of some long text to'); +explain extended select * from t1 where xxx regexp('is a test of some long text to'); select * from t1 where xxx regexp('is a test of some long text to '); select * from t1 where xxx regexp('is a test of some long text to s'); select * from t1 where xxx regexp('is a test of some long text to se'); diff --git a/mysql-test/t/func_set.test b/mysql-test/t/func_set.test index b152c94096c..7d24140c75d 100644 --- a/mysql-test/t/func_set.test +++ b/mysql-test/t/func_set.test @@ -3,6 +3,7 @@ # select interval(55,10,20,30,40,50,60,70,80,90,100),interval(3,1,1+1,1+1+1+1),field("IBM","NCA","ICL","SUN","IBM","DIGITAL"),field("A","B","C"),elt(2,"ONE","TWO","THREE"),interval(0,1,2,3,4),elt(1,1,2,3)|0,elt(1,1.1,1.2,1.3)+0; +explain extended select INTERVAL(55,10,20,30,40,50,60,70,80,90,100),interval(3,1,1+1,1+1+1+1),field("IBM","NCA","ICL","SUN","IBM","DIGITAL"),field("A","B","C"),elt(2,"ONE","TWO","THREE"),interval(0,1,2,3,4),elt(1,1,2,3)|0,elt(1,1.1,1.2,1.3)+0; select find_in_set("b","a,b,c"),find_in_set("c","a,b,c"),find_in_set("dd","a,bbb,dd"),find_in_set("bbb","a,bbb,dd"); select find_in_set("d","a,b,c"),find_in_set("dd","a,bbb,d"),find_in_set("bb","a,bbb,dd"); select make_set(0,'a','b','c'),make_set(-1,'a','b','c'),make_set(1,'a','b','c'),make_set(2,'a','b','c'),make_set(1+2,concat('a','b'),'c'); diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index b421f47e5b8..4ae586256ae 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -14,7 +14,9 @@ select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo'; select 'hello' 'monty'; select length('\n\t\r\b\0\_\%\\'); select bit_length('\n\t\r\b\0\_\%\\'); -select concat('monty',' was here ','again'),length('hello'),char(ascii('h')); +select char_length('\n\t\r\b\0\_\%\\'); +select length(_latin1'\n\t\n\b\0\\_\\%\\'); +select concat('monty',' was here ','again'),length('hello'),char(ascii('h')),ord('h'); select locate('he','hello'),locate('he','hello',2),locate('lo','hello',2) ; select instr('hello','HE'), instr('hello',binary 'HE'), instr(binary 'hello','HE'); select position(binary 'll' in 'hello'),position('a' in binary 'hello'); @@ -46,6 +48,7 @@ select null sounds like 'null'; select 'null' sounds like null; select null sounds like null; select md5('hello'); +select crc32("123"); select sha('abc'); select sha1('abc'); select aes_decrypt(aes_encrypt('abc','1'),'1'); @@ -336,3 +339,7 @@ INSERT INTO t1 VALUES ('Congress reconvenes in September to debate welfare and a INSERT INTO t1 VALUES ('House passes the CAREERS bill'); SELECT CONCAT("</a>",RPAD("",(55 - LENGTH(title)),".")) from t1; DROP TABLE t1; + +select substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', -2); + +explain extended select md5('hello'), sha('abc'), sha1('abc'), soundex(''), 'mood' sounds like 'mud', aes_decrypt(aes_encrypt('abc','1'),'1'),concat('*',space(5),'*'), reverse('abc'), rpad('a',4,'1'), lpad('a',4,'1'), concat_ws(',','',NULL,'a'),make_set(255,_latin2'a',_latin2'b',_latin2'c'),elt(2,1),locate("a","b",2),format(130,10),char(0),conv(130,16,10),hex(130),binary 'HE', export_set(255,_latin2'y',_latin2'n',_latin2' '),FIELD('b' COLLATE latin1_bin,'A','B'),FIND_IN_SET(_latin1'B',_latin1'a,b,c,d'),collation(conv(130,16,10)), coercibility(conv(130,16,10)),length('\n\t\r\b\0\_\%\\'),bit_length('\n\t\r\b\0\_\%\\'),bit_length('\n\t\r\b\0\_\%\\'),concat('monty',' was here ','again'),length('hello'),char(ascii('h')),ord('h'),quote(1/0),crc32("123"),replace('aaaa','a','b'),insert('txs',2,1,'hi'),left(_latin2'a',1),right(_latin2'a',1),lcase(_latin2'a'),ucase(_latin2'a'),SUBSTR('abcdefg',3,2),substring_index("1abcd;2abcd;3abcd;4abcd", ';', 2),trim(_latin2' a '),ltrim(_latin2' a '),rtrim(_latin2' a '), decode(encode(repeat("a",100000),"monty"),"monty"); diff --git a/mysql-test/t/func_system.test b/mysql-test/t/func_system.test index 998b2a5c3f4..f3b9b4ffc3f 100644 --- a/mysql-test/t/func_system.test +++ b/mysql-test/t/func_system.test @@ -17,6 +17,7 @@ select version()>="3.23.29"; select version()>=_utf8"3.23.29"; select version()>=_latin1"3.23.29"; select charset(version()); +explain extended select database(), user(); create table t1 (version char(40)) select database(), user(), version() as 'version'; show create table t1; diff --git a/mysql-test/t/func_test.test b/mysql-test/t/func_test.test index 95b10c4ffb9..86e0ee2637b 100644 --- a/mysql-test/t/func_test.test +++ b/mysql-test/t/func_test.test @@ -19,13 +19,19 @@ select 'b' between 'a' and 'c', 'B' between 'a' and 'c'; select 2 in (3,2,5,9,5,1),"monty" in ("david","monty","allan"), 1.2 in (1.4,1.2,1.0); select -1.49 or -1.49,0.6 or 0.6; select 3 ^ 11, 1 ^ 1, 1 ^ 0, 1 ^ NULL, NULL ^ 1; +explain extended select 3 ^ 11, 1 ^ 1, 1 ^ 0, 1 ^ NULL, NULL ^ 1; select 1 XOR 1, 1 XOR 0, 0 XOR 1, 0 XOR 0, NULL XOR 1, 1 XOR NULL, 0 XOR NULL; select 10 % 7, 10 mod 7, 10 div 3; +explain extended select 10 % 7, 10 mod 7, 10 div 3; select (1 << 64)-1, ((1 << 64)-1) DIV 1, ((1 << 64)-1) DIV 2; +explain extended select (1 << 64)-1, ((1 << 64)-1) DIV 1, ((1 << 64)-1) DIV 2; create table t1 (a int); insert t1 values (1); select * from t1 where 1 xor 1; +explain extended select * from t1 where 1 xor 1; +select - a from t1; +explain extended select - a from t1; drop table t1; # @@ -41,6 +47,7 @@ select 1 and 0 or 2, 2 or 1 and 0; # select _koi8r'a' = _koi8r'A'; select _koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci; +explain extended select _koi8r'a' = _koi8r'A' COLLATE koi8r_general_ci; select _koi8r'a' = _koi8r'A' COLLATE koi8r_bin; select _koi8r'a' COLLATE koi8r_general_ci = _koi8r'A'; select _koi8r'a' COLLATE koi8r_bin = _koi8r'A'; diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 30d616915ab..96bdb547469 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -7,6 +7,7 @@ drop table if exists t1,t2,t3; select from_days(to_days("960101")),to_days(960201)-to_days("19960101"),to_days(date_add(curdate(), interval 1 day))-to_days(curdate()),weekday("1997-11-29"); select period_add("9602",-12),period_diff(199505,"9404") ; + select now()-now(),weekday(curdate())-weekday(now()),unix_timestamp()-unix_timestamp(now()); select from_unixtime(unix_timestamp("1994-03-02 10:11:12")),from_unixtime(unix_timestamp("1994-03-02 10:11:12"),"%Y-%m-%d %h:%i:%s"),from_unixtime(unix_timestamp("1994-03-02 10:11:12"))+0; select sec_to_time(9001),sec_to_time(9001)+0,time_to_sec("15:12:22"), @@ -231,3 +232,5 @@ select strcmp(date_format(date_sub(localtimestamp(), interval 3 hour),"%Y-%m-%d" select strcmp(date_format(utc_timestamp(),"%T"), utc_time())=0; select strcmp(date_format(utc_timestamp(),"%Y-%m-%d"), utc_date())=0; select strcmp(concat(utc_date(),' ',utc_time()),utc_timestamp())=0; + +explain extended select period_add("9602",-12),period_diff(199505,"9404"),from_days(to_days("960101")),dayofmonth("1997-01-02"), month("1997-01-02"), monthname("1972-03-04"),dayofyear("0000-00-00"),HOUR("1997-03-03 23:03:22"),MINUTE("23:03:22"),SECOND(230322),QUARTER(980303),WEEK("1998-03-03"),yearweek("2000-01-01",1),week(19950101,1),year("98-02-03"),weekday(curdate())-weekday(now()),dayname("1962-03-03"),unix_timestamp(),sec_to_time(time_to_sec("0:30:47")/6.21),curtime(),utc_time(),curdate(),utc_date(),utc_timestamp(),date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w"),from_unixtime(unix_timestamp("1994-03-02 10:11:12")),"1997-12-31 23:59:59" + INTERVAL 1 SECOND,"1998-01-01 00:00:00" - INTERVAL 1 SECOND,INTERVAL 1 DAY + "1997-12-31", extract(YEAR FROM "1999-01-02 10:11:12"),date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND); diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index b7c41135123..c8f50e968ab 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -82,9 +82,11 @@ SELECT fid, Dimension(g) FROM geo; SELECT fid, GeometryType(g) FROM geo; SELECT fid, IsEmpty(g) FROM geo; SELECT fid, AsText(Envelope(g)) FROM geo; +explain extended select Dimension(g), GeometryType(g), IsEmpty(g), AsText(Envelope(g)) from geo; SELECT fid, X(g) FROM pt; SELECT fid, Y(g) FROM pt; +explain extended select X(g),Y(g) FROM pt; SELECT fid, AsText(StartPoint(g)) FROM ls; SELECT fid, AsText(EndPoint(g)) FROM ls; @@ -92,12 +94,14 @@ SELECT fid, GLength(g) FROM ls; SELECT fid, NumPoints(g) FROM ls; SELECT fid, AsText(PointN(g, 2)) FROM ls; SELECT fid, IsClosed(g) FROM ls; +explain extended select AsText(StartPoint(g)),AsText(EndPoint(g)),GLength(g),NumPoints(g),AsText(PointN(g, 2)),IsClosed(g) FROM ls; SELECT fid, AsText(Centroid(g)) FROM p; SELECT fid, Area(g) FROM p; SELECT fid, AsText(ExteriorRing(g)) FROM p; SELECT fid, NumInteriorRings(g) FROM p; SELECT fid, AsText(InteriorRingN(g, 1)) FROM p; +explain extended select AsText(Centroid(g)),Area(g),AsText(ExteriorRing(g)),NumInteriorRings(g),AsText(InteriorRingN(g, 1)) FROM p; SELECT fid, IsClosed(g) FROM mls; @@ -108,17 +112,24 @@ SELECT fid, NumGeometries(g) from mpt; SELECT fid, NumGeometries(g) from mls; SELECT fid, NumGeometries(g) from mp; SELECT fid, NumGeometries(g) from gc; +explain extended SELECT fid, NumGeometries(g) from mpt; SELECT fid, AsText(GeometryN(g, 2)) from mpt; SELECT fid, AsText(GeometryN(g, 2)) from mls; SELECT fid, AsText(GeometryN(g, 2)) from mp; SELECT fid, AsText(GeometryN(g, 2)) from gc; +explain extended SELECT fid, AsText(GeometryN(g, 2)) from mpt; SELECT g1.fid as first, g2.fid as second, Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r FROM gc g1, gc g2 ORDER BY first, second; +explain extended SELECT g1.fid as first, g2.fid as second, +Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o, +Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t, +Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r +FROM gc g1, gc g2 ORDER BY first, second; DROP TABLE pt, ls, p, mpt, mls, mp, gc, geo; @@ -142,3 +153,9 @@ SHOW FIELDS FROM g1; DROP TABLE g1; SELECT AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4)')))); +explain extended SELECT AsText(GeometryFromWKB(AsWKB(GeometryFromText('POINT(1 4)')))); +explain extended SELECT AsText(GeometryFromWKB(AsWKB(PointFromText('POINT(1 4)')))); +SELECT SRID(GeomFromText('LineString(1 1,2 2)',101)); +explain extended SELECT SRID(GeomFromText('LineString(1 1,2 2)',101)); +#select issimple(MultiPoint(Point(3, 6), Point(4, 10))), issimple(Point(3, 6)),issimple(PolygonFromText('POLYGON((10 10,20 10,20 20,10 20,10 10))')),issimple(GeometryFromText('POINT(1 4)')), issimple(AsWKB(GeometryFromText('POINT(1 4)'))); +explain extended select issimple(MultiPoint(Point(3, 6), Point(4, 10))), issimple(Point(3, 6)); diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 752896ce7b2..705e32c82df 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -260,7 +260,7 @@ explain select spid,count(*) from t1 where spid between 1 and 2 group by spid; explain select spid,count(*) from t1 where spid between 1 and 2 group by spid order by null; select spid,count(*) from t1 where spid between 1 and 2 group by spid; select spid,count(*) from t1 where spid between 1 and 2 group by spid desc; -explain select sql_big_result spid,sum(userid) from t1 group by spid desc; +explain extended select sql_big_result spid,sum(userid) from t1 group by spid desc; explain select sql_big_result spid,sum(userid) from t1 group by spid desc order by null; select sql_big_result spid,sum(userid) from t1 group by spid desc; explain select sql_big_result score,count(*) from t1 group by score desc; diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test index 7d5fbee011f..7e4cbe76cca 100644 --- a/mysql-test/t/having.test +++ b/mysql-test/t/having.test @@ -10,6 +10,7 @@ select count(a) as b from t1 where a=0 having b > 0; insert into t1 values (null); select count(a) as b from t1 where a=0 having b > 0; select count(a) as b from t1 where a=0 having b >=0; +explain extended select count(a) as b from t1 where a=0 having b >=0; drop table t1; # diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index 4f19aca8738..550bce867cd 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -23,4 +23,6 @@ INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0; SELECT * FROM t1; INSERT t1 VALUES (2,1,11), (7,4,40) ON DUPLICATE KEY UPDATE c=c+VALUES(a); SELECT *, VALUES(a) FROM t1; +explain extended SELECT *, VALUES(a) FROM t1; +explain extended select * from t1 where values(a); DROP TABLE t1; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 01db0420943..954fdcb925a 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -9,11 +9,16 @@ INSERT INTO t1 VALUES (1), (2); --exec $MYSQL_DUMP --skip-all -X test t1 DROP TABLE t1; +CREATE TABLE t1(a int, b text, c varchar(3)); +INSERT INTO t1 VALUES (1, "test", "tes"), (2, "TEST", "TES"); +--exec $MYSQL_DUMP --skip-all -X test t1 +DROP TABLE t1; + # # Bug #1707 # -CREATE TABLE `"t"1` (`a"b"` char(2)); -INSERT INTO `"t"1` VALUES ("1\""), ("\"2"); ---exec $MYSQL_DUMP --skip-all -X test \"t\"1 -DROP TABLE `"t"1`; +CREATE TABLE t1 (`a"b"` char(2)); +INSERT INTO t1 VALUES ("1\""), ("\"2"); +--exec $MYSQL_DUMP --skip-all -X test t1 +DROP TABLE t1; diff --git a/mysql-test/t/null.test b/mysql-test/t/null.test index fa36249dce0..0be755ba7ad 100644 --- a/mysql-test/t/null.test +++ b/mysql-test/t/null.test @@ -8,6 +8,7 @@ drop table if exists t1; # select null,\N,isnull(null),isnull(1/0),isnull(1/0 = null),ifnull(null,1),ifnull(null,"TRUE"),ifnull("TRUE","ERROR"),1/0 is null,1 is not null; +explain extended select null,\N,isnull(null),isnull(1/0),isnull(1/0 = null),ifnull(null,1),ifnull(null,"TRUE"),ifnull("TRUE","ERROR"),1/0 is null,1 is not null; select 1 | NULL,1 & NULL,1+NULL,1-NULL; select NULL=NULL,NULL<>NULL,IFNULL(NULL,1.1)+0,IFNULL(NULL,1) | 0; select strcmp("a",NULL),(1<NULL)+0.0,NULL regexp "a",null like "a%","a%" like null; @@ -15,10 +16,12 @@ select concat("a",NULL),replace(NULL,"a","b"),replace("string","i",NULL),replace select repeat("a",0),repeat("ab",5+5),repeat("ab",-1),reverse(NULL); select field(NULL,"a","b","c"); select 2 between null and 1,2 between 3 AND NULL,NULL between 1 and 2,2 between NULL and 3, 2 between 1 AND null; +explain extended select 2 between null and 1,2 between 3 AND NULL,NULL between 1 and 2,2 between NULL and 3, 2 between 1 AND null; SELECT NULL AND NULL, 1 AND NULL, NULL AND 1, NULL OR NULL, 0 OR NULL, NULL OR 0; SELECT (NULL OR NULL) IS NULL; select NULL AND 0, 0 and NULL; select inet_ntoa(null),inet_aton(null),inet_aton("122.256"),inet_aton("122.226."),inet_aton(""); +explain extended select inet_ntoa(null),inet_aton(null),inet_aton("122.256"),inet_aton("122.226."),inet_aton(""); create table t1 (x int); insert into t1 values (null); diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index 17bf6230f76..7443aeee6f4 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -32,7 +32,7 @@ select product, sum(profit),avg(profit) from t1 group by product with rollup; # Sub totals select product, country_id , year, sum(profit) from t1 group by product, country_id, year; select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; -explain select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; +explain extended select product, country_id , year, sum(profit) from t1 group by product, country_id, year with rollup; select product, country_id , sum(profit) from t1 group by product desc, country_id with rollup; # limit diff --git a/mysql-test/t/overflow.test b/mysql-test/t/overflow.test index 6619a87cabb..7a9616fd24e 100644 --- a/mysql-test/t/overflow.test +++ b/mysql-test/t/overflow.test @@ -1,4 +1,4 @@ connect (con1,localhost,boo,,); connection con1; --- error 1064,1102 +-- error 1064,1102,1279 drop database AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; diff --git a/mysql-test/t/query_cache-master.opt b/mysql-test/t/query_cache-master.opt deleted file mode 100644 index cfdce628e74..00000000000 --- a/mysql-test/t/query_cache-master.opt +++ /dev/null @@ -1 +0,0 @@ ---set-variable=query_cache_size=1355776 diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index ed4c5c91c4d..14cbf4c906d 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -3,6 +3,7 @@ # # Tests with query cache # +set GLOBAL query_cache_size=1355776; # Reset query cache variables. @@ -11,7 +12,7 @@ flush query cache; # This crashed in some versions reset query cache; flush status; --disable_warnings -drop table if exists t1,t2,t3; +drop table if exists t1,t2,t3,t4,t11,t21; drop database if exists mysqltest; --enable_warnings @@ -184,6 +185,7 @@ select RAND() from t1; select UNIX_TIMESTAMP() from t1; select USER() from t1; select benchmark(1,1) from t1; +explain extended select benchmark(1,1) from t1; show status like "Qcache_queries_in_cache"; # # Tests when the cache is filled @@ -489,6 +491,55 @@ SET OPTION SQL_SELECT_LIMIT=DEFAULT; drop table t1; # +# query cache crash on using same table twice in one query test +# +flush query cache; +reset query cache; +flush status; +set GLOBAL query_cache_size=1048576; + +create table t1 (a int not null); +insert into t1 values (1),(2),(3); +create table t2 (a text not null); +create table t3 (a text not null); +insert into t3 values("1111111111111111111111111111111111111111111111111111"); +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +insert into t2 select * from t3; +insert into t3 select * from t2; +drop table t2; +create table t2 (a int not null); +insert into t2 values (1),(2),(3); +create table t4 (a int not null); +insert into t4 values (1),(2),(3); + +disable_result_log; +select * from t4; +select * from t2; +select * from t1 as tt, t1 as ttt where tt.a=1 and ttt.a=2; +select * from t2; +select * from t4; +select * from t1 as tt, t1 as ttt where tt.a=1 and ttt.a=2; +select * from t2; +select * from t4; +select * from t1 as tt, t1 as ttt where tt.a=1 and ttt.a=2; + +delete from t2 where a=1; +flush query cache; +select * from t3; +enable_result_log; +delete from t4 where a=1; +flush query cache; + +drop table t1,t2,t3,t4; + +# # Test character set related variables: # character_set_result # character_set_client @@ -534,3 +585,4 @@ show status like "Qcache_queries_in_cache"; # Keep things tidy # DROP TABLE t1; +SET GLOBAL query_cache_size=0; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 40ae49f8005..65ba2ee6671 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -205,6 +205,30 @@ explain select * from t1, t2 where (t1.key1 <t2.keya + 1) and t2.keya=3; explain select * from t1 force index(i2), t2 where (t1.key1 <t2.keya + 1) and t2.keya=3; DROP TABLE t1,t2; +# +# bug #1724: use RANGE on more selective column instead of REF on less +# selective + +CREATE TABLE t1 ( + a int(11) default NULL, + b int(11) default NULL, + KEY a (a), + KEY b (b) +) TYPE=MyISAM; + + +INSERT INTO t1 VALUES +(1,1),(2,1),(3,1),(4,1),(5,1),(6,1),(7,1),(8,1),(9,1),(10,2),(10,2), +(13,2),(14,2),(15,2),(16,2),(17,3),(17,3),(16,3),(17,3),(19,3),(20,3), +(21,4),(22,5),(23,5),(24,5),(25,5),(26,5),(30,5),(31,5),(32,5),(33,5), +(33,5),(33,5),(33,5),(33,5),(34,5),(35,5); + +# we expect that optimizer will choose key on A +EXPLAIN SELECT * FROM t1 WHERE a IN(1,2) AND b=5; +SELECT * FROM t1 WHERE a IN(1,2) AND b=5; + +DROP TABLE t1; + # test for a bug with in() and unique key create table t1 (id int(10) primary key); diff --git a/mysql-test/t/row.test b/mysql-test/t/row.test index 252830cfc98..ecb0c6adfc1 100644 --- a/mysql-test/t/row.test +++ b/mysql-test/t/row.test @@ -18,6 +18,7 @@ select (1,2,(3,4)) IN ((3,2,(3,4)), (1,2,(3,4))); -- error 1240 select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,4)); select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))); +explain extended select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))); SELECT (1,2,3)=(0,NULL,3); SELECT (1,2,3)=(1,NULL,3); diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test index f464f1e2751..445bd579279 100644 --- a/mysql-test/t/rpl000001.test +++ b/mysql-test/t/rpl000001.test @@ -62,10 +62,12 @@ enable_query_log; # Try to cause a large relay log lag on the slave connection slave; select get_lock("hold_slave",10); +explain extended select get_lock("hold_slave",10); start slave; #hope this is long enough for I/O thread to fetch over 16K relay log data sleep 3; select release_lock("hold_slave"); +explain extended select release_lock("hold_slave"); unlock tables; connection master; diff --git a/mysql-test/t/rpl_chain_temp_table.test b/mysql-test/t/rpl_chain_temp_table.test new file mode 100644 index 00000000000..007b018e9d8 --- /dev/null +++ b/mysql-test/t/rpl_chain_temp_table.test @@ -0,0 +1,99 @@ + # This test makes some assumptions about values of thread ids, which should be +# true if the servers have been restarted for this test. So we want to +# stop/restart servers. Note that if assumptions are wrong, the test will not +# fail; it will just fail to test the error-prone scenario. +# Using the manager is the only way to have more than one slave server. +# So you must run this test with --manager. + +require_manager; +server_stop master; +server_start master; +server_stop slave; +server_start slave; +# no need for slave_sec (no assumptions on thread ids for this server). + +source include/master-slave.inc; +connect (slave_sec,localhost,root,,test,0,slave.sock-1); +connection master; +save_master_pos; +connection slave; +sync_with_master; +reset master; +save_master_pos; +connection slave_sec; +eval change master to master_host='127.0.0.1',master_port=$SLAVE_MYPORT, master_user='root'; +start slave; +sync_with_master; + +# :P now we have a chain ready-to-test. + +connection master; +create temporary table t1 (a int); +save_master_pos; +connection slave; +sync_with_master; +connection master1; +create temporary table t1 (a int); +save_master_pos; +connection slave; +sync_with_master; +save_master_pos; + +# First test: + +connection slave_sec; +# Before BUG#1686 ("If 2 master threads with same-name temp table, slave makes +# bad binlog") was fixed, sync_with_master failed +sync_with_master; +show status like 'slave_open_temp_tables'; + +# 'master' and 'master1' usually have thread id 2-3 or 3-4. +# 'slave' and 'slave1' usually have thread id 2-3. +connection slave; +create temporary table t1 (a int); +connection slave1; +create temporary table t1 (a int); +# So it's likely that in the binlog of slave we get +# server_id=of_master thread_id=3 create temp... +# server_id=of_slave thread_id=3 create temp... +# which would confuse slave-sec unless slave-sec uses server id to distinguish +# between temp tables (here thread id is obviously not enough to distinguish). + +save_master_pos; + +# Second test: + +connection slave_sec; +# If we did not use the server id to distinguish between temp tables, +# sync_with_master would fail +sync_with_master; +show status like 'slave_open_temp_tables'; + +# Third test (BUG#1240 "slave of slave breaks when STOP SLAVE was issud on +# parent slave and temp tables"). +stop slave; +connection slave; +insert into t1 values(1); +create table t2 as select * from t1; +save_master_pos; +connection slave_sec; +start slave; +sync_with_master; +show status like 'slave_open_temp_tables'; +select * from t2; + +# clean up +connection slave; +drop table t2; +save_master_pos; +connection slave_sec; +sync_with_master; + +# On purpose, we don't delete the temporary tables explicitely. +# So temp tables remain on slave (remember they are not deleted when the slave +# SQL thread terminates). If you run this test with +# --valgrind --valgrind-options=--show-reachable=yes +# you will see if they get cleaned up at slave's shutdown (that is, if the +# memory they use is freed (it should) by mysqld before it terminates). +# If they wouldn't be cleaned up, you would see some "still reachable" blocks in +# Valgrind. diff --git a/mysql-test/t/rpl_get_lock.test b/mysql-test/t/rpl_get_lock.test index e93268e6074..c3b033fb03a 100644 --- a/mysql-test/t/rpl_get_lock.test +++ b/mysql-test/t/rpl_get_lock.test @@ -5,6 +5,7 @@ insert into t1 values(get_lock("lock",2)); dirty_close master; connection master1; select get_lock("lock",2); + select release_lock("lock"); #ignore disable_query_log; @@ -21,7 +22,8 @@ connection slave; sync_with_master; select get_lock("lock",3); select * from t1; -select is_free_lock("lock"); +select is_free_lock("lock"), is_used_lock("lock"); +explain extended select is_free_lock("lock"), is_used_lock("lock"); # Check lock functions select is_free_lock("lock2"); select is_free_lock(NULL); diff --git a/mysql-test/t/rpl_master_pos_wait.test b/mysql-test/t/rpl_master_pos_wait.test index 24479636c91..4d4d51b04ab 100644 --- a/mysql-test/t/rpl_master_pos_wait.test +++ b/mysql-test/t/rpl_master_pos_wait.test @@ -7,6 +7,7 @@ sync_with_master; # Ask for a master log that has certainly not been reached yet # timeout= 2 seconds select master_pos_wait('master-bin.999999',0,2); +explain extended select master_pos_wait('master-bin.999999',0,2); # Testcase for bug 651 (master_pos_wait() hangs if slave idle and STOP SLAVE). send select master_pos_wait('master-bin.999999',0); connection slave1; diff --git a/mysql-test/t/rpl_reset_slave.test b/mysql-test/t/rpl_reset_slave.test index e03916ec73a..d58e9c711d1 100644 --- a/mysql-test/t/rpl_reset_slave.test +++ b/mysql-test/t/rpl_reset_slave.test @@ -2,6 +2,8 @@ # --master-* options from mysqld, as this is what is going to be used next time # slave threads will be started). In bug 985, it displayed old values (of before # RESET SLAVE). +# See if slave crashes when doing a CREATE TEMPORARY TABLE twice, separated by +# RESET SLAVE. source include/master-slave.inc; connection master; @@ -28,3 +30,19 @@ sync_with_master; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 33 # show slave status; + +# test of crash with temp tables & RESET SLAVE +# (test to see if RESET SLAVE clears temp tables in memory and disk) +stop slave; +reset slave; +start slave; +connection master; +create temporary table t1 (a int); +save_master_pos; +connection slave; +sync_with_master; +stop slave; +reset slave; +start slave; +sync_with_master; +show status like 'slave_open_temp_tables'; diff --git a/mysql-test/t/rpl_temporary-master.opt b/mysql-test/t/rpl_temporary-master.opt new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/mysql-test/t/rpl_temporary-master.opt diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test index f1373d7ef23..0df8ceb6377 100644 --- a/mysql-test/t/rpl_temporary.test +++ b/mysql-test/t/rpl_temporary.test @@ -108,3 +108,11 @@ drop temporary table t3; select * from t2; drop table t1,t2; + +# Create last a temporary table that is not dropped at end to ensure that we +# don't get any memory leaks for this + +create temporary table t3 (f int); +sync_with_master; + +# The server will now close done diff --git a/mysql-test/t/rpl_trunc_binlog.test b/mysql-test/t/rpl_trunc_binlog.test index 4c14ec72b5c..32052af9184 100644 --- a/mysql-test/t/rpl_trunc_binlog.test +++ b/mysql-test/t/rpl_trunc_binlog.test @@ -23,5 +23,3 @@ sleep 3; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 33 # show slave status; -connection master; -reset master; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index d727befe661..b817544bfb9 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -1596,6 +1596,7 @@ select count(*) from t1; select companynr,count(*),sum(fld1) from t2 group by companynr; select companynr,count(*) from t2 group by companynr order by companynr desc limit 5; select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 where companynr = 34 and fld4<>""; +explain extended select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 where companynr = 34 and fld4<>""; select companynr,count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 group by companynr limit 3; select companynr,t2nr,count(price),sum(price),min(price),max(price),avg(price) from t3 where companynr = 37 group by companynr,t2nr limit 10; select /*! SQL_SMALL_RESULT */ companynr,t2nr,count(price),sum(price),min(price),max(price),avg(price) from t3 where companynr = 37 group by companynr,t2nr limit 10; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 0b8d862a1fe..f356e7931c8 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4,11 +4,11 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t11,t12; --enable_warnings select (select 2); -explain select (select 2); +explain extended select (select 2); SELECT (SELECT 1) UNION SELECT (SELECT 2); -explain SELECT (SELECT 1) UNION SELECT (SELECT 2); +explain extended SELECT (SELECT 1) UNION SELECT (SELECT 2); SELECT (SELECT (SELECT 0 UNION SELECT 0)); -explain SELECT (SELECT (SELECT 0 UNION SELECT 0)); +explain extended SELECT (SELECT (SELECT 0 UNION SELECT 0)); -- error 1246 SELECT (SELECT 1 FROM (SELECT 1) as b HAVING a=1) as a; -- error 1246 @@ -16,7 +16,7 @@ SELECT (SELECT 1 FROM (SELECT 1) as b HAVING b=1) as a,(SELECT 1 FROM (SELECT 1) SELECT (SELECT 1),MAX(1) FROM (SELECT 1) as a; -- error 1246 SELECT (SELECT a) as a; -EXPLAIN SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; +EXPLAIN EXTENDED SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; -- error 1054 SELECT (SELECT 1), a; @@ -74,17 +74,17 @@ insert into t3 values (6),(7),(3); select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1); (select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 order by a limit 2) limit 3; (select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); -explain (select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); +explain extended (select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); select (select a from t3 where a<t2.a*4 order by 1 desc limit 1), a from t2; select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; -explain select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from +explain extended select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3) order by 1 desc limit 1); select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a > t1.a) order by 1 desc limit 1); select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a < t1.a) order by 1 desc limit 1); select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; -explain select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; +explain extended select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; select * from t3 where exists (select * from t2 where t2.b=t3.a); select * from t3 where not exists (select * from t2 where t2.b=t3.a); select * from t3 where a in (select b from t2); @@ -100,7 +100,7 @@ insert into t2 values (100, 5); select * from t3 where a < any (select b from t2); select * from t3 where a < all (select b from t2); select * from t3 where a >= any (select b from t2); -explain select * from t3 where a >= any (select b from t2); +explain extended select * from t3 where a >= any (select b from t2); select * from t3 where a >= all (select b from t2); delete from t2 where a=100; -- error 1240 @@ -120,7 +120,7 @@ insert into t5 values (5); select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; insert into t5 values (2); select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; -explain select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; +explain extended select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2; -- error 1241 select (select a from t1 where t1.a=t2.a union all select a from t5 where t5.a=t2.a), a from t2; create table t6 (patient_uq int, clinic_uq int, index i1 (clinic_uq)); @@ -128,7 +128,7 @@ create table t7( uq int primary key, name char(25)); insert into t7 values(1,"Oblastnaia bolnitsa"),(2,"Bolnitsa Krasnogo Kresta"); insert into t6 values (1,1),(1,2),(2,2),(1,3); select * from t6 where exists (select * from t7 where uq = clinic_uq); -explain select * from t6 where exists (select * from t7 where uq = clinic_uq); +explain extended select * from t6 where exists (select * from t7 where uq = clinic_uq); # not unique fields -- error 1052 @@ -157,7 +157,7 @@ CREATE TABLE `t8` ( INSERT INTO t8 (pseudo,email) VALUES ('joce','test'); INSERT INTO t8 (pseudo,email) VALUES ('joce1','test1'); INSERT INTO t8 (pseudo,email) VALUES ('2joce1','2test1'); -EXPLAIN SELECT pseudo,(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce')) FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'); +EXPLAIN EXTENDED SELECT pseudo,(SELECT email FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce')) FROM t8 WHERE pseudo=(SELECT pseudo FROM t8 WHERE pseudo='joce'); -- error 1240 SELECT pseudo FROM t8 WHERE pseudo=(SELECT pseudo,email FROM t8 WHERE pseudo='joce'); @@ -180,14 +180,14 @@ CREATE TABLE `t1` ( ) TYPE=MyISAM ROW_FORMAT=DYNAMIC; INSERT INTO t1 (topic,date,pseudo) VALUES ('43506','2002-10-02','joce'),('40143','2002-08-03','joce'); -EXPLAIN SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; -EXPLAIN SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'); +EXPLAIN EXTENDED SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; +EXPLAIN EXTENDED SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'); SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'); SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1) UNION ALL SELECT 1; -- error 1241 SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION ALL SELECT 1) UNION SELECT 1; -EXPLAIN SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1); +EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1); drop table t1; #forumconthardwarefr7 searchconthardwarefr7 @@ -276,9 +276,9 @@ SELECT numreponse, (SELECT numeropost FROM t1 HAVING numreponse=a) FROM (SELECT SELECT numreponse, (SELECT numeropost FROM t1 HAVING numreponse=1) FROM (SELECT * FROM t1) as a; INSERT INTO t1 (numeropost,numreponse,pseudo) VALUES (1,1,'joce'),(1,2,'joce'),(1,3,'test'); -- error 1241 -EXPLAIN SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT 1 FROM t1 WHERE numeropost='1'); -EXPLAIN SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'; -EXPLAIN SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'); +EXPLAIN EXTENDED SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT 1 FROM t1 WHERE numeropost='1'); +EXPLAIN EXTENDED SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'; +EXPLAIN EXTENDED SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'); drop table t1; CREATE TABLE t1 (a int(1)); @@ -395,11 +395,11 @@ SELECT * FROM (SELECT 1) b WHERE 1 IN (SELECT *); CREATE TABLE t2 (id int(11) default NULL, KEY id (id)) TYPE=MyISAM CHARSET=latin1; INSERT INTO t2 VALUES (1),(2); SELECT * FROM t2 WHERE id IN (SELECT 1); -EXPLAIN SELECT * FROM t2 WHERE id IN (SELECT 1); +EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1); SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3); SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1)); -EXPLAIN SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1)); -EXPLAIN SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3); +EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1)); +EXPLAIN EXTENDED SELECT * FROM t2 WHERE id IN (SELECT 1 UNION SELECT 3); SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 3); SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2); -- error 1093 @@ -455,7 +455,7 @@ select 1.5 > ALL (SELECT * from t1); select 10.5 > ALL (SELECT * from t1); select 1.5 > ANY (SELECT * from t1); select 10.5 > ANY (SELECT * from t1); -explain select (select a+1) from t1; +explain extended select (select a+1) from t1; select (select a+1) from t1; drop table t1; @@ -468,11 +468,11 @@ CREATE TABLE t2 (a int(11) default '0', INDEX (a)); INSERT INTO t1 VALUES (1),(2),(3),(4); INSERT INTO t2 VALUES (1),(2),(3); SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; -explain SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; +explain extended SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; CREATE TABLE t3 (a int(11) default '0'); INSERT INTO t3 VALUES (1),(2),(3); SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; -explain SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; +explain extended SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; drop table t1,t2,t3; #LIMIT is not supported now @@ -549,9 +549,9 @@ drop table t1; #test of uncacheable subqueries CREATE TABLE t1 (a int(1)); -EXPLAIN SELECT (SELECT RAND() FROM t1) FROM t1; -EXPLAIN SELECT (SELECT ENCRYPT('test') FROM t1) FROM t1; -EXPLAIN SELECT (SELECT BENCHMARK(1,1) FROM t1) FROM t1; +EXPLAIN EXTENDED SELECT (SELECT RAND() FROM t1) FROM t1; +EXPLAIN EXTENDED SELECT (SELECT ENCRYPT('test') FROM t1) FROM t1; +EXPLAIN EXTENDED SELECT (SELECT BENCHMARK(1,1) FROM t1) FROM t1; drop table t1; @@ -613,7 +613,7 @@ drop table t1; create table t1 (a int); insert into t1 values (1), (2), (3); -explain select a,(select (select rand() from t1 limit 1) from t1 limit 1) +explain extended select a,(select (select rand() from t1 limit 1) from t1 limit 1) from t1; drop table t1; @@ -677,10 +677,10 @@ CREATE TABLE `t1` ( ) TYPE=MyISAM PACK_KEYS=1 ROW_FORMAT=DYNAMIC; INSERT INTO t1 (pseudo) VALUES ('test'); SELECT 0 IN (SELECT 1 FROM t1 a); -EXPLAIN SELECT 0 IN (SELECT 1 FROM t1 a); +EXPLAIN EXTENDED SELECT 0 IN (SELECT 1 FROM t1 a); INSERT INTO t1 (pseudo) VALUES ('test1'); SELECT 0 IN (SELECT 1 FROM t1 a); -EXPLAIN SELECT 0 IN (SELECT 1 FROM t1 a); +EXPLAIN EXTENDED SELECT 0 IN (SELECT 1 FROM t1 a); drop table t1; CREATE TABLE `t1` ( @@ -727,7 +727,7 @@ drop table t1; # create table t1 (id int not null auto_increment primary key, salary int, key(salary)); insert into t1 (salary) values (100),(1000),(10000),(10),(500),(5000),(50000); -explain SELECT id FROM t1 where salary = (SELECT MAX(salary) FROM t1); +explain extended SELECT id FROM t1 where salary = (SELECT MAX(salary) FROM t1); drop table t1; CREATE TABLE t1 ( @@ -794,11 +794,11 @@ insert into t1 values (1,10), (2,20), (3,30), (4,40); insert into t2 values (2), (3), (4), (5); insert into t3 values (10,3), (20,4), (30,5); select * from t2 where t2.a in (select a from t1); -explain select * from t2 where t2.a in (select a from t1); +explain extended select * from t2 where t2.a in (select a from t1); select * from t2 where t2.a in (select a from t1 where t1.b <> 30); -explain select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); -explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); drop table t1, t2, t3; create table t1 (a int, b int, index a (a,b)); create table t2 (a int, index a (a)); @@ -816,15 +816,15 @@ enable_query_log; insert into t2 values (2), (3), (4), (5); insert into t3 values (10,3), (20,4), (30,5); select * from t2 where t2.a in (select a from t1); -explain select * from t2 where t2.a in (select a from t1); +explain extended select * from t2 where t2.a in (select a from t1); select * from t2 where t2.a in (select a from t1 where t1.b <> 30); -explain select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); -explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +explain extended select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); insert into t1 values (3,31); select * from t2 where t2.a in (select a from t1 where t1.b <> 30); select * from t2 where t2.a in (select a from t1 where t1.b <> 30 and t1.b <> 31); -explain select * from t2 where t2.a in (select a from t1 where t1.b <> 30); +explain extended select * from t2 where t2.a in (select a from t1 where t1.b <> 30); drop table t1, t2, t3; # @@ -891,7 +891,7 @@ create table t1 (s1 char(5)); select (select 'a','b' from t1 union select 'a','b' from t1) from t1; insert into t1 values ('tttt'); select * from t1 where ('a','b')=(select 'a','b' from t1 union select 'a','b' from t1); -explain (select * from t1); +explain extended (select * from t1); (select * from t1); drop table t1; @@ -906,10 +906,10 @@ select s1, s1 NOT IN (SELECT s1 FROM t2) from t1; select s1, s1 = ANY (SELECT s1 FROM t2) from t1; select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; -explain select s1, s1 NOT IN (SELECT s1 FROM t2) from t1; -explain select s1, s1 = ANY (SELECT s1 FROM t2) from t1; -explain select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; -explain select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; +explain extended select s1, s1 NOT IN (SELECT s1 FROM t2) from t1; +explain extended select s1, s1 = ANY (SELECT s1 FROM t2) from t1; +explain extended select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; +explain extended select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; drop table t1,t2; # @@ -919,14 +919,14 @@ create table t2 (a int, b int); create table t3 (a int); insert into t3 values (6),(7),(3); select * from t3 where a >= all (select b from t2); -explain select * from t3 where a >= all (select b from t2); +explain extended select * from t3 where a >= all (select b from t2); # # optimized static ALL/ANY with grouping # insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); -explain select * from t3 where a > all (select max(b) from t2 group by a); +explain extended select * from t3 where a > all (select max(b) from t2 group by a); drop table t2, t3; # diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test index f618c342936..4be0cd0c6a2 100644 --- a/mysql-test/t/symlink.test +++ b/mysql-test/t/symlink.test @@ -65,7 +65,7 @@ drop table t1; # disable_query_log; ---error 1103,1103 +--error 1279,1279 create table t1 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam data directory="tmp"; # Check that we cannot link over a table from another database. @@ -75,7 +75,7 @@ create database mysqltest; --error 1,1 create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="/this-dir-does-not-exist"; ---error 1103,1103 +--error 1279,1279 create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="not-hard-path"; --error 1,1 diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test index ebe342a4ef5..c9c3284fe0d 100644 --- a/mysql-test/t/type_blob.test +++ b/mysql-test/t/type_blob.test @@ -298,6 +298,10 @@ select charset(load_file('../../std_data/words.dat')), collation(load_file('../../std_data/words.dat')), coercibility(load_file('../../std_data/words.dat')); +explain extended select + charset(load_file('../../std_data/words.dat')), + collation(load_file('../../std_data/words.dat')), + coercibility(load_file('../../std_data/words.dat')); update t1 set imagem=load_file('../../std_data/words.dat') where id=1; select if(imagem is null, "ERROR", "OK"),length(imagem) from t1 where id = 1; drop table t1; diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index b64f0b4e2ee..1f3f4085734 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -25,7 +25,7 @@ select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 g (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; --error 1249 (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by t1.b; -explain (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; +explain extended (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; (select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2; select found_rows(); select sql_calc_found_rows a,b from t1 union all select a,b from t2 limit 2; @@ -275,7 +275,7 @@ create table t2 (a int not null primary key auto_increment, b int); insert into t1 (b) values (1),(2),(2),(3); insert into t2 (b) values (10),(11),(12),(13); -explain (select * from t1 where a=1) union (select * from t2 where a=1); +explain extended (select * from t1 where a=1) union (select * from t2 where a=1); (select * from t1 where a=5) union (select * from t2 where a=1); (select * from t1 where a=5 and a=6) union (select * from t2 where a=1); (select t1.a,t1.b from t1,t2 where t1.a=5) union (select * from t2 where a=1); diff --git a/mysql-test/t/varbinary.test b/mysql-test/t/varbinary.test index d58954a189b..9425bd7bd99 100644 --- a/mysql-test/t/varbinary.test +++ b/mysql-test/t/varbinary.test @@ -18,7 +18,7 @@ select x'31',X'ffff'+0; create table t1 (ID int(8) unsigned zerofill not null auto_increment,UNIQ bigint(21) unsigned zerofill not null,primary key (ID),unique (UNIQ) ); insert into t1 set UNIQ=0x38afba1d73e6a18a; insert into t1 set UNIQ=123; -explain select * from t1 where UNIQ=0x38afba1d73e6a18a; +explain extended select * from t1 where UNIQ=0x38afba1d73e6a18a; drop table t1; # diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index c53559ed4cf..6365ad77c57 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -16,6 +16,7 @@ select @test_int,@test_double,@test_string,@test_string2; set @test_int=null,@test_double=null,@test_string=null,@test_string2=null; select @test_int,@test_double,@test_string,@test_string2; select @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3; +explain extended select @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3; select @t5; # @@ -52,7 +53,9 @@ select @@local.max_join_size, @@global.max_join_size; select @@identity, length(@@version)>0; select @@VERSION=version(); select last_insert_id(345); +explain extended select last_insert_id(345); select @@IDENTITY,last_insert_id(), @@identity; +explain extended select @@IDENTITY,last_insert_id(), @@identity; set big_tables=OFF, big_tables=ON, big_tables=0, big_tables=1, big_tables="OFF", big_tables="ON"; diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 5ff682fbc80..37c79e28395 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -47,7 +47,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ my_delete.c my_rename.c my_redel.c my_tempnam.c \ my_chsize.c my_lread.c my_lwrite.c my_clock.c \ my_quick.c my_lockmem.c my_static.c \ - my_getopt.c my_mkdir.c \ + my_sync.c my_getopt.c my_mkdir.c \ default.c my_compress.c checksum.c raid.cc \ my_net.c my_semaphore.c my_port.c my_sleep.c \ charset.c charset-def.c my_bitmap.c my_bit.c md5.c \ diff --git a/mysys/default.c b/mysys/default.c index 15eb358df22..b1d9e40a1c2 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -214,6 +214,7 @@ int load_defaults(const char *conf_file, const char **groups, res= (char**) (ptr+sizeof(alloc)); /* copy name + found arguments + command line arguments to new array */ + res[0]= argv[0][0]; /* Name MUST be set, even by embedded library */ memcpy((gptr) (res+1), args.buffer, args.elements*sizeof(char*)); /* Skipp --defaults-file and --defaults-extra-file */ (*argc)-= args_used; diff --git a/mysys/errors.c b/mysys/errors.c index a2226fc12c5..255b6893c73 100644 --- a/mysys/errors.c +++ b/mysys/errors.c @@ -48,6 +48,7 @@ const char * NEAR globerrs[GLOBERRS]= "Can't read value for symlink '%s' (Error %d)", "Can't create symlink '%s' pointing at '%s' (Error %d)", "Error on realpath() on '%s' (Error %d)", + "Can't sync file '%s' to disk (Errcode: %d)", }; void init_glob_errs(void) @@ -84,8 +85,9 @@ void init_glob_errs() EE(EE_CANT_MKDIR) ="Can't create directory '%s' (Errcode: %d)"; EE(EE_UNKNOWN_CHARSET)= "Character set '%s' is not a compiled character set and is not specified in the %s file"; EE(EE_OUT_OF_FILERESOURCES)="Out of resources when opening file '%s' (Errcode: %d)"; - EE(EE_CANT_READLINK)="Can't read value for symlink '%s' (Error %d)"; - EE(EE_CANT_SYMLINK)="Can't create symlink '%s' pointing at '%s' (Error %d)"; - EE(EE_REALPATH)="Error on realpath() on '%s' (Error %d)"; + EE(EE_CANT_READLINK)= "Can't read value for symlink '%s' (Error %d)"; + EE(EE_CANT_SYMLINK)= "Can't create symlink '%s' pointing at '%s' (Error %d)"; + EE(EE_REALPATH)= "Error on realpath() on '%s' (Error %d)"; + EE(EE_SYNC)= "Can't sync file '%s' to disk (Errcode: %d)"; } #endif diff --git a/mysys/my_new.cc b/mysys/my_new.cc index 5cc291af9aa..5f2da90bbd1 100644 --- a/mysys/my_new.cc +++ b/mysys/my_new.cc @@ -25,12 +25,12 @@ void *operator new (size_t sz) { - return (void *) malloc (sz ? sz+1 : sz); + return (void *) malloc (sz ? sz : 1); } void *operator new[] (size_t sz) { - return (void *) malloc (sz ? sz+1 : sz); + return (void *) malloc (sz ? sz : 1); } void operator delete (void *ptr) diff --git a/mysys/my_sync.c b/mysys/my_sync.c new file mode 100644 index 00000000000..317ca039346 --- /dev/null +++ b/mysys/my_sync.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "mysys_priv.h" +#include "mysys_err.h" +#include <errno.h> + +/* + Sync data in file to disk + + SYNOPSIS + my_sync() + fd File descritor to sync + my_flags Flags (now only MY_WME is supported) + + NOTE + If file system supports its, only file data is synced, not inode date + + RETURN + 0 ok + -1 error +*/ + +int my_sync(File fd, myf my_flags) +{ + int res; + DBUG_ENTER("my_sync"); + DBUG_PRINT("my",("Fd: %d my_flags: %d", fd, my_flags)); + +#if defined(HAVE_FDATASYNC) + res= fdatasync(fd); +#elif defined(HAVE_FSYNC) + res=fsync(fd); +#elif defined(__WIN__) + res= _commit(fd); +#else + res= 0; /* No sync (strange OS) */ +#endif + if (res) + { + if (!(my_errno= errno)) + my_errno= -1; /* Unknown error */ + if (my_flags & MY_WME) + my_error(EE_SYNC, MYF(ME_BELL+ME_WAITTANG), my_filename(fd), my_errno); + } + DBUG_RETURN(res); +} /* my_read */ diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 32bc8ea3724..9ee7371b639 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -159,6 +159,7 @@ my_bool my_thread_init(void) tmp->id= ++thread_id; pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST); pthread_cond_init(&tmp->suspend, NULL); + tmp->init= 1; end: #if !defined(__WIN__) || defined(USE_TLS) || ! defined(SAFE_MUTEX) @@ -170,12 +171,14 @@ end: void my_thread_end(void) { - struct st_my_thread_var *tmp=my_thread_var; + struct st_my_thread_var *tmp; + tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys); + #ifdef EXTRA_DEBUG_THREADS fprintf(stderr,"my_thread_end(): tmp=%p,thread_id=%ld\n", tmp,pthread_self()); #endif - if (tmp) + if (tmp && tmp->init) { #if !defined(DBUG_OFF) /* tmp->dbug is allocated inside DBUG library */ @@ -191,6 +194,8 @@ void my_thread_end(void) pthread_mutex_destroy(&tmp->mutex); #if (!defined(__WIN__) && !defined(OS2)) || defined(USE_TLS) free(tmp); +#else + tmp->init= 0; #endif } /* The following free has to be done, even if my_thread_var() is 0 */ diff --git a/mysys/test_charset.c b/mysys/test_charset.c index 6b0f728593a..419332cb997 100644 --- a/mysys/test_charset.c +++ b/mysys/test_charset.c @@ -78,6 +78,7 @@ int main(int argc, char **argv) { _print_csinfo(cs); fflush(stdout); +#define NOT_USED_ANYMORE cs_list = list_charsets(MYF(MY_CS_COMPILED | MY_CS_CONFIG)); printf("LIST OF CHARSETS (compiled + *.conf):\n%s\n", cs_list); my_free(cs_list,MYF(0)); @@ -85,6 +86,7 @@ int main(int argc, char **argv) { cs_list = list_charsets(MYF(MY_CS_INDEX | MY_CS_LOADED)); printf("LIST OF CHARSETS (index + loaded):\n%s\n", cs_list); my_free(cs_list,MYF(0)); +#endif return 0; } diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index 36bbac16fef..bf40ffc5b4d 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -714,6 +714,9 @@ void thr_alarm_info(ALARM_INFO *info) bzero((char*) info, sizeof(*info)); } +void resize_thr_alarm(uint max_alarms) +{ +} /***************************************************************************** thr_alarm for win95 @@ -793,6 +796,10 @@ void thr_alarm_info(ALARM_INFO *info) bzero((char*) info, sizeof(*info)); } +void resize_thr_alarm(uint max_alarms) +{ +} + #endif /* __WIN__ */ #endif /* THREAD */ diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index adaac0f3102..acf0f8aa2c8 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -167,7 +167,7 @@ then fi fi -if test "$ip_only" ="1" +if test "$ip_only" = "1" then ip=`echo "$resolved" | awk '/ /{print $6}'` hostname=$ip diff --git a/scripts/mysql_secure_installation.sh b/scripts/mysql_secure_installation.sh index d6392c57731..1c7ca34ad59 100644 --- a/scripts/mysql_secure_installation.sh +++ b/scripts/mysql_secure_installation.sh @@ -85,9 +85,13 @@ set_root_password() { return 1 fi - do_query "SET PASSWORD FOR root=PASSWORD('$password1');" + do_query "UPDATE mysql.user SET Password=PASSWORD('$password1') WHERE User='root';" if [ $? -eq 0 ]; then echo "Password updated successfully!" + echo "Reloading privilege tables.." + if ! reload_privilege_tables; then + exit 1 + fi echo rootpass=$password1 make_config @@ -144,11 +148,11 @@ reload_privilege_tables() { do_query "FLUSH PRIVILEGES;" if [ $? -eq 0 ]; then echo " ... Success!" + return 0 else echo " ... Failed!" + return 1 fi - - return 0 } interrupt() { diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index f23955da06a..654e5466e12 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -37,7 +37,7 @@ WARNING: THIS PROGRAM IS STILL IN BETA. Comments/patches welcome. # Documentation continued at end of file -my $VERSION = "1.19"; +my $VERSION = "1.20"; my $opt_tmpdir = $ENV{TMPDIR} || "/tmp"; @@ -235,10 +235,15 @@ else # --- resolve database names from regexp --- if ( defined $opt{regexp} ) { + my $t_regex = '.*'; + if ( $opt{regexp} =~ s{^/(.+)/\./(.+)/$}{$1} ) { + $t_regex = $2; + } + my $sth_dbs = $dbh->prepare("show databases"); $sth_dbs->execute; while ( my ($db_name) = $sth_dbs->fetchrow_array ) { - push @db_desc, { 'src' => $db_name } if ( $db_name =~ m/$opt{regexp}/o ); + push @db_desc, { 'src' => $db_name, 't_regex' => $t_regex } if ( $db_name =~ m/$opt{regexp}/o ); } } @@ -413,6 +418,8 @@ foreach my $rdb ( @db_desc ) { else { mkdir($tgt_dirpath, 0750) or die "Can't create '$tgt_dirpath': $!\n" unless -d $tgt_dirpath; + my @f_info= stat "$datadir/$rdb->{src}"; + chown $f_info[4], $f_info[5], $tgt_dirpath; } } } @@ -938,6 +945,14 @@ server in a mutual replication setup. Copy all databases with names matching the pattern +=item --regexp /pattern1/./pattern2/ + +Copy all tables with names matching pattern2 from all databases with +names matching pattern1. For example, to select all tables which +names begin with 'bar' from all databases which names end with 'foo': + + mysqlhotcopy --indices --method=cp --regexp /foo$/./^bar/ + =item db_name./pattern/ Copy only tables matching pattern. Shell metacharacters ( (, ), |, !, diff --git a/sql-common/client.c b/sql-common/client.c index 15f906f4e34..85308539222 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1419,7 +1419,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, char buff[NAME_LEN+USERNAME_LENGTH+100],charset_name_buff[16]; char *end,*host_info,*charset_name; my_socket sock; - uint32 ip_addr; + in_addr_t ip_addr; struct sockaddr_in sock_addr; ulong pkt_length; NET *net= &mysql->net; diff --git a/sql/Makefile.am b/sql/Makefile.am index 69b9c58dd6d..0167124a892 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -63,7 +63,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \ thr_malloc.cc item_create.cc item_subselect.cc \ item_row.cc item_geofunc.cc \ - field.cc key.cc sql_class.cc sql_list.cc \ + field.cc strfunc.cc key.cc sql_class.cc sql_list.cc \ net_serv.cc protocol.cc sql_state.c \ lock.cc my_lock.c \ sql_string.cc sql_manager.cc sql_map.cc \ diff --git a/sql/derror.cc b/sql/derror.cc index f5fe92da238..ad7432f7675 100644 --- a/sql/derror.cc +++ b/sql/derror.cc @@ -117,7 +117,7 @@ Check that the above file is the right version for this program!", point[i]= *point +uint2korr(head+10+i+i); } VOID(my_close(file,MYF(0))); - DBUG_RETURN(FALSE); + DBUG_RETURN(0); err: switch (funktpos) { @@ -136,7 +136,7 @@ err1: if (file != FERR) VOID(my_close(file,MYF(MY_WME))); unireg_abort(1); - return 1; + DBUG_RETURN(1); // Impossible } /* read_texts */ diff --git a/sql/field.cc b/sql/field.cc index c30c06c6395..04e9c45327b 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -274,13 +274,14 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) return copy->length+(int) copy->strip; } -bool Field::get_date(TIME *ltime,bool fuzzydate) + +bool Field::get_date(TIME *ltime,uint fuzzydate) { char buff[40]; String tmp(buff,sizeof(buff),&my_charset_bin),tmp2,*res; if (!(res=val_str(&tmp,&tmp2)) || - str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate,current_thd)<= - WRONG_TIMESTAMP_FULL) + str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) <= + TIMESTAMP_DATETIME_ERROR) return 1; return 0; } @@ -290,39 +291,44 @@ bool Field::get_time(TIME *ltime) char buff[40]; String tmp(buff,sizeof(buff),&my_charset_bin),tmp2,*res; if (!(res=val_str(&tmp,&tmp2)) || - str_to_time(res->ptr(),res->length(),ltime,current_thd)) + str_to_time(res->ptr(),res->length(),ltime)) return 1; return 0; } +/* + This is called when storing a date in a string + + NOTES + Needs to be changed if/when we want to support different time formats +*/ -/* This is called when storing a date in a string */ void Field::store_time(TIME *ltime,timestamp_type type) { char buff[25]; - String tmp((char*) buff,sizeof(buff),&my_charset_bin); - DATETIME_FORMAT *tmp_format= 0; - bool is_time_only= 0; - switch (type) { case TIMESTAMP_NONE: - case WRONG_TIMESTAMP_FULL: + case TIMESTAMP_DATETIME_ERROR: store("",0,&my_charset_bin); // Probably an error - return; + break; case TIMESTAMP_DATE: - tmp_format= &t_datetime_frm(current_thd, DATE_FORMAT_TYPE).datetime_format; + sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day); + store(buff,10,&my_charset_bin); break; - case TIMESTAMP_FULL: - tmp_format=&t_datetime_frm(current_thd,DATETIME_FORMAT_TYPE).datetime_format; + case TIMESTAMP_DATETIME: + sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d", + ltime->year,ltime->month,ltime->day, + ltime->hour,ltime->minute,ltime->second); + store(buff,19,&my_charset_bin); break; case TIMESTAMP_TIME: - tmp_format= &t_datetime_frm(current_thd, TIME_FORMAT_TYPE).datetime_format; - is_time_only= 1; + { + ulong length= my_sprintf(buff, (buff, "%02d:%02d:%02d", + ltime->hour,ltime->minute,ltime->second)); + store(buff,(uint) length, &my_charset_bin); break; } - make_datetime(&tmp, ltime, is_time_only, 0, - tmp_format->format, tmp_format->format_length, 1); - store(tmp.ptr(),tmp.length(),&my_charset_bin); + } } @@ -2693,7 +2699,7 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) { - long tmp=(long) str_to_timestamp(from,len,current_thd); + long tmp=(long) str_to_timestamp(from,len); #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -2908,7 +2914,7 @@ String *Field_timestamp::val_str(String *val_buffer, } -bool Field_timestamp::get_date(TIME *ltime, bool fuzzydate) +bool Field_timestamp::get_date(TIME *ltime, uint fuzzydate) { long temp; #ifdef WORDS_BIGENDIAN @@ -2937,7 +2943,7 @@ bool Field_timestamp::get_date(TIME *ltime, bool fuzzydate) ltime->second= start->tm_sec; ltime->second_part= 0; ltime->neg= 0; - ltime->time_type=TIMESTAMP_FULL; + ltime->time_type=TIMESTAMP_DATETIME; } return 0; } @@ -2951,7 +2957,7 @@ bool Field_timestamp::get_time(TIME *ltime) bool Field_timestamp::send_binary(Protocol *protocol) { TIME tm; - Field_timestamp::get_date(&tm, 1); + Field_timestamp::get_date(&tm, TIME_FUZZY_DATE); return protocol->store(&tm); } @@ -3027,7 +3033,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) TIME ltime; long tmp; int error= 0; - if (str_to_time(from,len,<ime,current_thd)) + if (str_to_time(from,len,<ime)) { tmp=0L; error= 1; @@ -3137,27 +3143,23 @@ String *Field_time::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { TIME ltime; - val_buffer->alloc(16); + val_buffer->alloc(19); long tmp=(long) sint3korr(ptr); - const char *sign=""; ltime.neg= 0; if (tmp < 0) { tmp= -tmp; ltime.neg= 1; } - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (current_thd, TIME_FORMAT_TYPE).datetime_format); ltime.day= (uint) 0; ltime.hour= (uint) (tmp/10000); ltime.minute= (uint) (tmp/100 % 100); ltime.second= (uint) (tmp % 100); - make_datetime(val_buffer, <ime, 0, 0, - tmp_format->format, - tmp_format->format_length, 1); + make_time((DATE_TIME_FORMAT*) 0, <ime, val_buffer); return val_buffer; } + bool Field_time::get_time(TIME *ltime) { long tmp=(long) sint3korr(ptr); @@ -3320,7 +3322,7 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs) TIME l_time; uint32 tmp; int error= 0; - if (str_to_TIME(from,len,&l_time,1,current_thd) <= WRONG_TIMESTAMP_FULL) + if (str_to_TIME(from,len,&l_time,1) <= TIMESTAMP_DATETIME_ERROR) { tmp=0; error= 1; @@ -3432,7 +3434,6 @@ String *Field_date::val_str(String *val_buffer, { TIME ltime; val_buffer->alloc(field_length); - val_buffer->length(field_length); int32 tmp; #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -3440,18 +3441,15 @@ String *Field_date::val_str(String *val_buffer, else #endif longget(tmp,ptr); - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (current_thd, DATE_FORMAT_TYPE).datetime_format); ltime.neg= 0; ltime.year= (int) ((uint32) tmp/10000L % 10000); ltime.month= (int) ((uint32) tmp/100 % 100); ltime.day= (int) ((uint32) tmp % 100); - make_datetime(val_buffer, <ime, 0, 0, - tmp_format->format, - tmp_format->format_length, 1); + make_date((DATE_TIME_FORMAT *) 0, <ime, val_buffer); return val_buffer; } + int Field_date::cmp(const char *a_ptr, const char *b_ptr) { int32 a,b; @@ -3507,7 +3505,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs) TIME l_time; long tmp; int error= 0; - if (str_to_TIME(from,len,&l_time,1,current_thd) <= WRONG_TIMESTAMP_FULL) + if (str_to_TIME(from,len,&l_time,1) <= TIMESTAMP_DATETIME_ERROR) { tmp=0L; error= 1; @@ -3572,7 +3570,7 @@ int Field_newdate::store(longlong nr) void Field_newdate::store_time(TIME *ltime,timestamp_type type) { long tmp; - if (type == TIMESTAMP_DATE || type == TIMESTAMP_FULL) + if (type == TIMESTAMP_DATE || type == TIMESTAMP_DATETIME) tmp=ltime->year*16*32+ltime->month*32+ltime->day; else { @@ -3628,7 +3626,7 @@ String *Field_newdate::val_str(String *val_buffer, return val_buffer; } -bool Field_newdate::get_date(TIME *ltime,bool fuzzydate) +bool Field_newdate::get_date(TIME *ltime,uint fuzzydate) { if (is_null()) return 1; @@ -3676,7 +3674,7 @@ void Field_newdate::sql_type(String &res) const int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs) { - longlong tmp=str_to_datetime(from,len,1,current_thd); + longlong tmp=str_to_datetime(from,len,1); #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -3730,7 +3728,7 @@ int Field_datetime::store(longlong nr) void Field_datetime::store_time(TIME *ltime,timestamp_type type) { longlong tmp; - if (type == TIMESTAMP_DATE || type == TIMESTAMP_FULL) + if (type == TIMESTAMP_DATE || type == TIMESTAMP_DATETIME) tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+ (ltime->hour*10000L+ltime->minute*100+ltime->second)); else @@ -3751,7 +3749,7 @@ void Field_datetime::store_time(TIME *ltime,timestamp_type type) bool Field_datetime::send_binary(Protocol *protocol) { TIME tm; - Field_datetime::get_date(&tm, 1); + Field_datetime::get_date(&tm, TIME_FUZZY_DATE); return protocol->store(&tm); } @@ -3822,14 +3820,14 @@ String *Field_datetime::val_str(String *val_buffer, return val_buffer; } -bool Field_datetime::get_date(TIME *ltime,bool fuzzydate) +bool Field_datetime::get_date(TIME *ltime, uint fuzzydate) { longlong tmp=Field_datetime::val_int(); uint32 part1,part2; part1=(uint32) (tmp/LL(1000000)); part2=(uint32) (tmp - (ulonglong) part1*LL(1000000)); - ltime->time_type= TIMESTAMP_FULL; + ltime->time_type= TIMESTAMP_DATETIME; ltime->neg= 0; ltime->second_part= 0; ltime->second= (int) (part2%100); @@ -4921,26 +4919,6 @@ void Field_enum::store_type(ulonglong value) } -uint find_enum(TYPELIB *lib,const char *x, uint length) -{ - const char *end=x+length; - while (end > x && my_isspace(system_charset_info,end[-1])) - end--; - - const char *i; - const char *j; - for (uint pos=0 ; (j=lib->type_names[pos]) ; pos++) - { - for (i=x ; i != end && - my_toupper(system_charset_info,*i) == - my_toupper(system_charset_info,*j) ; i++, j++) ; - if (i == end && ! *j) - return(pos+1); - } - return(0); -} - - /* ** Note. Storing a empty string in a enum field gives a warning ** (if there isn't a empty value in the enum) @@ -4958,7 +4936,11 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) from= tmpstr.ptr(); length= tmpstr.length(); } - uint tmp=find_enum(typelib,from,length); + + /* Remove end space */ + while (length > 0 && my_isspace(system_charset_info,from[length-1])) + length--; + uint tmp=find_type(typelib, from, length, 0); if (!tmp) { if (length < 6) // Can't be more than 99999 enums @@ -5111,49 +5093,8 @@ void Field_enum::sql_type(String &res) const For example "One,two,five" If one uses this string in a number context one gets the bits as a longlong number. - - If there was a value in string that wasn't in set, the 'err_pos' points to - the last invalid value found. 'err_len' will be set to length of the - error string. */ -ulonglong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos, - uint *err_len, bool *set_warning) -{ - const char *end= x + length; - *err_pos= 0; // No error yet - while (end > x && my_isspace(system_charset_info, end[-1])) - end--; - - *err_len= 0; - ulonglong found= 0; - if (x != end) - { - const char *start= x; - for (;;) - { - const char *pos= start; - uint var_len; - - for (; pos != end && *pos != field_separator; pos++) ; - var_len= (uint) (pos - start); - uint find= find_enum(lib, start, var_len); - if (!find) - { - *err_pos= (char*) start; - *err_len= var_len; - *set_warning= 1; - } - else - found|= ((longlong) 1 << (find - 1)); - if (pos == end) - break; - start= pos + 1; - } - } - return found; -} - int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) { @@ -5512,7 +5453,7 @@ create_field::create_field(Field *old_field,Field *orig_field) case 3: sql_type= FIELD_TYPE_MEDIUM_BLOB; break; default: sql_type= FIELD_TYPE_LONG_BLOB; break; } - length /= charset->mbmaxlen; + length /= charset->mbmaxlen; // QQ: Probably not needed break; case FIELD_TYPE_STRING: case FIELD_TYPE_VAR_STRING: diff --git a/sql/field.h b/sql/field.h index e7d4bb2416a..692e64d1146 100644 --- a/sql/field.h +++ b/sql/field.h @@ -224,7 +224,7 @@ public: uint offset(); // Should be inline ... void copy_from_tmp(int offset); uint fill_cache_field(struct st_cache_field *copy); - virtual bool get_date(TIME *ltime,bool fuzzydate); + virtual bool get_date(TIME *ltime,uint fuzzydate); virtual bool get_time(TIME *ltime); virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; } virtual bool has_charset(void) const { return FALSE; } @@ -647,7 +647,7 @@ public: longget(tmp,ptr); return tmp; } - bool get_date(TIME *ltime,bool fuzzydate); + bool get_date(TIME *ltime,uint fuzzydate); bool get_time(TIME *ltime); }; @@ -735,7 +735,7 @@ public: void sql_type(String &str) const; bool store_for_compare() { return 1; } bool zero_pack() const { return 1; } - bool get_date(TIME *ltime,bool fuzzydate); + bool get_date(TIME *ltime,uint fuzzydate); bool get_time(TIME *ltime); }; @@ -805,7 +805,7 @@ public: void sql_type(String &str) const; bool store_for_compare() { return 1; } bool zero_pack() const { return 1; } - bool get_date(TIME *ltime,bool fuzzydate); + bool get_date(TIME *ltime,uint fuzzydate); bool get_time(TIME *ltime); }; @@ -1160,9 +1160,6 @@ uint pack_length_to_packflag(uint type); uint32 calc_pack_length(enum_field_types type,uint32 length); bool set_field_to_null(Field *field); bool set_field_to_null_with_conversions(Field *field, bool no_conversions); -uint find_enum(TYPELIB *typelib,const char *x, uint length); -ulonglong find_set(TYPELIB *typelib,const char *x, uint length, - char **err_pos, uint *err_len, bool *set_warning); bool test_if_int(const char *str, int length, const char *int_end, CHARSET_INFO *cs); diff --git a/sql/init.cc b/sql/init.cc index 8b15fef4ee3..033dfd72843 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -42,8 +42,6 @@ void unireg_init(ulong options) #endif VOID(strmov(reg_ext,".frm")); - for (i=0 ; i < 6 ; i++) // YYMMDDHHMMSS - dayord.pos[i]=i; specialflag=SPECIAL_SAME_DB_NAME; /* Make a tab of powers of 10 */ for (i=0,nr=1.0; i < array_elements(log_10) ; i++) diff --git a/sql/item.cc b/sql/item.cc index e1373cee41f..d76ab529db5 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -46,8 +46,10 @@ Item::Item(): collation.set(default_charset(), DERIVATION_COERCIBLE); name= 0; decimals= 0; max_length= 0; - thd= current_thd; - next= thd->free_list; // Put in free list + + /* Put item in free list so that we can free all items at end */ + THD *thd= current_thd; + next= thd->free_list; thd->free_list= this; /* Item constructor can be called during execution other then SQL_COM @@ -69,7 +71,7 @@ Item::Item(): Used for duplicating lists in processing queries with temporary tables */ -Item::Item(THD *c_thd, Item &item): +Item::Item(THD *thd, Item &item): str_value(item.str_value), name(item.name), max_length(item.max_length), @@ -82,11 +84,23 @@ Item::Item(THD *c_thd, Item &item): fixed(item.fixed), collation(item.collation) { - next=c_thd->free_list; // Put in free list - thd= c_thd; + next= thd->free_list; // Put in free list thd->free_list= this; } + +void Item::print_item_w_name(String *str) +{ + print(str); + if (name) + { + str->append(" AS `", 5); + str->append(name); + str->append('`'); + } +} + + // Constructor used by Item_field & Item_ref (see Item comment) Item_ident::Item_ident(THD *thd, Item_ident &item): Item(thd, item), @@ -170,13 +184,13 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const As a extra convenience the time structure is reset on error! */ -bool Item::get_date(TIME *ltime,bool fuzzydate) +bool Item::get_date(TIME *ltime,uint fuzzydate) { char buff[40]; String tmp(buff,sizeof(buff), &my_charset_bin),*res; if (!(res=val_str(&tmp)) || - str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate, thd) <= - WRONG_TIMESTAMP_FULL) + str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) <= + TIMESTAMP_DATETIME_ERROR) { bzero((char*) ltime,sizeof(*ltime)); return 1; @@ -194,7 +208,7 @@ bool Item::get_time(TIME *ltime) char buff[40]; String tmp(buff,sizeof(buff),&my_charset_bin),*res; if (!(res=val_str(&tmp)) || - str_to_time(res->ptr(),res->length(),ltime, thd)) + str_to_time(res->ptr(),res->length(),ltime)) { bzero((char*) ltime,sizeof(*ltime)); return 1; @@ -347,7 +361,7 @@ String *Item_field::str_result(String *str) return result_field->val_str(str,&str_value); } -bool Item_field::get_date(TIME *ltime,bool fuzzydate) +bool Item_field::get_date(TIME *ltime,uint fuzzydate) { if ((null_value=field->is_null()) || field->get_date(ltime,fuzzydate)) { @@ -357,7 +371,7 @@ bool Item_field::get_date(TIME *ltime,bool fuzzydate) return 0; } -bool Item_field::get_date_result(TIME *ltime,bool fuzzydate) +bool Item_field::get_date_result(TIME *ltime,uint fuzzydate) { if ((null_value=result_field->is_null()) || result_field->get_date(ltime,fuzzydate)) @@ -422,6 +436,7 @@ bool Item_field::eq(const Item *item, bool binary_cmp) const db_name)))))); } + table_map Item_field::used_tables() const { if (field->table->const_table) @@ -429,6 +444,7 @@ table_map Item_field::used_tables() const return (depended_from ? OUTER_REF_TABLE_BIT : field->table->map); } + Item *Item_field::get_tmp_table_item(THD *thd) { Item_field *new_item= new Item_field(thd, *this); @@ -437,49 +453,49 @@ Item *Item_field::get_tmp_table_item(THD *thd) return new_item; } + String *Item_int::val_str(String *str) { - str->set(value, default_charset()); + str->set(value, &my_charset_bin); return str; } void Item_int::print(String *str) { - if (!name) - { - str_value.set(value, default_charset()); - name=str_value.c_ptr(); - } - str->append(name); + // my_charset_bin is good enough for numbers + str_value.set(value, &my_charset_bin); + str->append(str_value); } + String *Item_uint::val_str(String *str) { - str->set((ulonglong) value, default_charset()); + str->set((ulonglong) value, &my_charset_bin); return str; } + void Item_uint::print(String *str) { - if (!name) - { - str_value.set((ulonglong) value, default_charset()); - name=str_value.c_ptr(); - } - str->append(name); + // latin1 is good enough for numbers + str_value.set((ulonglong) value, default_charset()); + str->append(str_value); } String *Item_real::val_str(String *str) { - str->set(value,decimals,default_charset()); + str->set(value,decimals,&my_charset_bin); return str; } + void Item_string::print(String *str) { + str->append('_'); + str->append(collation.collation->csname); str->append('\''); - str->append(full_name()); + str_value.print(str); str->append('\''); } @@ -677,30 +693,27 @@ String *Item_param::query_val_str(String* str) } else { - DATETIME_FORMAT *tmp_format= 0; - bool is_time_only= 0; + char buff[40]; + String tmp(buff,sizeof(buff), &my_charset_bin); switch (ltime.time_type) { - case TIMESTAMP_NONE: - case WRONG_TIMESTAMP_FULL: - break; - case TIMESTAMP_DATE: - tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format; - break; - case TIMESTAMP_FULL: - tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; - break; - case TIMESTAMP_TIME: - { - tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; - is_time_only= 1; - break; - } + case TIMESTAMP_NONE: + case TIMESTAMP_DATETIME_ERROR: + tmp.length(0); // Should never happen + break; + case TIMESTAMP_DATE: + make_date((DATE_TIME_FORMAT*) 0, <ime, &tmp); + break; + case TIMESTAMP_DATETIME: + make_datetime((DATE_TIME_FORMAT*) 0, <ime, &tmp); + break; + case TIMESTAMP_TIME: + make_time((DATE_TIME_FORMAT*) 0, <ime, &tmp); + break; } - make_datetime(str, <ime, is_time_only, 0, - tmp_format->format, tmp_format->format_length, 0); + str->append(tmp); } - str->append("'"); + str->append('\''); } return str; } @@ -754,7 +767,7 @@ String* Item_ref_null_helper::val_str(String* s) owner->was_null|= null_value= (*ref)->null_value; return tmp; } -bool Item_ref_null_helper::get_date(TIME *ltime, bool fuzzydate) +bool Item_ref_null_helper::get_date(TIME *ltime, uint fuzzydate) { return (owner->was_null|= null_value= (*ref)->get_date(ltime, fuzzydate)); } @@ -777,7 +790,7 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, // store pointer on SELECT_LEX from wich item is dependent item->depended_from= last; current->mark_as_dependent(last); - if (thd->lex.describe) + if (thd->lex.describe & DESCRIBE_EXTENDED) { char warn_buff[MYSQL_ERRMSG_SIZE]; sprintf(warn_buff, ER(ER_WARN_FIELD_RESOLVED), @@ -925,7 +938,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) set_field(tmp); } - else if (thd && thd->set_query_id && field->query_id != thd->query_id) + else if (thd->set_query_id && field->query_id != thd->query_id) { /* We only come here in unions */ TABLE *table=field->table; @@ -975,6 +988,7 @@ enum_field_types Item::field_type() const FIELD_TYPE_DOUBLE); } + Field *Item::tmp_table_field_from_field_type(TABLE *table) { switch (field_type()) @@ -1351,7 +1365,7 @@ bool Item::send(Protocol *protocol, String *buffer) case MYSQL_TYPE_TIMESTAMP: { TIME tm; - get_date(&tm, 1); + get_date(&tm, TIME_FUZZY_DATE); if (!null_value) { if (type == MYSQL_TYPE_DATE) @@ -1555,6 +1569,34 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) } +void Item_ref::print(String *str) +{ + if (ref && *ref) + (*ref)->print(str); + else + Item_ident::print(str); +} + + +void Item_ref_null_helper::print(String *str) +{ + str->append("<ref_null_helper>(", 18); + if (ref && *ref) + (*ref)->print(str); + else + str->append('?'); + str->append(')'); +} + + +void Item_null_helper::print(String *str) +{ + str->append("<null_helper>(", 14); + store->print(str); + str->append(')'); +} + + bool Item_default_value::eq(const Item *item, bool binary_cmp) const { return item->type() == DEFAULT_VALUE_ITEM && @@ -1596,10 +1638,10 @@ void Item_default_value::print(String *str) { if (!arg) { - str->append("DEFAULT"); + str->append("default", 7); return; } - str->append("DEFAULT("); + str->append("default(", 8); arg->print(str); str->append(')'); } @@ -1652,7 +1694,7 @@ bool Item_insert_value::fix_fields(THD *thd, struct st_table_list *table_list, I void Item_insert_value::print(String *str) { - str->append("VALUE("); + str->append("values(", 7); arg->print(str); str->append(')'); } @@ -1776,6 +1818,34 @@ Item_cache* Item_cache::get_cache(Item_result type) } } + +void Item_cache::print(String *str) +{ + str->append("<cache>(", 8); + if (example) + example->print(str); + else + Item::print(str); + str->append(')'); +} + + +void Item_cache_int::store(Item *item) +{ + value= item->val_int_result(); + null_value= item->null_value; + collation.set(item->collation); +} + + +void Item_cache_real::store(Item *item) +{ + value= item->val_result(); + null_value= item->null_value; + collation.set(item->collation); +} + + void Item_cache_str::store(Item *item) { value_buff.set(buffer, sizeof(buffer), item->collation.collation); @@ -1826,6 +1896,7 @@ bool Item_cache_row::allocate(uint num) bool Item_cache_row::setup(Item * item) { + example= item; if (!values && allocate(item->cols())) return 1; for (uint i= 0; i < item_count; i++) diff --git a/sql/item.h b/sql/item.h index 8bb28068618..f473ca33676 100644 --- a/sql/item.h +++ b/sql/item.h @@ -114,14 +114,6 @@ public: my_bool fixed; /* If item fixed with fix_fields */ DTCollation collation; - - /* - thd is current_thd value. Like some other Item's fields it - will be a problem for using one Item in different threads - (as stored procedures may want to do in the future) - */ - THD *thd; - // alloc & destruct is done as start of select using sql_alloc Item(); /* @@ -132,7 +124,7 @@ public: top AND/OR ctructure of WHERE clause to protect it of optimisation changes in prepared statements */ - Item(THD *c_thd, Item &item); + Item(THD *thd, Item &item); virtual ~Item() { name=0; } /*lint -e1509 */ void set_name(const char *str,uint length, CHARSET_INFO *cs); void init_make_field(Send_field *tmp_field,enum enum_field_types type); @@ -182,11 +174,12 @@ public: { return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} virtual bool const_item() const { return used_tables() == 0; } virtual void print(String *str_arg) { str_arg->append(full_name()); } + void print_item_w_name(String *); virtual void update_used_tables() {} virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields) {} - virtual bool get_date(TIME *ltime,bool fuzzydate); + virtual bool get_date(TIME *ltime,uint fuzzydate); virtual bool get_time(TIME *ltime); - virtual bool get_date_result(TIME *ltime,bool fuzzydate) + virtual bool get_date_result(TIME *ltime,uint fuzzydate) { return get_date(ltime,fuzzydate); } virtual bool is_null() { return 0; } virtual void top_level_item() {} @@ -285,8 +278,8 @@ public: } Field *get_tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return result_field; } - bool get_date(TIME *ltime,bool fuzzydate); - bool get_date_result(TIME *ltime,bool fuzzydate); + bool get_date(TIME *ltime,uint fuzzydate); + bool get_date_result(TIME *ltime,uint fuzzydate); bool get_time(TIME *ltime); bool is_null() { return field->is_null(); } Item *get_tmp_table_item(THD *thd); @@ -318,6 +311,7 @@ public: bool basic_const_item() const { return 1; } Item *new_item() { return new Item_null(name); } bool is_null() { return 1; } + void print(String *str) { str->append("NULL", 4); } }; class Item_param :public Item @@ -368,6 +362,7 @@ public: String *query_val_str(String *str); enum_field_types field_type() const { return MYSQL_TYPE_STRING; } Item *new_item() { return new Item_param(pos_in_query); } + void print(String *str) { str->append('?'); } }; class Item_int :public Item @@ -466,6 +461,13 @@ public: { collation.set(cs, dv); str_value.set(str,length,cs); + /* + We have to have a different max_length than 'length' here to + ensure that we get the right length if we do use the item + to create a new table. In this case max_length must be the maximum + number of chars for a string of this type because we in create_field:: + divide the max_length with mbmaxlen). + */ max_length= str_value.numchars()*cs->mbmaxlen; set_name(str, length, cs); decimals=NOT_FIXED_DEC; @@ -620,7 +622,7 @@ public: (void) (*ref)->val_int_result(); return (*ref)->null_value; } - bool get_date(TIME *ltime,bool fuzzydate) + bool get_date(TIME *ltime,uint fuzzydate) { return (null_value=(*ref)->get_date_result(ltime,fuzzydate)); } @@ -640,6 +642,7 @@ public: (*ref)->save_in_field(result_field, no_conversions); } Item *real_item() { return *ref; } + void print(String *str); }; class Item_in_subselect; @@ -654,16 +657,8 @@ public: double val(); longlong val_int(); String* val_str(String* s); - bool get_date(TIME *ltime, bool fuzzydate); - void print(String *str) - { - str->append("ref_null_helper("); - if (ref && *ref) - (*ref)->print(str); - else - str->append('?'); - str->append(')'); - } + bool get_date(TIME *ltime, uint fuzzydate); + void print(String *str); }; class Item_null_helper :public Item_ref_null_helper @@ -675,6 +670,7 @@ public: :Item_ref_null_helper(master, &store, table_name_par, field_name_par), store(item) {} + void print(String *str); }; /* @@ -856,14 +852,16 @@ public: class Item_cache: public Item { +protected: + Item *example; table_map used_table_map; public: - Item_cache(): used_table_map(0) {fixed= 1; null_value= 1;} + Item_cache(): example(0), used_table_map(0) {fixed= 1; null_value= 1;} void set_used_tables(table_map map) { used_table_map= map; } virtual bool allocate(uint i) { return 0; }; - virtual bool setup(Item *) { return 0; }; + virtual bool setup(Item *item) { example= item; return 0; }; virtual void store(Item *)= 0; void set_len_n_dec(uint32 max_len, uint8 dec) { @@ -873,6 +871,7 @@ public: enum Type type() const { return CACHE_ITEM; } static Item_cache* get_cache(Item_result type); table_map used_tables() const { return used_table_map; } + void print(String *str); }; class Item_cache_int: public Item_cache @@ -881,12 +880,7 @@ class Item_cache_int: public Item_cache public: Item_cache_int(): Item_cache() {} - void store(Item *item) - { - value= item->val_int_result(); - null_value= item->null_value; - collation.set(item->collation); - } + void store(Item *item); double val() { return (double) value; } longlong val_int() { return value; } String* val_str(String *str) { str->set(value, default_charset()); return str; } @@ -899,12 +893,7 @@ class Item_cache_real: public Item_cache public: Item_cache_real(): Item_cache() {} - void store(Item *item) - { - value= item->val_result(); - null_value= item->null_value; - collation.set(item->collation); - } + void store(Item *item); double val() { return value; } longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5)); } String* val_str(String *str) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d6c05f47964..8731e8fbe21 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -59,27 +59,38 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fnam fname); } -Item_bool_func2* Item_bool_func2::eq_creator(Item *a, Item *b) + +Item_bool_func2* Eq_creator::create(Item *a, Item *b) const { return new Item_func_eq(a, b); } -Item_bool_func2* Item_bool_func2::ne_creator(Item *a, Item *b) + + +Item_bool_func2* Ne_creator::create(Item *a, Item *b) const { return new Item_func_ne(a, b); } -Item_bool_func2* Item_bool_func2::gt_creator(Item *a, Item *b) + + +Item_bool_func2* Gt_creator::create(Item *a, Item *b) const { return new Item_func_gt(a, b); } -Item_bool_func2* Item_bool_func2::lt_creator(Item *a, Item *b) + + +Item_bool_func2* Lt_creator::create(Item *a, Item *b) const { return new Item_func_lt(a, b); } -Item_bool_func2* Item_bool_func2::ge_creator(Item *a, Item *b) + + +Item_bool_func2* Ge_creator::create(Item *a, Item *b) const { return new Item_func_ge(a, b); } -Item_bool_func2* Item_bool_func2::le_creator(Item *a, Item *b) + + +Item_bool_func2* Le_creator::create(Item *a, Item *b) const { return new Item_func_le(a, b); } @@ -113,6 +124,14 @@ longlong Item_func_not_all::val_int() return (!null_value && value == 0) ? 1 : 0; } +void Item_func_not_all::print(String *str) +{ + if (show) + Item_func::print(str); + else + args[0]->print(str); +} + /* Convert a constant expression or string to an integer. This is done when comparing DATE's of different formats and @@ -707,6 +726,18 @@ longlong Item_func_between::val_int() return 0; } + +void Item_func_between::print(String *str) +{ + str->append('('); + args[0]->print(str); + str->append(" between ", 9); + args[1]->print(str); + str->append(" and ", 5); + args[2]->print(str); + str->append(')'); +} + void Item_func_ifnull::fix_length_and_dec() { @@ -863,7 +894,7 @@ Item_func_nullif::fix_length_and_dec() } /* - nullif () returns NULL if arguments are different, else it returns the + nullif () returns NULL if arguments are equal, else it returns the first argument. Note that we have to evaluate the first argument twice as the compare may have been done with a different type than return value @@ -1100,7 +1131,27 @@ void Item_func_case::fix_length_and_dec() void Item_func_case::print(String *str) { - str->append("case "); // Not yet complete + str->append("(case ", 6); + if (first_expr_num != -1) + { + args[first_expr_num]->print(str); + str->append(' '); + } + for (uint i=0 ; i < ncases ; i+=2) + { + str->append("when ", 5); + args[i]->print(str); + str->append(" then ", 6); + args[i+1]->print(str); + str->append(' '); + } + if (else_expr_num != -1) + { + str->append("else ", 5); + args[else_expr_num]->print(str); + str->append(' '); + } + str->append("end)", 4); } /* @@ -1507,8 +1558,10 @@ void Item_func_in::fix_length_and_dec() void Item_func_in::print(String *str) { str->append('('); - Item_func::print(str); - str->append(')'); + args[0]->print(str); + str->append(" in (", 5); + print_args(str, 1); + str->append("))", 2); } @@ -1614,7 +1667,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) */ and_tables_cache= ~(table_map) 0; - if (thd && check_stack_overrun(thd,buff)) + if (check_stack_overrun(thd, buff)) return 1; // Fatal error flag is set! while ((item=li++)) { @@ -1643,8 +1696,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) if (item->maybe_null) maybe_null=1; } - if (thd) - thd->lex.current_select->cond_count+=list.elements; + thd->lex.current_select->cond_count+=list.elements; fix_length_and_dec(); fixed= 1; return 0; @@ -1882,12 +1934,21 @@ void Item_is_not_null_test::update_used_tables() } } + longlong Item_func_isnotnull::val_int() { return args[0]->is_null() ? 0 : 1; } +void Item_func_isnotnull::print(String *str) +{ + str->append('('); + args[0]->print(str); + str->append(" is not null)", 13); +} + + longlong Item_func_like::val_int() { String* res = args[0]->val_str(&tmp_value1); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 9a1b087a63c..081374345d8 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -105,10 +105,73 @@ public: Item_in_optimizer return NULL, else it evaluate Item_in_subselect. */ longlong val_int(); - const char *func_name() const { return "IN_OPTIMIZER"; } + const char *func_name() const { return "<in_optimizer>"; } Item_cache **get_cache() { return &cache; } }; +class Comp_creator +{ +public: + virtual Item_bool_func2* create(Item *a, Item *b) const = 0; + virtual const char* symbol(bool invert) const = 0; + virtual bool eqne_op() const = 0; + virtual bool l_op() const = 0; +}; + +class Eq_creator :public Comp_creator +{ +public: + virtual Item_bool_func2* create(Item *a, Item *b) const; + virtual const char* symbol(bool invert) const { return invert? "<>" : "="; } + virtual bool eqne_op() const { return 1; } + virtual bool l_op() const { return 0; } +}; + +class Ne_creator :public Comp_creator +{ +public: + virtual Item_bool_func2* create(Item *a, Item *b) const; + virtual const char* symbol(bool invert) const { return invert? "=" : "<>"; } + virtual bool eqne_op() const { return 1; } + virtual bool l_op() const { return 0; } +}; + +class Gt_creator :public Comp_creator +{ +public: + virtual Item_bool_func2* create(Item *a, Item *b) const; + virtual const char* symbol(bool invert) const { return invert? "<=" : ">"; } + virtual bool eqne_op() const { return 0; } + virtual bool l_op() const { return 0; } +}; + +class Lt_creator :public Comp_creator +{ +public: + virtual Item_bool_func2* create(Item *a, Item *b) const; + virtual const char* symbol(bool invert) const { return invert? ">=" : "<"; } + virtual bool eqne_op() const { return 0; } + virtual bool l_op() const { return 1; } +}; + +class Ge_creator :public Comp_creator +{ +public: + virtual Item_bool_func2* create(Item *a, Item *b) const; + virtual const char* symbol(bool invert) const { return invert? "<" : ">="; } + virtual bool eqne_op() const { return 0; } + virtual bool l_op() const { return 0; } +}; + +class Le_creator :public Comp_creator +{ +public: + virtual Item_bool_func2* create(Item *a, Item *b) const; + virtual const char* symbol(bool invert) const { return invert? ">" : "<="; } + virtual bool eqne_op() const { return 0; } + virtual bool l_op() const { return 1; } +}; + class Item_bool_func2 :public Item_int_func { /* Bool with 2 string args */ protected: @@ -129,13 +192,6 @@ public: void print(String *str) { Item_func::print_op(str); } bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); } - static Item_bool_func2* eq_creator(Item *a, Item *b); - static Item_bool_func2* ne_creator(Item *a, Item *b); - static Item_bool_func2* gt_creator(Item *a, Item *b); - static Item_bool_func2* lt_creator(Item *a, Item *b); - static Item_bool_func2* ge_creator(Item *a, Item *b); - static Item_bool_func2* le_creator(Item *a, Item *b); - friend class Arg_comparator; }; @@ -162,12 +218,15 @@ class Item_func_not_all :public Item_func_not { bool abort_on_null; public: - Item_func_not_all(Item *a) :Item_func_not(a), abort_on_null(0) {} + bool show; + + Item_func_not_all(Item *a) :Item_func_not(a), abort_on_null(0), show(0) {} virtual void top_level_item() { abort_on_null= 1; } bool top_level() { return abort_on_null; } longlong val_int(); enum Functype functype() const { return NOT_ALL_FUNC; } - const char *func_name() const { return "not_all"; } + const char *func_name() const { return "<not>"; } + void print(String *str); }; class Item_func_eq :public Item_bool_rowready_func2 @@ -272,6 +331,7 @@ public: enum Functype functype() const { return BETWEEN; } const char *func_name() const { return "between"; } void fix_length_and_dec(); + void print(String *str); }; @@ -354,6 +414,7 @@ public: enum Item_result result_type () const { return cached_result_type; } void fix_length_and_dec(); const char *func_name() const { return "nullif"; } + void print(String *str) { Item_func::print(str); } table_map not_null_tables() const { return 0; } }; @@ -714,7 +775,7 @@ public: {} enum Functype functype() const { return ISNOTNULLTEST_FUNC; } longlong val_int(); - const char *func_name() const { return "is_not_null_test"; } + const char *func_name() const { return "<is_not_null_test>"; } void update_used_tables(); }; @@ -733,6 +794,7 @@ public: optimize_type select_optimize() const { return OPTIMIZE_NULL; } table_map not_null_tables() const { return 0; } Item *neg_transformer(); + void print(String *str); }; @@ -785,7 +847,8 @@ public: ~Item_func_regex(); longlong val_int(); bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); - const char *func_name() const { return "regex"; } + const char *func_name() const { return "regexp"; } + void print(String *str) { print_op(str); } }; #else @@ -796,6 +859,7 @@ public: Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b) {} longlong val_int() { return 0;} const char *func_name() const { return "regex"; } + void print(String *str) { print_op(str); } }; #endif /* USE_REGEX */ diff --git a/sql/item_create.cc b/sql/item_create.cc index fce59d68c1f..5c44d8b00ff 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -292,7 +292,7 @@ Item *create_func_period_diff(Item* a, Item *b) Item *create_func_pi(void) { - return new Item_real(NullS,M_PI,6,8); + return new Item_real("pi()",M_PI,6,8); } Item *create_func_pow(Item* a, Item *b) @@ -450,7 +450,8 @@ Item *create_load_file(Item* a) } -Item *create_func_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs) +Item *create_func_cast(Item *a, Cast_target cast_type, int len, + CHARSET_INFO *cs) { Item *res; LINT_INIT(res); diff --git a/sql/item_func.cc b/sql/item_func.cc index b47c833d404..3112c73b188 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -197,7 +197,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) used_tables_cache= not_null_tables_cache= 0; const_item_cache=1; - if (thd && check_stack_overrun(thd,buff)) + if (check_stack_overrun(thd, buff)) return 1; // Fatal error if flag is set! if (arg_count) { // Print purify happy @@ -219,7 +219,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } } fix_length_and_dec(); - if (thd && thd->net.last_errno) // An error inside fix_length_and_dec accured + if (thd->net.last_errno) // An error inside fix_length_and_dec occured return 1; fixed= 1; return 0; @@ -287,13 +287,19 @@ void Item_func::print(String *str) { str->append(func_name()); str->append('('); - for (uint i=0 ; i < arg_count ; i++) + print_args(str, 0); + str->append(')'); +} + + +void Item_func::print_args(String *str, uint from) +{ + for (uint i=from ; i < arg_count ; i++) { - if (i) + if (i != from) str->append(','); args[i]->print(str); } - str->append(')'); } @@ -462,6 +468,24 @@ String *Item_num_op::val_str(String *str) } +void Item_func_signed::print(String *str) +{ + str->append("cast(", 5); + args[0]->print(str); + str->append(" as signed)", 11); + +} + + +void Item_func_unsigned::print(String *str) +{ + str->append("cast(", 5); + args[0]->print(str); + str->append(" as unsigned)", 13); + +} + + double Item_func_plus::val() { double value=args[0]->val()+args[1]->val(); @@ -1184,6 +1208,21 @@ longlong Item_func_locate::val_int() } +void Item_func_locate::print(String *str) +{ + str->append("locate(", 7); + args[1]->print(str); + str->append(','); + args[0]->print(str); + if (arg_count == 3) + { + str->append(','); + args[2]->print(str); + } + str->append(')'); +} + + longlong Item_func_field::val_int() { if (cmp_type == STRING_RESULT) @@ -1284,8 +1323,8 @@ void Item_func_find_in_set::fix_length_and_dec() String *find=args[0]->val_str(&value); if (find) { - enum_value=find_enum(((Field_enum*) field)->typelib,find->ptr(), - find->length()); + enum_value= find_type(((Field_enum*) field)->typelib,find->ptr(), + find->length(), 0); enum_bit=0; if (enum_value) enum_bit=LL(1) << (enum_value-1); @@ -1396,13 +1435,9 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, #endif DBUG_ENTER("Item_udf_func::fix_fields"); - if (thd) - { - if (check_stack_overrun(thd,buff)) - DBUG_RETURN(1); // Fatal error flag is set! - } - else - thd=current_thd; // In WHERE / const clause + if (check_stack_overrun(thd, buff)) + DBUG_RETURN(1); // Fatal error flag is set! + udf_func *tmp_udf=find_udf(u_d->name.str,(uint) u_d->name.length,1); if (!tmp_udf) @@ -1764,7 +1799,7 @@ void item_user_lock_release(ULL *ull) String tmp(buf,sizeof(buf), system_charset_info); tmp.copy(command, strlen(command), tmp.charset()); tmp.append(ull->key,ull->key_length); - tmp.append("\")"); + tmp.append("\")", 2); Query_log_event qev(current_thd, tmp.ptr(), tmp.length(),1); qev.error_code=0; // this query is always safe to run on slave mysql_bin_log.write(&qev); @@ -2049,6 +2084,19 @@ longlong Item_func_benchmark::val_int() } +void Item_func_benchmark::print(String *str) +{ + str->append("benchmark(", 10); + char buffer[20]; + // my_charset_bin is good enough for numbers + String st(buffer, sizeof(buffer), &my_charset_bin); + st.set((ulonglong)loop_count, &my_charset_bin); + str->append(st); + str->append(','); + args[0]->print(str); + str->append(')'); +} + #define extra_size sizeof(double) static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, @@ -2094,8 +2142,8 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, } /* - When a user variable is updated (in a SET command or a query like SELECT @a:= - ). + When a user variable is updated (in a SET command or a query like + SELECT @a:= ). */ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, @@ -2387,9 +2435,9 @@ String *Item_func_set_user_var::val_str(String *str) void Item_func_set_user_var::print(String *str) { - str->append("(@@",3); - str->append(name.str,name.length); - str->append(":=",2); + str->append("(@", 2); + str->append(name.str, name.length); + str->append(":=", 2); args[0]->print(str); str->append(')'); } @@ -2454,14 +2502,15 @@ void Item_func_get_user_var::fix_length_and_dec() sql_set_variables() is what is called from 'case SQLCOM_SET_OPTION' in dispatch_command()). Instead of building a one-element list to pass to sql_set_variables(), we could instead manually call check() and update(); - this would save memory and time; but calling sql_set_variables() makes one - unique place to maintain (sql_set_variables()). + this would save memory and time; but calling sql_set_variables() makes + one unique place to maintain (sql_set_variables()). */ List<set_var_base> tmp_var_list; tmp_var_list.push_back(new set_var_user(new Item_func_set_user_var(name, new Item_null()))); - if (sql_set_variables(thd, &tmp_var_list)) /* this will create the variable */ + /* Create the variable */ + if (sql_set_variables(thd, &tmp_var_list)) goto err; if (!(var_entry= get_variable(&thd->user_vars, name, 0))) goto err; @@ -2518,7 +2567,7 @@ err: bool Item_func_get_user_var::const_item() const { - return var_entry && current_thd->query_id != var_entry->update_query_id; + return (!var_entry || current_thd->query_id != var_entry->update_query_id); } @@ -2535,7 +2584,7 @@ enum Item_result Item_func_get_user_var::result_type() const void Item_func_get_user_var::print(String *str) { - str->append('@'); + str->append("(@", 2); str->append(name.str,name.length); str->append(')'); } @@ -2815,6 +2864,18 @@ double Item_func_match::val() table->record[0], 0)); } +void Item_func_match::print(String *str) +{ + str->append("(match ", 7); + print_args(str, 1); + str->append(" against (", 10); + args[0]->print(str); + if (flags & FT_BOOL) + str->append(" in boolean mode", 16); + else if (flags & FT_EXPAND) + str->append(" with query expansion", 21); + str->append("))", 2); +} longlong Item_func_bit_xor::val_int() { diff --git a/sql/item_func.h b/sql/item_func.h index 29e40f603b4..6b43ebaccbe 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -125,10 +125,11 @@ public: virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields); void print(String *str); void print_op(String *str); + void print_args(String *str, uint from); void fix_num_length_and_dec(); - inline bool get_arg0_date(TIME *ltime,bool fuzzy_date) + inline bool get_arg0_date(TIME *ltime, uint fuzzy_date) { - return (null_value=args[0]->get_date(ltime,fuzzy_date)); + return (null_value=args[0]->get_date(ltime, fuzzy_date)); } inline bool get_arg0_time(TIME *ltime) { @@ -215,6 +216,7 @@ public: longlong val_int() { return args[0]->val_int(); } void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=0; } + void print(String *str); }; @@ -226,6 +228,7 @@ public: longlong val_int() { return args[0]->val_int(); } void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=1; } + void print(String *str); }; @@ -607,6 +610,7 @@ public: const char *func_name() const { return "locate"; } longlong val_int(); void fix_length_and_dec(); + void print(String *str); }; @@ -663,6 +667,7 @@ public: longlong val_int(); const char *func_name() const { return "|"; } void fix_length_and_dec() { unsigned_flag=1; } + void print(String *str) { print_op(str); } }; class Item_func_bit_and :public Item_int_func @@ -672,6 +677,7 @@ public: longlong val_int(); const char *func_name() const { return "&"; } void fix_length_and_dec() { unsigned_flag=1; } + void print(String *str) { print_op(str); } }; class Item_func_bit_count :public Item_int_func @@ -690,6 +696,7 @@ public: longlong val_int(); const char *func_name() const { return "<<"; } void fix_length_and_dec() { unsigned_flag=1; } + void print(String *str) { print_op(str); } }; class Item_func_shift_right :public Item_int_func @@ -698,6 +705,7 @@ public: Item_func_shift_right(Item *a,Item *b) :Item_int_func(a,b) {} longlong val_int(); const char *func_name() const { return ">>"; } + void print(String *str) { print_op(str); } }; class Item_func_bit_neg :public Item_int_func @@ -728,6 +736,7 @@ class Item_func_benchmark :public Item_int_func longlong val_int(); const char *func_name() const { return "benchmark"; } void fix_length_and_dec() { max_length=1; maybe_null=0; } + void print(String *str); }; @@ -1005,6 +1014,7 @@ public: bool eq(const Item *, bool binary_cmp) const; longlong val_int() { return val()!=0.0; } double val(); + void print(String *str); bool fix_index(); void init_search(bool no_order); @@ -1018,6 +1028,7 @@ public: longlong val_int(); const char *func_name() const { return "^"; } void fix_length_xor_dec() { unsigned_flag=1; } + void print(String *str) { print_op(str); } }; class Item_func_is_free_lock :public Item_int_func @@ -1026,7 +1037,7 @@ class Item_func_is_free_lock :public Item_int_func public: Item_func_is_free_lock(Item *a) :Item_int_func(a) {} longlong val_int(); - const char *func_name() const { return "check_lock"; } + const char *func_name() const { return "is_free_lock"; } void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;} }; diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 79e45cca26f..f6f00ed2bab 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -118,6 +118,7 @@ public: case SP_EXTERIORRING: return "exteriorring"; default: + DBUG_ASSERT(0); // Should never happened return "spatial_decomp_unknown"; } } @@ -142,6 +143,7 @@ public: case SP_INTERIORRINGN: return "interiorringn"; default: + DBUG_ASSERT(0); // Should never happened return "spatial_decomp_n_unknown"; } } @@ -210,9 +212,11 @@ public: case SP_OVERLAPS_FUNC: return "overlaps"; default: + DBUG_ASSERT(0); // Should never happened return "sp_unknown"; } } + void print(String *str) { Item_func::print(str); } }; class Item_func_isempty: public Item_bool_func @@ -289,7 +293,7 @@ class Item_func_numinteriorring: public Item_int_func public: Item_func_numinteriorring(Item *a): Item_int_func(a) {} longlong val_int(); - const char *func_name() const { return "numinteriorring"; } + const char *func_name() const { return "numinteriorrings"; } void fix_length_and_dec() { max_length=10; } }; diff --git a/sql/item_row.cc b/sql/item_row.cc index fcc6e5192ec..89b38c8a753 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -118,6 +118,18 @@ bool Item_row::check_cols(uint c) return 0; } +void Item_row::print(String *str) +{ + str->append('('); + for (uint i= 0; i < arg_count; i++) + { + if (i) + str->append(','); + items[i]->print(str); + } + str->append(')'); +} + bool Item_row::walk(Item_processor processor, byte *arg) { for (uint i= 0; i < arg_count; i++) diff --git a/sql/item_row.h b/sql/item_row.h index 6dd955ed426..a09bd1a2c31 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -68,6 +68,7 @@ public: bool const_item() const { return const_item_cache; }; enum Item_result result_type() const { return ROW_RESULT; } void update_used_tables(); + void print(String *str); bool walk(Item_processor processor, byte *arg); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 99dd06c566c..dfaf3001a19 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -654,6 +654,17 @@ void Item_func_concat_ws::update_used_tables() const_item_cache&=separator->const_item(); } +void Item_func_concat_ws::print(String *str) +{ + str->append("concat_ws(", 10); + separator->print(str); + if (arg_count) + { + str->append(','); + print_args(str, 0); + } + str->append(')'); +} String *Item_func_reverse::val_str(String *str) { @@ -1613,6 +1624,19 @@ String *Item_func_format::val_str(String *str) } +void Item_func_format::print(String *str) +{ + str->append("format(", 7); + args[0]->print(str); + str->append(','); + // my_charset_bin is good enough for numbers + char buffer[20]; + String st(buffer, sizeof(buffer), &my_charset_bin); + st.set((ulonglong)decimals, &my_charset_bin); + str->append(st); + str->append(')'); +} + void Item_func_elt::fix_length_and_dec() { max_length=0; @@ -1764,6 +1788,19 @@ String *Item_func_make_set::val_str(String *str) } +void Item_func_make_set::print(String *str) +{ + str->append("make_set(", 9); + item->print(str); + if (arg_count) + { + str->append(','); + print_args(str, 0); + } + str->append(')'); +} + + String *Item_func_char::val_str(String *str) { str->length(0); @@ -2077,7 +2114,14 @@ void Item_func_conv_charset::fix_length_and_dec() max_length = args[0]->max_length*conv_charset->mbmaxlen; } - +void Item_func_conv_charset::print(String *str) +{ + str->append("convert(", 8); + args[0]->print(str); + str->append(" using ", 7); + str->append(conv_charset->csname); + str->append(')'); +} String *Item_func_conv_charset3::val_str(String *str) { @@ -2271,6 +2315,14 @@ String *Item_func_hex::val_str(String *str) } +void Item_func_binary::print(String *str) +{ + str->append("cast(", 5); + args[0]->print(str); + str->append(" as binary)", 11); +} + + #include <my_dir.h> // For my_stat String *Item_load_file::val_str(String *str) @@ -2524,7 +2576,15 @@ longlong Item_func_uncompressed_length::val_int() } null_value=0; if (res->is_empty()) return 0; - return uint4korr(res->c_ptr()) & 0x3FFFFFFF; + + /* + res->ptr() using is safe because we have tested that string is not empty, + res->c_ptr() is not used because: + - we do not need \0 terminated string to get first 4 bytes + - c_ptr() tests simbol after string end (uninitialiozed memory) which + confuse valgrind + */ + return uint4korr(res->ptr()) & 0x3FFFFFFF; } longlong Item_func_crc32::val_int() @@ -2570,10 +2630,12 @@ String *Item_func_compress::val_str(String *str) ulong new_size= (ulong)((res->length()*120)/100)+12; buffer.realloc((uint32)new_size + 4 + 1); - Byte *body= ((Byte*)buffer.c_ptr()) + 4; + Byte *body= ((Byte*)buffer.ptr()) + 4; + + // As far as we have checked res->is_empty() we can use ptr() if ((err= compress(body, &new_size, - (const Bytef*)res->c_ptr(), res->length())) != Z_OK) + (const Bytef*)res->ptr(), res->length())) != Z_OK) { code= err==Z_MEM_ERROR ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_BUF_ERROR; push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,code,ER(code)); @@ -2581,7 +2643,7 @@ String *Item_func_compress::val_str(String *str) return 0; } - char *tmp= buffer.c_ptr(); // int4store is a macro; avoid side effects + char *tmp= (char*)buffer.ptr(); // int4store is a macro; avoid side effects int4store(tmp, res->length() & 0x3FFFFFFF); /* This is for the stupid char fields which trim ' ': */ @@ -2593,46 +2655,46 @@ String *Item_func_compress::val_str(String *str) } buffer.length((uint32)new_size + 4); - return &buffer; } + String *Item_func_uncompress::val_str(String *str) { String *res= args[0]->val_str(str); - if (!res) - { - null_value= 1; - return 0; - } - if (res->is_empty()) return res; - - ulong new_size= uint4korr(res->c_ptr()) & 0x3FFFFFFF; - int err= Z_OK; + ulong new_size; + int err; uint code; + if (!res) + goto err; + if (res->is_empty()) + return res; + + new_size= uint4korr(res->ptr()) & 0x3FFFFFFF; if (new_size > current_thd->variables.max_allowed_packet) { push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, ER_TOO_BIG_FOR_UNCOMPRESS, ER(ER_TOO_BIG_FOR_UNCOMPRESS), current_thd->variables.max_allowed_packet); - null_value= 0; - return 0; + goto err; } + if (buffer.realloc((uint32)new_size)) + goto err; - buffer.realloc((uint32)new_size); - - if ((err= uncompress((Byte*)buffer.c_ptr(), &new_size, - ((const Bytef*)res->c_ptr())+4,res->length())) == Z_OK) + if ((err= uncompress((Byte*)buffer.ptr(), &new_size, + ((const Bytef*)res->ptr())+4,res->length())) == Z_OK) { - buffer.length((uint32)new_size); + buffer.length((uint32) new_size); return &buffer; } - code= err==Z_BUF_ERROR ? ER_ZLIB_Z_BUF_ERROR : - err==Z_MEM_ERROR ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_DATA_ERROR; + code= ((err == Z_BUF_ERROR) ? ER_ZLIB_Z_BUF_ERROR : + ((err == Z_MEM_ERROR) ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_DATA_ERROR)); push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,code,ER(code)); + +err: null_value= 1; return 0; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index b82dacb4fe0..a7949511f02 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -112,6 +112,7 @@ public: return separator->walk(processor, arg) || Item_str_func::walk(processor, arg); } + void print(String *str); }; class Item_func_reverse :public Item_str_func @@ -120,6 +121,7 @@ public: Item_func_reverse(Item *a) :Item_str_func(a) {} String *val_str(String *); void fix_length_and_dec(); + const char *func_name() const { return "reverse"; } }; @@ -324,10 +326,12 @@ public: Item_func_encrypt(Item *a, Item *b): Item_str_func(a,b) {} String *val_str(String *); void fix_length_and_dec() { maybe_null=1; max_length = 13; } + const char *func_name() const { return "ecrypt"; } }; #include "sql_crypt.h" + class Item_func_encode :public Item_str_func { protected: @@ -337,13 +341,16 @@ public: Item_str_func(a),sql_crypt(seed) {} String *val_str(String *); void fix_length_and_dec(); + const char *func_name() const { return "encode"; } }; + class Item_func_decode :public Item_func_encode { public: Item_func_decode(Item *a, char *seed): Item_func_encode(a,seed) {} String *val_str(String *); + const char *func_name() const { return "decode"; } }; @@ -354,7 +361,7 @@ public: String *val_str(String *); void fix_length_and_dec() { - max_length= MAX_FIELD_NAME * system_charset_info->mbmaxlen; + max_length= MAX_FIELD_NAME * system_charset_info->mbmaxlen; } const char *func_name() const { return "database"; } }; @@ -366,7 +373,7 @@ public: String *val_str(String *); void fix_length_and_dec() { - max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*system_charset_info->mbmaxlen; + max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*system_charset_info->mbmaxlen; } const char *func_name() const { return "user"; } }; @@ -420,6 +427,7 @@ public: return item->walk(processor, arg) || Item_str_func::walk(processor, arg); } + void print(String *str); }; @@ -435,6 +443,7 @@ public: max_length=args[0]->max_length+(args[0]->max_length-args[0]->decimals)/3; } const char *func_name() const { return "format"; } + void print(String *); }; @@ -520,7 +529,6 @@ class Item_func_binary :public Item_str_func { public: Item_func_binary(Item *a) :Item_str_func(a) {} - const char *func_name() const { return "binary"; } String *val_str(String *a) { String *tmp=args[0]->val_str(a); @@ -534,7 +542,7 @@ public: collation.set(&my_charset_bin); max_length=args[0]->max_length; } - void print(String *str) { print_op(str); } + void print(String *str); }; @@ -597,7 +605,8 @@ public: { conv_charset=cs; } String *val_str(String *); void fix_length_and_dec(); - const char *func_name() const { return "conv_charset"; } + const char *func_name() const { return "convert"; } + void print(String *str); }; class Item_func_set_collation :public Item_str_func @@ -607,7 +616,8 @@ public: String *val_str(String *); void fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; - const char *func_name() const { return "set_collation"; } + const char *func_name() const { return "collate"; } + void print(String *str) { print_op(str); } }; class Item_func_conv_charset3 :public Item_str_func @@ -617,7 +627,7 @@ public: :Item_str_func(arg1,arg2,arg3) {} String *val_str(String *); void fix_length_and_dec(); - const char *func_name() const { return "conv_charset3"; } + const char *func_name() const { return "convert"; } }; class Item_func_charset :public Item_str_func diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 062a7c2ee2b..9fd6dab83f6 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -146,21 +146,25 @@ Item::Type Item_subselect::type() const return SUBSELECT_ITEM; } + void Item_subselect::fix_length_and_dec() { engine->fix_length_and_dec(0); } + table_map Item_subselect::used_tables() const { return (table_map) (engine->dependent() ? used_tables_cache : 0L); } + bool Item_subselect::const_item() const { return const_item_cache; } + void Item_subselect::update_used_tables() { if (!engine->uncacheable()) @@ -171,6 +175,15 @@ void Item_subselect::update_used_tables() } } + +void Item_subselect::print(String *str) +{ + str->append('('); + engine->print(str); + str->append(')'); +} + + Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex) :Item_subselect(), value(0) { @@ -184,11 +197,12 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex) Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent, st_select_lex *select_lex, - bool max) + bool max_arg) :Item_singlerow_subselect() { DBUG_ENTER("Item_maxmin_subselect::Item_maxmin_subselect"); - init(select_lex, new select_max_min_finder_subselect(this, max)); + max= max_arg; + init(select_lex, new select_max_min_finder_subselect(this, max_arg)); max_columns= 1; maybe_null= 1; max_columns= 1; @@ -203,6 +217,12 @@ Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent, DBUG_VOID_RETURN; } +void Item_maxmin_subselect::print(String *str) +{ + str->append(max?"<max>":"<min>", 5); + Item_singlerow_subselect::print(str); +} + void Item_singlerow_subselect::reset() { null_value= 1; @@ -245,7 +265,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) */ substitution->walk(&Item::remove_dependence_processor, (byte *) select_lex->outer_select()); - if (select_lex->where || select_lex->having) + if (join->conds || join->having) { Item *cond; if (!join->having) @@ -365,6 +385,7 @@ String *Item_singlerow_subselect::val_str (String *str) } } + Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex): Item_subselect() { @@ -379,6 +400,14 @@ Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex): DBUG_VOID_RETURN; } + +void Item_exists_subselect::print(String *str) +{ + str->append("exists", 6); + Item_subselect::print(str); +} + + bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit) { if (unit->fake_select_lex && @@ -396,7 +425,7 @@ bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit) Item_in_subselect::Item_in_subselect(Item * left_exp, st_select_lex *select_lex): - Item_exists_subselect(), upper_not(0) + Item_exists_subselect(), transformed(0), upper_not(0) { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); left_expr= left_exp; @@ -411,9 +440,10 @@ Item_in_subselect::Item_in_subselect(Item * left_exp, } Item_allany_subselect::Item_allany_subselect(Item * left_exp, - compare_func_creator fn, - st_select_lex *select_lex) - :Item_in_subselect() + Comp_creator *fn, + st_select_lex *select_lex, + bool all_arg) + :Item_in_subselect(), all(all_arg) { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); left_expr= left_exp; @@ -512,7 +542,7 @@ String *Item_in_subselect::val_str(String *str) Item_subselect::trans_res Item_in_subselect::single_value_transformer(JOIN *join, - compare_func_creator func) + Comp_creator *func) { DBUG_ENTER("Item_in_subselect::single_value_transformer"); @@ -528,11 +558,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, } if ((abort_on_null || (upper_not && upper_not->top_level())) && - !select_lex->master_unit()->dependent && - (func == &Item_bool_func2::gt_creator || - func == &Item_bool_func2::lt_creator || - func == &Item_bool_func2::ge_creator || - func == &Item_bool_func2::le_creator)) + !select_lex->master_unit()->dependent && !func->eqne_op()) { if (substitution) { @@ -547,8 +573,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, { Item *item; subs_type type= substype(); - if (func == &Item_bool_func2::le_creator || - func == &Item_bool_func2::lt_creator) + if (func->l_op()) { /* (ALL && (> || =>)) || (ANY && (< || =<)) @@ -579,9 +604,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, // remove LIMIT placed by ALL/ANY subquery select_lex->master_unit()->global_parameters->select_limit= HA_POS_ERROR; - subs= new Item_maxmin_subselect(this, select_lex, - (func == &Item_bool_func2::le_creator || - func == &Item_bool_func2::lt_creator)); + subs= new Item_maxmin_subselect(this, select_lex, func->l_op()); } // left expression belong to outer select SELECT_LEX *current= thd->lex.current_select, *up; @@ -592,7 +615,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, DBUG_RETURN(RES_ERROR); } thd->lex.current_select= current; - substitution= (*func)(left_expr, subs); + substitution= func->create(left_expr, subs); DBUG_RETURN(RES_OK); } @@ -632,11 +655,11 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (join->having || select_lex->with_sum_func || select_lex->group_list.elements) { - item= (*func)(expr, - new Item_ref_null_helper(this, - select_lex->ref_pointer_array, - (char *)"<ref>", - this->full_name())); + item= func->create(expr, + new Item_ref_null_helper(this, + select_lex->ref_pointer_array, + (char *)"<ref>", + this->full_name())); join->having= and_items(join->having, item); select_lex->having_fix_field= 1; if (join->having->fix_fields(thd, join->tables_list, &join->having)) @@ -655,7 +678,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (select_lex->table_list.elements) { Item *having= item, *isnull= item; - item= (*func)(expr, item); + item= func->create(expr, item); if (!abort_on_null) { having= new Item_is_not_null_test(this, having); @@ -681,10 +704,10 @@ Item_in_subselect::single_value_transformer(JOIN *join, { if (select_lex->master_unit()->first_select()->next_select()) { - join->having= (*func)(expr, - new Item_null_helper(this, item, - (char *)"<no matter>", - (char *)"<result>")); + join->having= func->create(expr, + new Item_null_helper(this, item, + (char *)"<no matter>", + (char *)"<result>")); select_lex->having_fix_field= 1; if (join->having->fix_fields(thd, join->tables_list, &join->having)) { @@ -696,7 +719,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, else { // it is single select without tables => possible optimization - item= (*func)(left_expr, item); + item= func->create(left_expr, item); // fix_field of item will be done in time of substituting substitution= item; have_to_be_excluded= 1; @@ -763,11 +786,11 @@ Item_in_subselect::row_value_transformer(JOIN *join) (char *) "<no matter>", (char *) "<list ref>"); func= - Item_bool_func2::eq_creator(new Item_ref((*optimizer->get_cache())-> - addr(i), - (char *)"<no matter>", - (char *)in_left_expr_name), - func); + eq_creator.create(new Item_ref((*optimizer->get_cache())-> + addr(i), + (char *)"<no matter>", + (char *)in_left_expr_name), + func); item= and_items(item, func); } @@ -797,19 +820,51 @@ Item_in_subselect::row_value_transformer(JOIN *join) Item_subselect::trans_res Item_in_subselect::select_transformer(JOIN *join) { + transformed= 1; if (left_expr->cols() == 1) - return single_value_transformer(join, - &Item_bool_func2::eq_creator); + return single_value_transformer(join, &eq_creator); return row_value_transformer(join); } +void Item_in_subselect::print(String *str) +{ + if (transformed) + str->append("<exists>", 8); + else + { + left_expr->print(str); + str->append(" in ", 4); + } + Item_subselect::print(str); +} + + Item_subselect::trans_res Item_allany_subselect::select_transformer(JOIN *join) { + transformed= 1; + if (upper_not) + upper_not->show= 1; return single_value_transformer(join, func); } + +void Item_allany_subselect::print(String *str) +{ + if (transformed) + str->append("<exists>", 8); + else + { + left_expr->print(str); + str->append(' '); + str->append(func->symbol(all)); + str->append(all ? " all " : " any ", 5); + } + Item_subselect::print(str); +} + + subselect_single_select_engine:: subselect_single_select_engine(st_select_lex *select, select_subselect *result, @@ -1137,11 +1192,13 @@ uint subselect_single_select_engine::cols() return select_lex->item_list.elements; } + uint subselect_union_engine::cols() { return unit->first_select()->item_list.elements; } + bool subselect_single_select_engine::dependent() { return select_lex->dependent; @@ -1152,16 +1209,19 @@ bool subselect_union_engine::dependent() return unit->dependent; } + bool subselect_single_select_engine::uncacheable() { return select_lex->uncacheable; } + bool subselect_union_engine::uncacheable() { return unit->uncacheable; } + void subselect_single_select_engine::exclude() { select_lex->master_unit()->exclude_level(); @@ -1172,6 +1232,7 @@ void subselect_union_engine::exclude() unit->exclude_level(); } + void subselect_uniquesubquery_engine::exclude() { //this never should be called @@ -1198,8 +1259,59 @@ table_map subselect_single_select_engine::upper_select_const_tables() table_list.first); } + table_map subselect_union_engine::upper_select_const_tables() { return calc_const_tables((TABLE_LIST *) unit->outer_select()-> table_list.first); } + + +void subselect_single_select_engine::print(String *str) +{ + select_lex->print(thd, str); +} + + +void subselect_union_engine::print(String *str) +{ + unit->print(str); +} + + +void subselect_uniquesubquery_engine::print(String *str) +{ + str->append("<primary_index_lookup>(", 23); + tab->ref.items[0]->print(str); + str->append(" in ", 4); + str->append(tab->table->real_name); + KEY *key_info= tab->table->key_info+ tab->ref.key; + str->append(" on ", 4); + str->append(key_info->name); + if (cond) + { + str->append(" where ", 7); + cond->print(str); + } + str->append(')'); +} + + +void subselect_indexsubquery_engine::print(String *str) +{ + str->append("<index_lookup>(", 15); + tab->ref.items[0]->print(str); + str->append(" in ", 4); + str->append(tab->table->real_name); + KEY *key_info= tab->table->key_info+ tab->ref.key; + str->append(" on ", 4); + str->append(key_info->name); + if (check_null) + str->append(" chicking NULL", 14); + if (cond) + { + str->append(" where ", 7); + cond->print(str); + } + str->append(')'); +} diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 2a7f7b3f441..712b3de42ad 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -27,8 +27,6 @@ class select_subselect; class subselect_engine; class Item_bool_func2; -typedef Item_bool_func2* (*compare_func_creator)(Item*, Item*); - /* base class for subselects */ class Item_subselect :public Item_result_field @@ -92,13 +90,7 @@ public: inline table_map get_used_tables_cache() { return used_tables_cache; } inline bool get_const_item_cache() { return const_item_cache; } void update_used_tables(); - void print(String *str) - { - if (name) - str->append(name); - else - str->append("-subselect-"); - } + void print(String *str); bool change_engine(subselect_engine *eng) { engine= eng; @@ -147,9 +139,11 @@ public: /* used in static ALL/ANY optimisation */ class Item_maxmin_subselect :public Item_singlerow_subselect { + bool max; public: Item_maxmin_subselect(Item_subselect *parent, st_select_lex *select_lex, bool max); + void print(String *str); }; /* exists subselect */ @@ -174,6 +168,7 @@ public: double val(); String *val_str(String*); void fix_length_and_dec(); + void print(String *str); friend class select_exists_subselect; friend class subselect_uniquesubquery_engine; @@ -194,12 +189,15 @@ protected: Item_in_optimizer *optimizer; bool was_null; bool abort_on_null; + bool transformed; public: Item_func_not_all *upper_not; // point on NOT before ALL subquery Item_in_subselect(Item * left_expr, st_select_lex *select_lex); Item_in_subselect() - :Item_exists_subselect(), abort_on_null(0), upper_not(0) {} + :Item_exists_subselect(), abort_on_null(0), transformed(0), upper_not(0) + + {} subs_type substype() { return IN_SUBS; } void reset() @@ -210,13 +208,14 @@ public: } trans_res select_transformer(JOIN *join); trans_res single_value_transformer(JOIN *join, - compare_func_creator func); + Comp_creator *func); trans_res row_value_transformer(JOIN * join); longlong val_int(); double val(); String *val_str(String*); void top_level_item() { abort_on_null=1; } bool test_limit(st_select_lex_unit *unit); + void print(String *str); friend class Item_ref_null_helper; friend class Item_is_not_null_test; @@ -228,15 +227,18 @@ public: class Item_allany_subselect :public Item_in_subselect { protected: - compare_func_creator func; + Comp_creator *func; public: - Item_allany_subselect(Item * left_expr, compare_func_creator f, - st_select_lex *select_lex); + bool all; + + Item_allany_subselect(Item * left_expr, Comp_creator *f, + st_select_lex *select_lex, bool all); // only ALL subquery has upper not subs_type substype() { return upper_not?ALL_SUBS:ANY_SUBS; } trans_res select_transformer(JOIN *join); + void print(String *str); }; @@ -274,6 +276,7 @@ public: bool may_be_null() { return maybe_null; }; virtual table_map upper_select_const_tables()= 0; static table_map calc_const_tables(TABLE_LIST *); + virtual void print(String *str)= 0; }; @@ -296,6 +299,7 @@ public: bool uncacheable(); void exclude(); table_map upper_select_const_tables(); + void print (String *str); }; @@ -314,6 +318,7 @@ public: bool uncacheable(); void exclude(); table_map upper_select_const_tables(); + void print (String *str); }; @@ -341,6 +346,7 @@ public: bool uncacheable() { return 1; } void exclude(); table_map upper_select_const_tables() { return 0; } + void print (String *str); }; @@ -357,4 +363,5 @@ public: check_null(chk_null) {} int exec(); + void print (String *str); }; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index ed2a03beccf..74dd95bf0ab 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1366,6 +1366,14 @@ longlong Item_sum_count_distinct::val_int() return table->file->records; } + +void Item_sum_count_distinct::print(String *str) +{ + str->append("count(distinct ", 15); + args[0]->print(str); + str->append(')'); +} + /**************************************************************************** ** Functions to handle dynamic loadable aggregates ** Original source by: Alexis Mikhailov <root@medinf.chuvashia.su> @@ -1960,3 +1968,29 @@ String* Item_func_group_concat::val_str(String* str) } return &result; } + +void Item_func_group_concat::print(String *str) +{ + str->append("group_concat(", 13); + if (distinct) + str->append("distinct ", 9); + for (uint i= 0; i < arg_count; i++) + { + if (i) + str->append(','); + args[i]->print(str); + } + if (arg_count_order) + { + str->append(" order by ", 10); + for (uint i= 0 ; i < arg_count_order ; i++) + { + if (i) + str->append(','); + (*order[i]->item)->print(str); + } + } + str->append(" seperator \'", 12); + str->append(*separator); + str->append("\')", 2); +} diff --git a/sql/item_sum.h b/sql/item_sum.h index e5061e1e05a..d454f06ccde 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -238,6 +238,7 @@ class Item_sum_count_distinct :public Item_sum_int void make_unique(); Item *copy_or_same(THD* thd); void no_rows_in_result() {} + void print(String *str); }; @@ -748,4 +749,5 @@ class Item_func_group_concat : public Item_sum String* val_str(String* str); Item *copy_or_same(THD* thd); void no_rows_in_result() {} + void print(String *str); }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 4009256ee17..cf71f2b3bef 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,310 +25,290 @@ #include <m_ctype.h> #include <time.h> -/* -** Todo: Move month and days to language files -*/ +/* TODO: Move month and days to language files */ #define MAX_DAY_NUMBER 3652424L -static String month_names[] = -{ - String("January", &my_charset_latin1), - String("February", &my_charset_latin1), - String("March", &my_charset_latin1), - String("April", &my_charset_latin1), - String("May", &my_charset_latin1), - String("June", &my_charset_latin1), - String("July", &my_charset_latin1), - String("August", &my_charset_latin1), - String("September", &my_charset_latin1), - String("October", &my_charset_latin1), - String("November", &my_charset_latin1), - String("December", &my_charset_latin1) +static const char *month_names[]= +{ + "January", "February", "March", "April", "May", "June", "July", "August", + "September", "October", "November", "December", NullS +}; + +TYPELIB month_names_typelib= +{ array_elements(month_names)-1,"", month_names }; + +static const char *day_names[]= +{ + "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" ,"Sunday", NullS }; -static String day_names[] = + +TYPELIB day_names_typelib= +{ array_elements(day_names)-1,"", day_names}; + + +enum date_time_format_types { - String("Monday", &my_charset_latin1), - String("Tuesday", &my_charset_latin1), - String("Wednesday", &my_charset_latin1), - String("Thursday", &my_charset_latin1), - String("Friday", &my_charset_latin1), - String("Saturday", &my_charset_latin1), - String("Sunday", &my_charset_latin1) + TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND }; -uint check_names(String *arr,int item_count,const char *val_ptr, - const char *val_end, uint *val, bool check_part) +/* + OPTIMIZATION TODO: + - Replace the switch with a function that should be called for each + date type. + - Remove sprintf and opencode the conversion, like we do in + Field_datetime. + + The reason for this functions existence is that as we don't have a + way to know if a datetime/time value has microseconds in them + we are now only adding microseconds to the output if the + value has microseconds. + + We can't use a standard make_date_time() for this as we don't know + if someone will use %f in the format specifier in which case we would get + the microseconds twice. +*/ + +static bool make_datetime(date_time_format_types format, TIME *ltime, + String *str) { - for (int i= 0; i < item_count; i++) - { - String *tmp=&arr[i]; - if (!my_strnncoll(&my_charset_latin1, - (const uchar *) val_ptr, 3, - (const uchar *) tmp->ptr(), 3)) - { - if (check_part) - { - *val= i+1; - return 3; - } + char *buff; + CHARSET_INFO *cs= &my_charset_bin; + uint length= 30; - int part_len= tmp->length() - 3; - int val_len= val_end - val_ptr - 3; - if (val_len < part_len) - return 0; - val_ptr+=3; - if (!my_strnncoll(&my_charset_latin1, - (const uchar *) val_ptr, part_len, - (const uchar *) tmp->ptr() + 3, part_len)) - { - *val= i+1; - return tmp->length(); - } - return 0; - } - } - return 0; -} + if (str->alloc(length)) + return 1; + buff= (char*) str->ptr(); -uint check_val_is_digit(const char *ptr, uint val_len, uint digit_count) -{ - uint i; - uint verify_count= (val_len < digit_count ? val_len : digit_count); - uint digit_found= 0; - for (i= 0; i < verify_count; i++) - { - if (!my_isdigit(&my_charset_latin1, *(ptr+i))) - break; - digit_found++; + switch (format) { + case TIME_ONLY: + length= cs->cset->snprintf(cs, buff, length, "%s%02d:%02d:%02d", + ltime->neg ? "-" : "", + ltime->hour, ltime->minute, ltime->second); + break; + case TIME_MICROSECOND: + length= cs->cset->snprintf(cs, buff, length, "%s%02d:%02d:%02d.%06d", + ltime->neg ? "-" : "", + ltime->hour, ltime->minute, ltime->second, + ltime->second_part); + break; + case DATE_ONLY: + length= cs->cset->snprintf(cs, buff, length, "%04d-%02d-%02d", + ltime->year, ltime->month, ltime->day); + break; + case DATE_TIME: + length= cs->cset->snprintf(cs, buff, length, + "%04d-%02d-%02d %02d:%02d:%02d", + ltime->year, ltime->month, ltime->day, + ltime->hour, ltime->minute, ltime->second); + break; + case DATE_TIME_MICROSECOND: + length= cs->cset->snprintf(cs, buff, length, + "%04d-%02d-%02d %02d:%02d:%02d.%06d", + ltime->year, ltime->month, ltime->day, + ltime->hour, ltime->minute, ltime->second, + ltime->second_part); + break; } - return digit_found; + + str->length(length); + str->set_charset(cs); + return 0; } /* Extract datetime value to TIME struct from string value according to format string. + + SYNOPSIS + extract_date_time() + format date/time format specification + val String to decode + length Length of string + l_time Store result here + + RETURN + 0 ok + 1 error */ -bool extract_datetime(const char *str_val, uint str_val_len, - const char *str_format, uint str_format_len, - TIME *l_time) + +static bool extract_date_time(DATE_TIME_FORMAT *format, + const char *val, uint length, TIME *l_time) { - char intbuff[15]; int weekday= 0, yearday= 0, daypart= 0, len; - int val_len= 0; int week_number= -1; - ulong length; CHARSET_INFO *cs= &my_charset_bin; - int err= 0; + int error= 0; bool usa_time= 0; bool sunday_first= 0; - const char *rT_format= "%H:%i:%s"; uint part_len= 0; - const char *val_ptr=str_val; - const char *val_end= str_val + str_val_len; - const char *ptr=str_format; - const char *end=ptr+ str_format_len; + const char *val_ptr= val; + const char *val_end= val + length; + const char *ptr= format->format.str; + const char *end= ptr+ format->format.length; + DBUG_ENTER("extract_date_time"); + + bzero((char*) l_time, sizeof(*l_time)); - DBUG_ENTER("extract_datetime"); - for (; ptr != end && val_ptr != val_end; ptr++) + for (; ptr != end && val != val_end; ptr++) { + if (*ptr == '%' && ptr+1 != end) { - val_len= val_end - val_ptr; - char *val_end1= (char *) val_end; + int val_len; + char *tmp; + + /* Skip pre-space between each argument */ + while (my_isspace(cs, *val) && val != val_end) + val++; + + val_len= (uint) (val_end - val); switch (*++ptr) { - case 'h': - case 'I': - case 'H': - l_time->hour= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; - usa_time= (*ptr == 'I' || *ptr == 'h'); - val_ptr+=2; - break; - case 'k': - case 'l': - l_time->hour= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err) - return 1; - usa_time= (*ptr == 'l'); - val_ptr= val_end1; - break; - case 'e': - l_time->day= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err) - return 1; - val_ptr= val_end1; - break; - case 'c': - l_time->month= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err) - return 1; - val_ptr= val_end1; - break; + /* Year */ case 'Y': - l_time->year= my_strntoll(cs, val_ptr, - 4, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 4)) - return 1; - val_ptr+=4; + tmp= (char*) val + min(4, val_len); + l_time->year= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; case 'y': - l_time->year= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; + tmp= (char*) val + min(2, val_len); + l_time->year= (int) my_strtoll10(val, &tmp, &error); + val= tmp; l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); - val_ptr+=2; break; + + /* Month */ case 'm': - l_time->month= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; - val_ptr+=2; + case 'c': + tmp= (char*) val + min(2, val_len); + l_time->month= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; + case 'M': + case 'b': + if ((l_time->month= check_word(&month_names_typelib, + val, val_end, &val)) <= 0) + goto err; + break; + /* Day */ case 'd': - l_time->day= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; - val_ptr+=2; + case 'e': + tmp= (char*) val + min(2, val_len); + l_time->day= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; case 'D': - l_time->day= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_len < val_end1 - val_ptr + 2)) - return 1; - val_ptr= val_end1 + 2; + tmp= (char*) val + min(2, val_len); + l_time->day= (int) my_strtoll10(val, &tmp, &error); + /* Skip 'st, 'nd, 'th .. */ + val= tmp + min((int) (end-tmp), 2); + break; + + /* Hour */ + case 'h': + case 'I': + case 'l': + usa_time= 1; + /* fall through */ + case 'k': + case 'H': + tmp= (char*) val + min(2, val_len); + l_time->hour= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; + + /* Minute */ case 'i': - l_time->minute=my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; - val_ptr+=2; + tmp= (char*) val + min(2, val_len); + l_time->minute= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; + + /* Second */ case 's': case 'S': - l_time->second= my_strntoll(cs, val_ptr, - 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; - val_ptr+=2; + tmp= (char*) val + min(2, val_len); + l_time->second= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; - case 'M': - if (val_len < 3 || - !(part_len= check_names(month_names, 12 , val_ptr, - val_end, &l_time->month, 0))) - return 1; - val_ptr+= part_len; + + /* Second part */ + case 'f': + tmp= (char*) val_end; + l_time->second_part= my_strtoll10(val, &tmp, &error); + val= tmp; break; - case 'b': - if (val_len < 3 || - !(part_len= check_names(month_names, 12 , val_ptr, - val_end,(uint *) &l_time->month, 1))) - return 1; - val_ptr+= part_len; + + /* AM / PM */ + case 'p': + if (val_len < 2 || ! usa_time) + goto err; + if (!my_strnncoll(&my_charset_latin1, + (const uchar *) val, 2, + (const uchar *) "PM", 2)) + daypart= 12; + else if (my_strnncoll(&my_charset_latin1, + (const uchar *) val, 2, + (const uchar *) "AM", 2)) + goto err; break; + + /* Exotic things */ case 'W': - if (val_len < 3 || - !(part_len= check_names(day_names, 7 , val_ptr, - val_end,(uint *) &weekday, 0))) - return 1; - val_ptr+= part_len; - break; case 'a': - if (val_len < 3 || - !(part_len= check_names(day_names, 7 , val_ptr, - val_end,(uint *) &weekday, 1))) - return 1; - val_ptr+= part_len; + if ((weekday= check_word(&day_names_typelib, val, val_end, &val)) <= 0) + goto err; break; case 'w': - weekday= my_strntoll(cs, val_ptr, 1, 10, &val_end1, &err); - if (err) - return 1; - val_ptr++; + tmp= (char*) val + 1; + if ((weekday= (int) my_strtoll10(val, &tmp, &error)) <= 0 || + weekday >= 7) + goto err; + val= tmp; break; case 'j': - yearday= my_strntoll(cs, val_ptr, 3, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 3)) - return 1; - val_ptr+=3; - break; - case 'f': - l_time->second_part= my_strntoll(cs, val_ptr, 3, 10, &val_end1, &err); - if (err) - return 1; - val_ptr= val_end1; - break; - case 'p': - if (val_len < 2) - return 1; - if (!my_strnncoll(&my_charset_latin1, - (const uchar *) val_ptr, 2, - (const uchar *) "PM", 2)) - { - daypart= 12; - val_ptr+= 2; - } + tmp= (char*) val + min(val_len, 3); + yearday= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; + case 'U': - week_number= my_strntoll(cs, val_ptr, 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; sunday_first= 1; - val_ptr+=2; - break; + /* Fall through */ case 'u': - week_number= my_strntoll(cs, val_ptr, 2, 10, &val_end1, &err); - if (err || (val_end1 - val_ptr != 2)) - return 1; - sunday_first=0; - val_ptr+=2; - break; - case 'r': - case 'T': - usa_time= (*ptr == 'r'); - if (extract_datetime(val_ptr, val_end-val_ptr, - rT_format, strlen(rT_format), - l_time)) - return 1; - val_ptr+=8; + tmp= (char*) val + min(val_len, 2); + week_number= (int) my_strtoll10(val, &tmp, &error); + val= tmp; break; + default: - if (*val_ptr != *ptr) - return 1; - val_ptr++; + goto err; } + if (error) // Error from my_strtoll10 + goto err; } - else + else if (!my_isspace(cs, *ptr)) { - if (*val_ptr != *ptr) - return 1; - val_ptr++; + if (*val != *ptr) + goto err; + val++; } } if (usa_time) { if (l_time->hour > 12 || l_time->hour < 1) - return 1; + goto err; l_time->hour= l_time->hour%12+daypart; } if (yearday > 0) { uint days= calc_daynr(l_time->year,1,1) + yearday - 1; - if (days > 0 || days < MAX_DAY_NUMBER) - { - get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); - } + if (days <= 0 || days >= MAX_DAY_NUMBER) + goto err; + get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); } if (week_number >= 0 && weekday) @@ -337,7 +317,7 @@ bool extract_datetime(const char *str_val, uint str_val_len, uint weekday_b; if (weekday > 7 || weekday < 0) - return 1; + goto err; if (sunday_first) weekday = weekday%7; @@ -361,43 +341,43 @@ bool extract_datetime(const char *str_val, uint str_val_len, weekday =weekday - weekday_b - !sunday_first; days+= weekday; } - if (days > 0 || days < MAX_DAY_NUMBER) - { - get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); - } + if (days <= 0 || days >= MAX_DAY_NUMBER) + goto err; + get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day); } if (l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || l_time->minute > 59 || l_time->second > 59) - return 1; + goto err; DBUG_RETURN(0); -} +err: + DBUG_RETURN(1); +} /* - Print datetime string from TIME struct - according to format string. + Create a formated date/time value in a string */ - -String *make_datetime(String *str, TIME *l_time, - const bool is_time_only, - const bool add_second_frac, - const char *ptr, uint format_length, - bool set_len_to_zero) +bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, + timestamp_type type, String *str) { char intbuff[15]; uint days_i; uint hours_i; uint weekday; ulong length; - if (set_len_to_zero) - str->length(0); + const char *ptr, *end; + + str->length(0); + str->set_charset(&my_charset_bin); + if (l_time->neg) str->append("-", 1); - const char *end=ptr+format_length; + + end= (ptr= format->format.str) + format->format.length; for (; ptr != end ; ptr++) { if (*ptr != '%' || ptr+1 == end) @@ -407,33 +387,35 @@ String *make_datetime(String *str, TIME *l_time, switch (*++ptr) { case 'M': if (!l_time->month) - return 0; + return 1; str->append(month_names[l_time->month-1]); break; case 'b': if (!l_time->month) - return 0; - str->append(month_names[l_time->month-1].ptr(),3); + return 1; + str->append(month_names[l_time->month-1],3); break; case 'W': - if (is_time_only) - return 0; - weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,l_time->day),0); + if (type == TIMESTAMP_TIME) + return 1; + weekday= calc_weekday(calc_daynr(l_time->year,l_time->month, + l_time->day),0); str->append(day_names[weekday]); break; case 'a': - if (is_time_only) - return 0; - weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,l_time->day),0); - str->append(day_names[weekday].ptr(),3); + if (type == TIMESTAMP_TIME) + return 1; + weekday=calc_weekday(calc_daynr(l_time->year,l_time->month, + l_time->day),0); + str->append(day_names[weekday],3); break; case 'D': - if (is_time_only) - return 0; + if (type == TIMESTAMP_TIME) + return 1; length= int10_to_str(l_time->day, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 1, '0'); if (l_time->day >= 10 && l_time->day <= 19) - str->append("th"); + str->append("th", 2); else { switch (l_time->day %10) { @@ -496,9 +478,10 @@ String *make_datetime(String *str, TIME *l_time, str->append_with_prefill(intbuff, length, 2, '0'); break; case 'j': - if (is_time_only) - return 0; - length= int10_to_str(calc_daynr(l_time->year,l_time->month,l_time->day) - + if (type == TIMESTAMP_TIME) + return 1; + length= int10_to_str(calc_daynr(l_time->year,l_time->month, + l_time->day) - calc_daynr(l_time->year,1,1) + 1, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 3, '0'); break; @@ -529,12 +512,6 @@ String *make_datetime(String *str, TIME *l_time, case 's': length= int10_to_str(l_time->second, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 2, '0'); - if (add_second_frac) - { - str->append(".", 1); - length= int10_to_str(l_time->second_part, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 6, '0'); - } break; case 'T': length= my_sprintf(intbuff, @@ -549,8 +526,8 @@ String *make_datetime(String *str, TIME *l_time, case 'u': { uint year; - if (is_time_only) - return 0; + if (type == TIMESTAMP_TIME) + return 1; length= int10_to_str(calc_week(l_time, 0, (*ptr) == 'U', &year), intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 2, '0'); @@ -560,8 +537,8 @@ String *make_datetime(String *str, TIME *l_time, case 'V': { uint year; - if (is_time_only) - return 0; + if (type == TIMESTAMP_TIME) + return 1; length= int10_to_str(calc_week(l_time, 1, (*ptr) == 'V', &year), intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 2, '0'); @@ -571,27 +548,29 @@ String *make_datetime(String *str, TIME *l_time, case 'X': { uint year; - if (is_time_only) - return 0; + if (type == TIMESTAMP_TIME) + return 1; (void) calc_week(l_time, 1, (*ptr) == 'X', &year); length= int10_to_str(year, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 4, '0'); } break; case 'w': - if (is_time_only) - return 0; - weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,l_time->day),1); + if (type == TIMESTAMP_TIME) + return 1; + weekday=calc_weekday(calc_daynr(l_time->year,l_time->month, + l_time->day),1); length= int10_to_str(weekday, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 1, '0'); break; + default: str->append(*ptr); break; } } } - return str; + return 0; } @@ -691,21 +670,24 @@ longlong Item_func_month::val_int() return (longlong) ltime.month; } + String* Item_func_monthname::val_str(String* str) { + const char *name; uint month=(uint) Item_func_month::val_int(); + if (!month) // This is also true for NULL { null_value=1; return (String*) 0; } null_value=0; - - String *m=&month_names[month-1]; - str->copy(m->ptr(), m->length(), m->charset(), default_charset()); + name= month_names[month-1]; + str->set(name, strlen(name), system_charset_info); return str; } + // Returns the quarter of the year longlong Item_func_quarter::val_int() @@ -785,14 +767,17 @@ longlong Item_func_weekday::val_int() return (longlong) calc_weekday(tmp_value,odbc_type)+test(odbc_type); } + String* Item_func_dayname::val_str(String* str) { uint weekday=(uint) val_int(); // Always Item_func_daynr() + const char *name; + if (null_value) return (String*) 0; - String *d=&day_names[weekday]; - str->copy(d->ptr(), d->length(), d->charset(), default_charset()); + name= day_names[weekday]; + str->set(name, strlen(name), system_charset_info); return str; } @@ -808,7 +793,7 @@ longlong Item_func_year::val_int() longlong Item_func_unix_timestamp::val_int() { if (arg_count == 0) - return (longlong) thd->query_start(); + return (longlong) current_thd->query_start(); if (args[0]->type() == FIELD_ITEM) { // Optimize timestamp field Field *field=((Item_field*) args[0])->field; @@ -820,7 +805,7 @@ longlong Item_func_unix_timestamp::val_int() { return 0; /* purecov: inspected */ } - return (longlong) str_to_timestamp(str->ptr(),str->length(), thd); + return (longlong) str_to_timestamp(str->ptr(),str->length()); } @@ -840,15 +825,18 @@ longlong Item_func_time_to_sec::val_int() */ static bool get_interval_value(Item *args,interval_type int_type, - String *str_value, INTERVAL *t) + String *str_value, INTERVAL *interval) { long array[5],value; const char *str; uint32 length; - LINT_INIT(value); LINT_INIT(str); LINT_INIT(length); CHARSET_INFO *cs=str_value->charset(); - bzero((char*) t,sizeof(*t)); + LINT_INIT(value); + LINT_INIT(str); + LINT_INIT(length); + + bzero((char*) interval,sizeof(*interval)); if ((int) int_type <= INTERVAL_MICROSECOND) { value=(long) args->val_int(); @@ -856,7 +844,7 @@ static bool get_interval_value(Item *args,interval_type int_type, return 1; if (value < 0) { - t->neg=1; + interval->neg=1; value= -value; } } @@ -866,14 +854,14 @@ static bool get_interval_value(Item *args,interval_type int_type, if (!(res=args->val_str(str_value))) return (1); - /* record negative intervalls in t->neg */ + /* record negative intervalls in interval->neg */ str=res->ptr(); const char *end=str+res->length(); while (str != end && my_isspace(cs,*str)) str++; if (str != end && *str == '-') { - t->neg=1; + interval->neg=1; str++; } length=(uint32) (end-str); // Set up pointers to new str @@ -881,101 +869,101 @@ static bool get_interval_value(Item *args,interval_type int_type, switch (int_type) { case INTERVAL_YEAR: - t->year=value; + interval->year=value; break; case INTERVAL_MONTH: - t->month=value; + interval->month=value; break; case INTERVAL_DAY: - t->day=value; + interval->day=value; break; case INTERVAL_HOUR: - t->hour=value; + interval->hour=value; break; case INTERVAL_MICROSECOND: - t->second_part=value; + interval->second_part=value; break; case INTERVAL_MINUTE: - t->minute=value; + interval->minute=value; break; case INTERVAL_SECOND: - t->second=value; + interval->second=value; break; case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM if (get_interval_info(str,length,cs,2,array)) return (1); - t->year=array[0]; - t->month=array[1]; + interval->year=array[0]; + interval->month=array[1]; break; case INTERVAL_DAY_HOUR: if (get_interval_info(str,length,cs,2,array)) return (1); - t->day=array[0]; - t->hour=array[1]; + interval->day=array[0]; + interval->hour=array[1]; break; case INTERVAL_DAY_MICROSECOND: if (get_interval_info(str,length,cs,5,array)) return (1); - t->day=array[0]; - t->hour=array[1]; - t->minute=array[2]; - t->second=array[3]; - t->second_part=array[4]; + interval->day=array[0]; + interval->hour=array[1]; + interval->minute=array[2]; + interval->second=array[3]; + interval->second_part=array[4]; break; case INTERVAL_DAY_MINUTE: if (get_interval_info(str,length,cs,3,array)) return (1); - t->day=array[0]; - t->hour=array[1]; - t->minute=array[2]; + interval->day=array[0]; + interval->hour=array[1]; + interval->minute=array[2]; break; case INTERVAL_DAY_SECOND: if (get_interval_info(str,length,cs,4,array)) return (1); - t->day=array[0]; - t->hour=array[1]; - t->minute=array[2]; - t->second=array[3]; + interval->day=array[0]; + interval->hour=array[1]; + interval->minute=array[2]; + interval->second=array[3]; break; case INTERVAL_HOUR_MICROSECOND: if (get_interval_info(str,length,cs,4,array)) return (1); - t->hour=array[0]; - t->minute=array[1]; - t->second=array[2]; - t->second_part=array[3]; + interval->hour=array[0]; + interval->minute=array[1]; + interval->second=array[2]; + interval->second_part=array[3]; break; case INTERVAL_HOUR_MINUTE: if (get_interval_info(str,length,cs,2,array)) return (1); - t->hour=array[0]; - t->minute=array[1]; + interval->hour=array[0]; + interval->minute=array[1]; break; case INTERVAL_HOUR_SECOND: if (get_interval_info(str,length,cs,3,array)) return (1); - t->hour=array[0]; - t->minute=array[1]; - t->second=array[2]; + interval->hour=array[0]; + interval->minute=array[1]; + interval->second=array[2]; break; case INTERVAL_MINUTE_MICROSECOND: if (get_interval_info(str,length,cs,3,array)) return (1); - t->minute=array[0]; - t->second=array[1]; - t->second_part=array[2]; + interval->minute=array[0]; + interval->second=array[1]; + interval->second_part=array[2]; break; case INTERVAL_MINUTE_SECOND: if (get_interval_info(str,length,cs,2,array)) return (1); - t->minute=array[0]; - t->second=array[1]; + interval->minute=array[0]; + interval->second=array[1]; break; case INTERVAL_SECOND_MICROSECOND: if (get_interval_info(str,length,cs,2,array)) return (1); - t->second=array[0]; - t->second_part=array[1]; + interval->second=array[0]; + interval->second_part=array[1]; break; } return 0; @@ -984,34 +972,33 @@ static bool get_interval_value(Item *args,interval_type int_type, String *Item_date::val_str(String *str) { - DATETIME_FORMAT *tmp_format; TIME ltime; ulong value=(ulong) val_int(); if (null_value) - goto null_date; + return (String*) 0; + + if (str->alloc(11)) + { + null_value= 1; + return (String *) 0; + } ltime.year= (value/10000L) % 10000; ltime.month= (value/100)%100; ltime.day= (value%100); - ltime.neg=0; + ltime.neg= 0; ltime.time_type=TIMESTAMP_DATE; - tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format; - if (make_datetime(str, <ime, 0, 0, - tmp_format->format, tmp_format->format_length, 1)) - return str; - - null_value= 1; -null_date: - return 0; + make_date((DATE_TIME_FORMAT *) 0, <ime, str); + return str; } int Item_date::save_in_field(Field *field, bool no_conversions) { TIME ltime; - timestamp_type t_type=TIMESTAMP_FULL; - if (get_date(<ime,1)) + timestamp_type t_type=TIMESTAMP_DATETIME; + if (get_date(<ime, TIME_FUZZY_DATE)) { if (null_value) return set_field_to_null(field); @@ -1039,11 +1026,11 @@ void Item_func_curdate::fix_length_and_dec() { struct tm start; - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=10*default_charset()->mbmaxlen; + max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; - store_now_in_tm(thd->query_start(),&start); + store_now_in_tm(current_thd->query_start(),&start); value=(longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+ ((uint) start.tm_mon+1)*100+ @@ -1062,7 +1049,7 @@ void Item_func_curdate::fix_length_and_dec() bool Item_func_curdate::get_date(TIME *res, - bool fuzzy_date __attribute__((unused))) + uint fuzzy_date __attribute__((unused))) { *res=ltime; return 0; @@ -1091,19 +1078,19 @@ void Item_func_curdate_utc::store_now_in_tm(time_t now, struct tm *now_tm) String *Item_func_curtime::val_str(String *str) { - str_value.set(buff,buff_length,default_charset()); + str_value.set(buff, buff_length, &my_charset_bin); return &str_value; } + void Item_func_curtime::fix_length_and_dec() { struct tm start; - DATETIME_FORMAT *tmp_format; - String tmp((char*) buff,sizeof(buff),default_charset()); + String tmp((char*) buff,sizeof(buff), &my_charset_bin); TIME ltime; decimals=0; - store_now_in_tm(thd->query_start(),&start); + store_now_in_tm(current_thd->query_start(),&start); value=(longlong) ((ulong) ((uint) start.tm_hour)*10000L+ (ulong) (((uint) start.tm_min)*100L+ (uint) start.tm_sec)); @@ -1113,12 +1100,8 @@ void Item_func_curtime::fix_length_and_dec() ltime.second= start.tm_sec; ltime.second_part= 0; ltime.neg= 0; - ltime.time_type= TIMESTAMP_TIME; - tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; - make_datetime(&tmp, <ime, 0, 0, - tmp_format->format, tmp_format->format_length, 1); - buff_length= tmp.length(); - max_length= buff_length; + make_time((DATE_TIME_FORMAT *) 0, <ime, &tmp); + max_length= buff_length= tmp.length(); } @@ -1144,7 +1127,7 @@ void Item_func_curtime_utc::store_now_in_tm(time_t now, struct tm *now_tm) String *Item_func_now::val_str(String *str) { - str_value.set(buff,buff_length,default_charset()); + str_value.set(buff,buff_length, &my_charset_bin); return &str_value; } @@ -1152,11 +1135,12 @@ String *Item_func_now::val_str(String *str) void Item_func_now::fix_length_and_dec() { struct tm start; - DATETIME_FORMAT *tmp_format; String tmp((char*) buff,sizeof(buff),&my_charset_bin); - + decimals=0; - store_now_in_tm(thd->query_start(),&start); + collation.set(&my_charset_bin); + + store_now_in_tm(current_thd->query_start(),&start); value=((longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+ (((uint) start.tm_mon+1)*100+ (uint) start.tm_mday))*(longlong) 1000000L+ @@ -1173,17 +1157,15 @@ void Item_func_now::fix_length_and_dec() ltime.second= start.tm_sec; ltime.second_part= 0; ltime.neg= 0; - ltime.time_type= TIMESTAMP_FULL; + ltime.time_type= TIMESTAMP_DATETIME; - tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; - make_datetime(&tmp, <ime, 0, 0, - tmp_format->format, tmp_format->format_length, 1); - buff_length= tmp.length(); - max_length= buff_length; + make_datetime((DATE_TIME_FORMAT *) 0, <ime, &tmp); + max_length= buff_length= tmp.length(); } + bool Item_func_now::get_date(TIME *res, - bool fuzzy_date __attribute__((unused))) + uint fuzzy_date __attribute__((unused))) { *res=ltime; return 0; @@ -1193,7 +1175,7 @@ bool Item_func_now::get_date(TIME *res, int Item_func_now::save_in_field(Field *to, bool no_conversions) { to->set_notnull(); - to->store_time(<ime,TIMESTAMP_FULL); + to->store_time(<ime,TIMESTAMP_DATETIME); return 0; } @@ -1222,12 +1204,13 @@ String *Item_func_sec_to_time::val_str(String *str) { longlong seconds=(longlong) args[0]->val_int(); uint sec; - - DATETIME_FORMAT *tmp_format; TIME ltime; - if ((null_value=args[0]->null_value)) - goto null_date; + if ((null_value=args[0]->null_value) || str->alloc(19)) + { + null_value= 1; + return (String*) 0; + } ltime.neg= 0; if (seconds < 0) @@ -1242,14 +1225,8 @@ String *Item_func_sec_to_time::val_str(String *str) ltime.minute= sec/60; ltime.second= sec % 60; - tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; - if (make_datetime(str, <ime, 0, 0, - tmp_format->format, tmp_format->format_length, 1)) - return str; - - null_value= 1; -null_date: - return (String*) 0; + make_time((DATE_TIME_FORMAT *) 0, <ime, str); + return str; } @@ -1359,9 +1336,9 @@ String *Item_func_date_format::val_str(String *str) { String *format; TIME l_time; - uint size,weekday; + uint size; - if (!date_or_time) + if (!is_time_format) { if (get_arg0_date(&l_time,1)) return 0; @@ -1369,10 +1346,8 @@ String *Item_func_date_format::val_str(String *str) else { String *res; - if (!(res=args[0]->val_str(str))) - goto null_date; - - if (str_to_time(res->ptr(),res->length(),&l_time, thd)) + if (!(res=args[0]->val_str(str)) || + (str_to_time(res->ptr(),res->length(),&l_time))) goto null_date; l_time.year=l_time.month=l_time.day=0; @@ -1391,10 +1366,13 @@ String *Item_func_date_format::val_str(String *str) if (str->alloc(size)) goto null_date; + DATE_TIME_FORMAT date_time_format; + date_time_format.format.str= (char*) format->ptr(); + date_time_format.format.length= format->length(); /* Create the result string */ - if (make_datetime(str, &l_time, 0, 0, - format->ptr(), format->length(), 1)) + if (!make_date_time(&date_time_format, &l_time, + is_time_format ? TIMESTAMP_TIME : TIMESTAMP_DATE, str)) return str; null_date: @@ -1406,10 +1384,8 @@ null_date: String *Item_func_from_unixtime::val_str(String *str) { struct tm tm_tmp,*start; - DATETIME_FORMAT *tmp_format; time_t tmp=(time_t) args[0]->val_int(); - uint32 l; - CHARSET_INFO *cs=default_charset(); + CHARSET_INFO *cs= &my_charset_bin; TIME ltime; if ((null_value=args[0]->null_value)) @@ -1427,14 +1403,13 @@ String *Item_func_from_unixtime::val_str(String *str) ltime.second_part= 0; ltime.neg=0; - l=20*cs->mbmaxlen+32; - tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; - if (str->alloc(l) && make_datetime(str, <ime, 1, 0, - tmp_format->format, - tmp_format->format_length, 1)) - return str; - null_value= 1; + if (str->alloc(20*MY_CHARSET_BIN_MB_MAXLEN)) + goto null_date; + make_datetime((DATE_TIME_FORMAT *) 0, <ime, str); + return str; + null_date: + null_value=1; return 0; } @@ -1456,7 +1431,7 @@ longlong Item_func_from_unixtime::val_int() } bool Item_func_from_unixtime::get_date(TIME *ltime, - bool fuzzy_date __attribute__((unused))) + uint fuzzy_date __attribute__((unused))) { time_t tmp=(time_t) (ulong) args[0]->val_int(); if ((null_value=args[0]->null_value)) @@ -1479,10 +1454,11 @@ bool Item_func_from_unixtime::get_date(TIME *ltime, void Item_date_add_interval::fix_length_and_dec() { enum_field_types arg0_field_type; - collation.set(default_charset()); + + collation.set(&my_charset_bin); maybe_null=1; - max_length=26*MY_CHARSET_BIN_MB_MAXLEN; - value.alloc(32); + max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; + value.alloc(max_length); /* The field type for the result of an Item_date function is defined as @@ -1512,10 +1488,11 @@ void Item_date_add_interval::fix_length_and_dec() /* Here arg[1] is a Item_interval object */ -bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) +bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date) { long period,sign; INTERVAL interval; + ltime->neg= 0; if (args[0]->get_date(ltime,0) || get_interval_value(args[1],int_type,&value,&interval)) @@ -1541,7 +1518,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) case INTERVAL_DAY_MINUTE: case INTERVAL_DAY_HOUR: long sec,days,daynr,microseconds,extra_sec; - ltime->time_type=TIMESTAMP_FULL; // Return full date + ltime->time_type=TIMESTAMP_DATETIME; // Return full date microseconds= ltime->second_part + sign*interval.second_part; extra_sec= microseconds/1000000L; microseconds= microseconds%1000000L; @@ -1616,23 +1593,26 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) String *Item_date_add_interval::val_str(String *str) { TIME ltime; - DATETIME_FORMAT *tmp_format; + enum date_time_format_types format; if (Item_date_add_interval::get_date(<ime,0)) return 0; if (ltime.time_type == TIMESTAMP_DATE) - tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format; - else - tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; - if (make_datetime(str, <ime, 1, ltime.second_part, - tmp_format->format, tmp_format->format_length, 1)) + format= DATE_ONLY; + else if (ltime.second_part) + format= DATE_TIME_MICROSECOND; + else + format= DATE_TIME; + + if (!make_datetime(format, <ime, str)) return str; null_value=1; return 0; } + longlong Item_date_add_interval::val_int() { TIME ltime; @@ -1644,6 +1624,36 @@ longlong Item_date_add_interval::val_int() ((date*100L + ltime.hour)*100L+ ltime.minute)*100L + ltime.second; } +static const char *interval_names[]= +{ + "year", "month", "day", "hour", "minute", + "second", "microsecond", "year_month", + "day_hour", "day_minute", "day_second", + "hour_minute", "hour_second", "minute_second", + "day_microsecond", "hour_microsecond", + "minute_microsecond", "second_microsecond" +}; + +void Item_date_add_interval::print(String *str) +{ + str->append('('); + args[0]->print(str); + str->append(date_sub_interval?" - interval ":" + interval "); + args[1]->print(str); + str->append(' '); + str->append(interval_names[int_type]); + str->append(')'); +} + +void Item_extract::print(String *str) +{ + str->append("extract(", 8); + str->append(interval_names[int_type]); + str->append(" from ", 6); + args[0]->print(str); + str->append(')'); +} + void Item_extract::fix_length_and_dec() { value.alloc(32); // alloc buffer @@ -1685,7 +1695,7 @@ longlong Item_extract::val_int() else { String *res= args[0]->val_str(&value); - if (!res || str_to_time(res->ptr(),res->length(),<ime, thd)) + if (!res || str_to_time(res->ptr(),res->length(),<ime)) { null_value=1; return 0; @@ -1751,10 +1761,33 @@ bool Item_extract::eq(const Item *item, bool binary_cmp) const void Item_typecast::print(String *str) { - str->append("CAST("); + str->append("cast(", 5); args[0]->print(str); - str->append(" AS "); - str->append(func_name()); + str->append(" as ", 4); + str->append(cast_type()); + str->append(')'); +} + +void Item_char_typecast::print(String *str) +{ + str->append("cast(", 5); + args[0]->print(str); + str->append(" as char", 8); + if (cast_length >= 0) + { + str->append('('); + char buffer[20]; + // my_charset_bin is good enough for numbers + String st(buffer, sizeof(buffer), &my_charset_bin); + st.set((ulonglong)cast_length, &my_charset_bin); + str->append(st); + str->append(')'); + } + if (cast_cs) + { + str->append(" charset ", 9); + str->append(cast_cs->name); + } str->append(')'); } @@ -1811,15 +1844,13 @@ void Item_char_typecast::fix_length_and_dec() max_length= char_length * cast_cs->mbmaxlen; } + String *Item_datetime_typecast::val_str(String *str) { TIME ltime; - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (thd, DATETIME_FORMAT_TYPE).datetime_format); - if (!get_arg0_date(<ime,1) && - make_datetime(str, <ime, 1, ltime.second_part, - tmp_format->format, tmp_format->format_length, 1)) + !make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME, + <ime, str)) return str; null_date: @@ -1839,12 +1870,10 @@ bool Item_time_typecast::get_time(TIME *ltime) String *Item_time_typecast::val_str(String *str) { TIME ltime; - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (thd, TIME_FORMAT_TYPE).datetime_format); if (!get_arg0_time(<ime) && - make_datetime(str, <ime, 0, ltime.second_part, - tmp_format->format, tmp_format->format_length, 1)) + !make_datetime(ltime.second_part ? TIME_MICROSECOND : TIME_ONLY, + <ime, str)) return str; null_value=1; @@ -1852,7 +1881,7 @@ String *Item_time_typecast::val_str(String *str) } -bool Item_date_typecast::get_date(TIME *ltime, bool fuzzy_date) +bool Item_date_typecast::get_date(TIME *ltime, uint fuzzy_date) { bool res= get_arg0_date(ltime,1); ltime->time_type= TIMESTAMP_DATE; @@ -1863,19 +1892,18 @@ bool Item_date_typecast::get_date(TIME *ltime, bool fuzzy_date) String *Item_date_typecast::val_str(String *str) { TIME ltime; - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (thd, DATE_FORMAT_TYPE).datetime_format); - if (!get_arg0_date(<ime,1) && - make_datetime(str, <ime, 1, 0, - tmp_format->format, tmp_format->format_length, 1)) - return str; + if (!get_arg0_date(<ime,1) && !str->alloc(11)) + { + make_date((DATE_TIME_FORMAT *) 0,<ime, str); + return str; + } -null_date: null_value=1; return 0; } + /* MAKEDATE(a,b) is a date function that creates a date value from a year and day value. @@ -1890,22 +1918,21 @@ String *Item_func_makedate::val_str(String *str) if (args[0]->null_value || args[1]->null_value || yearnr < 0 || daynr <= 0) - goto null_date; + goto err; days= calc_daynr(yearnr,1,1) + daynr - 1; - if (days > 0 || days < MAX_DAY_NUMBER) // Day number from year 0 to 9999-12-31 + // Day number from year 0 to 9999-12-31 + if (days >= 0 && days < MAX_DAY_NUMBER) { null_value=0; get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day); - - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (thd, DATE_FORMAT_TYPE).datetime_format); - if (make_datetime(str, &l_time, 1, 0, - tmp_format->format, tmp_format->format_length, 1)) - return str; + if (str->alloc(11)) + goto err; + make_date((DATE_TIME_FORMAT *) 0, &l_time, str); + return str; } -null_date: +err: null_value=1; return 0; } @@ -1915,11 +1942,11 @@ void Item_func_add_time::fix_length_and_dec() { enum_field_types arg0_field_type; decimals=0; - max_length=26*MY_CHARSET_BIN_MB_MAXLEN; + max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; /* - The field type for the result of an Item_func_add_time function is defined as - follows: + The field type for the result of an Item_func_add_time function is defined + as follows: - If first arg is a MYSQL_TYPE_DATETIME or MYSQL_TYPE_TIMESTAMP result is MYSQL_TYPE_DATETIME @@ -1938,7 +1965,8 @@ void Item_func_add_time::fix_length_and_dec() } /* - ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a time/datetime value + ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a + time/datetime value t: time_or_datetime_expression a: time_expression @@ -1952,7 +1980,6 @@ String *Item_func_add_time::val_str(String *str) bool is_time= 0; long microseconds, seconds, days= 0; int l_sign= sign; - DATETIME_FORMAT *tmp_format; null_value=0; l_time3.neg= 0; @@ -1968,7 +1995,7 @@ String *Item_func_add_time::val_str(String *str) { if (args[0]->get_time(&l_time1) || args[1]->get_time(&l_time2) || - l_time2.time_type == TIMESTAMP_FULL) + l_time2.time_type == TIMESTAMP_DATETIME) goto null_date; is_time= (l_time1.time_type == TIMESTAMP_TIME); if (is_time && (l_time2.neg == l_time1.neg && l_time1.neg)) @@ -1984,7 +2011,8 @@ String *Item_func_add_time::val_str(String *str) if (is_time) seconds+= l_time1.day*86400L; else - days+= calc_daynr((uint) l_time1.year,(uint) l_time1.month, (uint) l_time1.day); + days+= calc_daynr((uint) l_time1.year,(uint) l_time1.month, + (uint) l_time1.day); seconds= seconds + microseconds/1000000L; microseconds= microseconds%1000000L; days+= seconds/86400L; @@ -2017,21 +2045,19 @@ String *Item_func_add_time::val_str(String *str) calc_time_from_sec(&l_time3, seconds, microseconds); if (!is_time) { - tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day); if (l_time3.day && - make_datetime(str, &l_time3, 1, - l_time1.second_part || l_time2.second_part, - tmp_format->format, tmp_format->format_length, 1)) + !make_datetime(l_time1.second_part || l_time2.second_part ? + DATE_TIME_MICROSECOND : DATE_TIME, + &l_time3, str)) return str; goto null_date; } - tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; l_time3.hour+= days*24; - if (make_datetime(str, &l_time3, 0, - l_time1.second_part || l_time2.second_part, - tmp_format->format, tmp_format->format_length, 1)) + if (!make_datetime(l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY, + &l_time3, str)) return str; null_date: @@ -2039,6 +2065,28 @@ null_date: return 0; } + +void Item_func_add_time::print(String *str) +{ + if (is_date) + { + DBUG_ASSERT(sign > 0); + str->append("timestamp(", 10); + } + else + { + if (sign > 0) + str->append("addtime(", 8); + else + str->append("subtime(", 8); + } + args[0]->print(str); + str->append(','); + args[0]->print(str); + str->append(')'); +} + + /* TIMEDIFF(t,s) is a time function that calculates the time value between a start and end time. @@ -2054,7 +2102,6 @@ String *Item_func_timediff::val_str(String *str) long days; int l_sign= 1; TIME l_time1 ,l_time2, l_time3; - DATETIME_FORMAT *tmp_format; null_value= 0; if (args[0]->get_time(&l_time1) || @@ -2101,10 +2148,9 @@ String *Item_func_timediff::val_str(String *str) calc_time_from_sec(&l_time3, seconds, microseconds); - tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; - if (make_datetime(str, &l_time3, 0, - l_time1.second_part || l_time2.second_part, - tmp_format->format, tmp_format->format_length, 1)) + if (!make_datetime(l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY, + &l_time3, str)) return str; null_date: @@ -2121,7 +2167,6 @@ null_date: String *Item_func_maketime::val_str(String *str) { TIME ltime; - DATETIME_FORMAT *tmp_format; long hour= args[0]->val_int(); long minute= args[1]->val_int(); @@ -2131,8 +2176,9 @@ String *Item_func_maketime::val_str(String *str) args[1]->null_value || args[2]->null_value || minute > 59 || minute < 0 || - second > 59 || second < 0))) - goto null_date; + second > 59 || second < 0 || + str->alloc(19)))) + return 0; ltime.neg= 0; if (hour < 0) @@ -2143,21 +2189,19 @@ String *Item_func_maketime::val_str(String *str) ltime.hour= (ulong)hour; ltime.minute= (ulong)minute; ltime.second= (ulong)second; - tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; - if (make_datetime(str, <ime, 0, 0, - tmp_format->format, tmp_format->format_length, 1)) - return str; - -null_date: - return 0; + make_time((DATE_TIME_FORMAT *) 0, <ime, str); + return str; } + /* - MICROSECOND(a) is a function ( extraction) that extracts the microseconds from a. + MICROSECOND(a) is a function ( extraction) that extracts the microseconds + from a. a: Datetime or time value Result: int value */ + longlong Item_func_microsecond::val_int() { TIME ltime; @@ -2166,78 +2210,103 @@ longlong Item_func_microsecond::val_int() return 0; } -/* - Array of MySQL date/time/datetime formats - Firts element is date format - Second element is time format - Third element is datetime format - Fourth is format name. -*/ - -const char *datetime_formats[4][5]= -{ - {"%m.%d.%Y", "%Y-%m-%d", "%Y-%m-%d", "%d.%m.%Y", "%Y%m%d"}, - {"%h:%i:%s %p", "%H:%i:%s", "%H:%i:%s", "%H.%i.%S", "%H%i%s"}, - {"%Y-%m-%d-%H.%i.%s", "%Y-%m-%d %H:%i:%s", "%Y-%m-%d %H:%i:%s", "%Y-%m-%d-%H.%i.%s", "%Y%m%d%H%i%s"}, - {"USA", "JIS", "ISO", "EUR", "INTERNAL"} -}; - - -/* - Return format string according format name. - If name is unknown, result is ISO format string -*/ String *Item_func_get_format::val_str(String *str) { - String *val=args[0]->val_str(str); - const char *format_str= datetime_formats[tm_format][ISO_FORMAT]; + const char *format_name; + KNOWN_DATE_TIME_FORMAT *format; + String *val= args[0]->val_str(str); + ulong val_len; + + if ((null_value= args[0]->null_value)) + return 0; - if (!args[0]->null_value) + val_len= val->length(); + for (format= &known_date_time_formats[0]; + (format_name= format->format_name); + format++) { - const char *val_ptr= val->ptr(); - uint val_len= val->length(); - for (int i= 0; i < 5; i++) + uint format_name_len; + format_name_len= strlen(format_name); + if (val_len == format_name_len && + !my_strnncoll(&my_charset_latin1, + (const uchar *) val->ptr(), val_len, + (const uchar *) format_name, val_len)) { - const char *name_format_str= datetime_formats[3][i]; - uint format_str_len= strlen(name_format_str); - if ( val_len == format_str_len && - !my_strnncoll(&my_charset_latin1, - (const uchar *) val_ptr, val_len, - (const uchar *) name_format_str, format_str_len)) - { - format_str= datetime_formats[tm_format][i]; - break; - } + const char *format_str= get_date_time_format_str(format, type); + str->set(format_str, strlen(format_str), &my_charset_bin); + return str; } } + null_value= 1; + return 0; +} + + +void Item_func_get_format::print(String *str) +{ + str->append(func_name()); + str->append('('); + + switch (type) { + case TIMESTAMP_DATE: + str->append("DATE, "); + break; + case TIMESTAMP_DATETIME: + str->append("DATETIME, "); + break; + case TIMESTAMP_TIME: + str->append("TIME, "); + break; + default: + DBUG_ASSERT(0); + } + args[0]->print(str); + str->append(')'); +} + + +bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date) +{ + DATE_TIME_FORMAT date_time_format; + char val_buff[64], format_buff[64]; + String val_str(val_buff, sizeof(val_buff), &my_charset_bin), *val; + String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format; + + val= args[0]->val_str(&val_str); + format= args[1]->val_str(&format_str); + if (args[0]->null_value || args[1]->null_value) + goto null_date; + null_value= 0; - str->length(0); - str->append(format_str); - return str; + bzero((char*) ltime, sizeof(ltime)); + date_time_format.format.str= (char*) format->ptr(); + date_time_format.format.length= format->length(); + if (extract_date_time(&date_time_format, val->ptr(), val->length(), + ltime)) + goto null_date; + return 0; + +null_date: + return (null_value=1); } String *Item_func_str_to_date::val_str(String *str) { TIME ltime; - bzero((char*) <ime, sizeof(ltime)); - DATETIME_FORMAT *tmp_format; - String *val=args[0]->val_str(str); - String *format=args[1]->val_str(str); - if (args[0]->null_value || args[1]->null_value || - extract_datetime(val->ptr(), val->length(), - format->ptr(), val->length(), - <ime)) - goto null_date; - tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; - if (make_datetime(str, <ime, 0, 0, tmp_format->format, - tmp_format->format_length, 1)) - return str; + if (Item_func_str_to_date::get_date(<ime, TIME_FUZZY_DATE)) + return 0; -null_date: - null_value=1; + /* + The following DATE_TIME should be done dynamicly based on the + format string (wen it's a constant). For example, we should only return + microseconds if there was an %f in the format + */ + if (!make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME, + <ime, str)) + return str; return 0; } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index b7bf294b83d..ef7fa1abfa0 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -29,7 +29,7 @@ public: const char *func_name() const { return "period_add"; } void fix_length_and_dec() { - max_length=6*default_charset()->mbmaxlen; + max_length=6*MY_CHARSET_BIN_MB_MAXLEN; } }; @@ -43,7 +43,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=6*default_charset()->mbmaxlen; + max_length=6*MY_CHARSET_BIN_MB_MAXLEN; } }; @@ -57,7 +57,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=6*default_charset()->mbmaxlen; + max_length=6*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -72,7 +72,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=2*default_charset()->mbmaxlen; + max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -86,16 +86,16 @@ public: double val() { return (double) Item_func_month::val_int(); } String *val_str(String *str) { - str->set(val_int(), default_charset()); + str->set(val_int(), &my_charset_bin); return null_value ? 0 : str; } const char *func_name() const { return "month"; } enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=2*default_charset()->mbmaxlen; + max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -110,9 +110,9 @@ public: enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=10*default_charset()->mbmaxlen; + max_length=10*my_charset_bin.mbmaxlen; maybe_null=1; } }; @@ -127,7 +127,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=3*default_charset()->mbmaxlen; + max_length=3*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -142,7 +142,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=2*default_charset()->mbmaxlen; + max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -157,7 +157,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=2*default_charset()->mbmaxlen; + max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -172,7 +172,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=1*default_charset()->mbmaxlen; + max_length=1*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -187,7 +187,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=2*default_charset()->mbmaxlen; + max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -202,7 +202,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=2*default_charset()->mbmaxlen; + max_length=2*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -216,7 +216,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=6*default_charset()->mbmaxlen; + max_length=6*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -231,7 +231,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=4*default_charset()->mbmaxlen; + max_length=4*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -247,16 +247,16 @@ public: double val() { return (double) val_int(); } String *val_str(String *str) { - str->set(val_int(), default_charset()); + str->set(val_int(), &my_charset_bin); return null_value ? 0 : str; } const char *func_name() const { return "weekday"; } enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=1*default_charset()->mbmaxlen; + max_length=1*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -270,9 +270,9 @@ class Item_func_dayname :public Item_func_weekday enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=9*default_charset()->mbmaxlen; + max_length=9*MY_CHARSET_BIN_MB_MAXLEN; maybe_null=1; } }; @@ -285,11 +285,11 @@ public: Item_func_unix_timestamp() :Item_int_func() {} Item_func_unix_timestamp(Item *a) :Item_int_func(a) {} longlong val_int(); - const char *func_name() const { return "timestamp"; } + const char *func_name() const { return "unix_timestamp"; } void fix_length_and_dec() { decimals=0; - max_length=10*default_charset()->mbmaxlen; + max_length=10*MY_CHARSET_BIN_MB_MAXLEN; } }; @@ -303,7 +303,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=10*default_charset()->mbmaxlen; + max_length=10*MY_CHARSET_BIN_MB_MAXLEN; } }; @@ -322,14 +322,14 @@ public: const char *func_name() const { return "date"; } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=10*default_charset()->mbmaxlen; + max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } int save_in_field(Field *to, bool no_conversions); Field *tmp_table_field(TABLE *t_arg) { - return (new Field_date(maybe_null, name, t_arg, default_charset())); + return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -343,7 +343,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_datetime(maybe_null, name, t_arg, default_charset())); + return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -366,7 +366,7 @@ public: void fix_length_and_dec(); Field *tmp_table_field(TABLE *t_arg) { - return (new Field_time(maybe_null, name, t_arg, default_charset())); + return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); } /* Abstract method that defines which time zone is used for conversion. @@ -408,7 +408,7 @@ public: void set_result_from_tm(struct tm *now); longlong val_int() { return (value) ; } void fix_length_and_dec(); - bool get_date(TIME *res,bool fuzzy_date); + bool get_date(TIME *res, uint fuzzy_date); virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0; }; @@ -448,7 +448,7 @@ public: int save_in_field(Field *to, bool no_conversions); String *val_str(String *str); void fix_length_and_dec(); - bool get_date(TIME *res,bool fuzzy_date); + bool get_date(TIME *res, uint fuzzy_date); virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0; }; @@ -485,11 +485,11 @@ public: class Item_func_date_format :public Item_str_func { int fixed_length; - const bool date_or_time; + const bool is_time_format; String value; public: - Item_func_date_format(Item *a,Item *b,bool date_or_time_arg) - :Item_str_func(a,b),date_or_time(date_or_time_arg) {} + Item_func_date_format(Item *a,Item *b,bool is_time_format_arg) + :Item_str_func(a,b),is_time_format(is_time_format_arg) {} String *val_str(String *str); const char *func_name() const { return "date_format"; } void fix_length_and_dec(); @@ -507,11 +507,11 @@ class Item_func_from_unixtime :public Item_date_func const char *func_name() const { return "from_unixtime"; } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); decimals=0; - max_length=19*default_charset()->mbmaxlen; + max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } - bool get_date(TIME *res,bool fuzzy_date); + bool get_date(TIME *res, uint fuzzy_date); }; @@ -524,15 +524,15 @@ public: String *val_str(String *); void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); maybe_null=1; - max_length=13*default_charset()->mbmaxlen; + max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } const char *func_name() const { return "sec_to_time"; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_time(maybe_null, name, t_arg, default_charset())); + return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -544,13 +544,13 @@ public: enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_HOUR, INTERVAL_MINUTE, - INTERVAL_SECOND, INTERVAL_MICROSECOND ,INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, - INTERVAL_DAY_MINUTE, INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, - INTERVAL_HOUR_SECOND, INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, - INTERVAL_HOUR_MICROSECOND, INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND + INTERVAL_SECOND, INTERVAL_MICROSECOND ,INTERVAL_YEAR_MONTH, + INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE, INTERVAL_DAY_SECOND, + INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND, INTERVAL_MINUTE_SECOND, + INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND, + INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND }; - class Item_date_add_interval :public Item_date_func { const interval_type int_type; @@ -567,7 +567,8 @@ public: enum_field_types field_type() const { return cached_field_type; } double val() { return (double) val_int(); } longlong val_int(); - bool get_date(TIME *res,bool fuzzy_date); + bool get_date(TIME *res, uint fuzzy_date); + void print(String *str); }; @@ -583,6 +584,7 @@ class Item_extract :public Item_int_func const char *func_name() const { return "extract"; } void fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; + void print(String *str); }; @@ -590,7 +592,6 @@ class Item_typecast :public Item_str_func { public: Item_typecast(Item *a) :Item_str_func(a) {} - const char *func_name() const { return "char"; } String *val_str(String *a) { String *tmp=args[0]->val_str(a); @@ -601,9 +602,10 @@ public: } void fix_length_and_dec() { - collation.set(default_charset()); + collation.set(&my_charset_bin); max_length=args[0]->max_length; } + virtual const char* cast_type() const= 0; void print(String *str); }; @@ -617,8 +619,10 @@ class Item_char_typecast :public Item_typecast public: Item_char_typecast(Item *a, int length_arg, CHARSET_INFO *cs_arg) :Item_typecast(a), cast_length(length_arg), cast_cs(cs_arg) {} + const char* cast_type() const { return "char"; }; String *val_str(String *a); void fix_length_and_dec(); + void print(String *str); }; @@ -627,12 +631,12 @@ class Item_date_typecast :public Item_typecast public: Item_date_typecast(Item *a) :Item_typecast(a) {} String *val_str(String *str); - bool get_date(TIME *ltime, bool fuzzy_date); - const char *func_name() const { return "date"; } + bool get_date(TIME *ltime, uint fuzzy_date); + const char *cast_type() const { return "date"; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_date(maybe_null, name, t_arg, default_charset())); + return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -643,11 +647,11 @@ public: Item_time_typecast(Item *a) :Item_typecast(a) {} String *val_str(String *str); bool get_time(TIME *ltime); - const char *func_name() const { return "time"; } + const char *cast_type() const { return "time"; } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_time(maybe_null, name, t_arg, default_charset())); + return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -657,11 +661,11 @@ class Item_datetime_typecast :public Item_typecast public: Item_datetime_typecast(Item *a) :Item_typecast(a) {} String *val_str(String *str); - const char *func_name() const { return "datetime"; } + const char *cast_type() const { return "datetime"; } enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_datetime(maybe_null, name, t_arg, default_charset())); + return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -675,7 +679,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=8*MY_CHARSET_BIN_MB_MAXLEN; + max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } Field *tmp_table_field(TABLE *t_arg) { @@ -694,7 +698,6 @@ public: Item_func_add_time(Item *a, Item *b, bool type_arg, bool neg_arg) :Item_str_func(a, b), is_date(type_arg) { sign= neg_arg ? -1 : 1; } String *val_str(String *str); - const char *func_name() const { return "addtime"; } enum_field_types field_type() const { return cached_field_type; } void fix_length_and_dec(); @@ -711,6 +714,7 @@ public: return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); return (new Field_string(max_length, maybe_null, name, t_arg, &my_charset_bin)); } + void print(String *str); }; class Item_func_timediff :public Item_str_func @@ -724,7 +728,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=17*MY_CHARSET_BIN_MB_MAXLEN; + max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } Field *tmp_table_field(TABLE *t_arg) { @@ -743,11 +747,11 @@ public: void fix_length_and_dec() { decimals=0; - max_length=8*MY_CHARSET_BIN_MB_MAXLEN; + max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } Field *tmp_table_field(TABLE *t_arg) { - return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); + return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); } }; @@ -765,44 +769,43 @@ public: }; -enum datetime_format +enum date_time_format { USA_FORMAT, JIS_FORMAT, ISO_FORMAT, EUR_FORMAT, INTERNAL_FORMAT }; - -enum datetime_format_types -{ - DATE_FORMAT_TYPE= 0, TIME_FORMAT_TYPE, DATETIME_FORMAT_TYPE -}; - - class Item_func_get_format :public Item_str_func { - const datetime_format_types tm_format; + const timestamp_type type; public: - Item_func_get_format(datetime_format_types type_arg1, Item *a) - :Item_str_func(a), tm_format(type_arg1) {} + Item_func_get_format(timestamp_type type_arg, Item *a) + :Item_str_func(a), type(type_arg) + {} String *val_str(String *str); const char *func_name() const { return "get_format"; } void fix_length_and_dec() { + maybe_null= 1; decimals=0; max_length=17*MY_CHARSET_BIN_MB_MAXLEN; } + void print(String *str); }; -class Item_func_str_to_date :public Item_str_func +class Item_func_str_to_date :public Item_date_func { public: Item_func_str_to_date(Item *a, Item *b) - :Item_str_func(a, b) {} + :Item_date_func(a, b) + {} String *val_str(String *str); + bool get_date(TIME *ltime, uint fuzzy_date); const char *func_name() const { return "str_to_date"; } void fix_length_and_dec() { + maybe_null= 1; decimals=0; - max_length=29*MY_CHARSET_BIN_MB_MAXLEN; + max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN; } }; diff --git a/sql/item_uniq.h b/sql/item_uniq.h index 9b370b70181..5c6f6eefb6b 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -29,6 +29,7 @@ public: :Item_real_func(list) {} double val() { return 0.0; } void fix_length_and_dec() { decimals=0; max_length=6; } + void print(String *str) { str->append("0.0", 3); } }; @@ -54,4 +55,5 @@ public: { return new Item_sum_unique_users(thd, *this); } + void print(String *str) { str->append("0.0", 3); } }; diff --git a/sql/key.cc b/sql/key.cc index 37ef6339f20..639b1e535a6 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -227,7 +227,7 @@ void key_unpack(String *to,TABLE *table,uint idx) { if (table->record[0][key_part->null_offset] & key_part->null_bit) { - to->append("NULL"); + to->append("NULL", 4); continue; } } @@ -239,7 +239,7 @@ void key_unpack(String *to,TABLE *table,uint idx) to->append(tmp); } else - to->append("???"); + to->append("???", 3); } DBUG_VOID_RETURN; } diff --git a/sql/log_event.cc b/sql/log_event.cc index 62dc56e7fd2..d0dc0a83b11 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -768,11 +768,49 @@ int Query_log_event::write(IO_CACHE* file) int Query_log_event::write_data(IO_CACHE* file) { + char buf[QUERY_HEADER_LEN]; + if (!query) return -1; - char buf[QUERY_HEADER_LEN]; - int4store(buf + Q_THREAD_ID_OFFSET, thread_id); + /* + We want to store the thread id: + (- as an information for the user when he reads the binlog) + - if the query uses temporary table: for the slave SQL thread to know to + which master connection the temp table belongs. + Now imagine we (write_data()) are called by the slave SQL thread (we are + logging a query executed by this thread; the slave runs with + --log-slave-updates). Then this query will be logged with + thread_id=the_thread_id_of_the_SQL_thread. Imagine that 2 temp tables of + the same name were created simultaneously on the master (in the master + binlog you have + CREATE TEMPORARY TABLE t; (thread 1) + CREATE TEMPORARY TABLE t; (thread 2) + ...) + then in the slave's binlog there will be + CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread) + CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread) + which is bad (same thread id!). + + To avoid this, we log the thread's thread id EXCEPT for the SQL + slave thread for which we log the original (master's) thread id. + Now this moves the bug: what happens if the thread id on the + master was 10 and when the slave replicates the query, a + connection number 10 is opened by a normal client on the slave, + and updates a temp table of the same name? We get a problem + again. To avoid this, in the handling of temp tables (sql_base.cc) + we use thread_id AND server_id. TODO when this is merged into + 4.1: in 4.1, slave_proxy_id has been renamed to pseudo_thread_id + and is a session variable: that's to make mysqlbinlog work with + temp tables. We probably need to introduce + + SET PSEUDO_SERVER_ID + for mysqlbinlog in 4.1. mysqlbinlog would print: + SET PSEUDO_SERVER_ID= + SET PSEUDO_THREAD_ID= + for each query using temp tables. + */ + int4store(buf + Q_THREAD_ID_OFFSET, slave_proxy_id); int4store(buf + Q_EXEC_TIME_OFFSET, exec_time); buf[Q_DB_LEN_OFFSET] = (char) db_len; int2store(buf + Q_ERR_CODE_OFFSET, error_code); @@ -790,12 +828,14 @@ int Query_log_event::write_data(IO_CACHE* file) #ifndef MYSQL_CLIENT Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans) - :Log_event(thd_arg, !thd_arg->tmp_table_used ? - 0 : LOG_EVENT_THREAD_SPECIFIC_F, using_trans), + :Log_event(thd_arg, !thd_arg->tmp_table_used ? + 0 : LOG_EVENT_THREAD_SPECIFIC_F, using_trans), data_buf(0), query(query_arg), db(thd_arg->db), q_len((uint32) query_length), - error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno), - thread_id(thd_arg->thread_id) + error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno), + thread_id(thd_arg->thread_id), + /* save the original thread id; we already know the server id */ + slave_proxy_id(thd_arg->variables.pseudo_thread_id) { time_t end_time; time(&end_time); @@ -836,7 +876,7 @@ Query_log_event::Query_log_event(const char* buf, int event_len, return; memcpy(data_buf, buf + Q_DATA_OFFSET, data_len); - thread_id = uint4korr(buf + Q_THREAD_ID_OFFSET); + slave_proxy_id= thread_id= uint4korr(buf + Q_THREAD_ID_OFFSET); db = data_buf; db_len = (uint)buf[Q_DB_LEN_OFFSET]; query=data_buf + db_len + 1; @@ -907,8 +947,8 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) { thd->set_time((time_t)when); thd->query_length= q_len; - VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query = (char*)query; + VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query_id = query_id++; VOID(pthread_mutex_unlock(&LOCK_thread_count)); thd->query_error= 0; // clear error @@ -1276,7 +1316,7 @@ void Load_log_event::pack_info(Protocol *protocol) int Load_log_event::write_data_header(IO_CACHE* file) { char buf[LOAD_HEADER_LEN]; - int4store(buf + L_THREAD_ID_OFFSET, thread_id); + int4store(buf + L_THREAD_ID_OFFSET, slave_proxy_id); int4store(buf + L_EXEC_TIME_OFFSET, exec_time); int4store(buf + L_SKIP_LINES_OFFSET, skip_lines); buf[L_TBL_LEN_OFFSET] = (char)table_name_len; @@ -1317,7 +1357,9 @@ Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex, enum enum_duplicates handle_dup, bool using_trans) :Log_event(thd_arg, 0, using_trans), thread_id(thd_arg->thread_id), - num_fields(0), fields(0), field_lens(0),field_block_len(0), + slave_proxy_id(thd_arg->variables.pseudo_thread_id), + num_fields(0),fields(0), + field_lens(0),field_block_len(0), table_name(table_name_arg ? table_name_arg : ""), db(db_arg), fname(ex->file_name) { @@ -1422,7 +1464,7 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len, char* buf_end = (char*)buf + event_len; uint header_len= old_format ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; const char* data_head = buf + header_len; - thread_id = uint4korr(data_head + L_THREAD_ID_OFFSET); + slave_proxy_id= thread_id= uint4korr(data_head + L_THREAD_ID_OFFSET); exec_time = uint4korr(data_head + L_EXEC_TIME_OFFSET); skip_lines = uint4korr(data_head + L_SKIP_LINES_OFFSET); table_name_len = (uint)data_head[L_TBL_LEN_OFFSET]; diff --git a/sql/log_event.h b/sql/log_event.h index 8ba5d0379a0..6cc8a7ca06d 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -455,6 +455,13 @@ public: uint32 db_len; uint16 error_code; ulong thread_id; + /* + For events created by Query_log_event::exec_event (and + Load_log_event::exec_event()) we need the *original* thread id, to be able + to log the event with the original (=master's) thread id (fix for + BUG#1686). + */ + ulong slave_proxy_id; #ifndef MYSQL_CLIENT Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, @@ -543,6 +550,7 @@ protected: public: ulong thread_id; + ulong slave_proxy_id; uint32 table_name_len; uint32 db_len; uint32 fname_len; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 53cbba36b93..12c772e7253 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -204,6 +204,9 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define OPTION_QUOTE_SHOW_CREATE OPTION_QUICK*2 #define OPTION_INTERNAL_SUBTRANSACTIONS OPTION_QUOTE_SHOW_CREATE*2 +/* options for UNION set by the yacc parser (stored in unit->union_option) */ +#define UNION_ALL 1 + /* Set if we are updating a non-transaction safe table */ #define OPTION_STATUS_NO_TRANS_UPDATE OPTION_INTERNAL_SUBTRANSACTIONS*2 @@ -335,7 +338,7 @@ inline THD *_current_thd(void) #include "protocol.h" #include "sql_udf.h" #include "item.h" -typedef compare_func_creator (*chooser_compare_func_creator)(bool invert); +typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); #include "sql_class.h" #include "opt_range.h" @@ -753,6 +756,13 @@ bool open_log(MYSQL_LOG *log, const char *hostname, /* mysqld.cc */ extern void yyerror(const char*); +/* strfunc.cc */ +ulonglong find_set(TYPELIB *typelib,const char *x, uint length, + char **err_pos, uint *err_len, bool *set_warning); +uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match); +uint check_word(TYPELIB *lib, const char *val, const char *end, + const char **end_of_word); + /* External variables */ @@ -767,6 +777,12 @@ extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword; extern const char **errmesg; /* Error messages */ extern const char *myisam_recover_options_str; extern const char *in_left_expr_name, *in_additional_cond; +extern Eq_creator eq_creator; +extern Ne_creator ne_creator; +extern Gt_creator gt_creator; +extern Lt_creator lt_creator; +extern Ge_creator ge_creator; +extern Le_creator le_creator; extern uchar *days_in_month; extern char language[LIBLEN],reg_ext[FN_EXTLEN]; extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN]; @@ -840,7 +856,6 @@ extern pthread_attr_t connection_attrib; extern I_List<THD> threads; extern I_List<NAMED_LIST> key_caches; extern MY_BITMAP temp_pool; -extern DATE_FORMAT dayord; extern String my_empty_string; extern String my_null_string; extern SHOW_VAR init_vars[],status_vars[], internal_vars[]; @@ -852,12 +867,8 @@ extern struct system_variables global_system_variables; extern struct system_variables max_system_variables; extern struct rand_struct sql_rand; -#define g_datetime_frm(a) (global_system_variables.datetime_formats[(a)]) -#define t_datetime_frm(a, b) ((a)->variables.datetime_formats[(b)]) - -extern const char *datetime_formats[4][5]; -extern const char *opt_datetime_format_names[3]; -extern const char *opt_datetime_formats[3]; +extern const char *opt_date_time_formats[]; +extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[]; extern String null_string; extern HASH open_cache; @@ -929,23 +940,26 @@ void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day); void init_time(void); long my_gmt_sec(TIME *, long *current_timezone); -time_t str_to_timestamp(const char *str,uint length, THD *thd); -bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd); -longlong str_to_datetime(const char *str,uint length,bool fuzzy_date, THD *thd); +time_t str_to_timestamp(const char *str,uint length); +bool str_to_time(const char *str,uint length,TIME *l_time); +longlong str_to_datetime(const char *str,uint length, uint fuzzy_date); timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time, - bool fuzzy_date, THD *thd); + uint flags); void localtime_to_TIME(TIME *to, struct tm *from); void calc_time_from_sec(TIME *to, long seconds, long microseconds); -extern DATETIME_FORMAT *make_format(DATETIME_FORMAT *datetime_format, - datetime_format_types format_type, - const char *format_str, - uint format_length, bool is_alloc); -extern String *make_datetime(String *str, TIME *l_time, - const bool is_time_only, - const bool add_second_frac, - const char *ptr, uint format_length, - bool set_len_to_zero); +extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type, + const char *format_str, + uint format_length); +extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd, + DATE_TIME_FORMAT *format); +const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format, + timestamp_type type); +extern bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, + timestamp_type type, String *str); +extern void make_time(DATE_TIME_FORMAT *format, TIME *l_time, String *str); +void make_date(DATE_TIME_FORMAT *format, TIME *l_time, String *str); +void make_datetime(DATE_TIME_FORMAT *format, TIME *l_time, String *str); int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(byte *,uint,char,char); @@ -1056,12 +1070,12 @@ inline void table_case_convert(char * name, uint length) my_casedn(files_charset_info, name, length); } -compare_func_creator comp_eq_creator(bool invert); -compare_func_creator comp_ge_creator(bool invert); -compare_func_creator comp_gt_creator(bool invert); -compare_func_creator comp_le_creator(bool invert); -compare_func_creator comp_lt_creator(bool invert); -compare_func_creator comp_ne_creator(bool invert); +Comp_creator *comp_eq_creator(bool invert); +Comp_creator *comp_ge_creator(bool invert); +Comp_creator *comp_gt_creator(bool invert); +Comp_creator *comp_le_creator(bool invert); +Comp_creator *comp_lt_creator(bool invert); +Comp_creator *comp_ne_creator(bool invert); Item * all_any_subquery_creator(Item *left_expr, chooser_compare_func_creator cmp, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 75e2fc957e4..7c432a05786 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -318,10 +318,7 @@ char mysql_real_data_home[FN_REFLEN], language[LIBLEN],reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN], max_sort_char,*mysqld_user,*mysqld_chroot, *opt_init_file; -const char *opt_datetime_formats[3]; -const char *opt_datetime_format_names[3]= {"date_format", - "time_format", - "datetime_format"}; +const char *opt_date_time_formats[3]; char *language_ptr, *default_collation_name, *default_character_set_name; char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home; @@ -335,6 +332,14 @@ const char *sql_mode_str="OFF"; const char *in_left_expr_name= "<left expr>"; /* name of additional condition */ const char *in_additional_cond= "<IN COND>"; +/* classes for comparation parsing/processing */ +Eq_creator eq_creator; +Ne_creator ne_creator; +Gt_creator gt_creator; +Lt_creator lt_creator; +Ge_creator ge_creator; +Le_creator le_creator; + FILE *bootstrap_file; @@ -349,7 +354,6 @@ struct system_variables global_system_variables; struct system_variables max_system_variables; MY_TMPDIR mysql_tmpdir_list; -DATE_FORMAT dayord; MY_BITMAP temp_pool; CHARSET_INFO *system_charset_info, *files_charset_info ; @@ -913,9 +917,12 @@ void clean_up(bool print_message) #ifdef USE_RAID end_raid(); #endif - g_datetime_frm(DATE_FORMAT_TYPE).clean(); - g_datetime_frm(TIME_FORMAT_TYPE).clean(); - g_datetime_frm(DATETIME_FORMAT_TYPE).clean(); + my_free((char*) global_system_variables.date_format, + MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*) global_system_variables.time_format, + MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*) global_system_variables.datetime_format, + MYF(MY_ALLOW_ZERO_PTR)); if (defaults_argv) free_defaults(defaults_argv); free_tmpdir(&mysql_tmpdir_list); @@ -1978,7 +1985,7 @@ extern "C" pthread_handler_decl(handle_shutdown,arg) #endif -const char *load_default_groups[]= { "mysqld","server",MYSQL_BASE_VERSION,0 }; +const char *load_default_groups[]= { "mysqld","server",MYSQL_BASE_VERSION,0,0}; bool open_log(MYSQL_LOG *log, const char *hostname, const char *opt_name, const char *extension, @@ -2011,33 +2018,46 @@ bool open_log(MYSQL_LOG *log, const char *hostname, } -int init_global_datetime_format(datetime_format_types format_type, bool is_alloc) +/* + Initialize one of the global date/time format variables + + SYNOPSIS + init_global_datetime_format() + format_type What kind of format should be supported + var_ptr Pointer to variable that should be updated + + NOTES + The default value is taken from either opt_date_time_formats[] or + the ISO format (ANSI SQL) + + RETURN + 0 ok + 1 error +*/ + +bool init_global_datetime_format(timestamp_type format_type, + DATE_TIME_FORMAT **var_ptr) { - const char *format_str= opt_datetime_formats[format_type]; - uint format_length= 0; - DATETIME_FORMAT *tmp_format= &g_datetime_frm(format_type).datetime_format; + /* Get command line option */ + const char *str= opt_date_time_formats[format_type]; + DATE_TIME_FORMAT *format; - if (format_str) - { - format_str= opt_datetime_formats[format_type]; - format_length= strlen(format_str); - } - else + if (!str) // No specified format { - format_str= datetime_formats[format_type][ISO_FORMAT]; - format_length= strlen(datetime_formats[format_type][ISO_FORMAT]); - opt_datetime_formats[format_type]= format_str; + str= get_date_time_format_str(&known_date_time_formats[ISO_FORMAT], + format_type); + /* + Set the "command line" option to point to the generated string so + that we can set global formats back to default + */ + opt_date_time_formats[format_type]= str; } - if (make_format(tmp_format, format_type, format_str, - format_length, is_alloc)) + if (!(*var_ptr= date_time_format_make(format_type, str, strlen(str)))) { - g_datetime_frm(format_type).name= opt_datetime_format_names[format_type]; - g_datetime_frm(format_type).name_length= - strlen(opt_datetime_format_names[format_type]); - g_datetime_frm(format_type).format_type= format_type; - return 0; + fprintf(stderr, "Wrong date/time format specifier: %s\n", str); + return 1; } - return 1; + return 0; } @@ -2152,17 +2172,12 @@ static int init_common_variables(const char *conf_file_name, int argc, } default_charset_info= default_collation; } - global_system_variables.collation_server= default_charset_info; - global_system_variables.collation_database= default_charset_info; - global_system_variables.collation_connection= default_charset_info; + /* Set collactions that depends on the default collation */ + global_system_variables.collation_server= default_charset_info; + global_system_variables.collation_database= default_charset_info; + global_system_variables.collation_connection= default_charset_info; global_system_variables.character_set_results= default_charset_info; - global_system_variables.character_set_client= default_charset_info; - global_system_variables.collation_connection= default_charset_info; - - if (init_global_datetime_format(DATE_FORMAT_TYPE, 1) || - init_global_datetime_format(TIME_FORMAT_TYPE, 1) || - init_global_datetime_format(DATETIME_FORMAT_TYPE, 1)) - return 1; + global_system_variables.character_set_client= default_charset_info; if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1)) return 1; @@ -2718,7 +2733,7 @@ default_service_handling(char **argv, const char *extra_opt) { char path_and_service[FN_REFLEN+FN_REFLEN+32], *pos, *end; - end= path_and_service + sizeof(path_and_service)-1; + end= path_and_service + sizeof(path_and_service)-3; /* We have to quote filename if it contains spaces */ pos= add_quoted_string(path_and_service, file_path, end); @@ -2728,7 +2743,9 @@ default_service_handling(char **argv, *pos++= ' '; pos= add_quoted_string(pos, extra_opt, end); } - *pos= 0; // Ensure end null + /* We must have servicename last */ + *pos++= ' '; + strmake(pos, servicename, (uint) (end+2 - pos)); if (Service.got_service_option(argv, "install")) { @@ -2771,10 +2788,16 @@ int main(int argc, char **argv) if (!default_service_handling(argv, MYSQL_SERVICENAME, MYSQL_SERVICENAME, file_path, "")) return 0; - if (Service.IsService(argv[1])) + if (Service.IsService(argv[1])) /* Start an optional service */ { - /* start an optional service */ - load_default_groups[0]= argv[1]; + /* + Only add the service name to the groups read from the config file + if it's not "MySQL". (The default service name should be 'mysqld' + but we started a bad tradition by calling it MySQL from the start + and we are now stuck with it. + */ + if (my_strcasecmp(argv[1],"mysql")) + load_default_groups[3]= argv[1]; start_mode= 1; Service.Init(argv[1], mysql_service); return 0; @@ -2782,8 +2805,7 @@ int main(int argc, char **argv) } else if (argc == 3) /* install or remove any optional service */ { - if (!default_service_handling(argv, argv[2], argv[2], file_path, - argv[2])) + if (!default_service_handling(argv, argv[2], argv[2], file_path, "")) return 0; if (Service.IsService(argv[2])) { @@ -2795,6 +2817,8 @@ int main(int argc, char **argv) opt_argc= 2; // Skip service-name opt_argv=argv; start_mode= 1; + if (my_strcasecmp(argv[2],"mysql")) + load_default_groups[3]= argv[2]; Service.Init(argv[2], mysql_service); return 0; } @@ -4598,7 +4622,7 @@ The minimum value for this variable is 4096.", (gptr*) &max_system_variables.net_wait_timeout, 0, GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, {"expire_logs_days", OPT_EXPIRE_LOGS_DAYS, - "Logs will be rotated after expire-log-days days. ", + "Logs will be rotated after expire-log-days days ", (gptr*) &expire_logs_days, (gptr*) &expire_logs_days, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 99, 0, 1, 0}, @@ -4608,23 +4632,24 @@ The minimum value for this variable is 4096.", (gptr*) &max_system_variables.default_week_format, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3L, 0, 1, 0}, { "date-format", OPT_DATE_FORMAT, - "The DATE format.", - (gptr*) &opt_datetime_formats[DATE_FORMAT_TYPE], - (gptr*) &opt_datetime_formats[DATE_FORMAT_TYPE], + "The DATE format (For future).", + (gptr*) &opt_date_time_formats[TIMESTAMP_DATE], + (gptr*) &opt_date_time_formats[TIMESTAMP_DATE], 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { "datetime-format", OPT_DATETIME_FORMAT, - "The DATETIME/TIMESTAMP format.", - (gptr*) &opt_datetime_formats[DATETIME_FORMAT_TYPE], - (gptr*) &opt_datetime_formats[DATETIME_FORMAT_TYPE], + "The DATETIME/TIMESTAMP format (for future).", + (gptr*) &opt_date_time_formats[TIMESTAMP_DATETIME], + (gptr*) &opt_date_time_formats[TIMESTAMP_DATETIME], 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { "time-format", OPT_TIME_FORMAT, - "The TIME format.", - (gptr*) &opt_datetime_formats[TIME_FORMAT_TYPE], - (gptr*) &opt_datetime_formats[TIME_FORMAT_TYPE], + "The TIME format (for future).", + (gptr*) &opt_date_time_formats[TIMESTAMP_TIME], + (gptr*) &opt_date_time_formats[TIMESTAMP_TIME], 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; + struct show_var_st status_vars[]= { {"Aborted_clients", (char*) &aborted_threads, SHOW_LONG}, {"Aborted_connects", (char*) &aborted_connects, SHOW_LONG}, @@ -4936,6 +4961,8 @@ static void mysql_init_variables(void) national_charset_info= &my_charset_utf8_general_ci; table_alias_charset= &my_charset_bin; + opt_date_time_formats[0]= opt_date_time_formats[1]= opt_date_time_formats[2]= 0; + /* Things with default values that are not zero */ delay_key_write_options= (uint) DELAY_KEY_WRITE_ON; opt_specialflag= SPECIAL_ENGLISH; @@ -4993,11 +5020,6 @@ static void mysql_init_variables(void) /* Set default values for some option variables */ - global_system_variables.collation_server= default_charset_info; - global_system_variables.collation_database= default_charset_info; - global_system_variables.collation_connection= default_charset_info; - global_system_variables.character_set_results= default_charset_info; - global_system_variables.character_set_client= default_charset_info; global_system_variables.table_type= DB_TYPE_MYISAM; global_system_variables.tx_isolation= ISO_REPEATABLE_READ; global_system_variables.select_limit= (ulonglong) HA_POS_ERROR; @@ -5006,10 +5028,6 @@ static void mysql_init_variables(void) max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; - init_global_datetime_format(DATE_FORMAT_TYPE, 0); - init_global_datetime_format(TIME_FORMAT_TYPE, 0); - init_global_datetime_format(DATETIME_FORMAT_TYPE, 0); - /* Variables that depends on compile options */ #ifndef DBUG_OFF default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace", @@ -5618,7 +5636,7 @@ static void get_options(int argc,char **argv) exit(ho_error); if (argc > 0) { - fprintf(stderr, "%s: Too many arguments.\nUse --help to get a list of available options\n", my_progname); + fprintf(stderr, "%s: Too many arguments (first extra is '%s').\nUse --help to get a list of available options\n", my_progname, *argv); exit(ho_error); } @@ -5673,6 +5691,15 @@ static void get_options(int argc,char **argv) opt_specialflag|= SPECIAL_SHORT_LOG_FORMAT; if (opt_log_queries_not_using_indexes) opt_specialflag|= SPECIAL_LOG_QUERIES_NOT_USING_INDEXES; + + if (init_global_datetime_format(TIMESTAMP_DATE, + &global_system_variables.date_format) || + init_global_datetime_format(TIMESTAMP_TIME, + &global_system_variables.time_format) || + init_global_datetime_format(TIMESTAMP_DATETIME, + &global_system_variables.datetime_format)) + exit(1); + /* Set up default values for a key cache */ KEY_CACHE_VAR *key_cache= &dflt_key_cache_var; dflt_key_cache_block_size= key_cache->block_size; diff --git a/sql/protocol.cc b/sql/protocol.cc index 0fe759cff67..8ba3cdec8e0 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -496,7 +496,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag) if (thd->client_capabilities & CLIENT_PROTOCOL_41) { - if (prot.store("std", 3, cs, thd_charset) || + if (prot.store("def", 3, cs, thd_charset) || prot.store(field.db_name, (uint) strlen(field.db_name), cs, thd_charset) || prot.store(field.table_name, (uint) strlen(field.table_name), @@ -833,12 +833,17 @@ bool Protocol_simple::store(TIME *tm) field_pos++; #endif char buff[40]; - String tmp((char*) buff,sizeof(buff),&my_charset_bin); - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (current_thd, DATETIME_FORMAT_TYPE).datetime_format); - make_datetime(&tmp, tm, 1, tm->second_part, - tmp_format->format, tmp_format->format_length, 1); - return net_store_data((char*) tmp.ptr(), tmp.length()); + uint length; + length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d", + (int) tm->year, + (int) tm->month, + (int) tm->day, + (int) tm->hour, + (int) tm->minute, + (int) tm->second)); + if (tm->second_part) + length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part)); + return net_store_data((char*) buff, length); } @@ -851,10 +856,7 @@ bool Protocol_simple::store_date(TIME *tm) #endif char buff[40]; String tmp((char*) buff,sizeof(buff),&my_charset_bin); - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (current_thd, DATE_FORMAT_TYPE).datetime_format); - make_datetime(&tmp, tm, 1, 0, - tmp_format->format, tmp_format->format_length, 1); + make_date((DATE_TIME_FORMAT *) 0, tm, &tmp); return net_store_data((char*) tmp.ptr(), tmp.length()); } @@ -873,14 +875,16 @@ bool Protocol_simple::store_time(TIME *tm) field_pos++; #endif char buff[40]; - String tmp((char*) buff,sizeof(buff),&my_charset_bin); - DATETIME_FORMAT *tmp_format= (&t_datetime_frm - (current_thd, TIME_FORMAT_TYPE).datetime_format); + uint length; uint day= (tm->year || tm->month) ? 0 : tm->day; - tm->hour= (long) day*24L+(long) tm->hour; - make_datetime(&tmp, tm, 0, tm->second_part, - tmp_format->format, tmp_format->format_length, 1); - return net_store_data((char*) tmp.ptr(), tmp.length()); + length= my_sprintf(buff,(buff, "%s%02ld:%02d:%02d", + tm->neg ? "-" : "", + (long) day*24L+(long) tm->hour, + (int) tm->minute, + (int) tm->second)); + if (tm->second_part) + length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part)); + return net_store_data((char*) buff, length); } diff --git a/sql/set_var.cc b/sql/set_var.cc index 66c8ef87d5a..76fb2e0a4b3 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -299,14 +299,25 @@ sys_var_thd_ulong sys_tmp_table_size("tmp_table_size", &SV::tmp_table_size); sys_var_thd_ulong sys_net_wait_timeout("wait_timeout", &SV::net_wait_timeout); - + #ifdef HAVE_INNOBASE_DB sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct", &srv_max_buf_pool_modified_pct); #endif -/* - Variables that are bits in THD -*/ + +/* Time/date/datetime formats */ + +sys_var_thd_date_time_format sys_time_format("time_format", + &SV::time_format, + TIMESTAMP_TIME); +sys_var_thd_date_time_format sys_date_format("date_format", + &SV::date_format, + TIMESTAMP_DATE); +sys_var_thd_date_time_format sys_datetime_format("datetime_format", + &SV::datetime_format, + TIMESTAMP_DATETIME); + +/* Variables that are bits in THD */ static sys_var_thd_bit sys_autocommit("autocommit", set_option_autocommit, @@ -413,9 +424,8 @@ sys_var *sys_variables[]= &sys_collation_server, &sys_concurrent_insert, &sys_connect_timeout, - &g_datetime_frm(DATE_FORMAT_TYPE), - &g_datetime_frm(DATETIME_FORMAT_TYPE), - &g_datetime_frm(TIME_FORMAT_TYPE), + &sys_date_format, + &sys_datetime_format, &sys_default_week_format, &sys_delay_key_write, &sys_delayed_insert_limit, @@ -485,6 +495,7 @@ sys_var *sys_variables[]= &sys_rand_seed1, &sys_rand_seed2, &sys_range_alloc_block_size, + &sys_readonly, &sys_read_buff_size, &sys_read_rnd_buff_size, #ifdef HAVE_REPLICATION @@ -500,7 +511,6 @@ sys_var *sys_variables[]= &sys_slave_net_timeout, &sys_slave_skip_counter, #endif - &sys_readonly, &sys_slow_launch_time, &sys_sort_buffer, &sys_sql_big_tables, @@ -511,6 +521,7 @@ sys_var *sys_variables[]= &sys_table_cache_size, &sys_table_type, &sys_thread_cache_size, + &sys_time_format, &sys_timestamp, &sys_tmp_table_size, &sys_trans_alloc_block_size, @@ -556,9 +567,9 @@ struct show_var_st init_vars[]= { {sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS}, {sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS}, {"datadir", mysql_real_data_home, SHOW_CHAR}, - {"date_format", (char*) &g_datetime_frm(DATE_FORMAT_TYPE), SHOW_SYS}, - {"datetime_format", (char*) &g_datetime_frm(DATETIME_FORMAT_TYPE), SHOW_SYS}, - {"default_week_format", (char*) &sys_default_week_format, SHOW_SYS}, + {sys_date_format.name, (char*) &sys_date_format, SHOW_SYS}, + {sys_datetime_format.name, (char*) &sys_datetime_format, SHOW_SYS}, + {sys_default_week_format.name, (char*) &sys_default_week_format, SHOW_SYS}, {sys_delay_key_write.name, (char*) &sys_delay_key_write, SHOW_SYS}, {sys_delayed_insert_limit.name, (char*) &sys_delayed_insert_limit,SHOW_SYS}, {sys_delayed_insert_timeout.name, (char*) &sys_delayed_insert_timeout, SHOW_SYS}, @@ -720,7 +731,7 @@ struct show_var_st init_vars[]= { #endif {"thread_stack", (char*) &thread_stack, SHOW_LONG}, {sys_tx_isolation.name, (char*) &sys_tx_isolation, SHOW_SYS}, - {"time_format", (char*) &g_datetime_frm(TIME_FORMAT_TYPE), SHOW_SYS}, + {sys_time_format.name, (char*) &sys_time_format, SHOW_SYS}, #ifdef HAVE_TZNAME {"timezone", time_zone, SHOW_CHAR}, #endif @@ -744,71 +755,6 @@ bool sys_var::check(THD *thd, set_var *var) /* Functions to check and update variables */ -char *update_datetime_format(THD *thd, enum enum_var_type type, - enum datetime_format_types format_type, - DATETIME_FORMAT *tmp_format) -{ - char *old_value; - if (type == OPT_GLOBAL) - { - pthread_mutex_lock(&LOCK_global_system_variables); - old_value= g_datetime_frm(format_type).datetime_format.format; - g_datetime_frm(format_type).datetime_format= *tmp_format; - pthread_mutex_unlock(&LOCK_global_system_variables); - } - else - { - old_value= t_datetime_frm(thd,format_type).datetime_format.format; - t_datetime_frm(thd, format_type).datetime_format= *tmp_format; - } - return old_value; -} - - -bool sys_var_datetime_format::update(THD *thd, set_var *var) -{ - DATETIME_FORMAT tmp_format; - char *old_value; - uint new_length; - - if ((new_length= var->value->str_value.length())) - { - if (!make_format(&tmp_format, format_type, - var->value->str_value.ptr(), - new_length, 1)) - return 1; - } - - old_value= update_datetime_format(thd, var->type, format_type, &tmp_format); - my_free(old_value, MYF(MY_ALLOW_ZERO_PTR)); - return 0; -} - -byte *sys_var_datetime_format::value_ptr(THD *thd, enum_var_type type, - LEX_STRING *base) -{ - if (type == OPT_GLOBAL) - return (byte*) g_datetime_frm(format_type).datetime_format.format; - return (byte*) t_datetime_frm(thd, format_type).datetime_format.format; -} - -void sys_var_datetime_format::set_default(THD *thd, enum_var_type type) -{ - DATETIME_FORMAT tmp_format; - char *old_value; - uint new_length; - - if ((new_length= strlen(opt_datetime_formats[format_type]))) - { - if (!make_format(&tmp_format, format_type, - opt_datetime_formats[format_type], - new_length, 1)) - return; - } - - old_value= update_datetime_format(thd, type, format_type, &tmp_format); - my_free(old_value, MYF(MY_ALLOW_ZERO_PTR)); -} /* The following 3 functions need to be changed in 4.1 when we allow @@ -1226,8 +1172,8 @@ bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names) { if (!(res=var->value->val_str(&str)) || ((long) (var->save_result.ulong_value= - (ulong) find_type(res->c_ptr(), enum_names, 3)-1)) - < 0) + (ulong) find_type(enum_names, res->ptr(), + res->length(),1)-1)) < 0) { value= res ? res->c_ptr() : "NULL"; goto err; @@ -1341,8 +1287,12 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) return new Item_int((int32) *(my_bool*) value_ptr(thd, var_type, base),1); case SHOW_CHAR: { + Item_string *tmp; + pthread_mutex_lock(&LOCK_global_system_variables); char *str= (char*) value_ptr(thd, var_type, base); - return new Item_string(str, strlen(str), system_charset_info); + tmp= new Item_string(str, strlen(str), system_charset_info); + pthread_mutex_unlock(&LOCK_global_system_variables); + return tmp; } default: net_printf(thd, ER_VAR_CANT_BE_READ, name); @@ -1383,7 +1333,6 @@ byte *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type, bool sys_var_thd_bit::update(THD *thd, set_var *var) { int res= (*update_func)(thd, var); - thd->lex.select_lex.options=thd->options; return res; } @@ -1401,6 +1350,112 @@ byte *sys_var_thd_bit::value_ptr(THD *thd, enum_var_type type, } +/* Update a date_time format variable based on given value */ + +void sys_var_thd_date_time_format::update2(THD *thd, enum_var_type type, + DATE_TIME_FORMAT *new_value) +{ + DATE_TIME_FORMAT *old; + DBUG_ENTER("sys_var_date_time_format::update2"); + DBUG_DUMP("positions",(char*) new_value->positions, + sizeof(new_value->positions)); + + if (type == OPT_GLOBAL) + { + pthread_mutex_lock(&LOCK_global_system_variables); + old= (global_system_variables.*offset); + (global_system_variables.*offset)= new_value; + pthread_mutex_unlock(&LOCK_global_system_variables); + } + else + { + old= (thd->variables.*offset); + (thd->variables.*offset)= new_value; + } + my_free((char*) old, MYF(MY_ALLOW_ZERO_PTR)); + DBUG_VOID_RETURN; +} + + +bool sys_var_thd_date_time_format::update(THD *thd, set_var *var) +{ + DATE_TIME_FORMAT *new_value; + /* We must make a copy of the last value to get it into normal memory */ + new_value= date_time_format_copy((THD*) 0, + var->save_result.date_time_format); + if (!new_value) + return 1; // Out of memory + update2(thd, var->type, new_value); // Can't fail + return 0; +} + + +bool sys_var_thd_date_time_format::check(THD *thd, set_var *var) +{ + char buff[80]; + String str(buff,sizeof(buff), system_charset_info), *res; + DATE_TIME_FORMAT *format; + + if (!(res=var->value->val_str(&str))) + res= &my_empty_string; + + if (!(format= date_time_format_make(date_time_type, + res->ptr(), res->length()))) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, res->c_ptr()); + return 1; + } + + /* + We must copy result to thread space to not get a memory leak if + update is aborted + */ + var->save_result.date_time_format= date_time_format_copy(thd, format); + my_free((char*) format, MYF(0)); + return var->save_result.date_time_format == 0; +} + + +void sys_var_thd_date_time_format::set_default(THD *thd, enum_var_type type) +{ + DATE_TIME_FORMAT *res= 0; + + if (type == OPT_GLOBAL) + { + const char *format; + if ((format= opt_date_time_formats[date_time_type])) + res= date_time_format_make(date_time_type, format, strlen(format)); + } + else + { + /* Make copy with malloc */ + res= date_time_format_copy((THD *) 0, global_system_variables.*offset); + } + + if (res) // Should always be true + update2(thd, type, res); +} + + +byte *sys_var_thd_date_time_format::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) +{ + if (type == OPT_GLOBAL) + { + char *res; + /* + We do a copy here just to be sure things will work even if someone + is modifying the original string while the copy is accessed + (Can't happen now in SQL SHOW, but this is a good safety for the future) + */ + res= thd->strmake((global_system_variables.*offset)->format.str, + (global_system_variables.*offset)->format.length); + return (byte*) res; + } + return (byte*) (thd->variables.*offset)->format.str; +} + + typedef struct old_names_map_st { const char *old_name; @@ -1409,17 +1464,17 @@ typedef struct old_names_map_st static my_old_conv old_conv[]= { - { "cp1251_koi8" , "cp1251" }, - { "cp1250_latin2" , "cp1250" }, - { "kam_latin2" , "keybcs2" }, - { "mac_latin2" , "MacRoman" }, - { "macce_latin2" , "MacCE" }, - { "pc2_latin2" , "pclatin2" }, - { "vga_latin2" , "pclatin1" }, - { "koi8_cp1251" , "koi8r" }, - { "win1251ukr_koi8_ukr" , "win1251ukr" }, - { "koi8_ukr_win1251ukr" , "koi8u" }, - { NULL , NULL } + { "cp1251_koi8" , "cp1251" }, + { "cp1250_latin2" , "cp1250" }, + { "kam_latin2" , "keybcs2" }, + { "mac_latin2" , "MacRoman" }, + { "macce_latin2" , "MacCE" }, + { "pc2_latin2" , "pclatin2" }, + { "vga_latin2" , "pclatin1" }, + { "koi8_cp1251" , "koi8r" }, + { "win1251ukr_koi8_ukr" , "win1251ukr" }, + { "koi8_ukr_win1251ukr" , "koi8u" }, + { NULL , NULL } }; CHARSET_INFO *get_old_charset_by_name(const char *name) diff --git a/sql/set_var.h b/sql/set_var.h index 16b2c1d5d37..c799eec750a 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -54,8 +54,6 @@ public: const char *name; sys_after_update_func after_update; - sys_var() - {} sys_var(const char *name_arg) :name(name_arg),after_update(0) {} sys_var(const char *name_arg,sys_after_update_func func) @@ -195,9 +193,6 @@ public: class sys_var_thd :public sys_var { public: - sys_var_thd() - :sys_var() - {} sys_var_thd(const char *name_arg) :sys_var(name_arg) {} @@ -621,46 +616,26 @@ public: }; -class sys_var_datetime_format :public sys_var_thd +class sys_var_thd_date_time_format :public sys_var_thd { + DATE_TIME_FORMAT *SV::*offset; + enum timestamp_type date_time_type; public: - enum datetime_format_types format_type; - DATETIME_FORMAT datetime_format; - sys_var_datetime_format(): sys_var_thd() + sys_var_thd_date_time_format(const char *name_arg, + DATE_TIME_FORMAT *SV::*offset_arg, + timestamp_type date_time_type_arg) + :sys_var_thd(name_arg), offset(offset_arg), + date_time_type(date_time_type_arg) {} - - void clean() - { - my_free(datetime_format.format, MYF(MY_ALLOW_ZERO_PTR)); - datetime_format.format=0; - } - - /* - It's for copying of global_system_variables structure - in THD constructor. - */ - inline sys_var_datetime_format& operator= (sys_var_datetime_format& s) - { - if (&s != this) - { - name= s.name; name_length= s.name_length; - datetime_format= s.datetime_format; - datetime_format.format= (my_strdup_with_length - (s.datetime_format.format, - s.datetime_format. - format_length, MYF(0))); - format_type= s.format_type; - } - return *this; - } - SHOW_TYPE type() { return SHOW_CHAR; } bool check_update_type(Item_result type) { return type != STRING_RESULT; /* Only accept strings */ } bool check_default(enum_var_type type) { return 0; } + bool check(THD *thd, set_var *var); bool update(THD *thd, set_var *var); + void update2(THD *thd, enum_var_type type, DATE_TIME_FORMAT *new_value); byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); void set_default(THD *thd, enum_var_type type); }; @@ -718,6 +693,7 @@ public: CHARSET_INFO *charset; ulong ulong_value; ulonglong ulonglong_value; + DATE_TIME_FORMAT *date_time_format; } save_result; LEX_STRING base; /* for structs */ diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 2176fcbd441..c01df3b53cd 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -276,21 +276,26 @@ character-set=latin2 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 791060ac744..e67c430c4f7 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -270,21 +270,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 62e210f1016..5f77163eeda 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -278,21 +278,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index a0d746ce0ca..baecefb8494 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -252,36 +252,41 @@ character-set=latin1 "Reference '%-.64s' not supported (%s)", "Every derived table must have it's own alias", "Select %u was reduced during optimisation", -"Table '%-.64s' from one of SELECT's can not be used in %-.32s" -"Client does not support authentication protocol requested by server; consider upgrading MySQL client" -"All parts of a SPATIAL KEY must be NOT NULL" -"COLLATION '%s' is not valid for CHARACTER SET '%s'" -"Slave is already running" -"Slave has already been stopped" -"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)" -"Z_MEM_ERROR: Not enough memory available for zlib" -"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)" -"Z_DATA_ERROR: Input data was corrupted for zlib" -"%d line(s) was(were) cut by group_concat()" +"Table '%-.64s' from one of SELECT's can not be used in %-.32s", +"Client does not support authentication protocol requested by server; consider upgrading MySQL client", +"All parts of a SPATIAL KEY must be NOT NULL", +"COLLATION '%s' is not valid for CHARACTER SET '%s'", +"Slave is already running", +"Slave has already been stopped", +"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", +"ZLIB: Not enough memory available for zlib", +"ZLIB: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", +"ZLIB: Input data was corrupted for zlib", +"%d line(s) was(were) cut by group_concat()", "Record count is fewer than the column count at row %ld"; "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format", +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to use --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL. Otherwise you will get problems if you get an unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 0510e3fc76b..09e63ddd804 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -272,21 +272,26 @@ character-set=latin7 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 485cbe45724..0956db6681e 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -267,21 +267,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index c9760879f3c..2cc98971915 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -293,7 +293,12 @@ character-set=latin1 "Feld oder Verweis '%-.64s%s%-.64s%s%-.64s' im SELECT-Befehl Nr. %d wurde im SELECT-Befehl Nr. %d aufgelöst", "Falscher Parameter oder falsche Kombination von Parametern für START SLAVE UNTIL", "Es wird empfohlen, mit --skip-slave-start zu starten, wenn mit START SLAVE UNTIL eine Schritt-für-Schritt-Replikation ausgeführt wird. Ansonsten gibt es Probleme, wenn der Slave-Server unerwartet neu startet", -"SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert" -"Incorrect index name '%-.100s'", +"SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 90ab24610ff..84e48d2f284 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -267,21 +267,26 @@ character-set=greek "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index c456e9580b3..da71f4b7da6 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -269,21 +269,26 @@ character-set=latin2 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 09b533c0fb7..4ed4d477ab8 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -267,21 +267,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 15b8640cb29..d28cc026159 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -269,21 +269,26 @@ character-set=ujis "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index d31efc94d46..b0c4bf9463e 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -267,21 +267,26 @@ character-set=euckr "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 515a322f136..1e9028de1d7 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -269,21 +269,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index faea5402fc6..942c18cc045 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -269,21 +269,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 2a7ea3accb8..17e6df6c443 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -271,21 +271,26 @@ character-set=latin2 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 1f3bbb5c02f..fdf428c9b6d 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -241,7 +241,7 @@ character-set=latin1 "Errado uso/colocação de '%s'", "Esta versão de MySQL não suporta ainda '%s'", "Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log", -"Slave SQL thread ignorado a consulta devido às normas de replicação-*-tabela" +"Slave SQL thread ignorado a consulta devido às normas de replicação-*-tabela", "Definição errada da chave estrangeira para '%-.64s': %s", "Referência da chave e referência da tabela não coincidem", "Operand should contain %d column(s)", @@ -268,21 +268,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Usando engine de armazenamento %s para tabela '%s'", "Combinação ilegal de collations (%s,%s) e (%s,%s) para operação '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 78daafe04d1..8f4fdb3a702 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -252,7 +252,7 @@ character-set=latin2 "Unknown prepared statement handler (%ld) given to %s", "Help database is corrupt or does not exist", "Cyclic reference on subqueries", -"Converting column '%s' from %s to %s" +"Converting column '%s' from %s to %s", "Reference '%-.64s' not supported (%s)", "Every derived table must have it's own alias", "Select %u was reduced during optimisation", @@ -271,21 +271,26 @@ character-set=latin2 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 462afdfa782..2ef6a2c553b 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -269,21 +269,26 @@ character-set=koi8r "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"óÅÒ×ÅÒ ÚÁÐÕÝÅÎ × ÒÅÖÉÍÅ --secure-auth (ÂÅÚÏÐÁÓÎÏÊ Á×ÔÏÒÉÚÁÃÉÉ), ÎÏ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%s@%s' ÐÁÒÏÌØ ÓÏÈÒÁÎ£Î × ÓÔÁÒÏÍ ÆÏÒÍÁÔÅ; ÎÅÏÂÈÏÄÉÍÏ ÏÂÎÏ×ÉÔØ ÆÏÒÍÁÔ ÐÁÒÏÌÑ" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"óÅÒ×ÅÒ ÚÁÐÕÝÅÎ × ÒÅÖÉÍÅ --secure-auth (ÂÅÚÏÐÁÓÎÏÊ Á×ÔÏÒÉÚÁÃÉÉ), ÎÏ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%s@%s' ÐÁÒÏÌØ ÓÏÈÒÁÎ£Î × ÓÔÁÒÏÍ ÆÏÒÍÁÔÅ; ÎÅÏÂÈÏÄÉÍÏ ÏÂÎÏ×ÉÔØ ÆÏÒÍÁÔ ÐÁÒÏÌÑ", "ðÏÌÅ ÉÌÉ ÓÓÙÌËÁ '%-.64s%s%-.64s%s%-.64s' ÉÚ SELECTÁ #%d ÂÙÌÁ ÎÁÊÄÅÎÁ × SELECTÅ #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "ëÅÛ ÚÁÐÒÏÓÏ× ÎÅ ÍÏÖÅÔ ÕÓÔÁÎÏ×ÉÔØ ÒÁÚÍÅÒ %lu, ÎÏ×ÙÊ ÒÁÚÍÅÒ ËÅÛÁ ÚÐÒÏÓÏ× - %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 9d12654f150..cddc1059f44 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -262,21 +262,26 @@ character-set=cp1250 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index dd222c2ef30..466e7d478b6 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -275,21 +275,26 @@ character-set=latin2 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index a21d306a3db..de8a245c7f9 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -242,7 +242,7 @@ character-set=latin1 "Equivocado uso/colocación de '%s'", "Esta versión de MySQL no soporta todavia '%s'", "Recibió fatal error %d: '%-.128s' del master cuando leyendo datos del binary log", -"Slave SQL thread ignorado el query debido a las reglas de replicación-*-tabla" +"Slave SQL thread ignorado el query debido a las reglas de replicación-*-tabla", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Operand should contain %d column(s)", @@ -269,21 +269,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 4d3e69a5b0f..d8695db30a4 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -225,7 +225,7 @@ character-set=latin1 "Fick fel vid utförande av command på mastern: %-.128s", "Fick fel vid utförande av %s: %-.128s", "Felaktig använding av %s and %s", -"SELECT-kommandona har olika antal kolumner" +"SELECT-kommandona har olika antal kolumner", "Kan inte utföra kommandot emedan du har ett READ-lås", "Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat", "Option '%s' användes två gånger", @@ -267,21 +267,26 @@ character-set=latin1 "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Använder handler %s för tabell '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", -"Query cache failed to set size %lu, new query cache size is %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Felaktigt %s namn '%-.100s'", +"tabell", +"databas", +"kolumn", +"index", +"katalog", +"Storleken av "Query cache" kunde inte sättas till %lu, ny storlek är %lu", +"Kolumn '%-.64s' kan inte vara del av ett FULLTEXT index", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 283700b7891..3a37ee02731 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -272,21 +272,26 @@ character-set=koi8u "Record count is more than the column count at row %ld"; "Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; "Data truncated, out of range for column '%s' at row %ld"; -"Data truncated for column '%s' at row %ld" +"Data truncated for column '%s' at row %ld", "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", -"Can't drop one or more of the requested users" -"Can't revoke all privileges, grant for one or more of the requested users" +"Can't drop one or more of the requested users", +"Can't revoke all privileges, grant for one or more of the requested users", "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", -"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format" +"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started.", +"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", "óÔÏ×ÂÅÃØ ÁÂÏ ÐÏÓÉÌÁÎÎÑ '%-.64s%s%-.64s%s%-.64s' ¦Ú SELECTÕ #%d ÂÕÌÏ ÚÎÁÊÄÅÎÅ Õ SELECT¦ #%d", -"Wrong parameter or combination of parameters for START SLAVE UNTIL" -"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" -"SQL thread is not to be started so UNTIL options are ignored" -"Incorrect index name '%-.100s'", +"Wrong parameter or combination of parameters for START SLAVE UNTIL", +"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart", +"SQL thread is not to be started so UNTIL options are ignored", +"Incorrect %s name '%-.100s'", +"table", +"database", +"column", +"index", +"catalog", "ëÅÛ ÚÁÐÉÔ¦× ÎÅÓÐÒÏÍÏÖÅÎ ×ÓÔÁÎÏ×ÉÔÉ ÒÏÚÍ¦Ò %lu, ÎÏ×ÉÊ ÒÏÚÍ¦Ò ËÅÛÁ ÚÁÐÉÔ¦× - %lu", -"Column '%-.64s' cannot be part of FULLTEXT index" +"Column '%-.64s' cannot be part of FULLTEXT index", diff --git a/sql/slave.cc b/sql/slave.cc index 415969a2955..561b32b668c 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -355,6 +355,22 @@ void init_slave_skip_errors(const char* arg) } } +void st_relay_log_info::close_temporary_tables() +{ + TABLE *table,*next; + + for (table=save_temporary_tables ; table ; table=next) + { + next=table->next; + /* + Don't ask for disk deletion. For now, anyway they will be deleted when + slave restarts, but it is a better intention to not delete them. + */ + close_temporary(table, 0); + } + save_temporary_tables= 0; + slave_open_temp_tables= 0; +} /* purge_relay_logs() @@ -847,6 +863,7 @@ static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/) void end_slave() { + /* This is called when the server terminates, in close_connections(). */ if (active_mi) { /* @@ -1428,7 +1445,7 @@ file '%s', errno %d)", fname, my_errno); if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */, &msg)) { - sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4"); + sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4)"); goto err; } rli->group_master_log_name[0]= 0; @@ -3166,8 +3183,6 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ RPL_LOG_NAME, llstr(rli->group_master_log_pos,llbuff)); err: - /* Free temporary tables etc */ - thd->cleanup(); VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query = thd->db = 0; // extra safety VOID(pthread_mutex_unlock(&LOCK_thread_count)); @@ -3585,6 +3600,12 @@ void end_relay_log_info(RELAY_LOG_INFO* rli) } rli->inited = 0; rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT); + /* + Delete the slave's temporary tables from memory. + In the future there will be other actions than this, to ensure persistance + of slave's temp tables after shutdown. + */ + rli->close_temporary_tables(); DBUG_VOID_RETURN; } diff --git a/sql/slave.h b/sql/slave.h index 618b04311b9..f8093826f58 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -320,10 +320,10 @@ typedef struct st_relay_log_info int wait_for_pos(THD* thd, String* log_name, longlong log_pos, longlong timeout); + void close_temporary_tables(); /* Check if UNTIL condition is satisfied. See slave.cc for more. */ bool is_until_satisfied(); - } RELAY_LOG_INFO; diff --git a/sql/spatial.cc b/sql/spatial.cc index 00db94a07d6..d19429fdd9c 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -1258,6 +1258,7 @@ int GMultiPolygon::geometry_n(uint32 num, String *result) const uint32 n_polygons; const char *data= m_data, *polygon_n; LINT_INIT(polygon_n); + if (no_data(data, 4)) return 1; n_polygons= uint4korr(data); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index cc068451ecf..3976ebd81f4 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -575,6 +575,8 @@ TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name) uint key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1; TABLE *table,**prev; + int4store(key+key_length,thd->server_id); + key_length += 4; int4store(key+key_length,thd->variables.pseudo_thread_id); key_length += 4; @@ -603,18 +605,27 @@ bool close_temporary_table(THD *thd, const char *db, const char *table_name) return 0; } +/* + Used by ALTER TABLE when the table is a temporary one. It changes something + only if the ALTER contained a RENAME clause (otherwise, table_name is the old + name). + Prepares a table cache key, which is the concatenation of db, table_name and + thd->slave_proxy_id, separated by '\0'. +*/ bool rename_temporary_table(THD* thd, TABLE *table, const char *db, const char *table_name) { char *key; if (!(key=(char*) alloc_root(&table->mem_root, (uint) strlen(db)+ - (uint) strlen(table_name)+6))) + (uint) strlen(table_name)+6+4))) return 1; /* purecov: inspected */ table->key_length=(uint) (strmov((table->real_name=strmov(table->table_cache_key=key, db)+1), table_name) - table->table_cache_key)+1; + int4store(key+table->key_length,thd->server_id); + table->key_length += 4; int4store(key+table->key_length,thd->variables.pseudo_thread_id); table->key_length += 4; return 0; @@ -771,12 +782,13 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, if (thd->killed) DBUG_RETURN(0); key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1; - int4store(key + key_length, thd->variables.pseudo_thread_id); + int4store(key + key_length, thd->server_id); + int4store(key + key_length + 4, thd->variables.pseudo_thread_id); for (table=thd->temporary_tables; table ; table=table->next) { - if (table->key_length == key_length+4 && - !memcmp(table->table_cache_key,key,key_length+4)) + if (table->key_length == key_length+8 && + !memcmp(table->table_cache_key,key,key_length+8)) { if (table->query_id == thd->query_id) { @@ -1671,7 +1683,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, total of 6 extra bytes in my_malloc in addition to table/db stuff */ if (!(tmp_table=(TABLE*) my_malloc(sizeof(*tmp_table)+(uint) strlen(db)+ - (uint) strlen(table_name)+6, + (uint) strlen(table_name)+6+4, MYF(MY_WME)))) DBUG_RETURN(0); /* purecov: inspected */ @@ -1694,6 +1706,9 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, +1), table_name) - tmp_table->table_cache_key)+1; int4store(tmp_table->table_cache_key + tmp_table->key_length, + thd->server_id); + tmp_table->key_length += 4; + int4store(tmp_table->table_cache_key + tmp_table->key_length, thd->variables.pseudo_thread_id); tmp_table->key_length += 4; @@ -2210,7 +2225,8 @@ void get_key_map_from_key_list(key_map *map, TABLE *table, map->clear_all(); while ((name=it++)) { - if ((pos=find_type(name->c_ptr(), &table->keynames, 1+2)) <= 0) + if ((pos= find_type(&table->keynames, name->ptr(), name->length(), 1)) <= + 0) { my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(), table->real_name); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 0bae41da002..396764cd532 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -770,9 +770,12 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) bzero(&flags, QUERY_CACHE_FLAGS_SIZE); flags.client_long_flag= (thd->client_capabilities & CLIENT_LONG_FLAG ? 1 : 0); - flags.character_set_client_num= thd->variables.character_set_client->number; - flags.character_set_results_num= thd->variables.character_set_results->number; - flags.collation_connection_num= thd->variables.collation_connection->number; + flags.character_set_client_num= + thd->variables.character_set_client->number; + flags.character_set_results_num= + thd->variables.character_set_results->number; + flags.collation_connection_num= + thd->variables.collation_connection->number; flags.limit= thd->variables.select_limit; STRUCT_LOCK(&structure_guard_mutex); @@ -953,7 +956,8 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) flags.client_long_flag= (thd->client_capabilities & CLIENT_LONG_FLAG ? 1 : 0); flags.character_set_client_num= thd->variables.character_set_client->number; - flags.character_set_results_num= thd->variables.character_set_results->number; + flags.character_set_results_num= + thd->variables.character_set_results->number; flags.collation_connection_num= thd->variables.collation_connection->number; flags.limit= thd->variables.select_limit; memcpy((void *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)), @@ -2761,11 +2765,33 @@ my_bool Query_cache::move_by_type(byte **border, relink(block, new_block, next, prev, pnext, pprev); if (queries_blocks == block) queries_blocks = new_block; + Query_cache_block_table *beg_of_table_table= block->table(0), + *end_of_table_table= block->table(n_tables); + byte *beg_of_new_table_table= (byte*) new_block->table(0); + for (TABLE_COUNTER_TYPE j=0; j < n_tables; j++) { Query_cache_block_table *block_table = new_block->table(j); - block_table->next->prev = block_table; - block_table->prev->next = block_table; + + // use aligment from begining of table if 'next' is in same block + if ((beg_of_table_table <= block_table->next) && + (block_table->next < end_of_table_table)) + ((Query_cache_block_table *)(beg_of_new_table_table + + (((byte*)block_table->next) - + ((byte*)beg_of_table_table))))->prev= + block_table; + else + block_table->next->prev= block_table; + + // use aligment from begining of table if 'prev' is in same block + if ((beg_of_table_table <= block_table->prev) && + (block_table->prev < end_of_table_table)) + ((Query_cache_block_table *)(beg_of_new_table_table + + (((byte*)block_table->prev) - + ((byte*)beg_of_table_table))))->next= + block_table; + else + block_table->prev->next = block_table; } DBUG_PRINT("qcache", ("after circle tt")); *border += len; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ed8eaba9128..4fcd6504a2f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -210,6 +210,12 @@ void THD::init(void) { pthread_mutex_lock(&LOCK_global_system_variables); variables= global_system_variables; + variables.time_format= date_time_format_copy((THD*) 0, + variables.time_format); + variables.date_format= date_time_format_copy((THD*) 0, + variables.date_format); + variables.datetime_format= date_time_format_copy((THD*) 0, + variables.datetime_format); pthread_mutex_unlock(&LOCK_global_system_variables); server_status= SERVER_STATUS_AUTOCOMMIT; options= thd_startup_options; @@ -281,9 +287,9 @@ void THD::cleanup(void) close_thread_tables(this); } close_temporary_tables(this); - variables.datetime_formats[DATE_FORMAT_TYPE].clean(); - variables.datetime_formats[TIME_FORMAT_TYPE].clean(); - variables.datetime_formats[DATETIME_FORMAT_TYPE].clean(); + my_free((char*) variables.time_format, MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*) variables.date_format, MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR)); delete_dynamic(&user_var_events); hash_free(&user_vars); if (global_read_lock) @@ -390,6 +396,11 @@ bool THD::store_globals() return 1; mysys_var=my_thread_var; dbug_thread_id=my_thread_id(); + /* + By default 'slave_proxy_id' is 'thread_id'. They may later become different + if this is the slave SQL thread. + */ + variables.pseudo_thread_id= thread_id; return 0; } diff --git a/sql/sql_class.h b/sql/sql_class.h index a103bab1d6c..7a8dc067256 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -421,7 +421,11 @@ struct system_variables CHARSET_INFO *collation_server; CHARSET_INFO *collation_database; CHARSET_INFO *collation_connection; - sys_var_datetime_format datetime_formats[3]; + + /* DATE, DATETIME and TIME formats */ + DATE_TIME_FORMAT *date_format; + DATE_TIME_FORMAT *datetime_format; + DATE_TIME_FORMAT *time_format; }; void free_tmp_table(THD *thd, TABLE *entry); @@ -477,7 +481,11 @@ public: char priv_host[MAX_HOSTNAME]; /* remote (peer) port */ uint16 peer_port; - /* Points to info-string that will show in SHOW PROCESSLIST */ + /* + Points to info-string that we show in SHOW PROCESSLIST + You are supposed to update thd->proc_info only if you have coded + a time-consuming piece that MySQL can get stuck in for a long time. + */ const char *proc_info; /* points to host if host is available, otherwise points to ip */ const char *host_or_ip; @@ -506,6 +514,11 @@ public: enum enum_server_command command; uint32 server_id; uint32 file_id; // for LOAD DATA INFILE + /* + Used in error messages to tell user in what part of MySQL we found an + error. E. g. when where= "having clause", if fix_fields() fails, user + will know that the error was in having clause. + */ const char *where; time_t start_time,time_after_lock,user_time; time_t connect_time,thr_create_time; // track down slow pthread_create diff --git a/sql/sql_db.cc b/sql/sql_db.cc index b0f4b4ef574..b7d6c642398 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -609,7 +609,7 @@ bool mysql_change_db(THD *thd, const char *name) } if ((db_length > NAME_LEN) || check_db_name(dbname)) { - net_printf(thd,ER_WRONG_DB_NAME, dbname); + net_printf(thd, ER_WRONG_NAME, ER(ER_DATABASE), dbname); x_free(dbname); DBUG_RETURN(1); } @@ -675,7 +675,7 @@ int mysqld_show_create_db(THD *thd, char *dbname, if (check_db_name(dbname)) { - net_printf(thd,ER_WRONG_DB_NAME, dbname); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), dbname); DBUG_RETURN(1); } diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 7fd2b751c1d..719686a56c3 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -222,10 +222,6 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, else unit->exclude_tree(); org_table_list->db= (char *)""; -#ifndef DBUG_OFF - /* Try to catch errors if this is accessed */ - org_table_list->derived=(SELECT_LEX_UNIT *) 1; -#endif // Force read of table stats in the optimizer table->file->info(HA_STATUS_VARIABLE); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f842e44ff7d..a55b801a0fc 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -40,10 +40,18 @@ LEX_STRING tmp_table_alias= {(char*) "tmp-table",8}; pthread_key(LEX*,THR_LEX); +/* Longest standard keyword name */ #define TOCK_NAME_LENGTH 24 /* - The following is based on the latin1 character set, and is only + Map to default keyword characters. This is used to test if an identifer + is 'simple', in which case we don't have to do any character set conversions + on it +*/ +uchar *bin_ident_map= my_charset_bin.ident_map; + +/* + The following data is based on the latin1 character set, and is only used when comparing keywords */ @@ -66,6 +74,7 @@ uchar to_upper_lex[] = { 208,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255 }; + inline int lex_casecmp(const char *s, const char *t, uint len) { while (len-- != 0 && @@ -410,15 +419,18 @@ inline static uint int_token(const char *str,uint length) } -// yylex remember the following states from the following yylex() -// MY_LEX_EOQ ; found end of query -// MY_LEX_OPERATOR_OR_IDENT ; last state was an ident, text or number -// (which can't be followed by a signed number) +/* + yylex remember the following states from the following yylex() + + - MY_LEX_EOQ Found end of query + - MY_LEX_OPERATOR_OR_IDENT Last state was an ident, text or number + (which can't be followed by a signed number) +*/ int yylex(void *arg, void *yythd) { reg1 uchar c; - int tokval; + int tokval, result_state; uint length; enum my_lex_states state,prev_state; LEX *lex= &(((THD *)yythd)->lex); @@ -503,6 +515,7 @@ int yylex(void *arg, void *yythd) #if defined(USE_MB) && defined(USE_MB_IDENT) if (use_mb(cs)) { + result_state= IDENT_QUOTED; if (my_mbcharlen(cs, yyGetLast()) > 1) { int l = my_ismbchar(cs, @@ -529,7 +542,15 @@ int yylex(void *arg, void *yythd) } else #endif - while (ident_map[c=yyGet()]) ; + { + result_state= bin_ident_map[c] ? IDENT : IDENT_QUOTED; + while (ident_map[c=yyGet()]) + { + /* If not simple character, mark that we must convert it */ + if (!bin_ident_map[c]) + result_state= IDENT_QUOTED; + } + } length= (uint) (lex->ptr - lex->tok_start)-1; if (lex->ignore_space) { @@ -560,8 +581,7 @@ int yylex(void *arg, void *yythd) (lex->charset=get_charset_by_csname(yylval->lex_str.str+1, MY_CS_PRIMARY,MYF(0)))) return(UNDERSCORE_CHARSET); - else - return(IDENT); + return(result_state); // IDENT or IDENT_QUOTED case MY_LEX_IDENT_SEP: // Found ident and now '.' yylval->lex_str.str=(char*) lex->ptr; @@ -611,21 +631,11 @@ int yylex(void *arg, void *yythd) } // fall through case MY_LEX_IDENT_START: // We come here after '.' + result_state= IDENT; #if defined(USE_MB) && defined(USE_MB_IDENT) if (use_mb(cs)) { - if (my_mbcharlen(cs, yyGetLast()) > 1) - { - int l = my_ismbchar(cs, - (const char *)lex->ptr-1, - (const char *)lex->end_of_query); - if (l == 0) - { - state = MY_LEX_CHAR; - continue; - } - lex->ptr += l - 1; - } + result_state= IDENT_QUOTED; while (ident_map[c=yyGet()]) { if (my_mbcharlen(cs, c) > 1) @@ -641,15 +651,17 @@ int yylex(void *arg, void *yythd) } else #endif - while (ident_map[c = yyGet()]) ; - + while (ident_map[c = yyGet()]) + { + /* If not simple character, mark that we must convert it */ + if (!bin_ident_map[c]) + result_state= IDENT_QUOTED; + } if (c == '.' && ident_map[yyPeek()]) lex->next_state=MY_LEX_IDENT_SEP;// Next is '.' - // fall through - case MY_LEX_FOUND_IDENT: // Complete ident - yylval->lex_str=get_token(lex,yyLength()); - return(IDENT); + yylval->lex_str= get_token(lex,yyLength()); + return(result_state); case MY_LEX_USER_VARIABLE_DELIMITER: { @@ -699,7 +711,7 @@ int yylex(void *arg, void *yythd) if (c == delim) yySkip(); // Skip end ` lex->next_state= MY_LEX_START; - return(IDENT); + return(IDENT_QUOTED); } case MY_LEX_INT_OR_REAL: // Compleat int or incompleat real if (c != '.') @@ -924,7 +936,13 @@ int yylex(void *arg, void *yythd) We should now be able to handle: [(global | local | session) .]variable_name */ - while (ident_map[c=yyGet()]) ; + result_state= IDENT; + while (ident_map[c=yyGet()]) + { + /* If not simple character, mark that we must convert it */ + if (!bin_ident_map[c]) + result_state= IDENT_QUOTED; + } if (c == '.') lex->next_state=MY_LEX_IDENT_SEP; length= (uint) (lex->ptr - lex->tok_start)-1; @@ -934,7 +952,7 @@ int yylex(void *arg, void *yythd) return(tokval); // Was keyword } yylval->lex_str=get_token(lex,length); - return(IDENT); + return(result_state); } } } @@ -1502,7 +1520,75 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) order_group_num)* 5)) == 0; } +void st_select_lex_unit::print(String *str) +{ + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + { + if (sl != first_select()) + { + str->append(" union ", 7); + if (union_option & UNION_ALL) + str->append("all ", 4); + } + if (sl->braces) + str->append('('); + sl->print(thd, str); + if (sl->braces) + str->append(')'); + } + if (fake_select_lex == global_parameters) + { + if (fake_select_lex->order_list.elements) + { + str->append(" order by ", 10); + fake_select_lex->print_order(str, + (ORDER *) fake_select_lex-> + order_list.first); + } + fake_select_lex->print_limit(thd, str); + } +} + + +void st_select_lex::print_order(String *str, ORDER *order) +{ + for (; order; order= order->next) + { + (*order->item)->print(str); + if (!order->asc) + str->append(" desc", 5); + if (order->next) + str->append(','); + } +} + +void st_select_lex::print_limit(THD *thd, String *str) +{ + if (!thd) + thd= current_thd; + + if (select_limit != thd->variables.select_limit || + select_limit != HA_POS_ERROR || + offset_limit != 0L) + { + str->append(" limit ", 7); + char buff[20]; + // latin1 is good enough for numbers + String st(buff, sizeof(buff), &my_charset_latin1); + st.set((ulonglong)select_limit, &my_charset_latin1); + str->append(st); + if (offset_limit) + { + str->append(','); + st.set((ulonglong)select_limit, &my_charset_latin1); + str->append(st); + } + } +} + /* There are st_select_lex::add_table_to_list & st_select_lex::set_lock_for_tables in sql_parse.cc + + st_select_lex::print is in sql_select.h */ diff --git a/sql/sql_lex.h b/sql/sql_lex.h index c31420b951c..be931c56247 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -80,6 +80,10 @@ enum enum_sql_command { SQLCOM_END }; +// describe/explain types +#define DESCRIBE_NORMAL 1 +#define DESCRIBE_EXTENDED 2 + typedef List<Item> List_item; typedef struct st_lex_master_info @@ -292,7 +296,7 @@ protected: select_result *result; int res; - ulong describe, found_rows_for_union; + ulong found_rows_for_union; bool prepared, // prepare phase already performed for UNION (unit) optimized, // optimize phase already performed for UNION (unit) executed, // already executed @@ -335,7 +339,9 @@ public: int prepare(THD *thd, select_result *result, bool tables_and_fields_initied); int exec(); int cleanup(); - + + void print(String *str); + friend void mysql_init_query(THD *thd); friend int subselect_union_engine::exec(); private: @@ -476,6 +482,9 @@ public: init_select(); } bool setup_ref_array(THD *thd, uint order_group_num); + void print(THD *thd, String *str); + static void print_order(String *str, ORDER *order); + void print_limit(THD *thd, String *str); }; typedef class st_select_lex SELECT_LEX; @@ -550,9 +559,10 @@ typedef struct st_lex uint fk_delete_opt, fk_update_opt, fk_match_option; uint param_count; uint slave_thd_opt; + uint8 describe; bool drop_primary, drop_if_exists, drop_temporary, local_file; bool in_comment, ignore_space, verbose, simple_alter, no_write_to_binlog; - bool derived_tables, describe; + bool derived_tables; bool safe_to_cache_query; st_lex() {} inline void uncacheable() diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 704ac726fa6..b3c17167a3a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -172,6 +172,7 @@ static int get_or_create_user_conn(THD *thd, const char *user, } } thd->user_connect=uc; + uc->connections++; end: (void) pthread_mutex_unlock(&LOCK_user_conn); return return_val; @@ -314,14 +315,15 @@ int check_user(THD *thd, enum enum_server_command command, thd->db_access=0; /* Don't allow user to connect if he has done too many queries */ - if ((ur.questions || ur.updates || - ur.connections || max_user_connections) && - get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur)) - DBUG_RETURN(-1); - if (thd->user_connect && (thd->user_connect->user_resources.connections || - max_user_connections) && - check_for_max_user_connections(thd, thd->user_connect)) - DBUG_RETURN(-1); + if ((ur.questions || ur.updates || ur.connections || + max_user_connections) && + get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur)) + DBUG_RETURN(-1); + if (thd->user_connect && + (thd->user_connect->user_resources.connections || + max_user_connections) && + check_for_max_user_connections(thd, thd->user_connect)) + DBUG_RETURN(-1); /* Change database if necessary: OK or FAIL is sent in mysql_change_db */ if (db && db[0]) @@ -386,42 +388,84 @@ void init_max_user_conn(void) } +/* + check if user has already too many connections + + SYNOPSIS + check_for_max_user_connections() + thd Thread handle + uc User connect object + + NOTES + If check fails, we decrease user connection count, which means one + shouldn't call decrease_user_connections() after this function. + + RETURN + 0 ok + 1 error +*/ + static int check_for_max_user_connections(THD *thd, USER_CONN *uc) { int error=0; DBUG_ENTER("check_for_max_user_connections"); + (void) pthread_mutex_lock(&LOCK_user_conn); if (max_user_connections && - (max_user_connections < (uint) uc->connections)) + max_user_connections < (uint) uc->connections) { net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user); error=1; goto end; } - uc->connections++; if (uc->user_resources.connections && - uc->conn_per_hour++ >= uc->user_resources.connections) + uc->user_resources.connections <= uc->conn_per_hour) { net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_connections", (long) uc->user_resources.connections); error=1; + goto end; } -end: + uc->conn_per_hour++; + + end: + if (error) + uc->connections--; // no need for decrease_user_connections() here + (void) pthread_mutex_unlock(&LOCK_user_conn); DBUG_RETURN(error); } +/* + Decrease user connection count + + SYNOPSIS + decrease_user_connections() + uc User connection object + + NOTES + If there is a n user connection object for a connection + (which only happens if 'max_user_connections' is defined or + if someone has created a resource grant for a user), then + the connection count is always incremented on connect. + + The user connect object is not freed if some users has + 'max connections per hour' defined as we need to be able to hold + count over the lifetime of the connection. +*/ + static void decrease_user_connections(USER_CONN *uc) { DBUG_ENTER("decrease_user_connections"); - if ((uc->connections && !--uc->connections) && !mqh_used) + (void) pthread_mutex_lock(&LOCK_user_conn); + DBUG_ASSERT(uc->connections); + if (!--uc->connections && !mqh_used) { /* Last connection for user; Delete it */ - (void) pthread_mutex_lock(&LOCK_user_conn); (void) hash_delete(&hash_user_connections,(byte*) uc); - (void) pthread_mutex_unlock(&LOCK_user_conn); } + (void) pthread_mutex_unlock(&LOCK_user_conn); DBUG_VOID_RETURN; } @@ -1041,7 +1085,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd) if (!db || check_db_name(db)) { - net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), db ? db : "NULL"); goto err; } if (lower_case_table_names) @@ -1227,15 +1271,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd, char *save_user= thd->user; char *save_priv_user= thd->priv_user; char *save_db= thd->db; - USER_CONN *save_uc= thd->user_connect; - thd->user= my_strdup(user, MYF(0)); - if (!thd->user) + USER_CONN *save_user_connect= thd->user_connect; + + if (!(thd->user= my_strdup(user, MYF(0)))) { thd->user= save_user; send_error(thd, ER_OUT_OF_RESOURCES); break; } + /* Clear variables that are allocated */ + thd->user_connect= 0; int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, false); if (res) @@ -1246,6 +1292,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, x_free(thd->user); thd->user= save_user; thd->priv_user= save_priv_user; + thd->user_connect= save_user_connect; thd->master_access= save_master_access; thd->db_access= save_db_access; thd->db= save_db; @@ -1254,8 +1301,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, else { /* we've authenticated new user */ - if (max_connections && save_uc) - decrease_user_connections(save_uc); + if (save_user_connect) + decrease_user_connections(save_user_connect); x_free((gptr) save_db); x_free((gptr) save_user); } @@ -1382,7 +1429,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, // null test to handle EOM if (!db || !strip_sp(db) || check_db_name(db)) { - net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), db ? db : "NULL"); break; } if (check_access(thd,CREATE_ACL,db,0,1,0)) @@ -1398,7 +1445,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, // null test to handle EOM if (!db || !strip_sp(db) || check_db_name(db)) { - net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), db ? db : "NULL"); break; } if (check_access(thd,DROP_ACL,db,0,1,0)) @@ -1777,6 +1824,16 @@ mysql_execute_command(THD *thd) res= mysql_explain_union(thd, &thd->lex.unit, result); MYSQL_LOCK *save_lock= thd->lock; thd->lock= (MYSQL_LOCK *)0; + if (lex->describe & DESCRIBE_EXTENDED) + { + char buff[1024]; + String str(buff,(uint32) sizeof(buff), system_charset_info); + str.length(0); + thd->lex.unit.print(&str); + str.append('\0'); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_YES, str.ptr()); + } result->send_eof(); thd->lock= save_lock; } @@ -1989,7 +2046,7 @@ mysql_execute_command(THD *thd) #endif if (strlen(tables->real_name) > NAME_LEN) { - net_printf(thd,ER_WRONG_TABLE_NAME,tables->real_name); + net_printf(thd,ER_WRONG_NAME, ER(ER_TABLE), tables->real_name); break; } LOCK_ACTIVE_MI; @@ -2034,7 +2091,7 @@ mysql_execute_command(THD *thd) #endif if (strlen(tables->real_name) > NAME_LEN) { - net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias); + net_printf(thd, ER_WRONG_NAME, ER(ER_TABLE), tables->alias); res=0; break; } @@ -2166,7 +2223,7 @@ mysql_execute_command(THD *thd) ulong priv=0; if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN)) { - net_printf(thd,ER_WRONG_TABLE_NAME,lex->name); + net_printf(thd, ER_WRONG_NAME, ER(ER_TABLE), lex->name); res=0; break; } @@ -2740,7 +2797,7 @@ mysql_execute_command(THD *thd) remove_escape(db); // Fix escaped '_' if (check_db_name(db)) { - net_printf(thd,ER_WRONG_DB_NAME, db); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), db); goto error; } #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -2905,7 +2962,7 @@ mysql_execute_command(THD *thd) { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(thd,ER_WRONG_DB_NAME, lex->name); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), lex->name); break; } /* @@ -2933,7 +2990,7 @@ mysql_execute_command(THD *thd) { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(thd,ER_WRONG_DB_NAME, lex->name); + net_printf(thd, ER_WRONG_NAME, ER(ER_DATABASE), lex->name); break; } /* @@ -2966,7 +3023,7 @@ mysql_execute_command(THD *thd) { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(thd,ER_WRONG_DB_NAME, lex->name); + net_printf(thd, ER_WRONG_NAME, ER(ER_DATABASE), lex->name); break; } if (check_access(thd,ALTER_ACL,lex->name,0,1,0)) @@ -2983,7 +3040,7 @@ mysql_execute_command(THD *thd) { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(thd,ER_WRONG_DB_NAME, lex->name); + net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), lex->name); break; } if (check_access(thd,DROP_ACL,lex->name,0,1,0)) @@ -4049,7 +4106,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, { char *not_used; uint not_used2; - bool not_used3; + bool not_used3; thd->cuted_fields=0; String str,*res; @@ -4079,7 +4136,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, { String str,*res; res=default_value->val_str(&str); - if (!find_enum(interval,res->ptr(),res->length())) + res->strip_sp(); + if (!find_type(interval, res->ptr(), res->length(), 0)) { net_printf(thd,ER_INVALID_DEFAULT,field_name); DBUG_RETURN(1); @@ -4232,7 +4290,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, if (check_table_name(table->table.str,table->table.length) || table->db.str && check_db_name(table->db.str)) { - net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str); + net_printf(thd, ER_WRONG_NAME, ER(ER_TABLE), table->table.str); DBUG_RETURN(0); } @@ -4586,7 +4644,7 @@ static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name) if (strlen(*filename_ptr)+strlen(table_name) >= FN_REFLEN-1 || !test_if_hard_path(*filename_ptr)) { - my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr); + my_error(ER_WRONG_NAME, MYF(0), ER(ER_TABLE), *filename_ptr); return 1; } /* Fix is using unix filename format on dos */ @@ -4626,39 +4684,39 @@ bool check_simple_select() } -compare_func_creator comp_eq_creator(bool invert) +Comp_creator *comp_eq_creator(bool invert) { - return invert?&Item_bool_func2::ne_creator:&Item_bool_func2::eq_creator; + return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator; } -compare_func_creator comp_ge_creator(bool invert) +Comp_creator *comp_ge_creator(bool invert) { - return invert?&Item_bool_func2::lt_creator:&Item_bool_func2::ge_creator; + return invert?(Comp_creator *)<_creator:(Comp_creator *)&ge_creator; } -compare_func_creator comp_gt_creator(bool invert) +Comp_creator *comp_gt_creator(bool invert) { - return invert?&Item_bool_func2::le_creator:&Item_bool_func2::gt_creator; + return invert?(Comp_creator *)&le_creator:(Comp_creator *)>_creator; } -compare_func_creator comp_le_creator(bool invert) +Comp_creator *comp_le_creator(bool invert) { - return invert?&Item_bool_func2::gt_creator:&Item_bool_func2::le_creator; + return invert?(Comp_creator *)>_creator:(Comp_creator *)&le_creator; } -compare_func_creator comp_lt_creator(bool invert) +Comp_creator *comp_lt_creator(bool invert) { - return invert?&Item_bool_func2::ge_creator:&Item_bool_func2::lt_creator; + return invert?(Comp_creator *)&ge_creator:(Comp_creator *)<_creator; } -compare_func_creator comp_ne_creator(bool invert) +Comp_creator *comp_ne_creator(bool invert) { - return invert?&Item_bool_func2::eq_creator:&Item_bool_func2::ne_creator; + return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator; } @@ -4687,7 +4745,7 @@ Item * all_any_subquery_creator(Item *left_expr, return new Item_func_not(new Item_in_subselect(left_expr, select_lex)); Item_allany_subselect *it= - new Item_allany_subselect(left_expr, (*cmp)(all), select_lex); + new Item_allany_subselect(left_expr, (*cmp)(all), select_lex, all); if (all) return it->upper_not= new Item_func_not_all(it); /* ALL */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index da62fc0a262..2fa08e2d649 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -332,7 +332,7 @@ SETUP_PARAM_FUNCTION(setup_param_datetime) tm.day= (uint) to[3]; tm.neg= 0; - param->set_time(&tm, TIMESTAMP_FULL); + param->set_time(&tm, TIMESTAMP_DATETIME); } *pos+= length; } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 5db3be7599b..ecad84ba0cb 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -625,7 +625,7 @@ Increase max_allowed_packet on master"; goto err; } packet->length(0); - packet->append("\0",1); + packet->append('\0'); } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d192ab1fb0e..c7f9de2ef6d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -862,7 +862,8 @@ JOIN::optimize() We only need to do this when we have a simple_order or simple_group as in other cases the join is done before the sort. */ - if ((order || group_list) && join_tab[const_tables].type != JT_ALL && + if (const_tables != tables && + (order || group_list) && join_tab[const_tables].type != JT_ALL && join_tab[const_tables].type != JT_FT && (order && simple_order || group_list && simple_group)) { @@ -882,12 +883,12 @@ JOIN::optimize() need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort } + tmp_having= having; if (select_options & SELECT_DESCRIBE) { error= 0; DBUG_RETURN(0); } - tmp_having= having; having= 0; /* Perform FULLTEXT search before all regular searches */ @@ -1453,10 +1454,21 @@ JOIN::exec() { DBUG_VOID_RETURN; } + /* + Here we sort rows for ORDER BY/GROUP BY clause, if the optimiser + chose FILESORT to be faster than INDEX SCAN or there is no + suitable index present. + Note, that create_sort_index calls test_if_skip_sort_order and may + finally replace sorting with index scan if there is a LIMIT clause in + the query. XXX: it's never shown in EXPLAIN! + OPTION_FOUND_ROWS supersedes LIMIT and is taken into account. + */ if (create_sort_index(thd, curr_join, curr_join->group_list ? curr_join->group_list : curr_join->order, - curr_join->select_limit, unit->select_limit_cnt)) + curr_join->select_limit, + (select_options & OPTION_FOUND_ROWS ? + HA_POS_ERROR : unit->select_limit_cnt))) DBUG_VOID_RETURN; } } @@ -1573,11 +1585,23 @@ mysql_select(THD *thd, Item ***rref_pointer_array, goto err; // 1 } + if (thd->lex.describe & DESCRIBE_EXTENDED) + { + join->conds_history= join->conds; + join->having_history= (join->having?join->having:join->tmp_having); + } + if (thd->net.report_error) goto err; join->exec(); + if (thd->lex.describe & DESCRIBE_EXTENDED) + { + select_lex->where= join->conds_history; + select_lex->having= join->having_history; + } + err: if (free_join) { @@ -2383,6 +2407,8 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array, keyuse.key = cond_func->key; keyuse.keypart= FT_KEYPART; keyuse.used_tables=cond_func->key_item()->used_tables(); + keyuse.optimize= 0; + keyuse.keypart_map= 0; VOID(insert_dynamic(keyuse_array,(gptr) &keyuse)); } @@ -2844,8 +2870,6 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, !(s->table->force_index && best_key)) { // Check full join ha_rows rnd_records= s->found_records; - /* Estimate cost of reading table. */ - tmp= s->table->file->scan_time(); /* If there is a restriction on the table, assume that 25% of the rows can be skipped on next part. @@ -2855,36 +2879,57 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, if (found_constraint) rnd_records-= rnd_records/4; - if (s->on_expr) // Can't use join cache + /* + Range optimizer never proposes a RANGE if it isn't better + than FULL: so if RANGE is present, it's always preferred to FULL. + Here we estimate its cost. + */ + if (s->quick) { + /* + For each record we: + - read record range through 'quick' + - skip rows which does not satisfy WHERE constraints + */ tmp= record_count * - /* We have to read the whole table for each record */ - (tmp + - /* - And we have to skip rows which does not satisfy join - condition for each record. - */ - (s->records - rnd_records)/(double) TIME_FOR_COMPARE); + (s->quick->read_time + + (s->found_records - rnd_records)/(double) TIME_FOR_COMPARE); } else { - /* We read the table as many times as join buffer becomes full. */ - tmp*= (1.0 + floor((double) cache_record_length(join,idx) * - record_count / - (double) thd->variables.join_buff_size)); - /* - We don't make full cartesian product between rows in the scanned - table and existing records because we skip all rows from the - scanned table, which does not satisfy join condition when - we read the table (see flush_cached_records for details). Here we - take into account cost to read and skip these records. - */ - tmp+= (s->records - rnd_records)/(double) TIME_FOR_COMPARE; + /* Estimate cost of reading table. */ + tmp= s->table->file->scan_time(); + if (s->on_expr) // Can't use join cache + { + /* + For each record we have to: + - read the whole table record + - skip rows which does not satisfy join condition + */ + tmp= record_count * + (tmp + + (s->records - rnd_records)/(double) TIME_FOR_COMPARE); + } + else + { + /* We read the table as many times as join buffer becomes full. */ + tmp*= (1.0 + floor((double) cache_record_length(join,idx) * + record_count / + (double) thd->variables.join_buff_size)); + /* + We don't make full cartesian product between rows in the scanned + table and existing records because we skip all rows from the + scanned table, which does not satisfy join condition when + we read the table (see flush_cached_records for details). Here we + take into account cost to read and skip these records. + */ + tmp+= (s->records - rnd_records)/(double) TIME_FOR_COMPARE; + } } /* We estimate the cost of evaluating WHERE clause for found records - as record_count * rnd_records + TIME_FOR_COMPARE. This cost plus + as record_count * rnd_records / TIME_FOR_COMPARE. This cost plus tmp give us total cost of using TABLE SCAN */ if (best == DBL_MAX || @@ -3308,6 +3353,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) table_map used_tables; if (join->tables > 1) cond->update_used_tables(); // Tablenr may have changed + if (join->const_tables == join->tables) + join->const_table_map|=RAND_TABLE_BIT; { // Check const tables COND *const_cond= make_cond_for_table(cond,join->const_table_map,(table_map) 0); @@ -9032,3 +9079,159 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, result, unit, select_lex, 0); DBUG_RETURN(res); } + + +void st_select_lex::print(THD *thd, String *str) +{ + if (!thd) + thd= current_thd; + + str->append("select ", 7); + + //options + if (options & SELECT_STRAIGHT_JOIN) + str->append("straight_join ", 14); + if ((thd->lex.lock_option & TL_READ_HIGH_PRIORITY) && + (this == &thd->lex.select_lex)) + str->append("high_priority ", 14); + if (options & SELECT_DISTINCT) + str->append("distinct ", 9); + if (options & SELECT_SMALL_RESULT) + str->append("small_result ", 13); + if (options & SELECT_BIG_RESULT) + str->append("big_result ", 11); + if (options & OPTION_BUFFER_RESULT) + str->append("buffer_result ", 14); + if (options & OPTION_FOUND_ROWS) + str->append("calc_found_rows ", 16); + if (!thd->lex.safe_to_cache_query) + str->append("no_cache ", 9); + if (options & OPTION_TO_QUERY_CACHE) + str->append("cache ", 6); + + //Item List + bool first= 1; + List_iterator_fast<Item> it(item_list); + Item *item; + while ((item= it++)) + { + if (first) + first= 0; + else + str->append(','); + item->print_item_w_name(str); + } + + /* + from clause + TODO: support USING/FORCE/IGNORE index + */ + if (table_list.elements) + { + str->append(" from ", 6); + Item *next_on= 0; + for (TABLE_LIST *table= (TABLE_LIST *) table_list.first; + table; + table= table->next) + { + if (table->derived) + { + str->append('('); + table->derived->print(str); + str->append(") "); + str->append(table->alias); + } + else + { + str->append(table->db); + str->append('.'); + str->append(table->real_name); + if (strcmp(table->real_name, table->alias)) + { + str->append(' '); + str->append(table->alias); + } + } + + if (table->on_expr && ((table->outer_join & JOIN_TYPE_LEFT) || + !(table->outer_join & JOIN_TYPE_RIGHT))) + next_on= table->on_expr; + + if (next_on) + { + str->append(" on(", 4); + next_on->print(str); + str->append(')'); + next_on= 0; + } + + TABLE_LIST *next; + if ((next= table->next)) + { + if (table->outer_join & JOIN_TYPE_RIGHT) + { + str->append(" right join ", 12); + if (!(table->outer_join & JOIN_TYPE_LEFT) && + table->on_expr) + next_on= table->on_expr; + } + else if (next->straight) + str->append(" straight_join ", 15); + else if (next->outer_join & JOIN_TYPE_LEFT) + str->append(" left join ", 11); + else + str->append(" join ", 6); + } + } + } + + //where + Item *where= this->where; + if (join) + where= join->conds; + if (where) + { + str->append(" where ", 7); + where->print(str); + } + + //group by & olap + if (group_list.elements) + { + str->append(" group by ", 10); + print_order(str, (ORDER *) group_list.first); + switch (olap) + { + case CUBE_TYPE: + str->append(" with cube", 10); + break; + case ROLLUP_TYPE: + str->append(" with rollup", 12); + break; + default: + ; //satisfy compiler + } + } + + //having + Item *having= this->having; + if (join) + having= join->having; + + if (having) + { + str->append(" having ", 8); + having->print(str); + } + + if (order_list.elements) + { + str->append(" order by ", 10); + print_order(str, (ORDER *) order_list.first); + } + + // limit + print_limit(thd, str); + + // PROCEDURE unsupported here +} diff --git a/sql/sql_select.h b/sql/sql_select.h index 569ca797b22..24854713a0e 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -152,7 +152,8 @@ class JOIN :public Sql_alloc Item_sum **sum_funcs2, ***sum_funcs_end2; Procedure *procedure; Item *having; - Item *tmp_having; // To store Having when processed temporary table + Item *tmp_having; // To store having when processed temporary table + Item *having_history; // Store having for explain uint select_options; select_result *result; TMP_TABLE_PARAM tmp_table_param; @@ -182,6 +183,7 @@ class JOIN :public Sql_alloc ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select COND *conds; // ---"--- + Item *conds_history; // store WHERE for explain TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_selec SQL_SELECT *select; //created in optimisation phase Item **ref_pointer_array; //used pointer reference for this select @@ -218,8 +220,7 @@ class JOIN :public Sql_alloc thd= thd_arg; sum_funcs= sum_funcs2= 0; procedure= 0; - having= 0; - tmp_having= 0; + having= tmp_having= having_history= 0; select_options= select_options_arg; result= result_arg; lock= thd_arg->lock; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 4f453bce903..95a6ebb36fb 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1111,12 +1111,12 @@ store_create_info(THD *thd, TABLE *table, String *packet) if (field->has_charset()) { if (field->charset() == &my_charset_bin) - packet->append(" binary"); + packet->append(" binary", 7); else if (!limited_mysql_mode && !foreign_db_mode) { if (field->charset() != table->table_charset) { - packet->append(" character set "); + packet->append(" character set ", 15); packet->append(field->charset()->csname); } /* @@ -1253,32 +1253,32 @@ store_create_info(THD *thd, TABLE *table, String *packet) !(thd->variables.sql_mode & MODE_MYSQL323) && !(thd->variables.sql_mode & MODE_MYSQL40)) { - packet->append(" CHARSET="); + packet->append(" CHARSET=", 9); packet->append(table->table_charset->csname); if (!(table->table_charset->state & MY_CS_PRIMARY)) { - packet->append(" COLLATE="); + packet->append(" COLLATE=", 9); packet->append(table->table_charset->name); } } if (table->min_rows) { - packet->append(" MIN_ROWS="); + packet->append(" MIN_ROWS=", 10); end= longlong10_to_str(table->min_rows, buff, 10); packet->append(buff, (uint) (end- buff)); } if (table->max_rows) { - packet->append(" MAX_ROWS="); + packet->append(" MAX_ROWS=", 10); end= longlong10_to_str(table->max_rows, buff, 10); packet->append(buff, (uint) (end - buff)); } if (table->avg_row_length) { - packet->append(" AVG_ROW_LENGTH="); + packet->append(" AVG_ROW_LENGTH=", 16); end= longlong10_to_str(table->avg_row_length, buff,10); packet->append(buff, (uint) (end - buff)); } diff --git a/sql/sql_string.cc b/sql/sql_string.cc index be9404ce0b8..61070f07266 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -680,3 +680,35 @@ outp: } return (uint32) (to - to_start); } + +void String::print(String *str) +{ + char *st= (char*)Ptr, *end= st+str_length; + for(; st < end; st++) + { + uchar c= *st; + switch (c) + { + case '\\': + str->append("\\\\", 2); + break; + case '\0': + str->append("\\0", 2); + break; + case '\'': + str->append("\\'", 2); + break; + case '\n': + str->append("\\n", 2); + break; + case '\r': + str->append("\\r", 2); + break; + case 26: //Ctrl-Z + str->append("\\z", 2); + break; + default: + str->append(c); + } + } +} diff --git a/sql/sql_string.h b/sql/sql_string.h index d446d26298b..325611737ca 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -289,4 +289,5 @@ public: str_length+= arg_length; return FALSE; } + void print(String *print); }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 1a2021abf90..d2d1926ea06 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -437,7 +437,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, if (check_column_name(sql_field->field_name)) { - my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name); + my_error(ER_WRONG_NAME, MYF(0), ER(ER_COLUMN), sql_field->field_name); DBUG_RETURN(-1); } @@ -888,7 +888,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, } if (!key_info->name || check_column_name(key_info->name)) { - my_error(ER_WRONG_INDEX_NAME, MYF(0), key_info->name); + my_error(ER_WRONG_NAME, MYF(0), ER(ER_INDEX), key_info->name); DBUG_RETURN(-1); } if (!(key_info->flags & HA_NULL_PART_KEY)) @@ -1777,7 +1777,7 @@ int mysql_create_like_table(THD* thd, TABLE_LIST* table, check_table_name(src_table,table_ident->table.length)) || table_ident->db.str && check_db_name((src_db= table_ident->db.str))) { - my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table); + my_error(ER_WRONG_NAME, MYF(0), ER(ER_TABLE), src_table); DBUG_RETURN(-1); } diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 47f0932b221..c14d30f8d34 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -22,7 +22,11 @@ #include "sql_select.h" #include <hash.h> #include <thr_alarm.h> +#if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H) #include <malloc.h> +#elif defined(HAVE_MALLINFO) && defined(HAVE_SYS_MALLOC_H) +#include <sys/malloc.h> +#endif /* Intern key cache variables */ extern "C" pthread_mutex_t THR_LOCK_keycache; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index de2bb4a786c..93541d66d65 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -377,11 +377,12 @@ int st_select_lex_unit::exec() offset_limit_cnt= global_parameters->offset_limit; select_limit_cnt= global_parameters->select_limit + global_parameters->offset_limit; + if (select_limit_cnt < global_parameters->select_limit) select_limit_cnt= HA_POS_ERROR; // no limit if (select_limit_cnt == HA_POS_ERROR) options&= ~OPTION_FOUND_ROWS; - else if (found_rows_for_union && !describe) + else if (found_rows_for_union && !thd->lex.describe) options|= OPTION_FOUND_ROWS; fake_select_lex->ftfunc_list= &empty_list; fake_select_lex->table_list.link_in_list((byte *)&result_table_list, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 00277759763..bb37c58004f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -78,7 +78,7 @@ inline Item *or_or_concat(THD *thd, Item* A, Item* B) CHARSET_INFO *charset; thr_lock_type lock_type; interval_type interval; - datetime_format_types datetime_format_type; + timestamp_type date_time_type; st_select_lex *select_lex; chooser_compare_func_creator boolfunc2creator; } @@ -246,6 +246,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token HIGH_PRIORITY %token HOSTS_SYM %token IDENT +%token IDENT_QUOTED %token IGNORE_SYM %token IMPORT %token INDEX @@ -584,8 +585,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %right BINARY COLLATE_SYM %type <lex_str> - IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME - ULONGLONG_NUM field_ident select_alias ident ident_or_text + IDENT IDENT_QUOTED TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM + LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal NCHAR_STRING opt_component @@ -648,7 +649,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); UDF_CHAR_FUNC UDF_FLOAT_FUNC UDF_INT_FUNC UDA_CHAR_SUM UDA_FLOAT_SUM UDA_INT_SUM -%type <datetime_format_type> datetime_format_type; +%type <date_time_type> date_time_type; %type <interval> interval %type <db_type> table_types @@ -713,6 +714,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); union_clause union_list union_option precision subselect_start opt_and charset subselect_end select_var_list select_var_list_init help opt_len + opt_extended_describe END_OF_INPUT %type <NONE> @@ -2303,15 +2305,22 @@ expr_expr: | expr OR expr { $$= new Item_cond_or($1,$3); } | expr XOR expr { $$= new Item_cond_xor($1,$3); } | expr AND expr { $$= new Item_cond_and($1,$3); } - | expr SOUNDS_SYM LIKE expr { $$= Item_bool_func2::eq_creator(new Item_func_soundex($1), new Item_func_soundex($4));} - | expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); } - | expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5));} + | expr SOUNDS_SYM LIKE expr + { + $$= new Item_func_eq(new Item_func_soundex($1), + new Item_func_soundex($4)); + } + | expr LIKE simple_expr opt_escape + { $$= new Item_func_like($1,$3,$4); } + | expr NOT LIKE simple_expr opt_escape + { $$= new Item_func_not(new Item_func_like($1,$4,$5));} | expr REGEXP expr { $$= new Item_func_regex($1,$3); } - | expr NOT REGEXP expr { $$= new Item_func_not(new Item_func_regex($1,$4)); } + | expr NOT REGEXP expr + { $$= new Item_func_not(new Item_func_regex($1,$4)); } | expr IS NULL_SYM { $$= new Item_func_isnull($1); } | expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); } | expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); } - | expr comp_op expr %prec EQ { $$= (*((*$2)(0)))($1,$3); } + | expr comp_op expr %prec EQ { $$= (*$2)(0)->create($1,$3); } | expr comp_op all_or_any in_subselect %prec EQ { $$= all_any_subquery_creator($1, $2, $3, $4); @@ -2344,15 +2353,22 @@ no_in_expr: | no_in_expr OR expr { $$= new Item_cond_or($1,$3); } | no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); } | no_in_expr AND expr { $$= new Item_cond_and($1,$3); } - | no_in_expr SOUNDS_SYM LIKE expr { $$= Item_bool_func2::eq_creator(new Item_func_soundex($1), new Item_func_soundex($4));} - | no_in_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); } - | no_in_expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5)); } + | no_in_expr SOUNDS_SYM LIKE expr + { + $$= new Item_func_eq(new Item_func_soundex($1), + new Item_func_soundex($4)); + } + | no_in_expr LIKE simple_expr opt_escape + { $$= new Item_func_like($1,$3,$4); } + | no_in_expr NOT LIKE simple_expr opt_escape + { $$= new Item_func_not(new Item_func_like($1,$4,$5)); } | no_in_expr REGEXP expr { $$= new Item_func_regex($1,$3); } - | no_in_expr NOT REGEXP expr { $$= new Item_func_not(new Item_func_regex($1,$4)); } + | no_in_expr NOT REGEXP expr + { $$= new Item_func_not(new Item_func_regex($1,$4)); } | no_in_expr IS NULL_SYM { $$= new Item_func_isnull($1); } | no_in_expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); } | no_in_expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); } - | no_in_expr comp_op expr %prec EQ { $$= (*((*$2)(0)))($1,$3); } + | no_in_expr comp_op expr %prec EQ { $$= (*$2)(0)->create($1,$3); } | no_in_expr comp_op all_or_any in_subselect %prec EQ { all_any_subquery_creator($1, $2, $3, $4); @@ -2394,15 +2410,22 @@ no_and_expr: | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | no_and_expr OR expr { $$= new Item_cond_or($1,$3); } | no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); } - | no_and_expr SOUNDS_SYM LIKE expr { $$= Item_bool_func2::eq_creator(new Item_func_soundex($1), new Item_func_soundex($4));} - | no_and_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); } - | no_and_expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5)); } + | no_and_expr SOUNDS_SYM LIKE expr + { + $$= new Item_func_eq(new Item_func_soundex($1), + new Item_func_soundex($4)); + } + | no_and_expr LIKE simple_expr opt_escape + { $$= new Item_func_like($1,$3,$4); } + | no_and_expr NOT LIKE simple_expr opt_escape + { $$= new Item_func_not(new Item_func_like($1,$4,$5)); } | no_and_expr REGEXP expr { $$= new Item_func_regex($1,$3); } - | no_and_expr NOT REGEXP expr { $$= new Item_func_not(new Item_func_regex($1,$4)); } + | no_and_expr NOT REGEXP expr + { $$= new Item_func_not(new Item_func_regex($1,$4)); } | no_and_expr IS NULL_SYM { $$= new Item_func_isnull($1); } | no_and_expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); } | no_and_expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); } - | no_and_expr comp_op expr %prec EQ { $$= (*((*$2)(0)))($1,$3); } + | no_and_expr comp_op expr %prec EQ { $$= (*$2)(0)->create($1,$3); } | no_and_expr comp_op all_or_any in_subselect %prec EQ { all_any_subquery_creator($1, $2, $3, $4); @@ -2609,7 +2632,7 @@ simple_expr: { $$= new Item_func_spatial_collection(* $3, Geometry::wkbGeometryCollection, Geometry::wkbPoint); } - | GET_FORMAT '(' datetime_format_type ',' expr ')' + | GET_FORMAT '(' date_time_type ',' expr ')' { $$= new Item_func_get_format($3, $5); } | HOUR_SYM '(' expr ')' { $$= new Item_func_hour($3); } @@ -2924,17 +2947,19 @@ opt_gconcat_separator: opt_gorder_clause: - /* empty */ - { - LEX *lex=Lex; - lex->gorder_list = NULL; - } - | order_clause - { - LEX *lex=Lex; - lex->gorder_list= (SQL_LIST*) sql_memdup((char*) &lex->current_select->order_list,sizeof(st_sql_list)); - lex->current_select->order_list.empty(); - }; + /* empty */ + { + LEX *lex=Lex; + lex->gorder_list = NULL; + } + | order_clause + { + LEX *lex=Lex; + lex->gorder_list= + (SQL_LIST*) sql_memdup((char*) &lex->current_select->order_list, + sizeof(st_sql_list)); + lex->current_select->order_list.empty(); + }; in_sum_expr: @@ -3230,10 +3255,10 @@ interval: | YEAR_MONTH_SYM { $$=INTERVAL_YEAR_MONTH; } | YEAR_SYM { $$=INTERVAL_YEAR; }; -datetime_format_type: - DATE_SYM {$$=DATE_FORMAT_TYPE;} - | TIME_SYM {$$=TIME_FORMAT_TYPE;} - | DATETIME {$$=DATETIME_FORMAT_TYPE;}; +date_time_type: + DATE_SYM {$$=TIMESTAMP_DATE;} + | TIME_SYM {$$=TIMESTAMP_TIME;} + | DATETIME {$$=TIMESTAMP_DATETIME;}; table_alias: /* empty */ @@ -4073,7 +4098,9 @@ describe: YYABORT; } opt_describe_column {} - | describe_command { Lex->describe=1; } select + | describe_command opt_extended_describe + { Lex->describe|= DESCRIBE_NORMAL; } + select { LEX *lex=Lex; lex->select_lex.options|= SELECT_DESCRIBE; @@ -4084,6 +4111,11 @@ describe_command: DESC | DESCRIBE; +opt_extended_describe: + /* empty */ {} + | EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; } + ; + opt_describe_column: /* empty */ {} | text_string { Lex->wild= $1; } @@ -4339,8 +4371,9 @@ literal: { Item *tmp= new Item_varbinary($2.str,$2.length); String *str= tmp ? tmp->val_str((String*) 0) : (String*) 0; - $$ = new Item_string(str ? str->ptr() : "", str ? str->length() : - 0, Lex->charset); + $$= new Item_string(str ? str->ptr() : "", + str ? str->length() : 0, + Lex->charset); } | DATE_SYM text_literal { $$ = $2; } | TIME_SYM text_literal { $$ = $2; } @@ -4447,15 +4480,16 @@ table_ident: /* For Delphi */; IDENT_sys: - IDENT - { - THD *thd= YYTHD; - if (thd->charset_is_system_charset) - $$= $1; - else - thd->convert_string(&$$, system_charset_info, - $1.str, $1.length, thd->charset()); - } + IDENT { $$= $1; } + | IDENT_QUOTED + { + THD *thd= YYTHD; + if (thd->charset_is_system_charset) + $$= $1; + else + thd->convert_string(&$$, system_charset_info, + $1.str, $1.length, thd->charset()); + } ; TEXT_STRING_sys: @@ -5399,7 +5433,7 @@ order_or_limit: union_option: /* empty */ {} - | ALL {Select->master_unit()->union_option= 1;}; + | ALL {Select->master_unit()->union_option|= UNION_ALL;}; singlerow_subselect: subselect_start singlerow_subselect_init diff --git a/sql/strfunc.cc b/sql/strfunc.cc new file mode 100644 index 00000000000..1db2124bcee --- /dev/null +++ b/sql/strfunc.cc @@ -0,0 +1,147 @@ +/* Copyright (C) 2003 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Some useful string utility functions used by the MySQL server */ + +#include "mysql_priv.h" + +/* + Return bitmap for strings used in a set + + SYNOPSIS + find_set() + lib Strings in set + str Strings of set-strings separated by ',' + err_pos If error, set to point to start of wrong set string + err_len If error, set to the length of wrong set string + set_warning Set to 1 if some string in set couldn't be used + + NOTE + We delete all end space from str before comparison + + RETURN + bitmap of all sets found in x. + set_warning is set to 1 if there was any sets that couldn't be set +*/ + +static const char field_separator=','; + +ulonglong find_set(TYPELIB *lib, const char *str, uint length, char **err_pos, + uint *err_len, bool *set_warning) +{ + const char *end= str + length; + *err_pos= 0; // No error yet + while (end > str && my_isspace(system_charset_info, end[-1])) + end--; + + *err_len= 0; + ulonglong found= 0; + if (str != end) + { + const char *start= str; + for (;;) + { + const char *pos= start; + uint var_len; + + for (; pos != end && *pos != field_separator; pos++) ; + var_len= (uint) (pos - start); + uint find= find_type(lib, start, var_len, 0); + if (!find) + { + *err_pos= (char*) start; + *err_len= var_len; + *set_warning= 1; + } + else + found|= ((longlong) 1 << (find - 1)); + if (pos == end) + break; + start= pos + 1; + } + } + return found; +} + + +/* + Function to find a string in a TYPELIB + (Same format as mysys/typelib.c) + + SYNOPSIS + find_type() + lib TYPELIB (struct of pointer to values + count) + find String to find + length Length of string to find + part_match Allow part matching of value + + RETURN + 0 error + > 0 position in TYPELIB->type_names +1 +*/ + +uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match) +{ + uint found_count=0, found_pos=0; + const char *end= find+length; + const char *i; + const char *j; + for (uint pos=0 ; (j=lib->type_names[pos++]) ; ) + { + for (i=find ; i != end && + my_toupper(system_charset_info,*i) == + my_toupper(system_charset_info,*j) ; i++, j++) ; + if (i == end) + { + if (! *j) + return(pos); + found_count++; + found_pos= pos; + } + } + return(found_count == 1 && part_match ? found_count : 0); +} + + +/* + Check if the first word in a string is one of the ones in TYPELIB + + SYNOPSIS + check_word() + lib TYPELIB + val String to check + end End of input + end_of_word Store value of last used byte here if we found word + + RETURN + 0 No matching value + > 1 lib->type_names[#-1] matched + end_of_word will point to separator character/end in 'val' +*/ + +uint check_word(TYPELIB *lib, const char *val, const char *end, + const char **end_of_word) +{ + int res; + const char *ptr; + + /* Fiend end of word */ + for (ptr= val ; ptr < end && my_isalpha(&my_charset_latin1, *ptr) ; ptr++) + ; + if ((res=find_type(lib, val, (uint) (ptr - val), 1)) > 0) + *end_of_word= ptr; + return res; +} diff --git a/sql/structs.h b/sql/structs.h index d9be230c049..352823cceb2 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -20,15 +20,19 @@ struct st_table; class Field; -typedef struct st_date_format { /* How to print date */ - uint pos[6]; /* Positions to YY.MM.DD HH:MM:SS */ -} DATE_FORMAT; +typedef struct lex_string { + char *str; + uint length; +} LEX_STRING; + + +typedef struct st_date_time_format { + uchar positions[8]; + char time_separator; /* Separator between hour and minute */ + uint flag; /* For future */ + LEX_STRING format; +} DATE_TIME_FORMAT; -typedef struct st_datetime_format { - byte dt_pos[8]; - char *format; - uint format_length; -} DATETIME_FORMAT; typedef struct st_keyfile_info { /* used with ha_info() */ byte ref[MAX_REFLENGTH]; /* Pointer to current row */ @@ -115,8 +119,17 @@ typedef struct st_read_record { /* Parameter to read_record */ bool print_error, ignore_not_found_rows; } READ_RECORD; -enum timestamp_type { TIMESTAMP_NONE, WRONG_TIMESTAMP_FULL, TIMESTAMP_DATE, TIMESTAMP_FULL, - TIMESTAMP_TIME}; + +enum timestamp_type +{ + TIMESTAMP_NONE= -2, TIMESTAMP_DATETIME_ERROR= -1, + TIMESTAMP_DATE= 0, TIMESTAMP_DATETIME= 1, TIMESTAMP_TIME= 2 +}; + +/* Parameters to str_to_TIME */ +#define TIME_FUZZY_DATE 1 +#define TIME_DATETIME_ONLY 2 + typedef struct st_time { uint year,month,day,hour,minute,second; @@ -125,12 +138,21 @@ typedef struct st_time { timestamp_type time_type; } TIME; + typedef struct { long year,month,day,hour,minute,second,second_part; bool neg; } INTERVAL; +typedef struct st_known_date_time_format { + const char *format_name; + const char *date_format; + const char *datetime_format; + const char *time_format; +} KNOWN_DATE_TIME_FORMAT; + + enum SHOW_TYPE { SHOW_UNDEF, @@ -168,11 +190,6 @@ typedef struct show_var_st { } SHOW_VAR; -typedef struct lex_string { - char *str; - uint length; -} LEX_STRING; - typedef struct st_lex_user { LEX_STRING user, host, password; } LEX_USER; diff --git a/sql/time.cc b/sql/time.cc index f2e41afa560..e696918dee3 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -23,14 +23,9 @@ static ulong const days_at_timestart=719528; /* daynr at 1970.01.01 */ uchar *days_in_month= (uchar*) "\037\034\037\036\037\036\037\037\036\037\036\037"; - /* Init some variabels needed when using my_local_time */ /* Currently only my_time_zone is inited */ -bool parse_datetime_formats(datetime_format_types format_type, - const char *format_str, uint format_length, - byte *dt_pos); - static long my_time_zone=0; void init_time(void) @@ -282,6 +277,7 @@ ulong convert_period_to_month(ulong period) return a*12+b-1; } + ulong convert_month_to_period(ulong month) { ulong year; @@ -295,6 +291,13 @@ ulong convert_month_to_period(ulong month) } +/* Position for YYYY-DD-MM HH-MM-DD.FFFFFF AM in default format */ + +static uchar internal_format_positions[]= +{0, 1, 2, 3, 4, 5, 6, (uchar) 255}; + +static char time_separator=':'; + /* Convert a timestamp string to a TIME value. @@ -303,7 +306,9 @@ ulong convert_month_to_period(ulong month) str String to parse length Length of string l_time Date is stored here - fuzzy_date 1 if we should allow dates where one part is zero + flags Bitmap of following items + TIME_FUZZY_DATE Set if we should allow partial dates + TIME_DATETIME_ONLY Set if we only allow full datetimes. DESCRIPTION At least the following formats are recogniced (based on number of digits) @@ -312,161 +317,250 @@ ulong convert_month_to_period(ulong month) YYYYMMDDTHHMMSS where T is a the character T (ISO8601) Also dates where all parts are zero are allowed + The second part may have an optional .###### fraction part. + + NOTES + This function should work with a format position vector as long as the + following things holds: + - All date are kept together and all time parts are kept together + - Date and time parts must be separated by blank + - Second fractions must come after second part and be separated + by a '.'. (The second fractions are optional) + - AM/PM must come after second fractions (or after seconds if no fractions) + - Year must always been specified. + - If time is before date, then we will use datetime format only if + the argument consist of two parts, separated by space. + Otherwise we will assume the argument is a date. + - The hour part must be specified in hour-minute-second order. + RETURN VALUES TIMESTAMP_NONE String wasn't a timestamp, like - [DD [HH:[MM:[SS]]]].fraction + [DD [HH:[MM:[SS]]]].fraction. + l_time is not changed. TIMESTAMP_DATE DATE string (YY MM and DD parts ok) - TIMESTAMP_FULL Full timestamp + TIMESTAMP_DATETIME Full timestamp + TIMESTAMP_DATETIME_ERROR Timestamp with wrong values. + All elements in l_time is set to 0 */ +#define MAX_DATE_PARTS 8 + timestamp_type -str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date,THD *thd) +str_to_TIME(const char *str, uint length, TIME *l_time, uint flags) { - uint field_length= 0, year_length= 0, digits, i, number_of_fields; - uint date[7], date_len[7]; - uint not_zero_date; - bool is_internal_format= 0; - const char *pos; + uint field_length, year_length, digits, i, number_of_fields; + uint date[MAX_DATE_PARTS], date_len[MAX_DATE_PARTS]; + uint add_hours= 0, start_loop; + ulong not_zero_date, allow_space; + bool is_internal_format; + const char *pos, *last_field_pos; const char *end=str+length; - bool found_delimitier= 0; + const uchar *format_position; + bool found_delimitier= 0, found_space= 0; + DATE_TIME_FORMAT *format; DBUG_ENTER("str_to_TIME"); - DBUG_PRINT("enter",("str: %.*s",length,str)); + DBUG_PRINT("ENTER",("str: %.*s",length,str)); - // Skip garbage - for (; str != end && !my_isdigit(&my_charset_latin1, *str) ; str++) ; - if (str == end) + LINT_INIT(field_length); + LINT_INIT(year_length); + LINT_INIT(last_field_pos); + + // Skip space at start + for (; str != end && my_isspace(&my_charset_latin1, *str) ; str++) + ; + if (str == end || ! my_isdigit(&my_charset_latin1, *str)) DBUG_RETURN(TIMESTAMP_NONE); + + is_internal_format= 0; + /* This has to be changed if want to activate different timestamp formats */ + format_position= internal_format_positions; + /* - Calculate first number of digits. + Calculate number of digits in first part. If length= 8 or >= 14 then year is of format YYYY. (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS) */ - for (pos=str; pos != end && my_isdigit(&my_charset_latin1,*pos) ; pos++) ; - /* Check for internal format */ - digits= (uint) (pos-str); + for (pos=str; pos != end && my_isdigit(&my_charset_latin1,*pos) ; pos++) + ; - if (pos == end || digits>=12) + digits= (uint) (pos-str); + start_loop= 0; // Start of scan loop + date_len[format_position[0]]= 0; // Length of year field + if (pos == end) { - is_internal_format= 1; + /* Found date in internal format (only numbers like YYYYMMDD) */ year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2; field_length=year_length-1; - date_len[0]= year_length; + is_internal_format= 1; + format_position= internal_format_positions; + } + else + { + if (format_position[0] >= 3) // If year is after HHMMDD + { + /* + If year is not in first part then we have to determinate if we got + a date field or a datetime field. + We do this by checking if there is two numbers separated by + space in the input. + */ + while (pos < end && !my_isspace(&my_charset_latin1, *pos)) + pos++; + while (pos < end && !my_isdigit(&my_charset_latin1, *pos)) + pos++; + if (pos == end) + { + if (flags & TIME_DATETIME_ONLY) + DBUG_RETURN(TIMESTAMP_NONE); // Can't be a full datetime + /* Date field. Set hour, minutes and seconds to 0 */ + date[0]= date[1]= date[2]= date[3]= date[4]= 0; + start_loop= 5; // Start with first date part + } + } } + + /* + Only allow space in the first "part" of the datetime field and: + - after days, part seconds + - before and after AM/PM (handled by code later) + + 2003-03-03 20:00:20 AM + 20:00:20.000000 AM 03-03-2000 + */ + i= max((uint) format_position[0], (uint) format_position[1]); + set_if_bigger(i, (uint) format_position[2]); + allow_space= ((1 << i) | (1 << format_position[6])); + allow_space&= (1 | 2 | 4 | 8); + not_zero_date= 0; - for (i=0 ; i < 6 && str != end && my_isdigit(&my_charset_latin1,*str) ; i++) + for (i = start_loop; + i < MAX_DATE_PARTS-1 && str != end && + my_isdigit(&my_charset_latin1,*str); + i++) { - if (!is_internal_format) - date_len[i]= 1; - uint tmp_value=(uint) (uchar) (*str++ - '0'); - while (str != end && my_isdigit(&my_charset_latin1,str[0]) - && (is_internal_format && field_length-- || !is_internal_format) ) + const char *start= str; + ulong tmp_value= (uint) (uchar) (*str++ - '0'); + while (str != end && my_isdigit(&my_charset_latin1,str[0]) && + (!is_internal_format || field_length--)) { - tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0'); + tmp_value=tmp_value*10 + (ulong) (uchar) (*str - '0'); str++; - if (!is_internal_format) - date_len[i]+= 1; } - if (i == 2 && *str == '.') + date_len[i]+= (uint) (str - start); + if (tmp_value > 999999) // Impossible date part DBUG_RETURN(TIMESTAMP_NONE); date[i]=tmp_value; not_zero_date|= tmp_value; - if (i == 2 && str != end && *str == 'T') + + /* Length-1 of next field */ + field_length= format_position[i+1] == 0 ? 3 : 1; + + if ((last_field_pos= str) == end) + { + i++; // Register last found part + break; + } + /* Allow a 'T' after day to allow CCYYMMDDT type of fields */ + if (i == format_position[2] && *str == 'T') + { str++; // ISO8601: CCYYMMDDThhmmss - else if ( i != 5 ) // Skip inter-field delimiters + continue; + } + if (i == format_position[5]) // Seconds { - while (str != end && - (my_ispunct(&my_charset_latin1,*str) || - my_isspace(&my_charset_latin1,*str))) + if (*str == '.') // Followed by part seconds { - // Only allow space between days and hours - if (my_isspace(&my_charset_latin1,*str) && i != 2) - DBUG_RETURN(TIMESTAMP_NONE); str++; - found_delimitier=1; // Should be a 'normal' date + field_length= 5; // 5 digits after first (=6) } + continue; + + /* No part seconds */ + date[++i]= 0; } - if (is_internal_format) - field_length=1; // Rest fields can only be 2 - } - /* Handle second fractions */ - if (i == 6 && (uint) (end-str) >= 2 && *str == '.' && - my_isdigit(&my_charset_latin1,str[1])) - { - str++; - uint tmp_value=(uint) (uchar) (*str - '0'); - field_length=5; - while (str++ != end && my_isdigit(&my_charset_latin1,str[0]) && - field_length--) - tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0'); - date[6]=tmp_value; - not_zero_date|= tmp_value; + while (str != end && + (my_ispunct(&my_charset_latin1,*str) || + my_isspace(&my_charset_latin1,*str))) + { + if (my_isspace(&my_charset_latin1,*str)) + { + if (!(allow_space & (1 << i))) + DBUG_RETURN(TIMESTAMP_NONE); + found_space= 1; + } + str++; + found_delimitier= 1; // Should be a 'normal' date + } + /* Check if next position is AM/PM */ + if (i == format_position[6]) // Seconds, time for AM/PM + { + i++; // Skip AM/PM part + if (format_position[7] != 255) // If using AM/PM + { + if (str+2 <= end && (str[1] == 'M' || str[1] == 'm')) + { + if (str[1] == 'p' || str[1] == 'P') + add_hours= 12; + else if (str[1] != 'a' || str[1] != 'A') + continue; // Not AM/PM + str+= 2; // Skip AM/PM + /* Skip space after AM/PM */ + while (str != end && my_isspace(&my_charset_latin1,*str)) + str++; + } + } + } + last_field_pos= str; } - else - date[6]=0; - - while (str != end && (my_ispunct(&my_charset_latin1,*str) || - my_isspace(&my_charset_latin1,*str))) - str++; + if (found_delimitier && !found_space && (flags & TIME_DATETIME_ONLY)) + DBUG_RETURN(TIMESTAMP_NONE); // Can't be a datetime - uint add_hours= 0; - if (!my_strnncoll(&my_charset_latin1, - (const uchar *)str, 2, - (const uchar *)"PM", 2)) - add_hours= 12; + str= last_field_pos; - number_of_fields=i; - while (i < 6) + number_of_fields= i - start_loop; + while (i < MAX_DATE_PARTS) date[i++]=0; if (!is_internal_format) { - byte *frm_pos; + year_length= date_len[(uint) format_position[0]]; + if (!year_length) // Year must be specified + DBUG_RETURN(TIMESTAMP_NONE); - if (number_of_fields <= 3) - { - frm_pos= t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format.dt_pos; - l_time->hour= 0; - l_time->minute= 0; - l_time->second= 0; - } - else + l_time->year= date[(uint) format_position[0]]; + l_time->month= date[(uint) format_position[1]]; + l_time->day= date[(uint) format_position[2]]; + l_time->hour= date[(uint) format_position[3]]; + l_time->minute= date[(uint) format_position[4]]; + l_time->second= date[(uint) format_position[5]]; + l_time->second_part= date[(uint) format_position[6]]; + if (format_position[7] != (uchar) 255) { - frm_pos= t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format.dt_pos; - l_time->hour= date[(int) frm_pos[3]]; - l_time->minute=date[(int) frm_pos[4]]; - l_time->second=date[(int) frm_pos[5]]; - if (frm_pos[6] == 1) - { - if (l_time->hour > 12) - DBUG_RETURN(WRONG_TIMESTAMP_FULL); - l_time->hour= l_time->hour%12 + add_hours; - } + if (l_time->hour > 12) + goto err; + l_time->hour= l_time->hour%12 + add_hours; } - - l_time->year= date[(int) frm_pos[0]]; - l_time->month= date[(int) frm_pos[1]]; - l_time->day= date[(int) frm_pos[2]]; - year_length= date_len[(int) frm_pos[0]]; } else { - l_time->year= date[0]; - l_time->month= date[1]; - l_time->day= date[2]; - l_time->hour= date[3]; - l_time->minute=date[4]; - l_time->second=date[5]; - } - l_time->second_part=date[6]; + l_time->year= date[0]; + l_time->month= date[1]; + l_time->day= date[2]; + l_time->hour= date[3]; + l_time->minute= date[4]; + l_time->second= date[5]; + l_time->second_part=date[6]; + } l_time->neg= 0; - if (year_length == 2 && i >=2 && (l_time->month || l_time->day)) - l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); + if (year_length == 2 && i >= format_position[1] && i >=format_position[2] && + (l_time->month || l_time->day)) + l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); if (number_of_fields < 3 || l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || l_time->minute > 59 || l_time->second > 59 || - (!fuzzy_date && (l_time->month == 0 || l_time->day == 0))) + (!(flags & TIME_FUZZY_DATE) && (l_time->month == 0 || l_time->day == 0))) { /* Only give warning for a zero date if there is some garbage after */ if (!not_zero_date) // If zero date @@ -481,46 +575,50 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date,THD *thd) } } if (not_zero_date) - thd->cuted_fields++; - DBUG_RETURN(WRONG_TIMESTAMP_FULL); + current_thd->cuted_fields++; + goto err; } - if (str != end && thd->count_cuted_fields) + if (str != end && current_thd->count_cuted_fields) { for (; str != end ; str++) { if (!my_isspace(&my_charset_latin1,*str)) { - thd->cuted_fields++; + current_thd->cuted_fields++; break; } } } DBUG_RETURN(l_time->time_type= - (number_of_fields <= 3 ? TIMESTAMP_DATE : TIMESTAMP_FULL)); + (number_of_fields <= 3 ? TIMESTAMP_DATE : TIMESTAMP_DATETIME)); + +err: + bzero((char*) l_time, sizeof(*l_time)); + DBUG_RETURN(TIMESTAMP_DATETIME_ERROR); } -time_t str_to_timestamp(const char *str,uint length, THD *thd) +time_t str_to_timestamp(const char *str,uint length) { TIME l_time; long not_used; - if (str_to_TIME(str,length,&l_time,0,thd) <= WRONG_TIMESTAMP_FULL) + if (str_to_TIME(str,length,&l_time,0) <= TIMESTAMP_DATETIME_ERROR) return(0); if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR) { - thd->cuted_fields++; + current_thd->cuted_fields++; return(0); } return(my_gmt_sec(&l_time, ¬_used)); } -longlong str_to_datetime(const char *str,uint length,bool fuzzy_date, THD *thd) +longlong str_to_datetime(const char *str,uint length, uint fuzzy_date) { TIME l_time; - if (str_to_TIME(str,length,&l_time,fuzzy_date,thd) <= WRONG_TIMESTAMP_FULL) + if (str_to_TIME(str,length,&l_time,fuzzy_date) <= TIMESTAMP_DATETIME_ERROR) return(0); return (longlong) (l_time.year*LL(10000000000) + l_time.month*LL(100000000)+ @@ -542,22 +640,24 @@ longlong str_to_datetime(const char *str,uint length,bool fuzzy_date, THD *thd) length Length of str l_time Store result here + NOTES + Because of the extra days argument, this function can only + work with times where the time arguments are in the above order. + RETURN 0 ok 1 error */ -bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) +bool str_to_time(const char *str,uint length,TIME *l_time) { long date[5],value; - const char *end=str+length; + const char *end=str+length, *end_of_days; bool found_days,found_hours; uint state; - byte *frm_pos= t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format.dt_pos; l_time->neg=0; - for (; str != end && - !my_isdigit(&my_charset_latin1,*str) && *str != '-' ; str++) + for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++) length--; if (str != end && *str == '-') { @@ -571,37 +671,33 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) /* Check first if this is a full TIMESTAMP */ if (length >= 12) { // Probably full timestamp - enum timestamp_type tres= str_to_TIME(str,length,l_time,1,thd); - if (tres == TIMESTAMP_FULL) - return 0; - else if (tres == WRONG_TIMESTAMP_FULL) - return 1; + enum timestamp_type res= str_to_TIME(str,length,l_time, + (TIME_FUZZY_DATE | + TIME_DATETIME_ONLY)); + if ((int) res >= (int) TIMESTAMP_DATETIME_ERROR) + return res == TIMESTAMP_DATETIME_ERROR; } /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */ for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++) value=value*10L + (long) (*str - '0'); - /* Move to last space */ - if (str != end && *str == ' ') - { - while (++str != end && str[0] == ' ') - {} - str--; - } + /* Skipp all space after 'days' */ + end_of_days= str; + for (; str != end && my_isspace(&my_charset_latin1, str[0]) ; str++) + ; LINT_INIT(state); found_days=found_hours=0; - if ((uint) (end-str) > 1 && (*str == ' ' && - my_isdigit(&my_charset_latin1,str[1]))) - { // days ! - date[0]=value; - state=1; // Assume next is hours - found_days=1; - str++; // Skip space; - } - else if ((end-str) > 1 && *str == frm_pos[7] && - my_isdigit(&my_charset_latin1,str[1])) + if ((uint) (end-str) > 1 && str != end_of_days && + my_isdigit(&my_charset_latin1, *str)) + { // Found days part + date[0]= value; + state= 1; // Assume next is hours + found_days= 1; + } + else if ((end-str) > 1 && *str == time_separator && + my_isdigit(&my_charset_latin1, str[1])) { date[0]=0; // Assume we found hours date[1]=value; @@ -626,10 +722,10 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++) value=value*10L + (long) (*str - '0'); date[state++]=value; - if (state == 4 || (end-str) < 2 || *str != frm_pos[7] || + if (state == 4 || (end-str) < 2 || *str != time_separator || !my_isdigit(&my_charset_latin1,str[1])) break; - str++; // Skip ':' + str++; // Skip time_separator (':') } if (state != 4) @@ -644,7 +740,8 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) else bzero((char*) (date+state), sizeof(long)*(4-state)); } - fractional: + +fractional: /* Get fractional second part */ if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1])) { @@ -659,18 +756,21 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) else date[4]=0; - while (str != end && !my_isalpha(&my_charset_latin1,*str)) - str++; - - if ( (end-str)>= 2 && - !my_strnncoll(&my_charset_latin1, - (const uchar *)str, 2, - (const uchar *)"PM", 2) && - frm_pos[6] == 1) + if (internal_format_positions[7] != 255) { - uint days_i= date[1]/24; - uint hours_i= date[1]%24; - date[1]= hours_i%12 + 12 + 24*days_i; + /* Read a possible AM/PM */ + while (str != end && my_isspace(&my_charset_latin1, *str)) + str++; + if (str+2 <= end && (str[1] == 'M' || str[1] == 'm')) + { + if (str[1] == 'p' || str[1] == 'P') + { + str+= 2; + date[1]= date[1]%12 + 12; + } + else if (str[1] == 'a' || str[1] == 'A') + str+=2; + } } /* Some simple checks */ @@ -679,12 +779,13 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) current_thd->cuted_fields++; return 1; } - l_time->month=0; - l_time->day=date[0]; - l_time->hour=date[frm_pos[3] + 1]; - l_time->minute=date[frm_pos[4] + 1]; - l_time->second=date[frm_pos[5] + 1]; - l_time->second_part=date[4]; + l_time->year= 0; // For protocol::store_time + l_time->month= 0; + l_time->day= date[0]; + l_time->hour= date[1]; + l_time->minute= date[2]; + l_time->second= date[3]; + l_time->second_part= date[4]; l_time->time_type= TIMESTAMP_TIME; /* Check if there is garbage at end of the TIME specification */ @@ -730,163 +831,404 @@ void calc_time_from_sec(TIME *to, long seconds, long microseconds) } -DATETIME_FORMAT *make_format(DATETIME_FORMAT *datetime_format, - datetime_format_types format_type, - const char *format_str, - uint format_length, bool is_alloc) -{ - if (format_length && - !parse_datetime_formats(format_type, format_str, - format_length, - datetime_format->dt_pos)) - { - if (is_alloc) - { - if (!(datetime_format->format= my_strdup_with_length(format_str, - format_length, - MYF(0)))) - return 0; - } - else - datetime_format->format= (char *) format_str; - datetime_format->format_length= format_length; - return datetime_format; - } - return 0; -} +/* + Parse a format string specification + SYNOPSIS + parse_date_time_format() + format_type Format of string (time, date or datetime) + format_str String to parse + format_length Length of string + date_time_format Format to fill in + + NOTES + Fills in date_time_format->positions for all date time parts. + + positions marks the position for a datetime element in the format string. + The position array elements are in the following order: + YYYY-DD-MM HH-MM-DD.FFFFFF AM + 0 1 2 3 4 5 6 7 + + If positions[0]= 5, it means that year will be the forth element to + read from the parsed date string. + + RETURN + 0 ok + 1 error +*/ -bool parse_datetime_formats(datetime_format_types format_type, - const char *format_str, uint format_length, - byte *dt_pos) +bool parse_date_time_format(timestamp_type format_type, + const char *format, uint format_length, + DATE_TIME_FORMAT *date_time_format) { - uint pos= 0; - dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]= - dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= -1; + uint offset= 0, separators= 0; + const char *ptr= format, *format_str; + const char *end= ptr+format_length; + uchar *dt_pos= date_time_format->positions; + /* need_p is set if we are using AM/PM format */ + bool need_p= 0, allow_separator= 0; + ulong part_map= 0, separator_map= 0; + const char *parts[16]; + + date_time_format->time_separator= 0; + date_time_format->flag= 0; // For future - const char *ptr=format_str; - const char *end=ptr+format_length; - bool need_p= 0; + /* + Fill position with 'dummy' arguments to found out if a format tag is + used twice (This limit's the format to 255 characters, but this is ok) + */ + dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]= + dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= 255; for (; ptr != end; ptr++) { if (*ptr == '%' && ptr+1 != end) { + uint position; + LINT_INIT(position); switch (*++ptr) { - case 'y': + case 'y': // Year case 'Y': - if (dt_pos[0] > -1) - return 1; - dt_pos[0]= pos; + position= 0; break; - case 'c': + case 'c': // Month case 'm': - if (dt_pos[1] > -1) - return 1; - dt_pos[1]= pos; + position= 1; break; case 'd': case 'e': - if (dt_pos[2] > -1) - return 1; - dt_pos[2]= pos; + position= 2; break; - case 'H': - case 'k': case 'h': case 'I': case 'l': - if (dt_pos[3] > -1) - return 1; - dt_pos[3]= pos; - need_p= (*ptr == 'h' || *ptr == 'l' || *ptr == 'I'); + need_p= 1; // Need AM/PM + /* Fall through */ + case 'k': + case 'H': + position= 3; break; case 'i': - if (dt_pos[4] > -1) - return 1; - dt_pos[4]= pos; + position= 4; break; case 's': case 'S': - if (dt_pos[5] > -1) - return 1; - dt_pos[5]= pos; + position= 5; break; - case 'p': - if (dt_pos[6] > -1) - return 1; - /* %p should be last in format string */ - if (format_type == DATE_FORMAT_TYPE || - (pos != 6 && format_type == DATETIME_FORMAT_TYPE) || - (pos != 3 && format_type == TIME_FORMAT_TYPE)) - return 1; - dt_pos[6]= 1; + case 'f': + position= 6; + if (dt_pos[5] != offset-1 || ptr[-2] != '.') + return 1; // Wrong usage of %f + break; + case 'p': // AM/PM + if (offset == 0) // Can't be first + return 0; + position= 7; break; default: - return 1; + return 1; // Unknown controll char } - if (dt_pos[6] == -1) - pos++; + if (dt_pos[position] != 255) // Don't allow same tag twice + return 1; + parts[position]= ptr-1; + + /* + If switching from time to date, ensure that all time parts + are used + */ + if (part_map && position <= 2 && !(part_map & (1 | 2 | 4))) + offset=5; + part_map|= (ulong) 1 << position; + dt_pos[position]= offset++; + allow_separator= 1; + } + else + { + /* + Don't allow any characters in format as this could easily confuse + the date reader + */ + if (!allow_separator) + return 1; // No separator here + allow_separator= 0; // Don't allow two separators + separators++; + /* Store in separator_map which parts are punct characters */ + if (my_ispunct(&my_charset_latin1, *ptr)) + separator_map|= (ulong) 1 << (offset-1); + else if (!my_isspace(&my_charset_latin1, *ptr)) + return 1; } } - if (pos > 5 && format_type == DATETIME_FORMAT_TYPE && - (dt_pos[0] + dt_pos[1] + dt_pos[2] + - dt_pos[3] + dt_pos[4] + dt_pos[5] != 15) || - pos > 2 && format_type == DATE_FORMAT_TYPE && - (dt_pos[0] + dt_pos[1] + dt_pos[2] != 3) || - pos > 2 && format_type == TIME_FORMAT_TYPE && - (dt_pos[3] + dt_pos[4] + dt_pos[5] != 3) || - (need_p && dt_pos[6] != 1)) - return 1; + /* If no %f, specify it after seconds. Move %p up, if necessary */ + if ((part_map & 32) && !(part_map & 64)) + { + dt_pos[6]= dt_pos[5] +1; + parts[6]= parts[5]; // For later test in (need_p) + if (dt_pos[6] == dt_pos[7]) // Move %p one step up if used + dt_pos[7]++; + } /* - Check for valid separators between date/time parst + Check that we have not used a non legal format specifier and that all + format specifiers have been used + + The last test is to ensure that %p is used if and only if + it's needed. */ - uint tmp_len= format_length; - if (dt_pos[6] == 1) + if ((format_type == TIMESTAMP_DATETIME && + !test_all_bits(part_map, (1 | 2 | 4 | 8 | 16 | 32))) || + (format_type == TIMESTAMP_DATE && part_map != (1 | 2 | 4)) || + (format_type == TIMESTAMP_TIME && + !test_all_bits(part_map, 8 | 16 | 32)) || + !allow_separator || // %option should be last + (need_p && dt_pos[6] +1 != dt_pos[7]) || + (need_p ^ (dt_pos[7] != 255))) + return 1; + + if (dt_pos[6] != 255) // If fractional seconds { - end= end - 2; - if (my_ispunct(&my_charset_latin1, *end) || my_isspace(&my_charset_latin1, *end)) - end--; - tmp_len= end - format_str; + /* remove fractional seconds from later tests */ + uint pos= dt_pos[6] -1; + /* Remove separator before %f from sep map */ + separator_map= ((separator_map & ((ulong) (1 << pos)-1)) | + ((separator_map & ~((ulong) (1 << pos)-1)) >> 1)); + if (part_map & 64) + { + separators--; // There is always a separator + need_p= 1; // force use of separators + } } + + /* + Remove possible separator before %p from sep_map + (This can either be at position 3, 4, 6 or 7) h.m.d.%f %p + */ + if (dt_pos[7] != 255) + { + if (need_p && parts[7] != parts[6]+2) + separators--; + } + /* + Calculate if %p is in first or last part of the datetime field + + At this point we have either %H-%i-%s %p 'year parts' or + 'year parts' &H-%i-%s %p" as %f was removed above + */ + offset= dt_pos[6] <= 3 ? 3 : 6; + /* Remove separator before %p from sep map */ + separator_map= ((separator_map & ((ulong) (1 << offset)-1)) | + ((separator_map & ~((ulong) (1 << offset)-1)) >> 1)); + + format_str= 0; switch (format_type) { - case DATE_FORMAT_TYPE: - case TIME_FORMAT_TYPE: - if ((tmp_len == 6 && - !my_strnncoll(&my_charset_bin, - (const uchar *) format_str, 6, - (const uchar *) datetime_formats - [format_type][INTERNAL_FORMAT], 6)) || - tmp_len == 8 && - my_ispunct(&my_charset_latin1, *(format_str+2)) && - my_ispunct(&my_charset_latin1, *(format_str+5))) + case TIMESTAMP_DATE: + format_str= known_date_time_formats[INTERNAL_FORMAT].date_format; + /* fall through */ + case TIMESTAMP_TIME: + if (!format_str) + format_str=known_date_time_formats[INTERNAL_FORMAT].time_format; + + /* + If there is no separators, allow the internal format as we can read + this. If separators are used, they must be between each part + */ + if (format_length == 6 && !need_p && + !my_strnncoll(&my_charset_bin, + (const uchar *) format, 6, + (const uchar *) format_str, 6)) + return 0; + if (separator_map == (1 | 2)) { - if (format_type == TIME_FORMAT_TYPE && tmp_len == 8) + if (format_type == TIMESTAMP_TIME) { - if (*(format_str+2) != *(format_str+5)) - return 1; - dt_pos[7]= *(format_str+2); + if (*(format+2) != *(format+5)) + break; // Error + /* Store the character used for time formats */ + date_time_format->time_separator= *(format+2); } return 0; } break; - case DATETIME_FORMAT_TYPE: - if ((tmp_len == 12 && + case TIMESTAMP_DATETIME: + /* + If there is no separators, allow the internal format as we can read + this. If separators are used, they must be between each part. + Between DATE and TIME we also allow space as separator + */ + if ((format_length == 12 && !need_p && !my_strnncoll(&my_charset_bin, - (const uchar *) format_str, 12, - (const uchar *) datetime_formats - [DATETIME_FORMAT_TYPE][INTERNAL_FORMAT], 12)) || - tmp_len == 17 && - my_ispunct(&my_charset_latin1, *(format_str+2)) && - my_ispunct(&my_charset_latin1, *(format_str+5)) && - my_ispunct(&my_charset_latin1, *(format_str+11)) && - my_ispunct(&my_charset_latin1, *(format_str+14)) && - (my_ispunct(&my_charset_latin1, *(format_str+8)) || - my_isspace(&my_charset_latin1, *(format_str+8)))) + (const uchar *) format, 12, + (const uchar*) known_date_time_formats[INTERNAL_FORMAT].datetime_format, + 12)) || + (separators == 5 && separator_map == (1 | 2 | 8 | 16))) return 0; break; - } - return 1; + default: + DBUG_ASSERT(1); + break; + } + return 1; // Error +} + + +/* + Create a DATE_TIME_FORMAT object from a format string specification + + SYNOPSIS + date_time_format_make() + format_type Format to parse (time, date or datetime) + format_str String to parse + format_length Length of string + + NOTES + The returned object should be freed with my_free() + + RETURN + NULL ponter: Error + new object +*/ + +DATE_TIME_FORMAT +*date_time_format_make(timestamp_type format_type, + const char *format_str, uint format_length) +{ + DATE_TIME_FORMAT tmp; + + if (format_length && format_length < 255 && + !parse_date_time_format(format_type, format_str, + format_length, &tmp)) + { + tmp.format.str= (char*) format_str; + tmp.format.length= format_length; + return date_time_format_copy((THD *)0, &tmp); + } + return 0; +} + + +/* + Create a copy of a DATE_TIME_FORMAT object + + SYNOPSIS + date_and_time_format_copy() + thd Set if variable should be allocated in thread mem + format format to copy + + NOTES + The returned object should be freed with my_free() + + RETURN + NULL ponter: Error + new object +*/ + +DATE_TIME_FORMAT *date_time_format_copy(THD *thd, DATE_TIME_FORMAT *format) +{ + DATE_TIME_FORMAT *new_format; + ulong length= sizeof(*format) + format->format.length + 1; + + if (thd) + new_format= (DATE_TIME_FORMAT *) thd->alloc(length); + else + new_format= (DATE_TIME_FORMAT *) my_malloc(length, MYF(MY_WME)); + if (new_format) + { + /* Put format string after current pos */ + new_format->format.str= (char*) (new_format+1); + memcpy((char*) new_format->positions, (char*) format->positions, + sizeof(format->positions)); + new_format->time_separator= format->time_separator; + /* We make the string null terminated for easy printf in SHOW VARIABLES */ + memcpy((char*) new_format->format.str, format->format.str, + format->format.length); + new_format->format.str[format->format.length]= 0; + new_format->format.length= format->format.length; + } + return new_format; +} + + +KNOWN_DATE_TIME_FORMAT known_date_time_formats[6]= +{ + {"USA", "%m.%d.%Y", "%Y-%m-%d %H.%i.%s", "%h:%i:%s %p" }, + {"JIS", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" }, + {"ISO", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" }, + {"EUR", "%d.%m.%Y", "%Y-%m-%d %H.%i.%s", "%H.%i.%s" }, + {"INTERNAL", "%Y%m%d", "%Y%m%d%H%i%s", "%H%i%s" }, + { 0, 0, 0, 0 } +}; + + +/* + Return format string according format name. + If name is unknown, result is NULL +*/ + +const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format, + timestamp_type type) +{ + switch (type) { + case TIMESTAMP_DATE: + return format->date_format; + case TIMESTAMP_DATETIME: + return format->datetime_format; + case TIMESTAMP_TIME: + return format->time_format; + default: + DBUG_ASSERT(0); // Impossible + return 0; + } +} + +/**************************************************************************** + Functions to create default time/date/datetime strings + + NOTE: + For the moment the DATE_TIME_FORMAT argument is ignored becasue + MySQL doesn't support comparing of date/time/datetime strings that + are not in arbutary order as dates are compared as strings in some + context) +****************************************************************************/ + +void make_time(DATE_TIME_FORMAT *format, TIME *l_time, String *str) +{ + long length= my_sprintf((char*) str->ptr(), + ((char*) str->ptr(), + "%s%02d:%02d:%02d", + (l_time->neg ? "-" : ""), + l_time->hour, + l_time->minute, + l_time->second)); + str->length(length); + str->set_charset(&my_charset_bin); +} + + +void make_date(DATE_TIME_FORMAT *format, TIME *l_time, String *str) +{ + long length= my_sprintf((char*) str->ptr(), + ((char*) str->ptr(), + "%04d-%02d-%02d", + l_time->year, + l_time->month, + l_time->day)); + str->length(length); + str->set_charset(&my_charset_bin); +} + + +void make_datetime(DATE_TIME_FORMAT *format, TIME *l_time, String *str) +{ + long length= my_sprintf((char*) str->ptr(), + ((char*) str->ptr(), + "%04d-%02d-%02d %02d:%02d:%02d", + l_time->year, + l_time->month, + l_time->day, + l_time->hour, + l_time->minute, + l_time->second)); + str->length(length); + str->set_charset(&my_charset_bin); } diff --git a/sql/unireg.cc b/sql/unireg.cc index 8606830e450..fc948ddd5a6 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -150,16 +150,19 @@ int rea_create_table(THD *thd, my_string file_name, my_free((gptr) screen_buff,MYF(0)); my_free((gptr) keybuff, MYF(0)); - VOID(my_close(file,MYF(MY_WME))); - if (ha_create_table(file_name,create_info,0)) + if (my_sync(file, MYF(MY_WME))) goto err2; + if (my_close(file,MYF(MY_WME)) || + ha_create_table(file_name,create_info,0)) + goto err3; DBUG_RETURN(0); err: my_free((gptr) screen_buff,MYF(0)); my_free((gptr) keybuff, MYF(0)); +err2: VOID(my_close(file,MYF(MY_WME))); - err2: +err3: my_delete(file_name,MYF(0)); DBUG_RETURN(1); } /* rea_create_table */ @@ -302,6 +305,7 @@ static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo) { keybuff[0]=(uchar) key_count; keybuff[1]=(uchar) key_parts; + keybuff[2]= keybuff[3]= 0; } length=(uint) (pos-keyname_pos); int2store(keybuff+4,length); diff --git a/sql/unireg.h b/sql/unireg.h index ef6a2f44ea7..8d62959317d 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -43,7 +43,7 @@ #define ERRMAPP 1 /* Errormap f|r my_error */ #define LIBLEN FN_REFLEN-FN_LEN /* Max l{ngd p} dev */ -#define MAX_DBKEY_LENGTH (FN_LEN*2+6) /* extra 4 bytes for slave tmp +#define MAX_DBKEY_LENGTH (FN_LEN*2+1+1+4+4) /* extra 4+4 bytes for slave tmp * tables */ #define MAX_ALIAS_NAME 256 #define MAX_FIELD_NAME 34 /* Max colum name length +2 */ @@ -63,6 +63,10 @@ /* Max column width +1 */ #define MAX_FIELD_WIDTH (MAX_FIELD_CHARLENGTH*MAX_MBWIDTH+1) +#define MAX_DATE_WIDTH 10 /* YYYY-MM-DD */ +#define MAX_TIME_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */ +#define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */ +#define MAX_DATETIME_WIDTH 19 /* YYYY-MM-DD HH:MM:SS */ #define MAX_TABLES (sizeof(table_map)*8-2) /* Max tables in join */ #define OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2)) diff --git a/strings/Makefile.am b/strings/Makefile.am index 7b2fdcccc55..61219c8abb9 100644 --- a/strings/Makefile.am +++ b/strings/Makefile.am @@ -21,20 +21,20 @@ pkglib_LIBRARIES = libmystrings.a # Exact one of ASSEMBLER_X if ASSEMBLER_x86 -ASRCS = strings-x86.s longlong2str-x86.s +ASRCS = strings-x86.s longlong2str-x86.s my_strtoll10-x86.s CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c else if ASSEMBLER_sparc32 # These file MUST all be on the same line!! Otherwise automake # generats a very broken makefile ASRCS = bmove_upp-sparc.s strappend-sparc.s strend-sparc.s strinstr-sparc.s strmake-sparc.s strmov-sparc.s strnmov-sparc.s strstr-sparc.s -CSRCS = strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c strxmov.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c +CSRCS = strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c strxmov.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c my_strtoll10.c else #no assembler ASRCS = # These file MUST all be on the same line!! Otherwise automake # generats a very broken makefile -CSRCS = strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c +CSRCS = strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c my_strtoll10.c endif endif @@ -47,6 +47,7 @@ EXTRA_DIST = ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-win1250ch.c \ ctype-ucs2.c ctype-tis620.c ctype-ujis.c \ xml.c strto.c strings-x86.s \ longlong2str.c longlong2str-x86.s \ + my_strtoll10.c my_strtoll10-x86.s \ strxmov.c bmove_upp.c strappend.c strcont.c strend.c \ strfill.c strcend.c is_prefix.c strstr.c strinstr.c \ strmake.c strnmov.c strmov.c strnlen.c \ diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 5a785552b45..6f28c43b2c6 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -35,12 +35,12 @@ static uchar ctype_bin[]= 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 16, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 72, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 16, 2, 2, 2, 2, 2, 2, 2, 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; diff --git a/strings/my_vsnprintf.c b/strings/my_vsnprintf.c index deb9448857e..4fd288d257e 100644 --- a/strings/my_vsnprintf.c +++ b/strings/my_vsnprintf.c @@ -95,26 +95,32 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap) else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */ { register int iarg; - char *to_start= to; - if ((uint) (end-to) < max(16,length)) - break; + uint res_length, to_length; + char *store_start= to, *store_end; + char buff[16]; + + if ((to_length= (uint) (end-to)) < 16 || length) + store_start= buff; iarg = va_arg(ap, int); if (*fmt == 'd') - to=int10_to_str((long) iarg,to, -10); + store_end= int10_to_str((long) iarg, store_start, -10); else - to=int10_to_str((long) (uint) iarg,to,10); + store_end= int10_to_str((long) (uint) iarg, store_start, 10); + if ((res_length= (uint) (store_end - store_start)) > to_length) + break; /* num doesn't fit in output */ /* If %#d syntax was used, we have to pre-zero/pre-space the string */ - if (length) + if (store_start == buff) { - uint res_length= (uint) (to - to_start); + length= min(length, to_length); if (res_length < length) { uint diff= (length- res_length); - bmove_upp(to+diff, to, res_length); - bfill(to-res_length, diff, pre_zero ? '0' : ' '); + bfill(to, diff, pre_zero ? '0' : ' '); to+= diff; } + bmove(to, store_start, res_length); } + to+= res_length; continue; } /* We come here on '%%', unknown code or too long parameter */ diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index dec77a15dc5..30ee4ab545f 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -109,19 +109,6 @@ else fi # -# Set pid file if not given -# -if test -z "$pid_file" -then - pid_file=$datadir/`@HOSTNAME@`.pid -else - case "$pid_file" in - /* ) ;; - * ) pid_file="$datadir/$pid_file" ;; - esac -fi - -# # Test if someone changed datadir; In this case we should also read the # default arguments from this directory # @@ -134,6 +121,19 @@ fi parse_arguments `$print_defaults $extra_args mysqld server mysql_server mysql.server` +# +# Set pid file if not given +# +if test -z "$pid_file" +then + pid_file=$datadir/`@HOSTNAME@`.pid +else + case "$pid_file" in + /* ) ;; + * ) pid_file="$datadir/$pid_file" ;; + esac +fi + # Safeguard (relative paths, core dumps..) cd $basedir |