diff options
317 files changed, 12040 insertions, 4315 deletions
diff --git a/BUILD/autorun.sh b/BUILD/autorun.sh index 08651f656f2..8e4ef85657e 100755 --- a/BUILD/autorun.sh +++ b/BUILD/autorun.sh @@ -4,8 +4,14 @@ aclocal || (echo "Can't execute aclocal" && exit 1) autoheader || (echo "Can't execute autoheader" && exit 1) # --force means overwrite ltmain.sh script if it already exists -libtoolize --automake --force \ - || (echo "Can't execute libtoolize" && exit 1) +# Added glibtoolize reference to make native OSX autotools work +if [ -f /usr/bin/glibtoolize ] ; then + glibtoolize --automake --force \ + || (echo "Can't execute glibtoolize" && exit 1) +else + libtoolize --automake --force \ + || (echo "Can't execute libtoolize" && exit 1) +fi # --add-missing instructs automake to install missing auxiliary files # and --force to overwrite them if they already exist automake --add-missing --force \ diff --git a/Docs/Makefile.am b/Docs/Makefile.am index 6f8c51e79f0..b1f69381774 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -36,22 +36,22 @@ CLEAN_FILES: $(txt_files) GT = $(srcdir)/Support/generate-text-files.pl ../INSTALL-SOURCE: mysql.info $(GT) - perl -w $(GT) mysql.info "Installing" "Tutorial" > $@ + perl -w $(GT) mysql.info "installing-source" "windows-source-build" > $@ ../INSTALL-WIN-SOURCE: mysql.info $(GT) - perl -w $(GT) mysql.info "Windows source build" "Post-installation" > $@ + perl -w $(GT) mysql.info "windows-source-build" "post-installation" > $@ # We put the description for the binary installation here so that # people who download source wont have to see it. It is moved up to # the toplevel by the script that makes the binary tar files. INSTALL-BINARY: mysql.info $(GT) - perl -w $(GT) mysql.info "Installing binary" "Installing source" > $@ + perl -w $(GT) mysql.info "installing-binary" "installing-source" > $@ ../EXCEPTIONS-CLIENT: mysql.info $(GT) - perl -w $(GT) mysql.info "MySQL FLOSS License Exception" "Function Index" > $@ + perl -w $(GT) mysql.info "mysql-floss-license-exception" "function-index" > $@ ../support-files/MacOSX/ReadMe.txt: mysql.info $(GT) - perl -w $(GT) mysql.info "Mac OS X installation" "NetWare installation" > $@ + perl -w $(GT) mysql.info "mac-os-x-installation" "netware-installation" > $@ # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/Docs/README.1st b/Docs/README.1st deleted file mode 100644 index 980c043224a..00000000000 --- a/Docs/README.1st +++ /dev/null @@ -1,76 +0,0 @@ -This ALPHA build of MySQL 4.1 for the Windows platform does not come -with an installer. A full-featured installer is being developed for the -4.1 series, and it is scheduled to be released with MySQL 4.1 BETA. - -** FRESH INSTALL ** - -To install MySQL 4.1 as a 'fresh' install, unzip this archive to a directory -of your choice (we suggest 'c:\', which will cause MySQL to be installed in -a directory named 'mysql' in 'c:\'). You should then follow the directions -in the user manual for starting/stopping MySQL: - -(Windows 9x/ME) http://www.mysql.com/doc/en/Win95_start.html -(Windows NT/2000/XP) http://www.mysql.com/doc/en/NT_start.html - -** UPGRADE INSTALL ** - -To install MySQL 4.1 as an upgrade to your current version of MySQL, you need -to perform the following steps: - -* Back up your original installation (always a good idea!) - -* Unzip the 4.1 archive to a directory that is different than where your - current MySQL installation is located. (Or, if you do unzip this - archive into the same location as your existing installation, do NOT - unpack the 'data' subdirectory. If you unpack the 'data' directory, - your existing databases will be overwritten.) - -* Shut down all MySQL server processes/services. - -* Remove the Win32 MySQL service (if appropriate for your OS): - - c:\mysql\bin\mysqld-nt --remove - -* Exit 'WinMySQLAdmin' (if it is running). - -* If you unzipped this archive into a directory different than that - of your existing MySQL installation, copy from the archive all its - directories and their contents EXCEPT the 'data' directory into the - existing installation. - -* Start the MySQL server with the '--skip-grant-tables' option. Assuming - your MySQL installation is located at 'c:\mysql', the command looks like - this: - - c:\mysql\bin\mysqld-opt --skip-grant-tables - - If your installation is located in some other directory, adjust the - pathname in that command (and in the following commands). - -* Execute the 'mysql_fix_privilege_tables.sql' script that is located in - the 'scripts' directory: - - c:\mysql\bin\mysql -f mysql < c:\mysql\scripts\mysql_fix_privilege_tables.sql - - This script performs any actions necessary to convert your grant tables - to the current format. You may see some "duplicate column" warnings as - it runs; these can be ignored. - -* Stop the server: - - c:\mysql\bin\mysqladmin -u root shutdown - -* Re-install the Win32 MySQL service (if required): - - c:\mysql\bin\mysqld-nt --install - -* Re-start the server or service using your normal startup procedure. - -** Further Questions ** - -You can find further information about running MySQL on Windows in the -manual that ships in the 'Doc' subdirectory, or online at the MySQL AB -web site: - -http://www.mysql.com/doc/en/Windows.html - diff --git a/Docs/Support/generate-flag-images b/Docs/Support/generate-flag-images deleted file mode 100755 index 21140388012..00000000000 --- a/Docs/Support/generate-flag-images +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh - -flags=`grep @image mirrors.texi | cut -d" " -f1 | cut -d/ -f2 | tr -d "}" | sort | uniq` - -set -x -cd Flags - -for c in $flags -do - # For PNM, to be used later - giftopnm ../Raw-Flags/$c.gif | pnmscale -xsize 30 > $c-tmp.pnm - pnmpaste $c-tmp.pnm 1 1 ../Images/flag-background.pnm > $c.pnm - rm -f $c-tmp.pnm - - # For GIF version - ppmtogif $c.pnm > $c.gif - # or cjpeg -optimize -quality 70 -outfile $c.jpg - - # For EPS version - pnmtops -noturn $c.pnm > $c.eps - - # For PDF version - ps2pdf $c.eps $c.pdf - - # For text version - echo -n "" > $c.txt - - # PNM isn't really needed - rm -f $c.pnm - -done diff --git a/Docs/Support/generate-text-files.pl b/Docs/Support/generate-text-files.pl index 6470baaa6e9..0829525f679 100755 --- a/Docs/Support/generate-text-files.pl +++ b/Docs/Support/generate-text-files.pl @@ -13,7 +13,7 @@ while (<IN>) { if ($in) { - if (/Node: $tnode,/) + if (/Node: $tnode,/ || /\[index/) { $in = 0; } diff --git a/Makefile.am b/Makefile.am index 514cd21274f..830c68df3f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,7 +23,7 @@ EXTRA_DIST = INSTALL-SOURCE README COPYING EXCEPTIONS-CLIENT SUBDIRS = . include @docs_dirs@ @zlib_dir@ @yassl_dir@ \ @readline_topdir@ sql-common \ @thread_dirs@ pstack \ - @sql_union_dirs@ scripts man tests \ + @sql_union_dirs@ scripts @man_dirs@ tests \ netware @libmysqld_dirs@ \ @bench_dirs@ support-files @tools_dirs@ @@ -103,12 +103,12 @@ tags: test: cd mysql-test; \ - perl mysql-test-run.pl && perl mysql-test-run.pl --ps-protocol + ./mysql-test-run && ./mysql-test-run --ps-protocol test-force: cd mysql-test; \ - perl mysql-test-run.pl --force ;\ - perl mysql-test-run.pl --ps-protocol --force + ./mysql-test-run --force ;\ + ./mysql-test-run --ps-protocol --force # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp index 4b49f5290c7..e8f24b300cb 100644 --- a/VC++Files/sql/mysqld.dsp +++ b/VC++Files/sql/mysqld.dsp @@ -84,7 +84,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=xilink6.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_debug\dbug.lib ..\lib_debug\vio.lib ..\lib_debug\mysys.lib ..\lib_debug\strings.lib ..\lib_debug\regex.lib ..\lib_debug\heap.lib ..\lib_debug\bdb.lib ..\lib_debug\innodb.lib ..\extra\yassl\Release\yassl.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../client_debug/mysqld-debug.exe" /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib ..\lib_debug\dbug.lib ..\lib_debug\vio.lib ..\lib_debug\mysys.lib ..\lib_debug\strings.lib ..\lib_debug\regex.lib ..\lib_debug\heap.lib ..\lib_debug\bdb.lib ..\lib_debug\innodb.lib ..\extra\yassl\Debug\yassl.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"../client_debug/mysqld-debug.exe" /pdbtype:sept !ELSEIF "$(CFG)" == "mysqld - Win32 nt" diff --git a/VC++Files/tests/mysql_client_test.dsp b/VC++Files/tests/mysql_client_test.dsp index 1d780ca5e0c..b9d3916f398 100644 --- a/VC++Files/tests/mysql_client_test.dsp +++ b/VC++Files/tests/mysql_client_test.dsp @@ -51,8 +51,8 @@ BSC32=bscmake.exe # ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib mysqlclient.lib wsock32.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib /nologo /out:"..\mysql_client_test.exe" /incremental:yes /libpath:"..\lib_debug\" /debug /pdb:".\Debug\mysql_client_test.pdb" /pdbtype:sept /map:".\Debug\mysql_client_test.map" /subsystem:console -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib mysqlclient.lib wsock32.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib /nologo /out:"..\mysql_client_test.exe" /incremental:yes /libpath:"..\lib_debug\" /debug /pdb:".\Debug\mysql_client_test.pdb" /pdbtype:sept /map:".\Debug\mysql_client_test.map" /subsystem:console +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib mysqlclient.lib wsock32.lib mysys.lib regex.lib ..\extra\yassl\Debug\yassl.lib /nologo /out:"..\client_debug\mysql_client_test.exe" /incremental:yes /libpath:"..\lib_debug\" /debug /pdb:".\Debug\mysql_client_test.pdb" /pdbtype:sept /map:".\Debug\mysql_client_test.map" /subsystem:console +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib mysqlclient.lib wsock32.lib mysys.lib regex.lib ..\extra\yassl\Debug\yassl.lib /nologo /out:"..\client_debug\mysql_client_test.exe" /incremental:yes /libpath:"..\lib_debug\" /debug /pdb:".\Debug\mysql_client_test.pdb" /pdbtype:sept /map:".\Debug\mysql_client_test.map" /subsystem:console !ELSEIF "$(CFG)" == "mysql_client_test - Win32 Release"
@@ -76,8 +76,8 @@ BSC32=bscmake.exe # ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib Ws2_32.lib mysqlclient.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib /nologo /out:"..\mysql_client_test.exe" /incremental:no /pdb:".\Release\mysql_client_test.pdb" /pdbtype:sept /subsystem:console -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib Ws2_32.lib mysqlclient.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib /nologo /out:"..\mysql_client_test.exe" /incremental:no /pdb:".\Release\mysql_client_test.pdb" /pdbtype:sept /subsystem:console +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib Ws2_32.lib mysqlclient.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib /nologo /out:"..\client_release\mysql_client_test.exe" /incremental:no /pdb:".\Release\mysql_client_test.pdb" /pdbtype:sept /subsystem:console +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib Ws2_32.lib mysqlclient.lib mysys.lib regex.lib ..\extra\yassl\Release\yassl.lib /nologo /out:"..\client_release\mysql_client_test.exe" /incremental:no /pdb:".\Release\mysql_client_test.pdb" /pdbtype:sept /subsystem:console !ENDIF
diff --git a/client/Makefile.am b/client/Makefile.am index a301d55efe4..d47e9f98f5e 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -22,8 +22,8 @@ else yassl_dummy_link_fix= endif #AUTOMAKE_OPTIONS = nostdinc -INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/regex \ - $(openssl_includes) -I$(top_builddir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/regex $(openssl_includes) LIBS = @CLIENT_LIBS@ LDADD= @CLIENT_EXTRA_LDFLAGS@ \ $(top_builddir)/libmysql/libmysqlclient.la diff --git a/client/mysqldump.c b/client/mysqldump.c index 907b6233590..5705571777a 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -57,6 +57,7 @@ #define EX_CONSCHECK 3 #define EX_EOM 4 #define EX_EOF 5 /* ferror for output file was got */ +#define EX_ILLEGAL_TABLE 6 /* index into 'show fields from table' */ @@ -142,14 +143,6 @@ const char *compatible_mode_names[]= TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1, "", compatible_mode_names, NULL}; -#define TABLE_RULE_HASH_SIZE 16 - -typedef struct st_table_rule_ent -{ - char* key; /* dbname.tablename */ - uint key_len; -} TABLE_RULE_ENT; - HASH ignore_table; static struct my_option my_long_options[] = @@ -476,7 +469,10 @@ static void write_header(FILE *sql_file, char *db_name) if (opt_xml) { fputs("<?xml version=\"1.0\"?>\n", sql_file); - fputs("<mysqldump>\n", sql_file); + fputs("<mysqldump ", sql_file); + fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", + sql_file); + fputs(">\n", sql_file); check_io(sql_file); } else if (!opt_compact) @@ -543,30 +539,29 @@ static void write_footer(FILE *sql_file) } } /* write_footer */ +static void free_table_ent(char *key) -static void free_table_ent(TABLE_RULE_ENT* e) { - my_free((gptr) e, MYF(0)); + my_free((gptr) key, MYF(0)); } -static byte* get_table_key(TABLE_RULE_ENT* e, uint* len, - my_bool not_used __attribute__((unused))) +byte* get_table_key(const char *entry, uint *length, + my_bool not_used __attribute__((unused))) { - *len= e->key_len; - return (byte*)e->key; + *length= strlen(entry); + return (byte*) entry; } void init_table_rule_hash(HASH* h) { - if(hash_init(h, charset_info, TABLE_RULE_HASH_SIZE, 0, 0, - (hash_get_key) get_table_key, - (hash_free_key) free_table_ent, 0)) + if (hash_init(h, charset_info, 16, 0, 0, + (hash_get_key) get_table_key, + (hash_free_key) free_table_ent, 0)) exit(EX_EOM); } - static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) @@ -639,25 +634,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case (int) OPT_IGNORE_TABLE: { - uint len= (uint)strlen(argument); - TABLE_RULE_ENT* e; if (!strchr(argument, '.')) { fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n"); exit(1); } - /* len is always > 0 because we know the there exists a '.' */ - e= (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) + len, MYF(MY_WME)); - if (!e) - exit(EX_EOM); - e->key= (char*)e + sizeof(TABLE_RULE_ENT); - e->key_len= len; - memcpy(e->key, argument, len); - if (!hash_inited(&ignore_table)) init_table_rule_hash(&ignore_table); - if(my_hash_insert(&ignore_table, (byte*)e)) + if (my_hash_insert(&ignore_table, (byte*)my_strdup(argument, MYF(0)))) exit(EX_EOM); break; } @@ -828,7 +813,8 @@ static void DB_error(MYSQL *mysql, const char *when) SYNOPSIS mysql_query_with_error_report() mysql_con connection to use - res if non zero, result will be put there with mysql_store_result + res if non zero, result will be put there with + mysql_store_result() query query to send to server RETURN VALUES @@ -981,14 +967,41 @@ static char *quote_name(const char *name, char *buff, my_bool force) } /* quote_name */ +/* + Quote a table name so it can be used in "SHOW TABLES LIKE <tabname>" + + SYNOPSIS + quote_for_like() + name name of the table + buff quoted name of the table + + DESCRIPTION + Quote \, _, ' and % characters + + Note: Because MySQL uses the C escape syntax in strings + (for example, '\n' to represent newline), you must double + any '\' that you use in your LIKE strings. For example, to + search for '\n', specify it as '\\n'. To search for '\', specify + it as '\\\\' (the backslashes are stripped once by the parser + and another time when the pattern match is done, leaving a + single backslash to be matched). + + Example: "t\1" => "t\\\\1" +*/ static char *quote_for_like(const char *name, char *buff) { char *to= buff; *to++= '\''; while (*name) { - if (*name == '\'' || *name == '_' || *name == '\\' || *name == '%') + if (*name == '\\') + { + *to++='\\'; + *to++='\\'; + *to++='\\'; + } + else if (*name == '\'' || *name == '_' || *name == '%') *to++= '\\'; *to++= *name++; } @@ -1074,6 +1087,40 @@ static void print_xml_tag1(FILE * xml_file, const char* sbeg, /* + Print xml tag with for a field that is null + + SYNOPSIS + print_xml_null_tag() + 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: + <stag_atr="sval" xsi:nil="true"/> + NOTE + sval MUST be a NULL terminated string. + sval string will be qouted before output. +*/ + +static void print_xml_null_tag(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("\" xsi:nil=\"true\" />", xml_file); + fputs(send, xml_file); + check_io(xml_file); +} + + +/* Print xml tag with many attributes. SYNOPSIS @@ -1139,6 +1186,7 @@ static uint get_table_structure(char *table, char *db) FILE *sql_file = md_result_file; int len; DBUG_ENTER("get_table_structure"); + DBUG_PRINT("enter", ("db: %s, table: %s", db, table)); if (!insert_pat_inited) { @@ -1212,7 +1260,54 @@ static uint get_table_structure(char *table, char *db) if (strcmp(field->name, "View") == 0) { if (verbose) - fprintf(stderr, "-- It's a view, skipped\n"); + fprintf(stderr, "-- It's a view, create dummy table for view\n"); + + mysql_free_result(tableRes); + + /* Create a dummy table for the view. ie. a table which has the + same columns as the view should have. This table is dropped + just before the view is created. The table is used to handle the + case where a view references another view, which hasn't yet been + created(during the load of the dump). BUG#10927 */ + + /* Create temp table by selecting from the view */ + my_snprintf(query_buff, sizeof(query_buff), + "CREATE TEMPORARY TABLE %s SELECT * FROM %s WHERE 0", + result_table, result_table); + if (mysql_query_with_error_report(sock, 0, query_buff)) + { + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } + + /* Get CREATE statement for the temp table */ + my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE TABLE %s", + result_table); + if (mysql_query_with_error_report(sock, 0, query_buff)) + { + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } + tableRes= mysql_store_result(sock); + row= mysql_fetch_row(tableRes); + + if (opt_drop) + fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n",opt_quoted_table); + + /* Print CREATE statement but remove TEMPORARY */ + fprintf(sql_file, "CREATE %s;\n", row[1]+17); + check_io(sql_file); + + mysql_free_result(tableRes); + + /* Drop the temp table */ + my_snprintf(buff, sizeof(buff), + "DROP TEMPORARY TABLE %s", result_table); + if (mysql_query_with_error_report(sock, 0, buff)) + { + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } was_views= 1; DBUG_RETURN(0); } @@ -1592,6 +1687,26 @@ static void dump_table(uint numFields, char *table) const char *table_type; int error= 0; + /* Check --no-data flag */ + if (dFlag) + { + if (verbose) + fprintf(stderr, + "-- Skipping dump data for table '%s', --no-data was used\n", + table); + return; + } + + /* Check that there are any fields in the table */ + if (numFields == 0) + { + if (verbose) + fprintf(stderr, + "-- Skipping dump data for table '%s', it has no fields\n", + table); + return; + } + result_table= quote_name(table,table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); @@ -1912,7 +2027,14 @@ static void dump_table(uint numFields, char *table) } } else - fputs("NULL", md_result_file); + { + /* The field value is NULL */ + if (!opt_xml) + fputs("NULL", md_result_file); + else + print_xml_null_tag(md_result_file, "\t\t", "field name=", + field->name, "\n"); + } check_io(md_result_file); } } @@ -2201,8 +2323,7 @@ static int dump_all_tables_in_db(char *database) if (include_table(hash_key, end - hash_key)) { numrows = get_table_structure(table, database); - if (!dFlag && numrows > 0) - dump_table(numrows,table); + dump_table(numrows,table); my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); order_by= 0; } @@ -2327,27 +2448,61 @@ static int get_actual_table_name(const char *old_table_name, static int dump_selected_tables(char *db, char **table_names, int tables) { - uint numrows; - int i; + uint numrows, i; char table_buff[NAME_LEN*+3]; + char new_table_name[NAME_LEN]; + DYNAMIC_STRING lock_tables_query; + HASH dump_tables; + char *table_name; + DBUG_ENTER("dump_selected_tables"); if (init_dumping(db)) return 1; - if (lock_tables) + + /* Init hash table for storing the actual name of tables to dump */ + if (hash_init(&dump_tables, charset_info, 16, 0, 0, + (hash_get_key) get_table_key, (hash_free_key) free_table_ent, + 0)) + exit(EX_EOM); + + init_dynamic_string(&lock_tables_query, "LOCK TABLES ", 256, 1024); + for (; tables > 0 ; tables-- , table_names++) { - DYNAMIC_STRING query; + /* the table name passed on commandline may be wrong case */ + if (!get_actual_table_name(*table_names, + new_table_name, sizeof(new_table_name))) + { + /* Add found table name to lock_tables_query */ + if (lock_tables) + { + dynstr_append(&lock_tables_query, + quote_name(new_table_name, table_buff, 1)); + dynstr_append(&lock_tables_query, " READ /*!32311 LOCAL */,"); + } - init_dynamic_string(&query, "LOCK TABLES ", 256, 1024); - for (i=0 ; i < tables ; i++) + /* Add found table name to dump_tables list */ + if (my_hash_insert(&dump_tables, + (byte*)my_strdup(new_table_name, MYF(0)))) + exit(EX_EOM); + + } + else { - dynstr_append(&query, quote_name(table_names[i], table_buff, 1)); - dynstr_append(&query, " READ /*!32311 LOCAL */,"); + my_printf_error(0,"Couldn't find table: \"%s\"\n", MYF(0), + *table_names); + safe_exit(EX_ILLEGAL_TABLE); + /* We shall countinue here, if --force was given */ } - if (mysql_real_query(sock, query.str, query.length-1)) + } + + if (lock_tables) + { + if (mysql_real_query(sock, lock_tables_query.str, + lock_tables_query.length-1)) DB_error(sock, "when doing LOCK TABLES"); /* We shall countinue here, if --force was given */ - dynstr_free(&query); } + dynstr_free(&lock_tables_query); if (flush_logs) { if (mysql_refresh(sock, REFRESH_LOG)) @@ -2356,25 +2511,28 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } if (opt_xml) print_xml_tag1(md_result_file, "", "database name=", db, "\n"); - for (i=0 ; i < tables ; i++) - { - char new_table_name[NAME_LEN]; - /* the table name passed on commandline may be wrong case */ - if (!get_actual_table_name( table_names[i], new_table_name, - sizeof(new_table_name))) - { - numrows= get_table_structure(new_table_name, db); - dump_table(numrows, new_table_name); - } - my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); - order_by= 0; + /* Dump each selected table */ + for (i= 0; i < dump_tables.records; i++) + { + table_name= hash_element(&dump_tables, i); + DBUG_PRINT("info",("Dumping table %s", table_name)); + numrows= get_table_structure(table_name, db); + dump_table(numrows, table_name); } + + /* Dump each selected view */ if (was_views) { - for (i=0 ; i < tables ; i++) - get_view_structure(table_names[i], db); + for(i=0; i < dump_tables.records; i++) + { + table_name= hash_element(&dump_tables, i); + get_view_structure(table_name, db); + } } + hash_free(&dump_tables); + my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); + order_by= 0; if (opt_xml) { fputs("</database>\n", md_result_file); @@ -2382,7 +2540,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } if (lock_tables) mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"); - return 0; + DBUG_RETURN(0); } /* dump_selected_tables */ @@ -2403,6 +2561,7 @@ static int do_show_master_status(MYSQL *mysql_con) row = mysql_fetch_row(master); if (row && row[0] && row[1]) { + /* SHOW MASTER STATUS reports file and position */ if (opt_comments) fprintf(md_result_file, "\n--\n-- Position to start replication or point-in-time " @@ -2412,6 +2571,14 @@ static int do_show_master_status(MYSQL *mysql_con) comment_prefix, row[0], row[1]); check_io(md_result_file); } + else if (!ignore_errors) + { + /* SHOW MASTER STATUS reports nothing and --force is not enabled */ + my_printf_error(0, "Error: Binlogging on server not active", + MYF(0), mysql_error(mysql_con)); + mysql_free_result(master); + return 1; + } mysql_free_result(master); } return 0; @@ -2752,6 +2919,7 @@ static my_bool get_view_structure(char *table, char* db) } if (opt_drop) { + fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table); fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n", opt_quoted_table); check_io(sql_file); } @@ -2775,8 +2943,9 @@ int main(int argc, char **argv) { compatible_mode_normal_str[0]= 0; default_charset= (char *)mysql_universal_client_charset; + bzero((char*) &ignore_table, sizeof(ignore_table)); - MY_INIT(argv[0]); + MY_INIT("mysqldump"); if (get_options(&argc, &argv)) { my_end(0); @@ -2833,6 +3002,8 @@ err: if (md_result_file != stdout) my_fclose(md_result_file, MYF(0)); my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); + if (hash_inited(&ignore_table)) + hash_free(&ignore_table); if (extended_insert) dynstr_free(&extended_row); if (insert_pat_inited) diff --git a/client/mysqltest.c b/client/mysqltest.c index ad1bc8f7269..67fa931a3f3 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -60,6 +60,12 @@ #include <sys/stat.h> #include <violite.h> #include <regex.h> /* Our own version of lib */ +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif #define MAX_QUERY 131072 #define MAX_VAR_NAME 256 #define MAX_COLUMNS 256 @@ -986,9 +992,39 @@ static void do_exec(struct st_query* q) replace_dynstr_append(ds, buf); } error= pclose(res_file); - if (error != 0) - die("command \"%s\" failed", cmd); + { + uint status= WEXITSTATUS(error), i; + my_bool ok= 0; + + if (q->abort_on_error) + die("At line %u: command \"%s\" failed", start_lineno, cmd); + + DBUG_PRINT("info", + ("error: %d, status: %d", error, status)); + for (i=0 ; (uint) i < q->expected_errors ; i++) + { + DBUG_PRINT("info", + ("error: %d, status: %d", error, status)); + DBUG_PRINT("info", ("expected error: %d", + q->expected_errno[i].code.errnum)); + if ((q->expected_errno[i].type == ERR_ERRNO) && + (q->expected_errno[i].code.errnum == status)) + ok= 1; + verbose_msg("At line %u: command \"%s\" failed with expected error: %d", + start_lineno, cmd, status); + } + if (!ok) + die("At line: %u: command \"%s\" failed with wrong error: %d", + start_lineno, cmd, status); + } + else if (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0) + { + /* Error code we wanted was != 0, i.e. not an expected success */ + die("At line: %u: command \"%s\" succeeded - should have failed with errno %d...", + start_lineno, cmd, q->expected_errno[0].code.errnum); + } if (!disable_result_log) { diff --git a/cmd-line-utils/libedit/Makefile.am b/cmd-line-utils/libedit/Makefile.am index 03f3eb65fbc..af1bf8b2c97 100644 --- a/cmd-line-utils/libedit/Makefile.am +++ b/cmd-line-utils/libedit/Makefile.am @@ -5,7 +5,8 @@ ASRC=vi.c emacs.c common.c AHDR=vi.h emacs.h common.h -INCLUDES = -I$(top_srcdir)/include -I$(srcdir)/../.. -I.. +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(srcdir)/../.. -I.. noinst_LIBRARIES = libedit.a diff --git a/cmd-line-utils/libedit/chared.c b/cmd-line-utils/libedit/chared.c index 21fc8bc2c1d..4cb6e00d26e 100644 --- a/cmd-line-utils/libedit/chared.c +++ b/cmd-line-utils/libedit/chared.c @@ -51,13 +51,13 @@ cv_undo(EditLine *el) { c_undo_t *vu = &el->el_chared.c_undo; c_redo_t *r = &el->el_chared.c_redo; - uint size; + int size; /* Save entire line for undo */ size = el->el_line.lastchar - el->el_line.buffer; vu->len = size; vu->cursor = el->el_line.cursor - el->el_line.buffer; - memcpy(vu->buf, el->el_line.buffer, size); + memcpy(vu->buf, el->el_line.buffer, (size_t)size); /* save command info for redo */ r->count = el->el_state.doingarg ? el->el_state.argument : 0; diff --git a/cmd-line-utils/readline/Makefile.am b/cmd-line-utils/readline/Makefile.am index 87880517166..14d25ff62c0 100644 --- a/cmd-line-utils/readline/Makefile.am +++ b/cmd-line-utils/readline/Makefile.am @@ -3,7 +3,8 @@ # Copyright (C) 1994,1996,1997 Free Software Foundation, Inc. # Last -I$(top_srcdir) needed for RedHat! -INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir) +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir) noinst_LIBRARIES = libreadline.a diff --git a/configure.in b/configure.in index bdaf5b46846..cffed5f0417 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ dnl -*- ksh -*- dnl Process this file with autoconf to produce a configure script. -AC_PREREQ(2.50)dnl Minimum Autoconf version required. +AC_PREREQ(2.58)dnl Minimum Autoconf version required. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM @@ -343,7 +343,7 @@ AC_SUBST(CXXFLAGS) AC_SUBST(LD) AC_SUBST(INSTALL_SCRIPT) -export CC CXX CFLAGS LD LDFLAGS AR +export CC CXX CFLAGS LD LDFLAGS AR ARFLAGS if test "$GCC" = "yes" then diff --git a/dbug/Makefile.am b/dbug/Makefile.am index 0810b13cceb..38705e63847 100644 --- a/dbug/Makefile.am +++ b/dbug/Makefile.am @@ -15,7 +15,7 @@ # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, # MA 02111-1307, USA -INCLUDES = -I$(top_srcdir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include LDADD = libdbug.a ../mysys/libmysys.a ../strings/libmystrings.a pkglib_LIBRARIES = libdbug.a noinst_HEADERS = dbug_long.h diff --git a/extra/Makefile.am b/extra/Makefile.am index 3aa4c531709..cb06e7495f9 100644 --- a/extra/Makefile.am +++ b/extra/Makefile.am @@ -14,9 +14,8 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -INCLUDES = -I$(top_srcdir)/include \ - @ndbcluster_includes@ -I$(top_srcdir)/sql \ - -I$(top_builddir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ + @ndbcluster_includes@ -I$(top_srcdir)/sql LDADD = @CLIENT_EXTRA_LDFLAGS@ ../mysys/libmysys.a \ ../dbug/libdbug.a ../strings/libmystrings.a BUILT_SOURCES= $(top_builddir)/include/mysqld_error.h \ diff --git a/extra/yassl/include/yassl_types.hpp b/extra/yassl/include/yassl_types.hpp index 01b82d95039..ec9e6fb7ceb 100644 --- a/extra/yassl/include/yassl_types.hpp +++ b/extra/yassl/include/yassl_types.hpp @@ -445,7 +445,7 @@ const opaque master_label[MASTER_LABEL_SZ + 1] = "master secret"; const opaque key_label [KEY_LABEL_SZ + 1] = "key expansion"; -} // namespace +} // naemspace #if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 /* @@ -456,4 +456,5 @@ const opaque key_label [KEY_LABEL_SZ + 1] = "key expansion"; using yaSSL::byte; #endif + #endif // yaSSL_TYPES_HPP diff --git a/extra/yassl/src/Makefile.am b/extra/yassl/src/Makefile.am index 1f5f1ee7a4e..4ebb9a2d862 100644 --- a/extra/yassl/src/Makefile.am +++ b/extra/yassl/src/Makefile.am @@ -5,3 +5,4 @@ libyassl_a_SOURCES = buffer.cpp cert_wrapper.cpp crypto_wrapper.cpp \ handshake.cpp lock.cpp log.cpp socket_wrapper.cpp ssl.cpp \ template_instnt.cpp timer.cpp yassl_imp.cpp yassl_error.cpp yassl_int.cpp EXTRA_DIST = ../include/*.hpp ../include/openssl/*.h +AM_CXXFLAGS = -DYASSL_PURE_C diff --git a/extra/yassl/src/buffer.cpp b/extra/yassl/src/buffer.cpp index 1da0827ac4e..56d355bea80 100644 --- a/extra/yassl/src/buffer.cpp +++ b/extra/yassl/src/buffer.cpp @@ -25,6 +25,7 @@ */ #include <string.h> // memcpy +#include "runtime.hpp" #include "buffer.hpp" #include "yassl_types.hpp" diff --git a/extra/yassl/src/cert_wrapper.cpp b/extra/yassl/src/cert_wrapper.cpp index 7a8c7dfe253..a775c366a92 100644 --- a/extra/yassl/src/cert_wrapper.cpp +++ b/extra/yassl/src/cert_wrapper.cpp @@ -24,6 +24,7 @@ * */ +#include "runtime.hpp" #include "cert_wrapper.hpp" #include "yassl_int.hpp" diff --git a/extra/yassl/src/lock.cpp b/extra/yassl/src/lock.cpp index 8a0b66ead42..4827d396e81 100644 --- a/extra/yassl/src/lock.cpp +++ b/extra/yassl/src/lock.cpp @@ -22,6 +22,7 @@ /* Locking functions */ +#include "runtime.hpp" #include "lock.hpp" diff --git a/extra/yassl/src/log.cpp b/extra/yassl/src/log.cpp index 38633cd1210..8ab351ee2b1 100644 --- a/extra/yassl/src/log.cpp +++ b/extra/yassl/src/log.cpp @@ -22,6 +22,8 @@ /* Debug logging functions */ + +#include "runtime.hpp" #include "log.hpp" #ifdef YASSL_LOG diff --git a/extra/yassl/src/socket_wrapper.cpp b/extra/yassl/src/socket_wrapper.cpp index 00f9c8d170c..2252dfafdc5 100644 --- a/extra/yassl/src/socket_wrapper.cpp +++ b/extra/yassl/src/socket_wrapper.cpp @@ -26,6 +26,7 @@ */ +#include "runtime.hpp" #include "socket_wrapper.hpp" #ifndef _WIN32 diff --git a/extra/yassl/src/template_instnt.cpp b/extra/yassl/src/template_instnt.cpp index 5cf4f8c39f8..5ee57e76aed 100644 --- a/extra/yassl/src/template_instnt.cpp +++ b/extra/yassl/src/template_instnt.cpp @@ -1,3 +1,29 @@ +/* template_instnt.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* Explicit template instantiation requests + */ + + #include "runtime.hpp" #include "handshake.hpp" #include "yassl_int.hpp" @@ -15,7 +41,7 @@ template class HMAC<MD5>; template class HMAC<SHA>; template class HMAC<RIPEMD160>; } -#endif +#endif // USE_CRYPTOPP_LIB namespace mySTL { template class list<unsigned char*>; @@ -64,4 +90,6 @@ template void ysDelete<Message>(Message*); template void ysArrayDelete<unsigned char>(unsigned char*); template void ysArrayDelete<char>(char*); } -#endif + +#endif // HAVE_EXPLICIT_TEMPLATE_INSTANTIATION + diff --git a/extra/yassl/src/timer.cpp b/extra/yassl/src/timer.cpp index cfa1319ae80..4fe0d3aa4f9 100644 --- a/extra/yassl/src/timer.cpp +++ b/extra/yassl/src/timer.cpp @@ -23,6 +23,7 @@ * */ +#include "runtime.hpp" #include "timer.hpp" namespace yaSSL { diff --git a/extra/yassl/src/yassl_error.cpp b/extra/yassl/src/yassl_error.cpp index 6ae5a9f6663..c53aef2068d 100644 --- a/extra/yassl/src/yassl_error.cpp +++ b/extra/yassl/src/yassl_error.cpp @@ -23,6 +23,7 @@ /* yaSSL error implements and an exception class */ +#include "runtime.hpp" #include "yassl_error.hpp" namespace yaSSL { diff --git a/extra/yassl/src/yassl_int.cpp b/extra/yassl/src/yassl_int.cpp index e9c1ed53816..740618ce701 100644 --- a/extra/yassl/src/yassl_int.cpp +++ b/extra/yassl/src/yassl_int.cpp @@ -33,28 +33,36 @@ void* operator new(size_t sz, yaSSL::new_t) { +#ifdef YASSL_PURE_C void* ptr = malloc(sz ? sz : 1); if (!ptr) abort(); return ptr; +#else + return ::operator new(sz); +#endif } -void* operator new[](size_t sz, yaSSL::new_t) -{ - void* ptr = malloc(sz ? sz : 1); - if (!ptr) abort(); - - return ptr; -} void operator delete(void* ptr, yaSSL::new_t) { +#ifdef YASSL_PURE_C if (ptr) free(ptr); +#else + ::operator delete(ptr); +#endif +} + + +void* operator new[](size_t sz, yaSSL::new_t nt) +{ + return ::operator new(sz, nt); } -void operator delete[](void* ptr, yaSSL::new_t) + +void operator delete[](void* ptr, yaSSL::new_t nt) { - if (ptr) free(ptr); + ::operator delete(ptr, nt); } @@ -923,7 +931,7 @@ void SSL::setKeys() // local functors -namespace yassl_int_cpp_local1 { +namespace yassl_int_cpp_local1 { // for explicit templates struct SumData { uint total_; @@ -1385,7 +1393,8 @@ Sessions::~Sessions() } -namespace yassl_int_cpp_local2 { // locals +// locals +namespace yassl_int_cpp_local2 { // for explicit templates typedef mySTL::list<SSL_SESSION*>::iterator iterator; @@ -1974,6 +1983,8 @@ X509_NAME* X509::GetSubject() return &subject_; } + + } // namespace #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION @@ -1983,3 +1994,4 @@ template yaSSL::yassl_int_cpp_local1::SumBuffer for_each<mySTL::list<yaSSL::outp template mySTL::list<yaSSL::SSL_SESSION*>::iterator find_if<mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match>(mySTL::list<yaSSL::SSL_SESSION*>::iterator, mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match); } #endif + diff --git a/extra/yassl/taocrypt/include/runtime.hpp b/extra/yassl/taocrypt/include/runtime.hpp index 70768bb01d1..f506040f0d8 100644 --- a/extra/yassl/taocrypt/include/runtime.hpp +++ b/extra/yassl/taocrypt/include/runtime.hpp @@ -25,7 +25,7 @@ -#if !defined(yaSSL_NEW_HPP) && defined(__GNUC__) +#if !defined(yaSSL_NEW_HPP) && defined(__GNUC__) && !defined(__ICC) #define yaSSL_NEW_HPP diff --git a/extra/yassl/taocrypt/include/types.hpp b/extra/yassl/taocrypt/include/types.hpp index 18961cf4d6f..92164eaaab4 100644 --- a/extra/yassl/taocrypt/include/types.hpp +++ b/extra/yassl/taocrypt/include/types.hpp @@ -31,10 +31,8 @@ namespace TaoCrypt { -// define this if running on a big-endian CPU -#if !defined(LITTLE_ENDIAN_ORDER) && (defined(__BIG_ENDIAN__) || \ - defined(__sparc) || defined(__sparc__) || defined(__hppa__) || \ - defined(__mips__) || (defined(__MWERKS__) && !defined(__INTEL__))) + +#if defined(WORDS_BIGENDIAN) || (defined(__MWERKS__) && !defined(__INTEL__)) #define BIG_ENDIAN_ORDER #endif @@ -47,34 +45,28 @@ typedef unsigned char byte; typedef unsigned short word16; typedef unsigned int word32; -#if defined(__GNUC__) || defined(__MWERKS__) || defined(_LONGLONG_TYPE) - #define WORD64_AVAILABLE - #define WORD64_IS_DISTINCT_TYPE - typedef unsigned long long word64; - #define W64LIT(x) x##LL -#elif defined(_MSC_VER) || defined(__BCPLUSPLUS__) +#if defined(_MSC_VER) || defined(__BCPLUSPLUS__) #define WORD64_AVAILABLE #define WORD64_IS_DISTINCT_TYPE typedef unsigned __int64 word64; - #define W64LIT(x) x##ui64 -#elif defined(__DECCXX) +#elif SIZEOF_LONG == 8 #define WORD64_AVAILABLE typedef unsigned long word64; +#elif SIZEOF_LONG_LONG == 8 + #define WORD64_AVAILABLE + #define WORD64_IS_DISTINCT_TYPE + typedef unsigned long long word64; #endif -// define largest word type -#ifdef WORD64_AVAILABLE - typedef word64 lword; -#else - typedef word32 lword; -#endif +// compilers we've found 64-bit multiply insructions for +#if defined(__GNUC__) || defined(_MSC_VER) || defined(__DECCXX) + #define HAVE_64_MULTIPLY +#endif -// TODO: FIXME, add asm multiply for x86_64 on Solaris and remove !__sun -#if defined(__alpha__) || (defined(__ia64__) && !defined(__INTEL_COMPILER)) || \ - defined(_ARCH_PPC64) || defined(__mips64) || \ - (defined(__x86_64__) && !defined(__sun)) +#if defined(HAVE_64_MULTIPLY) && (defined(__alpha__) || defined(__ia64__) \ + || defined(_ARCH_PPC64) || defined(__mips64) || defined(__x86_64__)) // These platforms have 64-bit CPU registers. Unfortunately most C++ compilers // don't allow any way to access the 64-bit by 64-bit multiply instruction // without using assembly, so in order to use word64 as word, the assembly @@ -84,7 +76,7 @@ typedef unsigned int word32; #else #define TAOCRYPT_NATIVE_DWORD_AVAILABLE #ifdef WORD64_AVAILABLE - #define TAOCRYPT_SLOW_WORD64 + #define TAOCRYPT_SLOW_WORD64 typedef word16 hword; typedef word32 word; typedef word64 dword; diff --git a/extra/yassl/taocrypt/src/Makefile.am b/extra/yassl/taocrypt/src/Makefile.am index 4005be94fb2..5bf45074a98 100644 --- a/extra/yassl/taocrypt/src/Makefile.am +++ b/extra/yassl/taocrypt/src/Makefile.am @@ -6,3 +6,4 @@ libtaocrypt_a_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \ md2.cpp md5.cpp misc.cpp random.cpp ripemd.cpp rsa.cpp sha.cpp \ template_instnt.cpp EXTRA_DIST = ../include/*.hpp +AM_CXXFLAGS = -DYASSL_PURE_C diff --git a/extra/yassl/taocrypt/src/aestables.cpp b/extra/yassl/taocrypt/src/aestables.cpp index 5a125dfd44d..7ba25bc9ffb 100644 --- a/extra/yassl/taocrypt/src/aestables.cpp +++ b/extra/yassl/taocrypt/src/aestables.cpp @@ -21,6 +21,7 @@ /* based on Wei Dai's aestables.cpp from CryptoPP */ +#include "runtime.hpp" #include "aes.hpp" diff --git a/extra/yassl/taocrypt/src/algebra.cpp b/extra/yassl/taocrypt/src/algebra.cpp index e0472f2fc76..45bbcfa662a 100644 --- a/extra/yassl/taocrypt/src/algebra.cpp +++ b/extra/yassl/taocrypt/src/algebra.cpp @@ -319,9 +319,11 @@ void AbstractRing::SimultaneousExponentiate(Integer *results, } // namespace + #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION namespace mySTL { template TaoCrypt::WindowSlider* uninit_copy<TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*>(TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*); template void destroy<TaoCrypt::WindowSlider*>(TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*); } #endif + diff --git a/extra/yassl/taocrypt/src/arc4.cpp b/extra/yassl/taocrypt/src/arc4.cpp index bbd77cd822c..1e521b48f0c 100644 --- a/extra/yassl/taocrypt/src/arc4.cpp +++ b/extra/yassl/taocrypt/src/arc4.cpp @@ -21,6 +21,7 @@ /* based on Wei Dai's arc4.cpp from CryptoPP */ +#include "runtime.hpp" #include "arc4.hpp" diff --git a/extra/yassl/taocrypt/src/coding.cpp b/extra/yassl/taocrypt/src/coding.cpp index 6514ed4d46d..944a47c288e 100644 --- a/extra/yassl/taocrypt/src/coding.cpp +++ b/extra/yassl/taocrypt/src/coding.cpp @@ -22,6 +22,7 @@ /* coding.cpp implements hex and base64 encoding/decoing */ +#include "runtime.hpp" #include "coding.hpp" #include "file.hpp" diff --git a/extra/yassl/taocrypt/src/file.cpp b/extra/yassl/taocrypt/src/file.cpp index 75df80608ae..4d48b9e7bca 100644 --- a/extra/yassl/taocrypt/src/file.cpp +++ b/extra/yassl/taocrypt/src/file.cpp @@ -22,6 +22,7 @@ /* file.cpp implements File Sources and Sinks */ +#include "runtime.hpp" #include "file.hpp" diff --git a/extra/yassl/taocrypt/src/integer.cpp b/extra/yassl/taocrypt/src/integer.cpp index 0f06bb4e044..71324b04b92 100644 --- a/extra/yassl/taocrypt/src/integer.cpp +++ b/extra/yassl/taocrypt/src/integer.cpp @@ -35,7 +35,9 @@ #endif -#if defined(_MSC_VER) && defined(_WIN64) // 64 bit X overflow intrinsic +// 64bit multiply overflow intrinsic +#if defined(_MSC_VER) && defined(_WIN64) && !defined(__INTEL_COMPILER) && \ + !defined(TAOCRYPT_NATIVE_DWORD_AVAILABLE) #ifdef __ia64__ #define myUMULH __UMULH #elif __x86_64__ @@ -3956,6 +3958,7 @@ Integer CRT(const Integer &xp, const Integer &p, const Integer &xq, return p * (u * (xq-xp) % q) + xp; } + #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION #ifndef TAOCRYPT_NATIVE_DWORD_AVAILABLE template hword DivideThreeWordsByTwo<hword, Word>(hword*, hword, hword, Word*); diff --git a/extra/yassl/taocrypt/src/misc.cpp b/extra/yassl/taocrypt/src/misc.cpp index 6a801a9995a..ef051332098 100644 --- a/extra/yassl/taocrypt/src/misc.cpp +++ b/extra/yassl/taocrypt/src/misc.cpp @@ -22,34 +22,43 @@ /* based on Wei Dai's misc.cpp from CryptoPP */ +#include "runtime.hpp" #include "misc.hpp" #include <new> // for NewHandler void* operator new(size_t sz, TaoCrypt::new_t) { +#ifdef YASSL_PURE_C void* ptr = malloc(sz ? sz : 1); if (!ptr) abort(); return ptr; +#else + return ::operator new(sz); +#endif } -void* operator new[](size_t sz, TaoCrypt::new_t) -{ - void* ptr = malloc(sz ? sz : 1); - if (!ptr) abort(); - - return ptr; -} void operator delete(void* ptr, TaoCrypt::new_t) { +#ifdef YASSL_PURE_C if (ptr) free(ptr); +#else + ::operator delete(ptr); +#endif } -void operator delete[](void* ptr, TaoCrypt::new_t) + +void* operator new[](size_t sz, TaoCrypt::new_t nt) { - if (ptr) free(ptr); + return ::operator new(sz, nt); +} + + +void operator delete[](void* ptr, TaoCrypt::new_t nt) +{ + ::operator delete(ptr, nt); } diff --git a/extra/yassl/taocrypt/src/random.cpp b/extra/yassl/taocrypt/src/random.cpp index 69fb180720a..e1e6416eb00 100644 --- a/extra/yassl/taocrypt/src/random.cpp +++ b/extra/yassl/taocrypt/src/random.cpp @@ -24,6 +24,7 @@ specific seed, switch to /dev/random for more security but may block */ +#include "runtime.hpp" #include "random.hpp" #if defined(_WIN32) diff --git a/extra/yassl/taocrypt/src/template_instnt.cpp b/extra/yassl/taocrypt/src/template_instnt.cpp index 28994282669..9a3c12badfc 100644 --- a/extra/yassl/taocrypt/src/template_instnt.cpp +++ b/extra/yassl/taocrypt/src/template_instnt.cpp @@ -1,3 +1,29 @@ +/* template_instnt.cpp + * + * Copyright (C) 2003 Sawtooth Consulting Ltd. + * + * This file is part of yaSSL. + * + * yaSSL 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. + * + * yaSSL 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 + */ + + +/* Explicit template instantiation requests + */ + + #include "integer.hpp" #include "rsa.hpp" #include "algebra.hpp" @@ -6,9 +32,11 @@ #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION namespace TaoCrypt { + #if defined(SSE2_INTRINSICS_AVAILABLE) template AlignedAllocator<unsigned int>::pointer StdReallocate<unsigned int, AlignedAllocator<unsigned int> >(AlignedAllocator<unsigned int>&, unsigned int*, AlignedAllocator<unsigned int>::size_type, AlignedAllocator<unsigned int>::size_type, bool); #endif + template class RSA_Decryptor<RSA_BlockType2>; template class RSA_Encryptor<RSA_BlockType1>; template class RSA_Encryptor<RSA_BlockType2>; @@ -17,10 +45,12 @@ template void tcArrayDelete<byte>(byte*); template AllocatorWithCleanup<byte>::pointer StdReallocate<byte, AllocatorWithCleanup<byte> >(AllocatorWithCleanup<byte>&, byte*, AllocatorWithCleanup<byte>::size_type, AllocatorWithCleanup<byte>::size_type, bool); template void tcArrayDelete<word>(word*); template AllocatorWithCleanup<word>::pointer StdReallocate<word, AllocatorWithCleanup<word> >(AllocatorWithCleanup<word>&, word*, AllocatorWithCleanup<word>::size_type, AllocatorWithCleanup<word>::size_type, bool); + #ifndef TAOCRYPT_SLOW_WORD64 // defined when word != word32 template void tcArrayDelete<word32>(word32*); template AllocatorWithCleanup<word32>::pointer StdReallocate<word32, AllocatorWithCleanup<word32> >(AllocatorWithCleanup<word32>&, word32*, AllocatorWithCleanup<word32>::size_type, AllocatorWithCleanup<word32>::size_type, bool); #endif + template void tcArrayDelete<char>(char*); } diff --git a/include/config-netware.h b/include/config-netware.h index 4a6dc3b1bb9..906f557f608 100644 --- a/include/config-netware.h +++ b/include/config-netware.h @@ -46,11 +46,21 @@ extern "C" { #undef HAVE_SYS_MMAN_H #undef HAVE_SYNCH_H #undef HAVE_MMAP + #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 #define HAVE_PTHREAD_SIGMASK 1 #define HAVE_PTHREAD_YIELD_ZERO_ARG 1 #define HAVE_BROKEN_REALPATH 1 +#undef HAVE_POSIX_SIGNALS +#undef HAVE_PTHREAD_ATTR_SETSCOPE +#undef HAVE_ALLOC_A +#undef HAVE_FINITE +#undef HAVE_GETPWNAM +#undef HAVE_GETPWUID +#undef HAVE_PTHREAD_SETSCHEDPARAM +#undef HAVE_READLINK +#undef HAVE_STPCPY /* no libc crypt() function */ #ifdef HAVE_OPENSSL #define HAVE_CRYPT 1 diff --git a/include/my_base.h b/include/my_base.h index 25fa683744e..c76cf8c604e 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -367,6 +367,7 @@ enum ha_base_keytype { #define HA_STATE_EXTEND_BLOCK 2048 #define HA_STATE_RNEXT_SAME 4096 /* rnext_same was called */ +/* myisampack expects no more than 32 field types. */ enum en_fieldtype { FIELD_LAST=-1,FIELD_NORMAL,FIELD_SKIP_ENDSPACE,FIELD_SKIP_PRESPACE, FIELD_SKIP_ZERO,FIELD_BLOB,FIELD_CONSTANT,FIELD_INTERVALL,FIELD_ZERO, diff --git a/include/my_bitmap.h b/include/my_bitmap.h index e6e985d92d7..e0cc929bce6 100644 --- a/include/my_bitmap.h +++ b/include/my_bitmap.h @@ -46,6 +46,8 @@ extern my_bool bitmap_is_clear_all(const MY_BITMAP *map); extern my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size); extern my_bool bitmap_is_set_all(const MY_BITMAP *map); extern my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2); +extern my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit); +extern my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit); extern uint bitmap_set_next(MY_BITMAP *map); extern uint bitmap_get_first(const MY_BITMAP *map); extern uint bitmap_get_first_set(const MY_BITMAP *map); diff --git a/include/my_global.h b/include/my_global.h index 04d33be38b4..bb1ab71fa70 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -295,10 +295,8 @@ C_MODE_END #include <alloca.h> #endif #ifdef HAVE_ATOMIC_ADD -#if defined(__ia64__) #define new my_arg_new #define need_to_restore_new 1 -#endif C_MODE_START #include <asm/atomic.h> C_MODE_END @@ -341,6 +339,11 @@ C_MODE_END #undef HAVE_FINITE #undef LONGLONG_MIN /* These get wrongly defined in QNX 6.2 */ #undef LONGLONG_MAX /* standard system library 'limits.h' */ +#ifdef __cplusplus +#define HAVE_RINT /* rint() and isnan() functions are not */ +#define rint(a) std::rint(a) /* visible in C++ scope due to an error */ +#define isnan(a) std::isnan(a) /* in the usr/include/math.h on QNX */ +#endif #endif /* We can not live without the following defines */ @@ -393,10 +396,7 @@ int __void__; #endif /* Define some useful general macros */ -#if defined(__cplusplus) && defined(__GNUC__) -#define max(a, b) ((a) >? (b)) -#define min(a, b) ((a) <? (b)) -#elif !defined(max) +#if !defined(max) #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) #endif diff --git a/include/my_sys.h b/include/my_sys.h index a3d6f6827d3..e31659c0652 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -866,6 +866,9 @@ extern void add_compiled_collation(CHARSET_INFO *cs); extern ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to, ulong to_length, const char *from, ulong length); +extern ulong escape_quotes_for_mysql(CHARSET_INFO *charset_info, + char *to, ulong to_length, + const char *from, ulong length); extern void thd_increment_bytes_sent(ulong length); extern void thd_increment_bytes_received(ulong length); diff --git a/include/mysql.h b/include/mysql.h index 84284fa0661..daa29f70e16 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -218,6 +218,18 @@ enum mysql_rpl_type MYSQL_RPL_MASTER, MYSQL_RPL_SLAVE, MYSQL_RPL_ADMIN }; +typedef struct character_set +{ + unsigned int number; /* character set number */ + unsigned int state; /* character set state */ + const char *csname; /* collation name */ + const char *name; /* character set name */ + const char *comment; /* comment */ + const char *dir; /* character set directory */ + unsigned int mbminlen; /* min. length for multibyte strings */ + unsigned int mbmaxlen; /* max. length for multibyte strings */ +} MY_CHARSET_INFO; + struct st_mysql_methods; typedef struct st_mysql @@ -418,6 +430,8 @@ my_bool STDCALL mysql_slave_query(MYSQL *mysql, const char *q, unsigned long length); my_bool STDCALL mysql_slave_send_query(MYSQL *mysql, const char *q, unsigned long length); +void STDCALL mysql_get_character_set_info(MYSQL *mysql, + MY_CHARSET_INFO *charset); /* local infile support */ diff --git a/include/mysql_com.h b/include/mysql_com.h index 2293476c76c..969fba4a433 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -137,17 +137,18 @@ enum enum_server_command #define SERVER_QUERY_NO_GOOD_INDEX_USED 16 #define SERVER_QUERY_NO_INDEX_USED 32 /* - The server was able to fulfill client request and open read-only - non-scrollable cursor for the query. This flag comes in server - status with reply to COM_EXECUTE and COM_EXECUTE_DIRECT commands. + The server was able to fulfill the clients request and opened a + read-only non-scrollable cursor for a query. This flag comes + in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands. */ #define SERVER_STATUS_CURSOR_EXISTS 64 /* - This flag is sent with last row of read-only cursor, in reply to - COM_FETCH command. + This flag is sent when a read-only cursor is exhausted, in reply to + COM_STMT_FETCH command. */ #define SERVER_STATUS_LAST_ROW_SENT 128 #define SERVER_STATUS_DB_DROPPED 256 /* A database was dropped */ +#define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512 #define MYSQL_ERRMSG_SIZE 512 #define NET_READ_TIMEOUT 30 /* Timeout on read */ diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am index 0670a0befa8..4bd9eddafb0 100644 --- a/libmysql/Makefile.am +++ b/libmysql/Makefile.am @@ -23,8 +23,8 @@ target = libmysqlclient.la target_defs = -DUNDEF_THREADS_HACK -DDONT_USE_RAID @LIB_EXTRA_CCFLAGS@ LIBS = @CLIENT_LIBS@ -INCLUDES = -I$(top_srcdir)/include $(openssl_includes) @ZLIB_INCLUDES@ \ - -I$(top_builddir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ + $(openssl_includes) @ZLIB_INCLUDES@ include $(srcdir)/Makefile.shared diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 8ee11519615..2074abd0f85 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1495,6 +1495,21 @@ const char * STDCALL mysql_character_set_name(MYSQL *mysql) return mysql->charset->csname; } +void STDCALL mysql_get_character_set_info(MYSQL *mysql, MY_CHARSET_INFO *csinfo) +{ + csinfo->number = mysql->charset->number; + csinfo->state = mysql->charset->state; + csinfo->csname = mysql->charset->csname; + csinfo->name = mysql->charset->name; + csinfo->comment = mysql->charset->comment; + csinfo->mbminlen = mysql->charset->mbminlen; + csinfo->mbmaxlen = mysql->charset->mbmaxlen; + + if (mysql->options.charset_dir) + csinfo->dir = mysql->options.charset_dir; + else + csinfo->dir = charsets_dir; +} int STDCALL mysql_set_character_set(MYSQL *mysql, char *cs_name) { @@ -1616,7 +1631,14 @@ ulong STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, ulong length) { - return escape_string_for_mysql(mysql->charset, to, 0, from, length); + if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) + { + return escape_quotes_for_mysql(mysql->charset, to, 0, from, length); + } + else + { + return escape_string_for_mysql(mysql->charset, to, 0, from, length); + } } @@ -2726,7 +2748,6 @@ stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row) set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); return 1; } - stmt->server_status= mysql->server_status; if (cli_read_binary_rows(stmt)) return 1; stmt->server_status= mysql->server_status; diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 2da88c271ba..0688ea5732b 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -149,5 +149,6 @@ EXPORTS mysql_server_init mysql_server_end mysql_set_character_set + mysql_get_character_set_info get_defaults_files modify_defaults_file diff --git a/libmysql_r/Makefile.am b/libmysql_r/Makefile.am index 1a69dbb804a..65255066d45 100644 --- a/libmysql_r/Makefile.am +++ b/libmysql_r/Makefile.am @@ -24,8 +24,8 @@ target = libmysqlclient_r.la target_defs = -DDONT_USE_RAID -DMYSQL_CLIENT @LIB_EXTRA_CCFLAGS@ LIBS = @LIBS@ @ZLIB_LIBS@ @openssl_libs@ -INCLUDES = -I$(top_srcdir)/include $(openssl_includes) @ZLIB_INCLUDES@ \ - -I$(top_builddir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ + $(openssl_includes) @ZLIB_INCLUDES@ ## automake barfs if you don't use $(srcdir) or $(top_srcdir) in include include $(top_srcdir)/libmysql/Makefile.shared diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index b4abce128fe..9c322478ad9 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -25,10 +25,10 @@ DEFS = -DEMBEDDED_LIBRARY -DMYSQL_SERVER \ -DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \ -DDATADIR="\"$(MYSQLDATAdir)\"" \ -DSHAREDIR="\"$(MYSQLSHAREdir)\"" -INCLUDES= @bdb_includes@ -I$(top_srcdir)/include \ +INCLUDES= @bdb_includes@ \ + -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(top_srcdir)/sql -I$(top_srcdir)/sql/examples \ -I$(top_srcdir)/regex \ - -I$(top_builddir)/include \ $(openssl_includes) @ZLIB_INCLUDES@ noinst_LIBRARIES = libmysqld_int.a diff --git a/libmysqld/examples/Makefile.am b/libmysqld/examples/Makefile.am index 071a133ca2d..476f297fe0d 100644 --- a/libmysqld/examples/Makefile.am +++ b/libmysqld/examples/Makefile.am @@ -31,9 +31,9 @@ link_sources: done; DEFS = -DEMBEDDED_LIBRARY -INCLUDES = -I$(top_srcdir)/include -I$(srcdir) \ +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(srcdir) \ -I$(top_srcdir) -I$(top_srcdir)/client -I$(top_srcdir)/regex \ - -I$(top_builddir)/include $(openssl_includes) + $(openssl_includes) LIBS = @LIBS@ @WRAPLIBS@ @CLIENT_LIBS@ LDADD = @CLIENT_EXTRA_LDFLAGS@ ../libmysqld.a @innodb_system_libs@ @LIBDL@ $(CXXLDFLAGS) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index dd4ba939ebe..c3b239ac7b9 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -773,7 +773,7 @@ send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message) } void -send_eof(THD *thd, bool no_flush) +send_eof(THD *thd) { } diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index f8e1d99bfab..7c7ceb349a4 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -39,7 +39,7 @@ test_DATA = std_data/client-key.pem std_data/client-cert.pem std_data/cacert.pem std_data/server-cert.pem std_data/server-key.pem CLEANFILES = $(test_SCRIPTS) $(test_DATA) -INCLUDES = -I$(srcdir)/../include -I../include -I.. +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I.. EXTRA_PROGRAMS = mysql_test_run_new noinst_HEADERS = my_manage.h mysql_test_run_new_SOURCES= mysql_test_run_new.c my_manage.c my_create_tables.c @@ -48,6 +48,7 @@ mysql_test_run_new_SOURCES= mysql_test_run_new.c my_manage.c my_create_tables.c dist-hook: mkdir -p $(distdir)/t $(distdir)/r $(distdir)/include \ $(distdir)/std_data $(distdir)/lib + -$(INSTALL_DATA) $(srcdir)/t/*.def $(distdir)/t $(INSTALL_DATA) $(srcdir)/t/*.test $(distdir)/t $(INSTALL_DATA) $(srcdir)/t/*.sql $(distdir)/t -$(INSTALL_DATA) $(srcdir)/t/*.disabled $(distdir)/t @@ -70,6 +71,7 @@ install-data-local: $(DESTDIR)$(testdir)/std_data \ $(DESTDIR)$(testdir)/lib $(INSTALL_DATA) $(srcdir)/README $(DESTDIR)$(testdir) + -$(INSTALL_DATA) $(srcdir)/t/*.def $(DESTDIR)$(testdir)/t $(INSTALL_DATA) $(srcdir)/t/*.test $(DESTDIR)$(testdir)/t $(INSTALL_DATA) $(srcdir)/t/*.sql $(DESTDIR)$(testdir)/t -$(INSTALL_DATA) $(srcdir)/t/*.disabled $(DESTDIR)$(testdir)/t diff --git a/mysql-test/include/not_openssl.inc b/mysql-test/include/not_openssl.inc new file mode 100644 index 00000000000..afe2ed37c28 --- /dev/null +++ b/mysql-test/include/not_openssl.inc @@ -0,0 +1,4 @@ +-- require r/not_openssl.require +disable_query_log; +show variables like "have_openssl"; +enable_query_log; diff --git a/mysql-test/include/ps_create.inc b/mysql-test/include/ps_create.inc index 306ed3f1cac..b2a6fc4b920 100644 --- a/mysql-test/include/ps_create.inc +++ b/mysql-test/include/ps_create.inc @@ -33,7 +33,7 @@ eval create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), - c13 date, c14 datetime, c15 timestamp(14), c16 time, + c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, diff --git a/mysql-test/lib/init_db.sql b/mysql-test/lib/init_db.sql index 9671de49ca5..77f9b18cb08 100644 --- a/mysql-test/lib/init_db.sql +++ b/mysql-test/lib/init_db.sql @@ -128,7 +128,7 @@ CREATE TABLE tables_priv ( Table_name char(64) binary DEFAULT '' NOT NULL, Grantor char(77) DEFAULT '' NOT NULL, Timestamp timestamp(14), - Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter') COLLATE utf8_general_ci DEFAULT '' NOT NULL, + Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL, PRIMARY KEY (Host,Db,User,Table_name),KEY Grantor (Grantor) ) engine=MyISAM diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 2babaabc24c..12714ddc1ad 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -8,7 +8,7 @@ use File::Basename; use strict; sub collect_test_cases ($); -sub collect_one_test_case ($$$$$); +sub collect_one_test_case ($$$$$$); ############################################################################## # @@ -46,18 +46,36 @@ sub collect_test_cases ($) { { mtr_error("Test case $tname ($testdir/$elem) is not found"); } - collect_one_test_case($testdir,$resdir,$tname,$elem,$cases); + collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,{}); } closedir TESTDIR; } else { + # ---------------------------------------------------------------------- + # Skip some tests listed in disabled.def + # ---------------------------------------------------------------------- + my %skiplist; + my $skipfile= "$testdir/disabled.def"; + if ( open(SKIPFILE, $skipfile) ) + { + while ( <SKIPFILE> ) + { + chomp; + if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ ) + { + $skiplist{$1}= $2; + } + } + close SKIPFILE; + } + foreach my $elem ( sort readdir(TESTDIR) ) { my $tname= mtr_match_extension($elem,"test"); next if ! defined $tname; next if $::opt_do_test and ! defined mtr_match_prefix($elem,$::opt_do_test); - collect_one_test_case($testdir,$resdir,$tname,$elem,$cases); + collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%skiplist); } closedir TESTDIR; } @@ -95,12 +113,13 @@ sub collect_test_cases ($) { ############################################################################## -sub collect_one_test_case($$$$$) { +sub collect_one_test_case($$$$$$) { my $testdir= shift; my $resdir= shift; my $tname= shift; my $elem= shift; my $cases= shift; + my $skiplist=shift; my $path= "$testdir/$elem"; @@ -272,6 +291,14 @@ sub collect_one_test_case($$$$$) { } } + # FIXME why this late? + if ( $skiplist->{$tname} ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'disable'}= 1; # Sub type of 'skip' + $tinfo->{'comment'}= $skiplist->{$tname} if $skiplist->{$tname}; + } + if ( -f $disabled ) { $tinfo->{'skip'}= 1; diff --git a/mysql-test/lib/mtr_misc.pl b/mysql-test/lib/mtr_misc.pl index aba6f78c9de..c1aab340a16 100644 --- a/mysql-test/lib/mtr_misc.pl +++ b/mysql-test/lib/mtr_misc.pl @@ -83,18 +83,19 @@ sub mtr_script_exists (@) { } sub mtr_exe_exists (@) { - foreach my $path ( @_ ) + my @path= @_; + map {$_.= ".exe"} @path if $::glob_win32; + foreach my $path ( @path ) { - $path.= ".exe" if $::opt_win32; return $path if -x $path; } - if ( @_ == 1 ) + if ( @path == 1 ) { - mtr_error("Could not find $_[0]"); + mtr_error("Could not find $path[0]"); } else { - mtr_error("Could not find any of " . join(" ", @_)); + mtr_error("Could not find any of " . join(" ", @path)); } } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index e3b35bb1e17..269cdb1340d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -303,7 +303,7 @@ sub mysqld_arguments ($$$$$); sub stop_masters_slaves (); sub stop_masters (); sub stop_slaves (); -sub run_mysqltest ($$); +sub run_mysqltest ($); sub usage ($); ###################################################################### @@ -419,7 +419,8 @@ sub initial_setup () { { # Windows programs like 'mysqld' needs Windows paths $glob_mysql_test_dir= `cygpath -m $glob_mysql_test_dir`; - $glob_cygwin_shell= `cygpath -w $ENV{'SHELL'}`; # The Windows path c:\... + my $shell= $ENV{'SHELL'} || "/bin/bash"; + $glob_cygwin_shell= `cygpath -w $shell`; # The Windows path c:\... chomp($glob_mysql_test_dir); chomp($glob_cygwin_shell); } @@ -791,13 +792,15 @@ sub executable_setup () { my $path_examples= "$glob_basedir/libmysqld/examples"; $exe_mysqltest= mtr_exe_exists("$path_examples/mysqltest"); $exe_mysql_client_test= - mtr_exe_exists("$path_examples/mysql_client_test_embedded"); + mtr_exe_exists("$path_examples/mysql_client_test_embedded", + "/usr/bin/false"); } else { $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/tests/mysql_client_test"); + mtr_exe_exists("$glob_basedir/tests/mysql_client_test", + "/usr/bin/false"); } $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); @@ -819,7 +822,8 @@ sub executable_setup () { $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); $exe_mysql_fix_system_tables= - mtr_script_exists("$path_client_bindir/mysql_fix_privilege_tables"); + mtr_script_exists("$path_client_bindir/mysql_fix_privilege_tables", + "$glob_basedir/scripts/mysql_fix_privilege_tables"); $path_language= mtr_path_exists("$glob_basedir/share/mysql/english/", "$glob_basedir/share/english/"); @@ -833,13 +837,15 @@ sub executable_setup () { $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest_embedded"); $exe_mysql_client_test= mtr_exe_exists("$glob_basedir/tests/mysql_client_test_embedded", - "$path_client_bindir/mysql_client_test_embedded"); + "$path_client_bindir/mysql_client_test_embedded", + "/usr/bin/false"); } else { $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); $exe_mysql_client_test= - mtr_exe_exists("$path_client_bindir/mysql_client_test"); + mtr_exe_exists("$path_client_bindir/mysql_client_test", + "/usr/bin/false"); # FIXME temporary } $path_ndb_tools_dir= "$glob_basedir/bin"; @@ -1342,10 +1348,11 @@ sub run_testcase ($) { if ( ! $glob_use_running_server and ! $glob_use_embedded_server ) { - if ( $tinfo->{'master_restart'} or $master->[0]->{'uses_special_flags'} ) + if ( $tinfo->{'master_restart'} or + $master->[0]->{'running_master_is_special'} ) { stop_masters(); - $master->[0]->{'uses_special_flags'}= 0; # Forget about why we stopped + $master->[0]->{'running_master_is_special'}= 0; # Forget why we stopped } # ---------------------------------------------------------------------- @@ -1423,9 +1430,9 @@ sub run_testcase ($) { } } - if ( @{$tinfo->{'master_opt'}} ) + if ( $tinfo->{'master_restart'} ) { - $master->[0]->{'uses_special_flags'}= 1; + $master->[0]->{'running_master_is_special'}= 1; } } @@ -1472,7 +1479,7 @@ sub run_testcase ($) { } unlink($path_timefile); - my $res= run_mysqltest($tinfo, $tinfo->{'master_opt'}); + my $res= run_mysqltest($tinfo); if ( $res == 0 ) { @@ -1547,17 +1554,18 @@ sub do_before_start_master ($$) { $tname ne "rpl_crash_binlog_ib_3b") { # FIXME we really want separate dir for binlogs - foreach my $bin ( glob("$opt_vardir/log/master*-bin.*") ) + foreach my $bin ( glob("$opt_vardir/log/master*-bin*") ) { unlink($bin); } } + # FIXME only remove the ones that are tied to this master # Remove old master.info and relay-log.info files - unlink("$opt_vardir/master-data/master.info"); - unlink("$opt_vardir/master-data/relay-log.info"); - unlink("$opt_vardir/master1-data/master.info"); - unlink("$opt_vardir/master1-data/relay-log.info"); + unlink("$master->[0]->{'path_myddir'}/master.info"); + unlink("$master->[0]->{'path_myddir'}/relay-log.info"); + unlink("$master->[1]->{'path_myddir'}/master.info"); + unlink("$master->[1]->{'path_myddir'}/relay-log.info"); # Run master initialization shell script if one exists if ( $init_script ) @@ -1584,13 +1592,13 @@ sub do_before_start_slave ($$) { $tname ne "rpl_crash_binlog_ib_3b" ) { # FIXME we really want separate dir for binlogs - foreach my $bin ( glob("$opt_vardir/log/slave*-bin.*") ) + foreach my $bin ( glob("$opt_vardir/log/slave*-bin*") ) { unlink($bin); } # FIXME really master?! - unlink("$opt_vardir/slave-data/master.info"); - unlink("$opt_vardir/slave-data/relay-log.info"); + unlink("$slave->[0]->{'path_myddir'}/master.info"); + unlink("$slave->[0]->{'path_myddir'}/relay-log.info"); } # Run slave initialization shell script if one exists @@ -1604,8 +1612,10 @@ sub do_before_start_slave ($$) { } } - `rm -f $opt_vardir/slave-data/log.*`; -# unlink("$opt_vardir/slave-data/log.*"); + foreach my $bin ( glob("$slave->[0]->{'path_myddir'}/log.*") ) + { + unlink($bin); + } } sub mysqld_arguments ($$$$$) { @@ -1637,6 +1647,7 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--basedir=%s", $prefix, $path_my_basedir); mtr_add_arg($args, "%s--character-sets-dir=%s", $prefix, $path_charsetsdir); mtr_add_arg($args, "%s--core", $prefix); + mtr_add_arg($args, "%s--log-bin-trust-routine-creators", $prefix); mtr_add_arg($args, "%s--default-character-set=latin1", $prefix); mtr_add_arg($args, "%s--language=%s", $prefix, $path_language); mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix); @@ -1651,12 +1662,15 @@ sub mysqld_arguments ($$$$$) { if ( $type eq 'master' ) { - mtr_add_arg($args, "%s--log-bin=%s/log/master-bin", $prefix, $opt_vardir); + my $id= $idx > 0 ? $idx + 101 : 1; + + mtr_add_arg($args, "%s--log-bin=%s/log/master-bin%s", $prefix, + $opt_vardir, $sidx); mtr_add_arg($args, "%s--pid-file=%s", $prefix, $master->[$idx]->{'path_mypid'}); mtr_add_arg($args, "%s--port=%d", $prefix, $master->[$idx]->{'path_myport'}); - mtr_add_arg($args, "%s--server-id=1", $prefix); + mtr_add_arg($args, "%s--server-id=%d", $prefix, $id); mtr_add_arg($args, "%s--socket=%s", $prefix, $master->[$idx]->{'path_mysock'}); mtr_add_arg($args, "%s--innodb_data_file_path=ibdata1:128M:autoextend", $prefix); @@ -1664,6 +1678,11 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--datadir=%s", $prefix, $master->[$idx]->{'path_myddir'}); + if ( $idx > 0 ) + { + mtr_add_arg($args, "%s--skip-innodb", $prefix); + } + if ( $opt_skip_ndbcluster ) { mtr_add_arg($args, "%s--skip-ndbcluster", $prefix); @@ -1673,7 +1692,7 @@ sub mysqld_arguments ($$$$$) { if ( $type eq 'slave' ) { my $slave_server_id= 2 + $idx; - my $slave_rpl_rank= $idx > 0 ? 2 : $slave_server_id; + my $slave_rpl_rank= $slave_server_id; mtr_add_arg($args, "%s--datadir=%s", $prefix, $slave->[$idx]->{'path_myddir'}); @@ -1973,9 +1992,8 @@ sub stop_slaves () { } -sub run_mysqltest ($$) { +sub run_mysqltest ($) { my $tinfo= shift; - my $master_opts= shift; my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " . "--socket=$master->[0]->{'path_mysock'} --password="; diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 79dfcd03df8..4ca591452d2 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -307,7 +307,7 @@ while test $# -gt 0; do --ssl-ca=$MYSQL_TEST_DIR/std_data/cacert.pem \ --ssl-cert=$MYSQL_TEST_DIR/std_data/server-cert.pem \ --ssl-key=$MYSQL_TEST_DIR/std_data/server-key.pem" - MYSQL_TEST_SSL_OPTS="--ssl-ca=$BASEDIR/SSL/cacert.pem \ + MYSQL_TEST_SSL_OPTS="--ssl-ca=$MYSQL_TEST_DIR/std_data/cacert.pem \ --ssl-cert=$MYSQL_TEST_DIR/std_data/client-cert.pem \ --ssl-key=$MYSQL_TEST_DIR/std_data/client-key.pem" ;; --no-manager | --skip-manager) USE_MANAGER=0 ;; @@ -707,6 +707,9 @@ MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST --no-defaults --testcase --user=root --soc if [ "x$USE_EMBEDDED_SERVER" = "x1" ]; then MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST -A --language=$LANGUAGE -A --datadir=$SLAVE_MYDDIR -A --character-sets-dir=$CHARSETSDIR" fi +# Save path and name of mysqldump +MYSQL_DUMP_DIR="$MYSQL_DUMP" +export MYSQL_DUMP_DIR MYSQL_DUMP="$MYSQL_DUMP --no-defaults -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLDUMP_OPT" MYSQL_SHOW="$MYSQL_SHOW -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLSHOW_OPT" MYSQL_BINLOG="$MYSQL_BINLOG --no-defaults --local-load=$MYSQL_TMP_DIR --character-sets-dir=$CHARSETSDIR $EXTRA_MYSQLBINLOG_OPT" diff --git a/mysql-test/mysql_test_run_new.c b/mysql-test/mysql_test_run_new.c index b8e7f1ba2b7..b23b7ceb6a1 100644 --- a/mysql-test/mysql_test_run_new.c +++ b/mysql-test/mysql_test_run_new.c @@ -486,6 +486,7 @@ void start_master() #endif add_arg(&al, "--local-infile"); add_arg(&al, "--core"); + add_arg(&al, "--log-bin-trust-routine-creators"); add_arg(&al, "--datadir=%s", master_dir); #ifndef __WIN__ add_arg(&al, "--pid-file=%s", master_pid); diff --git a/mysql-test/r/alias.result b/mysql-test/r/alias.result index 395f49f3635..6f0315da234 100644 --- a/mysql-test/r/alias.result +++ b/mysql-test/r/alias.result @@ -27,7 +27,7 @@ hdl_name varchar(30) default NULL, prov_hdl_nr int(11) NOT NULL default '0', auto_wirknetz varchar(50) default NULL, auto_billing varchar(50) default NULL, -touch timestamp(14) NOT NULL, +touch timestamp NOT NULL, kategorie varchar(50) default NULL, kundentyp varchar(20) NOT NULL default '', sammel_rech_msisdn varchar(30) NOT NULL default '', diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index 793e50cf653..54780dbbd22 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -2617,6 +2617,1220 @@ auto fld1 companynr fld3 fld4 fld5 fld6 2 011401 37 breaking dreaded Steinberg W 3 011402 37 Romans scholastics jarring 4 011403 37 intercepted audiology tinily +INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W'); +INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring',''); +INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); +OPTIMIZE TABLE t2 EXTENDED; +Table Op Msg_type Msg_text +test.t2 optimize status OK +SELECT * FROM t2; +auto fld1 companynr fld3 fld4 fld5 fld6 +1 000001 00 Omaha teethe neat +2 011401 37 breaking dreaded Steinberg W +3 011402 37 Romans scholastics jarring +4 011403 37 intercepted audiology tinily +5 011501 37 bewilderingly wallet balled +6 011701 37 astound parters persist W +7 011702 37 admonishing eschew attainments +8 011703 37 sumac quitter fanatic +9 012001 37 flanking neat measures FAS +10 012003 37 combed Steinberg rightfulness +11 012004 37 subjective jarring capably +12 012005 37 scatterbrain tinily impulsive +13 012301 37 Eulerian balled starlet +14 012302 36 dubbed persist terminators +15 012303 37 Kane attainments untying +16 012304 37 overlay fanatic announces FAS +17 012305 37 perturb measures featherweight FAS +18 012306 37 goblins rightfulness pessimist FAS +19 012501 37 annihilates capably daughter +20 012602 37 Wotan impulsive decliner FAS +21 012603 37 snatching starlet lawgiver +22 012604 37 concludes terminators stated +23 012605 37 laterally untying readable +24 012606 37 yelped announces attrition +25 012701 37 grazing featherweight cascade FAS +26 012702 37 Baird pessimist motors FAS +27 012703 37 celery daughter interrogate +28 012704 37 misunderstander decliner pests W +29 013601 37 handgun lawgiver stairway +30 013602 37 foldout stated dopers FAS +31 013603 37 mystic readable testicle W +32 013604 37 succumbed attrition Parsifal W +33 013605 37 Nabisco cascade leavings +34 013606 37 fingerings motors postulation W +35 013607 37 aging interrogate squeaking +36 013608 37 afield pests contrasted +37 013609 37 ammonium stairway leftover +38 013610 37 boat dopers whiteners +39 013801 37 intelligibility testicle erases W +40 013802 37 Augustine Parsifal Punjab W +41 013803 37 teethe leavings Merritt +42 013804 37 dreaded postulation Quixotism +43 013901 37 scholastics squeaking sweetish FAS +44 016001 37 audiology contrasted dogging FAS +45 016201 37 wallet leftover scornfully FAS +46 016202 37 parters whiteners bellow +47 016301 37 eschew erases bills +48 016302 37 quitter Punjab cupboard FAS +49 016303 37 neat Merritt sureties FAS +50 016304 37 Steinberg Quixotism puddings +51 018001 37 jarring sweetish tapestry +52 018002 37 tinily dogging fetters +53 018003 37 balled scornfully bivalves +54 018004 37 persist bellow incurring +55 018005 37 attainments bills Adolph +56 018007 37 fanatic cupboard pithed +57 018008 37 measures sureties emergency +58 018009 37 rightfulness puddings Miles +59 018010 37 capably tapestry trimmings +60 018012 37 impulsive fetters tragedies W +61 018013 37 starlet bivalves skulking W +62 018014 37 terminators incurring flint +63 018015 37 untying Adolph flopping W +64 018016 37 announces pithed relaxing FAS +65 018017 37 featherweight emergency offload FAS +66 018018 37 pessimist Miles suites W +67 018019 37 daughter trimmings lists FAS +68 018020 37 decliner tragedies animized FAS +69 018021 37 lawgiver skulking multilayer W +70 018022 37 stated flint standardizes FAS +71 018023 37 readable flopping Judas +72 018024 37 attrition relaxing vacuuming W +73 018025 37 cascade offload dentally W +74 018026 37 motors suites humanness W +75 018027 37 interrogate lists inch W +76 018028 37 pests animized Weissmuller W +77 018029 37 stairway multilayer irresponsibly W +78 018030 37 dopers standardizes luckily FAS +79 018032 37 testicle Judas culled W +80 018033 37 Parsifal vacuuming medical FAS +81 018034 37 leavings dentally bloodbath FAS +82 018035 37 postulation humanness subschema W +83 018036 37 squeaking inch animals W +84 018037 37 contrasted Weissmuller Micronesia +85 018038 37 leftover irresponsibly repetitions +86 018039 37 whiteners luckily Antares +87 018040 37 erases culled ventilate W +88 018041 37 Punjab medical pityingly +89 018042 37 Merritt bloodbath interdependent +90 018043 37 Quixotism subschema Graves FAS +91 018044 37 sweetish animals neonatal +92 018045 37 dogging Micronesia scribbled FAS +93 018046 37 scornfully repetitions chafe W +94 018048 37 bellow Antares honoring +95 018049 37 bills ventilate realtor +96 018050 37 cupboard pityingly elite +97 018051 37 sureties interdependent funereal +98 018052 37 puddings Graves abrogating +99 018053 50 tapestry neonatal sorters +100 018054 37 fetters scribbled Conley +101 018055 37 bivalves chafe lectured +102 018056 37 incurring honoring Abraham +103 018057 37 Adolph realtor Hawaii W +104 018058 37 pithed elite cage +105 018059 36 emergency funereal hushes +106 018060 37 Miles abrogating Simla +107 018061 37 trimmings sorters reporters +108 018101 37 tragedies Conley Dutchman FAS +109 018102 37 skulking lectured descendants FAS +110 018103 37 flint Abraham groupings FAS +111 018104 37 flopping Hawaii dissociate +112 018201 37 relaxing cage coexist W +113 018202 37 offload hushes Beebe +114 018402 37 suites Simla Taoism +115 018403 37 lists reporters Connally +116 018404 37 animized Dutchman fetched FAS +117 018405 37 multilayer descendants checkpoints FAS +118 018406 37 standardizes groupings rusting +119 018409 37 Judas dissociate galling +120 018601 37 vacuuming coexist obliterates +121 018602 37 dentally Beebe traitor +122 018603 37 humanness Taoism resumes FAS +123 018801 37 inch Connally analyzable FAS +124 018802 37 Weissmuller fetched terminator FAS +125 018803 37 irresponsibly checkpoints gritty FAS +126 018804 37 luckily rusting firearm W +127 018805 37 culled galling minima +128 018806 37 medical obliterates Selfridge +129 018807 37 bloodbath traitor disable +130 018808 37 subschema resumes witchcraft W +131 018809 37 animals analyzable betroth W +132 018810 37 Micronesia terminator Manhattanize +133 018811 37 repetitions gritty imprint +134 018812 37 Antares firearm peeked +135 019101 37 ventilate minima swelling +136 019102 37 pityingly Selfridge interrelationships W +137 019103 37 interdependent disable riser +138 019201 37 Graves witchcraft Gandhian W +139 030501 37 neonatal betroth peacock A +140 030502 50 scribbled Manhattanize bee A +141 030503 37 chafe imprint kanji +142 030504 37 honoring peeked dental +143 031901 37 realtor swelling scarf FAS +144 036001 37 elite interrelationships chasm A +145 036002 37 funereal riser insolence A +146 036004 37 abrogating Gandhian syndicate +147 036005 37 sorters peacock alike +148 038001 37 Conley bee imperial A +149 038002 37 lectured kanji convulsion A +150 038003 37 Abraham dental railway A +151 038004 37 Hawaii scarf validate A +152 038005 37 cage chasm normalizes A +153 038006 37 hushes insolence comprehensive +154 038007 37 Simla syndicate chewing +155 038008 37 reporters alike denizen +156 038009 37 Dutchman imperial schemer +157 038010 37 descendants convulsion chronicle +158 038011 37 groupings railway Kline +159 038012 37 dissociate validate Anatole +160 038013 37 coexist normalizes partridges +161 038014 37 Beebe comprehensive brunch +162 038015 37 Taoism chewing recruited +163 038016 37 Connally denizen dimensions W +164 038017 37 fetched schemer Chicana W +165 038018 37 checkpoints chronicle announced +166 038101 37 rusting Kline praised FAS +167 038102 37 galling Anatole employing +168 038103 37 obliterates partridges linear +169 038104 37 traitor brunch quagmire +170 038201 37 resumes recruited western A +171 038202 37 analyzable dimensions relishing +172 038203 37 terminator Chicana serving A +173 038204 37 gritty announced scheduling +174 038205 37 firearm praised lore +175 038206 37 minima employing eventful +176 038208 37 Selfridge linear arteriole A +177 042801 37 disable quagmire disentangle +178 042802 37 witchcraft western cured A +179 046101 37 betroth relishing Fenton W +180 048001 37 Manhattanize serving avoidable A +181 048002 37 imprint scheduling drains A +182 048003 37 peeked lore detectably FAS +183 048004 37 swelling eventful husky +184 048005 37 interrelationships arteriole impelling +185 048006 37 riser disentangle undoes +186 048007 37 Gandhian cured evened +187 048008 37 peacock Fenton squeezes +188 048101 37 bee avoidable destroyer FAS +189 048102 37 kanji drains rudeness +190 048201 37 dental detectably beaner FAS +191 048202 37 scarf husky boorish +192 048203 37 chasm impelling Everhart +193 048204 37 insolence undoes encompass A +194 048205 37 syndicate evened mushrooms +195 048301 37 alike squeezes Alison A +196 048302 37 imperial destroyer externally FAS +197 048303 37 convulsion rudeness pellagra +198 048304 37 railway beaner cult +199 048305 37 validate boorish creek A +200 048401 37 normalizes Everhart Huffman +201 048402 37 comprehensive encompass Majorca FAS +202 048403 37 chewing mushrooms governing A +203 048404 37 denizen Alison gadfly FAS +204 048405 37 schemer externally reassigned FAS +205 048406 37 chronicle pellagra intentness W +206 048407 37 Kline cult craziness +207 048408 37 Anatole creek psychic +208 048409 37 partridges Huffman squabbled +209 048410 37 brunch Majorca burlesque +210 048411 37 recruited governing capped +211 048412 37 dimensions gadfly extracted A +212 048413 37 Chicana reassigned DiMaggio +213 048601 37 announced intentness exclamation FAS +214 048602 37 praised craziness subdirectory +215 048603 37 employing psychic fangs +216 048604 37 linear squabbled buyer A +217 048801 37 quagmire burlesque pithing A +218 050901 37 western capped transistorizing A +219 051201 37 relishing extracted nonbiodegradable +220 056002 37 serving DiMaggio dislocate +221 056003 37 scheduling exclamation monochromatic FAS +222 056004 37 lore subdirectory batting +223 056102 37 eventful fangs postcondition A +224 056203 37 arteriole buyer catalog FAS +225 056204 37 disentangle pithing Remus +226 058003 37 cured transistorizing devices A +227 058004 37 Fenton nonbiodegradable bike A +228 058005 37 avoidable dislocate qualify +229 058006 37 drains monochromatic detained +230 058007 37 detectably batting commended +231 058101 37 husky postcondition civilize +232 058102 37 impelling catalog Elmhurst +233 058103 37 undoes Remus anesthetizing +234 058105 37 evened devices deaf +235 058111 37 squeezes bike Brigham +236 058112 37 destroyer qualify title +237 058113 37 rudeness detained coarse +238 058114 37 beaner commended combinations +239 058115 37 boorish civilize grayness +240 058116 37 Everhart Elmhurst innumerable FAS +241 058117 37 encompass anesthetizing Caroline A +242 058118 37 mushrooms deaf fatty FAS +243 058119 37 Alison Brigham eastbound +244 058120 37 externally title inexperienced +245 058121 37 pellagra coarse hoarder A +246 058122 37 cult combinations scotch W +247 058123 37 creek grayness passport A +248 058124 37 Huffman innumerable strategic FAS +249 058125 37 Majorca Caroline gated +250 058126 37 governing fatty flog +251 058127 37 gadfly eastbound Pipestone +252 058128 37 reassigned inexperienced Dar +253 058201 37 intentness hoarder Corcoran +254 058202 37 craziness scotch flyers A +255 058303 37 psychic passport competitions W +256 058304 37 squabbled strategic suppliers FAS +257 058602 37 burlesque gated skips +258 058603 37 capped flog institutes +259 058604 37 extracted Pipestone troop A +260 058605 37 DiMaggio Dar connective W +261 058606 37 exclamation Corcoran denies +262 058607 37 subdirectory flyers polka +263 060401 36 fangs competitions observations FAS +264 061701 36 buyer suppliers askers +265 066201 36 pithing skips homeless FAS +266 066501 36 transistorizing institutes Anna +267 068001 36 nonbiodegradable troop subdirectories W +268 068002 36 dislocate connective decaying FAS +269 068005 36 monochromatic denies outwitting W +270 068006 36 batting polka Harpy W +271 068007 36 postcondition observations crazed +272 068008 36 catalog askers suffocate +273 068009 36 Remus homeless provers FAS +274 068010 36 devices Anna technically +275 068011 36 bike subdirectories Franklinizations +276 068202 36 qualify decaying considered +277 068302 36 detained outwitting tinnily +278 068303 36 commended Harpy uninterruptedly +279 068401 36 civilize crazed whistled A +280 068501 36 Elmhurst suffocate automate +281 068502 36 anesthetizing provers gutting W +282 068503 36 deaf technically surreptitious +283 068602 36 Brigham Franklinizations Choctaw +284 068603 36 title considered cooks +285 068701 36 coarse tinnily millivolt FAS +286 068702 36 combinations uninterruptedly counterpoise +287 068703 36 grayness whistled Gothicism +288 076001 36 innumerable automate feminine +289 076002 36 Caroline gutting metaphysically W +290 076101 36 fatty surreptitious sanding A +291 076102 36 eastbound Choctaw contributorily +292 076103 36 inexperienced cooks receivers FAS +293 076302 36 hoarder millivolt adjourn +294 076303 36 scotch counterpoise straggled A +295 076304 36 passport Gothicism druggists +296 076305 36 strategic feminine thanking FAS +297 076306 36 gated metaphysically ostrich +298 076307 36 flog sanding hopelessness FAS +299 076402 36 Pipestone contributorily Eurydice +300 076501 36 Dar receivers excitation W +301 076502 36 Corcoran adjourn presumes FAS +302 076701 36 flyers straggled imaginable FAS +303 078001 36 competitions druggists concoct W +304 078002 36 suppliers thanking peering W +305 078003 36 skips ostrich Phelps FAS +306 078004 36 institutes hopelessness ferociousness FAS +307 078005 36 troop Eurydice sentences +308 078006 36 connective excitation unlocks +309 078007 36 denies presumes engrossing W +310 078008 36 polka imaginable Ruth +311 078101 36 observations concoct tying +312 078103 36 askers peering exclaimers +313 078104 36 homeless Phelps synergy +314 078105 36 Anna ferociousness Huey W +315 082101 36 subdirectories sentences merging +316 083401 36 decaying unlocks judges A +317 084001 36 outwitting engrossing Shylock W +318 084002 36 Harpy Ruth Miltonism +319 086001 36 crazed tying hen W +320 086102 36 suffocate exclaimers honeybee FAS +321 086201 36 provers synergy towers +322 088001 36 technically Huey dilutes W +323 088002 36 Franklinizations merging numerals FAS +324 088003 36 considered judges democracy FAS +325 088004 36 tinnily Shylock Ibero- +326 088101 36 uninterruptedly Miltonism invalids +327 088102 36 whistled hen behavior +328 088103 36 automate honeybee accruing +329 088104 36 gutting towers relics A +330 088105 36 surreptitious dilutes rackets +331 088106 36 Choctaw numerals Fischbein W +332 088201 36 cooks democracy phony W +333 088203 36 millivolt Ibero- cross FAS +334 088204 36 counterpoise invalids cleanup +335 088302 37 Gothicism behavior conspirator +336 088303 37 feminine accruing label FAS +337 088305 37 metaphysically relics university +338 088402 37 sanding rackets cleansed FAS +339 088501 36 contributorily Fischbein ballgown +340 088502 36 receivers phony starlet +341 088503 36 adjourn cross aqueous +342 098001 58 straggled cleanup portrayal A +343 098002 58 druggists conspirator despising W +344 098003 58 thanking label distort W +345 098004 58 ostrich university palmed +346 098005 58 hopelessness cleansed faced +347 098006 58 Eurydice ballgown silverware +348 141903 29 excitation starlet assessor +349 098008 58 presumes aqueous spiders +350 098009 58 imaginable portrayal artificially +351 098010 58 concoct despising reminiscence +352 098011 58 peering distort Mexican +353 098012 58 Phelps palmed obnoxious +354 098013 58 ferociousness faced fragile +355 098014 58 sentences silverware apprehensible +356 098015 58 unlocks assessor births +357 098016 58 engrossing spiders garages +358 098017 58 Ruth artificially panty +359 098018 58 tying reminiscence anteater +360 098019 58 exclaimers Mexican displacement A +361 098020 58 synergy obnoxious drovers A +362 098021 58 Huey fragile patenting A +363 098022 58 merging apprehensible far A +364 098023 58 judges births shrieks +365 098024 58 Shylock garages aligning W +366 098025 37 Miltonism panty pragmatism +367 106001 36 hen anteater fevers W +368 108001 36 honeybee displacement reexamines A +369 108002 36 towers drovers occupancies +370 108003 36 dilutes patenting sweats FAS +371 108004 36 numerals far modulators +372 108005 36 democracy shrieks demand W +373 108007 36 Ibero- aligning Madeira +374 108008 36 invalids pragmatism Viennese W +375 108009 36 behavior fevers chillier W +376 108010 36 accruing reexamines wildcats FAS +377 108011 36 relics occupancies gentle +378 108012 36 rackets sweats Angles W +379 108101 36 Fischbein modulators accuracies +380 108102 36 phony demand toggle +381 108103 36 cross Madeira Mendelssohn W +382 108111 50 cleanup Viennese behaviorally +383 108105 36 conspirator chillier Rochford +384 108106 36 label wildcats mirror W +385 108107 36 university gentle Modula +386 108108 50 cleansed Angles clobbering +387 108109 36 ballgown accuracies chronography +388 108110 36 starlet toggle Eskimoizeds +389 108201 36 aqueous Mendelssohn British W +390 108202 36 portrayal behaviorally pitfalls +391 108203 36 despising Rochford verify W +392 108204 36 distort mirror scatter FAS +393 108205 36 palmed Modula Aztecan +394 108301 36 faced clobbering acuity W +395 108302 36 silverware chronography sinking W +396 112101 36 assessor Eskimoizeds beasts FAS +397 112102 36 spiders British Witt W +398 113701 36 artificially pitfalls physicists FAS +399 116001 36 reminiscence verify folksong A +400 116201 36 Mexican scatter strokes FAS +401 116301 36 obnoxious Aztecan crowder +402 116302 36 fragile acuity merry +403 116601 36 apprehensible sinking cadenced +404 116602 36 births beasts alimony A +405 116603 36 garages Witt principled A +406 116701 36 panty physicists golfing +407 116702 36 anteater folksong undiscovered +408 118001 36 displacement strokes irritates +409 118002 36 drovers crowder patriots A +410 118003 36 patenting merry rooms FAS +411 118004 36 far cadenced towering W +412 118005 36 shrieks alimony displease +413 118006 36 aligning principled photosensitive +414 118007 36 pragmatism golfing inking +415 118008 36 fevers undiscovered gainers +416 118101 36 reexamines irritates leaning A +417 118102 36 occupancies patriots hydrant A +418 118103 36 sweats rooms preserve +419 118202 36 modulators towering blinded A +420 118203 36 demand displease interactions A +421 118204 36 Madeira photosensitive Barry +422 118302 36 Viennese inking whiteness A +423 118304 36 chillier gainers pastimes W +424 118305 36 wildcats leaning Edenization +425 118306 36 gentle hydrant Muscat +426 118307 36 Angles preserve assassinated +427 123101 36 accuracies blinded labeled +428 123102 36 toggle interactions glacial A +429 123301 36 Mendelssohn Barry implied W +430 126001 36 behaviorally whiteness bibliographies W +431 126002 36 Rochford pastimes Buchanan +432 126003 36 mirror Edenization forgivably FAS +433 126101 36 Modula Muscat innuendo A +434 126301 36 clobbering assassinated den FAS +435 126302 36 chronography labeled submarines W +436 126402 36 Eskimoizeds glacial mouthful A +437 126601 36 British implied expiring +438 126602 36 pitfalls bibliographies unfulfilled FAS +439 126702 36 verify Buchanan precession +440 128001 36 scatter forgivably nullified +441 128002 36 Aztecan innuendo affects +442 128003 36 acuity den Cynthia +443 128004 36 sinking submarines Chablis A +444 128005 36 beasts mouthful betterments FAS +445 128007 36 Witt expiring advertising +446 128008 36 physicists unfulfilled rubies A +447 128009 36 folksong precession southwest FAS +448 128010 36 strokes nullified superstitious A +449 128011 36 crowder affects tabernacle W +450 128012 36 merry Cynthia silk A +451 128013 36 cadenced Chablis handsomest A +452 128014 36 alimony betterments Persian A +453 128015 36 principled advertising analog W +454 128016 36 golfing rubies complex W +455 128017 36 undiscovered southwest Taoist +456 128018 36 irritates superstitious suspend +457 128019 36 patriots tabernacle relegated +458 128020 36 rooms silk awesome W +459 128021 36 towering handsomest Bruxelles +460 128022 36 displease Persian imprecisely A +461 128023 36 photosensitive analog televise +462 128101 36 inking complex braking +463 128102 36 gainers Taoist true FAS +464 128103 36 leaning suspend disappointing FAS +465 128104 36 hydrant relegated navally W +466 128106 36 preserve awesome circus +467 128107 36 blinded Bruxelles beetles +468 128108 36 interactions imprecisely trumps +469 128202 36 Barry televise fourscore W +470 128203 36 whiteness braking Blackfoots +471 128301 36 pastimes true Grady +472 128302 36 Edenization disappointing quiets FAS +473 128303 36 Muscat navally floundered FAS +474 128304 36 assassinated circus profundity W +475 128305 36 labeled beetles Garrisonian W +476 128307 36 glacial trumps Strauss +477 128401 36 implied fourscore cemented FAS +478 128502 36 bibliographies Blackfoots contrition A +479 128503 36 Buchanan Grady mutations +480 128504 36 forgivably quiets exhibits W +481 128505 36 innuendo floundered tits +482 128601 36 den profundity mate A +483 128603 36 submarines Garrisonian arches +484 128604 36 mouthful Strauss Moll +485 128702 36 expiring cemented ropers +486 128703 36 unfulfilled contrition bombast +487 128704 36 precession mutations difficultly A +488 138001 36 nullified exhibits adsorption +489 138002 36 affects tits definiteness FAS +490 138003 36 Cynthia mate cultivation A +491 138004 36 Chablis arches heals A +492 138005 36 betterments Moll Heusen W +493 138006 36 advertising ropers target FAS +494 138007 36 rubies bombast cited A +495 138008 36 southwest difficultly congresswoman W +496 138009 36 superstitious adsorption Katherine +497 138102 36 tabernacle definiteness titter A +498 138103 36 silk cultivation aspire A +499 138104 36 handsomest heals Mardis +500 138105 36 Persian Heusen Nadia W +501 138201 36 analog target estimating FAS +502 138302 36 complex cited stuck A +503 138303 36 Taoist congresswoman fifteenth A +504 138304 36 suspend Katherine Colombo +505 138401 29 relegated titter survey A +506 140102 29 awesome aspire staffing +507 140103 29 Bruxelles Mardis obtain +508 140104 29 imprecisely Nadia loaded +509 140105 29 televise estimating slaughtered +510 140201 29 braking stuck lights A +511 140701 29 true fifteenth circumference +512 141501 29 disappointing Colombo dull A +513 141502 29 navally survey weekly A +514 141901 29 circus staffing wetness +515 141902 29 beetles obtain visualized +516 142101 29 trumps loaded Tannenbaum +517 142102 29 fourscore slaughtered moribund +518 142103 29 Blackfoots lights demultiplex +519 142701 29 Grady circumference lockings +520 143001 29 quiets dull thugs FAS +521 143501 29 floundered weekly unnerves +522 143502 29 profundity wetness abut +523 148001 29 Garrisonian visualized Chippewa A +524 148002 29 Strauss Tannenbaum stratifications A +525 148003 29 cemented moribund signaled +526 148004 29 contrition demultiplex Italianizes A +527 148005 29 mutations lockings algorithmic A +528 148006 29 exhibits thugs paranoid FAS +529 148007 29 tits unnerves camping A +530 148009 29 mate abut signifying A +531 148010 29 arches Chippewa Patrice W +532 148011 29 Moll stratifications search A +533 148012 29 ropers signaled Angeles A +534 148013 29 bombast Italianizes semblance +535 148023 36 difficultly algorithmic taxed +536 148015 29 adsorption paranoid Beatrice +537 148016 29 definiteness camping retrace +538 148017 29 cultivation signifying lockout +539 148018 29 heals Patrice grammatic +540 148019 29 Heusen search helmsman +541 148020 29 target Angeles uniform W +542 148021 29 cited semblance hamming +543 148022 29 congresswoman taxed disobedience +544 148101 29 Katherine Beatrice captivated A +545 148102 29 titter retrace transferals A +546 148201 29 aspire lockout cartographer A +547 148401 29 Mardis grammatic aims FAS +548 148402 29 Nadia helmsman Pakistani +549 148501 29 estimating uniform burglarized FAS +550 148502 29 stuck hamming saucepans A +551 148503 29 fifteenth disobedience lacerating A +552 148504 29 Colombo captivated corny +553 148601 29 survey transferals megabytes FAS +554 148602 29 staffing cartographer chancellor +555 150701 29 obtain aims bulk A +556 152101 29 loaded Pakistani commits A +557 152102 29 slaughtered burglarized meson W +558 155202 36 lights saucepans deputies +559 155203 29 circumference lacerating northeaster A +560 155204 29 dull corny dipole +561 155205 29 weekly megabytes machining 0 +562 156001 29 wetness chancellor therefore +563 156002 29 visualized bulk Telefunken +564 156102 29 Tannenbaum commits salvaging +565 156301 29 moribund meson Corinthianizes A +566 156302 29 demultiplex deputies restlessly A +567 156303 29 lockings northeaster bromides +568 156304 29 thugs dipole generalized A +569 156305 29 unnerves machining mishaps +570 156306 29 abut therefore quelling +571 156501 29 Chippewa Telefunken spiritual A +572 158001 29 stratifications salvaging beguiles FAS +573 158002 29 signaled Corinthianizes Trobriand FAS +574 158101 29 Italianizes restlessly fleeing A +575 158102 29 algorithmic bromides Armour A +576 158103 29 paranoid generalized chin A +577 158201 29 camping mishaps provers A +578 158202 29 signifying quelling aeronautic A +579 158203 29 Patrice spiritual voltage W +580 158204 29 search beguiles sash +581 158301 29 Angeles Trobriand anaerobic A +582 158302 29 semblance fleeing simultaneous A +583 158303 29 taxed Armour accumulating A +584 158304 29 Beatrice chin Medusan A +585 158305 29 retrace provers shouted A +586 158306 29 lockout aeronautic freakish +587 158501 29 grammatic voltage index FAS +588 160301 29 helmsman sash commercially +589 166101 50 uniform anaerobic mistiness A +590 166102 50 hamming simultaneous endpoint +591 168001 29 disobedience accumulating straight A +592 168002 29 captivated Medusan flurried +593 168003 29 transferals shouted denotative A +594 168101 29 cartographer freakish coming FAS +595 168102 29 aims index commencements FAS +596 168103 29 Pakistani commercially gentleman +597 168104 29 burglarized mistiness gifted +598 168202 29 saucepans endpoint Shanghais +599 168301 29 lacerating straight sportswriting A +600 168502 29 corny flurried sloping A +601 168503 29 megabytes denotative navies +602 168601 29 chancellor coming leaflet A +603 173001 40 bulk commencements shooter +604 173701 40 commits gentleman Joplin FAS +605 173702 40 meson gifted babies +606 176001 40 deputies Shanghais subdivision FAS +607 176101 40 northeaster sportswriting burstiness W +608 176201 40 dipole sloping belted FAS +609 176401 40 machining navies assails FAS +610 176501 40 therefore leaflet admiring W +611 176601 40 Telefunken shooter swaying 0 +612 176602 40 salvaging Joplin Goldstine FAS +613 176603 40 Corinthianizes babies fitting +614 178001 40 restlessly subdivision Norwalk W +615 178002 40 bromides burstiness weakening W +616 178003 40 generalized belted analogy FAS +617 178004 40 mishaps assails deludes +618 178005 40 quelling admiring cokes +619 178006 40 spiritual swaying Clayton +620 178007 40 beguiles Goldstine exhausts +621 178008 40 Trobriand fitting causality +622 178101 40 fleeing Norwalk sating FAS +623 178102 40 Armour weakening icon +624 178103 40 chin analogy throttles +625 178201 40 provers deludes communicants FAS +626 178202 40 aeronautic cokes dehydrate FAS +627 178301 40 voltage Clayton priceless FAS +628 178302 40 sash exhausts publicly +629 178401 40 anaerobic causality incidentals FAS +630 178402 40 simultaneous sating commonplace +631 178403 40 accumulating icon mumbles +632 178404 40 Medusan throttles furthermore W +633 178501 40 shouted communicants cautioned W +634 186002 37 freakish dehydrate parametrized A +635 186102 37 index priceless registration A +636 186201 40 commercially publicly sadly FAS +637 186202 40 mistiness incidentals positioning +638 186203 40 endpoint commonplace babysitting +639 186302 37 straight mumbles eternal A +640 188007 37 flurried furthermore hoarder +641 188008 37 denotative cautioned congregates +642 188009 37 coming parametrized rains +643 188010 37 commencements registration workers W +644 188011 37 gentleman sadly sags A +645 188012 37 gifted positioning unplug W +646 188013 37 Shanghais babysitting garage A +647 188014 37 sportswriting eternal boulder A +648 188015 37 sloping hoarder hollowly A +649 188016 37 navies congregates specifics +650 188017 37 leaflet rains Teresa +651 188102 37 shooter workers Winsett +652 188103 37 Joplin sags convenient A +653 188202 37 babies unplug buckboards FAS +654 188301 40 subdivision garage amenities +655 188302 40 burstiness boulder resplendent FAS +656 188303 40 belted hollowly priding FAS +657 188401 37 assails specifics configurations +658 188402 37 admiring Teresa untidiness A +659 188503 37 swaying Winsett Brice W +660 188504 37 Goldstine convenient sews FAS +661 188505 37 fitting buckboards participated +662 190701 37 Norwalk amenities Simon FAS +663 190703 50 weakening resplendent certificates +664 191701 37 analogy priding Fitzpatrick +665 191702 37 deludes configurations Evanston A +666 191703 37 cokes untidiness misted +667 196001 37 Clayton Brice textures A +668 196002 37 exhausts sews save +669 196003 37 causality participated count +670 196101 37 sating Simon rightful A +671 196103 37 icon certificates chaperone +672 196104 37 throttles Fitzpatrick Lizzy A +673 196201 37 communicants Evanston clenched A +674 196202 37 dehydrate misted effortlessly +675 196203 37 priceless textures accessed +676 198001 37 publicly save beaters A +677 198003 37 incidentals count Hornblower FAS +678 198004 37 commonplace rightful vests A +679 198005 37 mumbles chaperone indulgences FAS +680 198006 37 furthermore Lizzy infallibly A +681 198007 37 cautioned clenched unwilling FAS +682 198008 37 parametrized effortlessly excrete FAS +683 198009 37 registration accessed spools A +684 198010 37 sadly beaters crunches FAS +685 198011 37 positioning Hornblower overestimating FAS +686 198012 37 babysitting vests ineffective +687 198013 37 eternal indulgences humiliation A +688 198014 37 hoarder infallibly sophomore +689 198015 37 congregates unwilling star +690 198017 37 rains excrete rifles +691 198018 37 workers spools dialysis +692 198019 37 sags crunches arriving +693 198020 37 unplug overestimating indulge +694 198021 37 garage ineffective clockers +695 198022 37 boulder humiliation languages +696 198023 50 hollowly sophomore Antarctica A +697 198024 37 specifics star percentage +698 198101 37 Teresa rifles ceiling A +699 198103 37 Winsett dialysis specification +700 198105 37 convenient arriving regimented A +701 198106 37 buckboards indulge ciphers +702 198201 37 amenities clockers pictures A +703 198204 37 resplendent languages serpents A +704 198301 53 priding Antarctica allot A +705 198302 53 configurations percentage realized A +706 198303 53 untidiness ceiling mayoral A +707 198304 53 Brice specification opaquely A +708 198401 37 sews regimented hostess FAS +709 198402 37 participated ciphers fiftieth +710 198403 37 Simon pictures incorrectly +711 202101 37 certificates serpents decomposition FAS +712 202301 37 Fitzpatrick allot stranglings +713 202302 37 Evanston realized mixture FAS +714 202303 37 misted mayoral electroencephalography FAS +715 202304 37 textures opaquely similarities FAS +716 202305 37 save hostess charges W +717 202601 37 count fiftieth freest FAS +718 202602 37 rightful incorrectly Greenberg FAS +719 202605 37 chaperone decomposition tinting +720 202606 37 Lizzy stranglings expelled W +721 202607 37 clenched mixture warm +722 202901 37 effortlessly electroencephalography smoothed +723 202902 37 accessed similarities deductions FAS +724 202903 37 beaters charges Romano W +725 202904 37 Hornblower freest bitterroot +726 202907 37 vests Greenberg corset +727 202908 37 indulgences tinting securing +728 203101 37 infallibly expelled environing FAS +729 203103 37 unwilling warm cute +730 203104 37 excrete smoothed Crays +731 203105 37 spools deductions heiress FAS +732 203401 37 crunches Romano inform FAS +733 203402 37 overestimating bitterroot avenge +734 203404 37 ineffective corset universals +735 203901 37 humiliation securing Kinsey W +736 203902 37 sophomore environing ravines FAS +737 203903 37 star cute bestseller +738 203906 37 rifles Crays equilibrium +739 203907 37 dialysis heiress extents 0 +740 203908 37 arriving inform relatively +741 203909 37 indulge avenge pressure FAS +742 206101 37 clockers universals critiques FAS +743 206201 37 languages Kinsey befouled +744 206202 37 Antarctica ravines rightfully FAS +745 206203 37 percentage bestseller mechanizing FAS +746 206206 37 ceiling equilibrium Latinizes +747 206207 37 specification extents timesharing +748 206208 37 regimented relatively Aden +749 208001 37 ciphers pressure embassies +750 208002 37 pictures critiques males FAS +751 208003 37 serpents befouled shapelessly FAS +752 208004 37 allot rightfully genres FAS +753 208008 37 realized mechanizing mastering +754 208009 37 mayoral Latinizes Newtonian +755 208010 37 opaquely timesharing finishers FAS +756 208011 37 hostess Aden abates +757 208101 37 fiftieth embassies teem +758 208102 37 incorrectly males kiting FAS +759 208103 37 decomposition shapelessly stodgy FAS +760 208104 37 stranglings genres scalps FAS +761 208105 37 mixture mastering feed FAS +762 208110 37 electroencephalography Newtonian guitars +763 208111 37 similarities finishers airships +764 208112 37 charges abates store +765 208113 37 freest teem denounces +766 208201 37 Greenberg kiting Pyle FAS +767 208203 37 tinting stodgy Saxony +768 208301 37 expelled scalps serializations FAS +769 208302 37 warm feed Peruvian FAS +770 208305 37 smoothed guitars taxonomically FAS +771 208401 37 deductions airships kingdom A +772 208402 37 Romano store stint A +773 208403 37 bitterroot denounces Sault A +774 208404 37 corset Pyle faithful +775 208501 37 securing Saxony Ganymede FAS +776 208502 37 environing serializations tidiness FAS +777 208503 37 cute Peruvian gainful FAS +778 208504 37 Crays taxonomically contrary FAS +779 208505 37 heiress kingdom Tipperary FAS +780 210101 37 inform stint tropics W +781 210102 37 avenge Sault theorizers +782 210103 37 universals faithful renew 0 +783 210104 37 Kinsey Ganymede already +784 210105 37 ravines tidiness terminal +785 210106 37 bestseller gainful Hegelian +786 210107 37 equilibrium contrary hypothesizer +787 210401 37 extents Tipperary warningly FAS +788 213201 37 relatively tropics journalizing FAS +789 213203 37 pressure theorizers nested +790 213204 37 critiques renew Lars +791 213205 37 befouled already saplings +792 213206 37 rightfully terminal foothill +793 213207 37 mechanizing Hegelian labeled +794 216101 37 Latinizes hypothesizer imperiously FAS +795 216103 37 timesharing warningly reporters FAS +796 218001 37 Aden journalizing furnishings FAS +797 218002 37 embassies nested precipitable FAS +798 218003 37 males Lars discounts FAS +799 218004 37 shapelessly saplings excises FAS +800 143503 50 genres foothill Stalin +801 218006 37 mastering labeled despot FAS +802 218007 37 Newtonian imperiously ripeness FAS +803 218008 37 finishers reporters Arabia +804 218009 37 abates furnishings unruly +805 218010 37 teem precipitable mournfulness +806 218011 37 kiting discounts boom FAS +807 218020 37 stodgy excises slaughter A +808 218021 50 scalps Stalin Sabine +809 218022 37 feed despot handy FAS +810 218023 37 guitars ripeness rural +811 218024 37 airships Arabia organizer +812 218101 37 store unruly shipyard FAS +813 218102 37 denounces mournfulness civics FAS +814 218103 37 Pyle boom inaccuracy FAS +815 218201 37 Saxony slaughter rules FAS +816 218202 37 serializations Sabine juveniles FAS +817 218203 37 Peruvian handy comprised W +818 218204 37 taxonomically rural investigations +819 218205 37 kingdom organizer stabilizes A +820 218301 37 stint shipyard seminaries FAS +821 218302 37 Sault civics Hunter A +822 218401 37 faithful inaccuracy sporty FAS +823 218402 37 Ganymede rules test FAS +824 218403 37 tidiness juveniles weasels +825 218404 37 gainful comprised CERN +826 218407 37 contrary investigations tempering +827 218408 37 Tipperary stabilizes afore FAS +828 218409 37 tropics seminaries Galatean +829 218410 37 theorizers Hunter techniques W +830 226001 37 renew sporty error +831 226002 37 already test veranda +832 226003 37 terminal weasels severely +833 226004 37 Hegelian CERN Cassites FAS +834 226005 37 hypothesizer tempering forthcoming +835 226006 37 warningly afore guides +836 226007 37 journalizing Galatean vanish FAS +837 226008 37 nested techniques lied A +838 226203 37 Lars error sawtooth FAS +839 226204 37 saplings veranda fated FAS +840 226205 37 foothill severely gradually +841 226206 37 labeled Cassites widens +842 226207 37 imperiously forthcoming preclude +843 226208 37 reporters guides Jobrel +844 226209 37 furnishings vanish hooker +845 226210 37 precipitable lied rainstorm +846 226211 37 discounts sawtooth disconnects +847 228001 37 excises fated cruelty +848 228004 37 Stalin gradually exponentials A +849 228005 37 despot widens affective A +850 228006 37 ripeness preclude arteries +851 228007 37 Arabia Jobrel Crosby FAS +852 228008 37 unruly hooker acquaint +853 228009 37 mournfulness rainstorm evenhandedly +854 228101 37 boom disconnects percentage +855 228108 37 slaughter cruelty disobedience +856 228109 37 Sabine exponentials humility +857 228110 37 handy affective gleaning A +858 228111 37 rural arteries petted A +859 228112 37 organizer Crosby bloater A +860 228113 37 shipyard acquaint minion A +861 228114 37 civics evenhandedly marginal A +862 228115 37 inaccuracy percentage apiary A +863 228116 37 rules disobedience measures +864 228117 37 juveniles humility precaution +865 228118 37 comprised gleaning repelled +866 228119 37 investigations petted primary FAS +867 228120 37 stabilizes bloater coverings +868 228121 37 seminaries minion Artemia A +869 228122 37 Hunter marginal navigate +870 228201 37 sporty apiary spatial +871 228206 37 test measures Gurkha +872 228207 37 weasels precaution meanwhile A +873 228208 37 CERN repelled Melinda A +874 228209 37 tempering primary Butterfield +875 228210 37 afore coverings Aldrich A +876 228211 37 Galatean Artemia previewing A +877 228212 37 techniques navigate glut A +878 228213 37 error spatial unaffected +879 228214 37 veranda Gurkha inmate +880 228301 37 severely meanwhile mineral +881 228305 37 Cassites Melinda impending A +882 228306 37 forthcoming Butterfield meditation A +883 228307 37 guides Aldrich ideas +884 228308 37 vanish previewing miniaturizes W +885 228309 37 lied glut lewdly +886 228310 37 sawtooth unaffected title +887 228311 37 fated inmate youthfulness +888 228312 37 gradually mineral creak FAS +889 228313 37 widens impending Chippewa +890 228314 37 preclude meditation clamored +891 228401 65 Jobrel ideas freezes +892 228402 65 hooker miniaturizes forgivably FAS +893 228403 65 rainstorm lewdly reduce FAS +894 228404 65 disconnects title McGovern W +895 228405 65 cruelty youthfulness Nazis W +896 228406 65 exponentials creak epistle W +897 228407 65 affective Chippewa socializes W +898 228408 65 arteries clamored conceptions +899 228409 65 Crosby freezes Kevin +900 228410 65 acquaint forgivably uncovering +901 230301 37 evenhandedly reduce chews FAS +902 230302 37 percentage McGovern appendixes FAS +903 230303 37 disobedience Nazis raining +904 018062 37 humility epistle infest +905 230501 37 gleaning socializes compartment +906 230502 37 petted conceptions minting +907 230503 37 bloater Kevin ducks +908 230504 37 minion uncovering roped A +909 230505 37 marginal chews waltz +910 230506 37 apiary appendixes Lillian +911 230507 37 measures raining repressions A +912 230508 37 precaution infest chillingly +913 230509 37 repelled compartment noncritical +914 230901 37 primary minting lithograph +915 230902 37 coverings ducks spongers +916 230903 37 Artemia roped parenthood +917 230904 37 navigate waltz posed +918 230905 37 spatial Lillian instruments +919 230906 37 Gurkha repressions filial +920 230907 37 meanwhile chillingly fixedly +921 230908 37 Melinda noncritical relives +922 230909 37 Butterfield lithograph Pandora +923 230910 37 Aldrich spongers watering A +924 230911 37 previewing parenthood ungrateful +925 230912 37 glut posed secures +926 230913 37 unaffected instruments chastisers +927 230914 37 inmate filial icon +928 231304 37 mineral fixedly reuniting A +929 231305 37 impending relives imagining A +930 231306 37 meditation Pandora abiding A +931 231307 37 ideas watering omnisciently +932 231308 37 miniaturizes ungrateful Britannic +933 231309 37 lewdly secures scholastics A +934 231310 37 title chastisers mechanics A +935 231311 37 youthfulness icon humidly A +936 231312 37 creak reuniting masterpiece +937 231313 37 Chippewa imagining however +938 231314 37 clamored abiding Mendelian +939 231315 37 freezes omnisciently jarred +940 232102 37 forgivably Britannic scolds +941 232103 37 reduce scholastics infatuate +942 232104 37 McGovern mechanics willed A +943 232105 37 Nazis humidly joyfully +944 232106 37 epistle masterpiece Microsoft +945 232107 37 socializes however fibrosities +946 232108 37 conceptions Mendelian Baltimorean +947 232601 37 Kevin jarred equestrian +948 232602 37 uncovering scolds Goodrich +949 232603 37 chews infatuate apish A +950 232605 37 appendixes willed Adlerian +5950 1232605 37 appendixes willed Adlerian +5951 1232606 37 appendixes willed Adlerian +5952 1232607 37 appendixes willed Adlerian +5953 1232608 37 appendixes willed Adlerian +5954 1232609 37 appendixes willed Adlerian +951 232606 37 raining joyfully Tropez +952 232607 37 infest Microsoft nouns +953 232608 37 compartment fibrosities distracting +954 232609 37 minting Baltimorean mutton +955 236104 37 ducks equestrian bridgeable A +956 236105 37 roped Goodrich stickers A +957 236106 37 waltz apish transcontinental A +958 236107 37 Lillian Adlerian amateurish +959 236108 37 repressions Tropez Gandhian +960 236109 37 chillingly nouns stratified +961 236110 37 noncritical distracting chamberlains +962 236111 37 lithograph mutton creditably +963 236112 37 spongers bridgeable philosophic +964 236113 37 parenthood stickers ores +965 238005 37 posed transcontinental Carleton +966 238006 37 instruments amateurish tape A +967 238007 37 filial Gandhian afloat A +968 238008 37 fixedly stratified goodness A +969 238009 37 relives chamberlains welcoming +970 238010 37 Pandora creditably Pinsky FAS +971 238011 37 watering philosophic halting +972 238012 37 ungrateful ores bibliography +973 238013 37 secures Carleton decoding +974 240401 41 chastisers tape variance A +975 240402 41 icon afloat allowed A +976 240901 41 reuniting goodness dire A +977 240902 41 imagining welcoming dub A +978 241801 41 abiding Pinsky poisoning +979 242101 41 omnisciently halting Iraqis A +980 242102 41 Britannic bibliography heaving +981 242201 41 scholastics decoding population A +982 242202 41 mechanics variance bomb A +983 242501 41 humidly allowed Majorca A +984 242502 41 masterpiece dire Gershwins +985 246201 41 however dub explorers +986 246202 41 Mendelian poisoning libretto A +987 246203 41 jarred Iraqis occurred +988 246204 41 scolds heaving Lagos +989 246205 41 infatuate population rats +990 246301 41 willed bomb bankruptcies A +991 246302 41 joyfully Majorca crying +992 248001 41 Microsoft Gershwins unexpected +993 248002 41 fibrosities explorers accessed A +994 248003 41 Baltimorean libretto colorful A +995 248004 41 equestrian occurred versatility A +996 248005 41 Goodrich Lagos cosy +997 248006 41 apish rats Darius A +998 248007 41 Adlerian bankruptcies mastering A +999 248008 41 Tropez crying Asiaticizations A +1000 248009 41 nouns unexpected offerers A +1001 248010 41 distracting accessed uncles A +1002 248011 41 mutton colorful sleepwalk +1003 248012 41 bridgeable versatility Ernestine +1004 248013 41 stickers cosy checksumming +1005 248014 41 transcontinental Darius stopped +1006 248015 41 amateurish mastering sicker +1007 248016 41 Gandhian Asiaticizations Italianization +1008 248017 41 stratified offerers alphabetic +1009 248018 41 chamberlains uncles pharmaceutic +1010 248019 41 creditably sleepwalk creator +1011 248020 41 philosophic Ernestine chess +1012 248021 41 ores checksumming charcoal +1013 248101 41 Carleton stopped Epiphany A +1014 248102 41 tape sicker bulldozes A +1015 248201 41 afloat Italianization Pygmalion A +1016 248202 41 goodness alphabetic caressing A +1017 248203 41 welcoming pharmaceutic Palestine A +1018 248204 41 Pinsky creator regimented A +1019 248205 41 halting chess scars A +1020 248206 41 bibliography charcoal realest A +1021 248207 41 decoding Epiphany diffusing A +1022 248208 41 variance bulldozes clubroom A +1023 248209 41 allowed Pygmalion Blythe A +1024 248210 41 dire caressing ahead +1025 248211 50 dub Palestine reviver +1026 250501 34 poisoning regimented retransmitting A +1027 250502 34 Iraqis scars landslide +1028 250503 34 heaving realest Eiffel +1029 250504 34 population diffusing absentee +1030 250505 34 bomb clubroom aye +1031 250601 34 Majorca Blythe forked A +1032 250602 34 Gershwins ahead Peruvianizes +1033 250603 34 explorers reviver clerked +1034 250604 34 libretto retransmitting tutor +1035 250605 34 occurred landslide boulevard +1036 251001 34 Lagos Eiffel shuttered +1037 251002 34 rats absentee quotes A +1038 251003 34 bankruptcies aye Caltech +1039 251004 34 crying forked Mossberg +1040 251005 34 unexpected Peruvianizes kept +1041 251301 34 accessed clerked roundly +1042 251302 34 colorful tutor features A +1043 251303 34 versatility boulevard imaginable A +1044 251304 34 cosy shuttered controller +1045 251305 34 Darius quotes racial +1046 251401 34 mastering Caltech uprisings A +1047 251402 34 Asiaticizations Mossberg narrowed A +1048 251403 34 offerers kept cannot A +1049 251404 34 uncles roundly vest +1050 251405 34 sleepwalk features famine +1051 251406 34 Ernestine imaginable sugars +1052 251801 34 checksumming controller exterminated A +1053 251802 34 stopped racial belays +1054 252101 34 sicker uprisings Hodges A +1055 252102 34 Italianization narrowed translatable +1056 252301 34 alphabetic cannot duality A +1057 252302 34 pharmaceutic vest recording A +1058 252303 34 creator famine rouses A +1059 252304 34 chess sugars poison +1060 252305 34 charcoal exterminated attitude +1061 252306 34 Epiphany belays dusted +1062 252307 34 bulldozes Hodges encompasses +1063 252308 34 Pygmalion translatable presentation +1064 252309 34 caressing duality Kantian +1065 256001 34 Palestine recording imprecision A +1066 256002 34 regimented rouses saving +1067 256003 34 scars poison maternal +1068 256004 34 realest attitude hewed +1069 256005 34 diffusing dusted kerosene +1070 258001 34 clubroom encompasses Cubans +1071 258002 34 Blythe presentation photographers +1072 258003 34 ahead Kantian nymph A +1073 258004 34 reviver imprecision bedlam A +1074 258005 34 retransmitting saving north A +1075 258006 34 landslide maternal Schoenberg A +1076 258007 34 Eiffel hewed botany A +1077 258008 34 absentee kerosene curs +1078 258009 34 aye Cubans solidification +1079 258010 34 forked photographers inheritresses +1080 258011 34 Peruvianizes nymph stiller +1081 258101 68 clerked bedlam t1 A +1082 258102 68 tutor north suite A +1083 258103 34 boulevard Schoenberg ransomer +1084 258104 68 shuttered botany Willy +1085 258105 68 quotes curs Rena A +1086 258106 68 Caltech solidification Seattle A +1087 258107 68 Mossberg inheritresses relaxes A +1088 258108 68 kept stiller exclaim +1089 258109 68 roundly t1 implicated A +1090 258110 68 features suite distinguish +1091 258111 68 imaginable ransomer assayed +1092 258112 68 controller Willy homeowner +1093 258113 68 racial Rena and +1094 258201 34 uprisings Seattle stealth +1095 258202 34 narrowed relaxes coinciding A +1096 258203 34 cannot exclaim founder A +1097 258204 34 vest implicated environing +1098 258205 34 famine distinguish jewelry +1099 258301 34 sugars assayed lemons A +1100 258401 34 exterminated homeowner brokenness A +1101 258402 34 belays and bedpost A +1102 258403 34 Hodges stealth assurers A +1103 258404 34 translatable coinciding annoyers +1104 258405 34 duality founder affixed +1105 258406 34 recording environing warbling +1106 258407 34 rouses jewelry seriously +1107 228123 37 poison lemons boasted +1108 250606 34 attitude brokenness Chantilly +1109 208405 37 dusted bedpost Iranizes +1110 212101 37 encompasses assurers violinist +1111 218206 37 presentation annoyers extramarital +1112 150401 37 Kantian affixed spates +1113 248212 41 imprecision warbling cloakroom +1114 128026 00 saving seriously gazer +1115 128024 00 maternal boasted hand +1116 128027 00 hewed Chantilly tucked +1117 128025 00 kerosene Iranizes gems +1118 128109 00 Cubans violinist clinker +1119 128705 00 photographers extramarital refiner +1120 126303 00 nymph spates callus +1121 128308 00 bedlam cloakroom leopards +1122 128204 00 north gazer comfortingly +1123 128205 00 Schoenberg hand generically +1124 128206 00 botany tucked getters +1125 128207 00 curs gems sexually +1126 118205 00 solidification clinker spear +1127 116801 00 inheritresses refiner serums +1128 116803 00 stiller callus Italianization +1129 116804 00 t1 leopards attendants +1130 116802 00 suite comfortingly spies +1131 128605 00 ransomer generically Anthony +1132 118308 00 Willy getters planar +1133 113702 00 Rena sexually cupped +1134 113703 00 Seattle spear cleanser +1135 112103 00 relaxes serums commuters +1136 118009 00 exclaim Italianization honeysuckle +5136 1118009 00 exclaim Italianization honeysuckle +1137 138011 00 implicated attendants orphanage +1138 138010 00 distinguish spies skies +1139 138012 00 assayed Anthony crushers +1140 068304 00 homeowner planar Puritan +1141 078009 00 and cupped squeezer +1142 108013 00 stealth cleanser bruises +1143 084004 00 coinciding commuters bonfire +1144 083402 00 founder honeysuckle Colombo +1145 084003 00 environing orphanage nondecreasing +1146 088504 00 jewelry skies innocents +1147 088005 00 lemons crushers masked +1148 088007 00 brokenness Puritan file +1149 088006 00 bedpost squeezer brush +1150 148025 00 assurers bruises mutilate +1151 148024 00 annoyers bonfire mommy +1152 138305 00 affixed Colombo bulkheads +1153 138306 00 warbling nondecreasing undeclared +1154 152701 00 seriously innocents displacements +1155 148505 00 boasted masked nieces +1156 158003 00 Chantilly file coeducation +1157 156201 00 Iranizes brush brassy +1158 156202 00 violinist mutilate authenticator +1159 158307 00 extramarital mommy Washoe +1160 158402 00 spates bulkheads penny +1161 158401 00 cloakroom undeclared Flagler +1162 068013 00 gazer displacements stoned +1163 068012 00 hand nieces cranes +1164 068203 00 tucked coeducation masterful +1165 088205 00 gems brassy biracial +1166 068704 00 clinker authenticator steamships +1167 068604 00 refiner Washoe windmills +1168 158502 00 callus penny exploit +1169 123103 00 leopards Flagler riverfront +1170 148026 00 comfortingly stoned sisterly +1171 123302 00 generically cranes sharpshoot +1172 076503 00 getters masterful mittens +1173 126304 00 sexually biracial interdependency +1174 068306 00 spear steamships policy +1175 143504 00 serums windmills unleashing +1176 160201 00 Italianization exploit pretenders +1177 148028 00 attendants riverfront overstatements +1178 148027 00 spies sisterly birthed +1179 143505 00 Anthony sharpshoot opportunism +1180 108014 00 planar mittens showroom +1181 076104 00 cupped interdependency compromisingly +1182 078106 00 cleanser policy Medicare +1183 126102 00 commuters unleashing corresponds +1184 128029 00 honeysuckle pretenders hardware +1185 128028 00 orphanage overstatements implant +1186 018410 00 skies birthed Alicia +1187 128110 00 crushers opportunism requesting +1188 148506 00 Puritan showroom produced +1189 123303 00 squeezer compromisingly criticizes +1190 123304 00 bruises Medicare backer +1191 068504 00 bonfire corresponds positively +1192 068305 00 Colombo hardware colicky +1193 000000 00 nondecreasing implant thrillingly +1 000001 00 Omaha teethe neat +2 011401 37 breaking dreaded Steinberg W +3 011402 37 Romans scholastics jarring +4 011403 37 intercepted audiology tinily +2 011401 37 breaking dreaded Steinberg W +3 011402 37 Romans scholastics jarring +4 011403 37 intercepted audiology tinily REPAIR TABLE t2; Table Op Msg_type Msg_text test.t2 repair status OK @@ -3825,6 +5039,9 @@ auto fld1 companynr fld3 fld4 fld5 fld6 2 011401 37 breaking dreaded Steinberg W 3 011402 37 Romans scholastics jarring 4 011403 37 intercepted audiology tinily +2 011401 37 breaking dreaded Steinberg W +3 011402 37 Romans scholastics jarring +4 011403 37 intercepted audiology tinily INSERT INTO t2 VALUES (1,000001,00,'Omaha','teethe','neat','') , (2,011401,37,'breaking','dreaded','Steinberg','W') , (3,011402,37,'Romans','scholastics','jarring','') , (4,011403,37,'intercepted','audiology','tinily',''); SELECT * FROM t2; auto fld1 companynr fld3 fld4 fld5 fld6 @@ -5031,6 +6248,9 @@ auto fld1 companynr fld3 fld4 fld5 fld6 2 011401 37 breaking dreaded Steinberg W 3 011402 37 Romans scholastics jarring 4 011403 37 intercepted audiology tinily +2 011401 37 breaking dreaded Steinberg W +3 011402 37 Romans scholastics jarring +4 011403 37 intercepted audiology tinily 1 000001 00 Omaha teethe neat 2 011401 37 breaking dreaded Steinberg W 3 011402 37 Romans scholastics jarring diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index a854cf4c7b0..b02f85132aa 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -160,6 +160,21 @@ t1 CREATE TABLE `t1` ( `COALESCE('a' COLLATE latin1_bin,'b')` varchar(1) character set latin1 collate latin1_bin NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; +SELECT 'case+union+test' +UNION +SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END; +case+union+test +case+union+test +nobug +SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END; +CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END +nobug +SELECT 'case+union+test' +UNION +SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END; +case+union+test +case+union+test +nobug CREATE TABLE t1 (EMPNUM INT); INSERT INTO t1 VALUES (0), (2); CREATE TABLE t2 (EMPNUM DECIMAL (4, 2)); diff --git a/mysql-test/r/client_xml.result b/mysql-test/r/client_xml.result index a4164148159..24c05c7f9d6 100644 --- a/mysql-test/r/client_xml.result +++ b/mysql-test/r/client_xml.result @@ -15,7 +15,7 @@ insert into t1 values (1, 2, 'a&b a<b a>b'); </row> </resultset> <?xml version="1.0"?> -<mysqldump> +<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <database name="test"> <table_structure name="t1"> <field Field="a&b" Type="int(11)" Null="YES" Key="" Extra="" /> diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 338fc429090..dd1fb491064 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -638,6 +638,17 @@ Warnings: Warning 1264 Out of range value adjusted for column 'Field1' at row 1 DROP TABLE t1; SET NAMES latin1; +CREATE TABLE t1 ( +a varchar(255) NOT NULL default '', +KEY a (a) +) ENGINE=MyISAM DEFAULT CHARSET=ucs2 COLLATE ucs2_general_ci; +insert into t1 values (0x803d); +insert into t1 values (0x005b); +select hex(a) from t1; +hex(a) +005B +803D +drop table t1; CREATE TABLE t1 (a varchar(64) character set ucs2, b decimal(10,3)); INSERT INTO t1 VALUES ("1.1", 0), ("2.1", 0); update t1 set b=a; diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 0407a7f388c..de2e96acd2e 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -939,3 +939,44 @@ content msisdn ERR Имри.Ðфимим.Ðеимимримдмримрмрирор имримримримр имридм ирбднримрфмририримрфмфмим.Ðд.Д имдимримрад.Ðдимримримрмдиримримримр м.Дадимфшьмримд им.Ðдимимрн имадми 1234567890 11 g 1234567890 DROP TABLE t1,t2; +create table t1 (a char(20) character set utf8); +insert into t1 values ('123456'),('андрей'); +alter table t1 modify a char(2) character set utf8; +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +Warning 1265 Data truncated for column 'a' at row 2 +select char_length(a), length(a), a from t1 order by a; +char_length(a) length(a) a +2 2 12 +2 4 ан +drop table t1; +CREATE TABLE t1 ( +a varchar(255) NOT NULL default '', +KEY a (a) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE utf8_general_ci; +insert into t1 values (_utf8 0xe880bd); +insert into t1 values (_utf8 0x5b); +select hex(a) from t1; +hex(a) +5B +E880BD +drop table t1; +CREATE TABLE t1(id varchar(20) NOT NULL) DEFAULT CHARSET=utf8; +INSERT INTO t1 VALUES ('xxx'), ('aa'), ('yyy'), ('aa'); +SELECT id FROM t1; +id +xxx +aa +yyy +aa +SELECT DISTINCT id FROM t1; +id +xxx +aa +yyy +SELECT DISTINCT id FROM t1 ORDER BY id; +id +aa +xxx +yyy +DROP TABLE t1; diff --git a/mysql-test/r/func_date_add.result b/mysql-test/r/func_date_add.result index f4091ff4c0e..50889943b56 100644 --- a/mysql-test/r/func_date_add.result +++ b/mysql-test/r/func_date_add.result @@ -4,7 +4,7 @@ visitor_id int(10) unsigned DEFAULT '0' NOT NULL, group_id int(10) unsigned DEFAULT '0' NOT NULL, hits int(10) unsigned DEFAULT '0' NOT NULL, sessions int(10) unsigned DEFAULT '0' NOT NULL, -ts timestamp(14), +ts timestamp, PRIMARY KEY (visitor_id,group_id) )/*! engine=MyISAM */; INSERT INTO t1 VALUES (465931136,7,2,2,20000318160952); diff --git a/mysql-test/r/func_encrypt.result b/mysql-test/r/func_encrypt.result index d32e67fe7d5..3eb8ec4354c 100644 --- a/mysql-test/r/func_encrypt.result +++ b/mysql-test/r/func_encrypt.result @@ -120,6 +120,48 @@ hello select des_decrypt(des_encrypt("hello",4),'password4'); des_decrypt(des_encrypt("hello",4),'password4') hello +select des_encrypt("hello",10); +des_encrypt("hello",10) +NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_encrypt' +select des_encrypt(NULL); +des_encrypt(NULL) +NULL +select des_encrypt(NULL, 10); +des_encrypt(NULL, 10) +NULL +select des_encrypt(NULL, NULL); +des_encrypt(NULL, NULL) +NULL +select des_encrypt(10, NULL); +des_encrypt(10, NULL) +NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_encrypt' +select des_encrypt("hello", NULL); +des_encrypt("hello", NULL) +NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_encrypt' +select des_decrypt("hello",10); +des_decrypt("hello",10) +hello +select des_decrypt(NULL); +des_decrypt(NULL) +NULL +select des_decrypt(NULL, 10); +des_decrypt(NULL, 10) +NULL +select des_decrypt(NULL, NULL); +des_decrypt(NULL, NULL) +NULL +select des_decrypt(10, NULL); +des_decrypt(10, NULL) +10 +select des_decrypt("hello", NULL); +des_decrypt("hello", NULL) +hello SET @a=des_decrypt(des_encrypt("hello")); flush des_key_file; select @a = des_decrypt(des_encrypt("hello")); @@ -134,6 +176,8 @@ NULL select hex(des_decrypt(des_encrypt("hello","hidden"))); hex(des_decrypt(des_encrypt("hello","hidden"))) NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_decrypt' 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 diff --git a/mysql-test/r/func_encrypt_nossl.result b/mysql-test/r/func_encrypt_nossl.result new file mode 100644 index 00000000000..d0df2335afa --- /dev/null +++ b/mysql-test/r/func_encrypt_nossl.result @@ -0,0 +1,98 @@ +select des_encrypt("test", 'akeystr'); +des_encrypt("test", 'akeystr') +NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_encrypt("test", 1); +des_encrypt("test", 1) +NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_encrypt("test", 9); +des_encrypt("test", 9) +NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_encrypt("test", 100); +des_encrypt("test", 100) +NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_encrypt("test", NULL); +des_encrypt("test", NULL) +NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_encrypt(NULL, NULL); +des_encrypt(NULL, NULL) +NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt("test", 'anotherkeystr'); +des_decrypt("test", 'anotherkeystr') +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt(1, 1); +des_decrypt(1, 1) +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt(des_encrypt("test", 'thekey')); +des_decrypt(des_encrypt("test", 'thekey')) +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select hex(des_encrypt("hello")),des_decrypt(des_encrypt("hello")); +hex(des_encrypt("hello")) des_decrypt(des_encrypt("hello")) +NULL NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt(des_encrypt("hello",4)); +des_decrypt(des_encrypt("hello",4)) +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt(des_encrypt("hello",'test'),'test'); +des_decrypt(des_encrypt("hello",'test'),'test') +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select hex(des_encrypt("hello")),hex(des_encrypt("hello",5)),hex(des_encrypt("hello",'default_password')); +hex(des_encrypt("hello")) hex(des_encrypt("hello",5)) hex(des_encrypt("hello",'default_password')) +NULL NULL NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt(des_encrypt("hello"),'default_password'); +des_decrypt(des_encrypt("hello"),'default_password') +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt(des_encrypt("hello",4),'password4'); +des_decrypt(des_encrypt("hello",4),'password4') +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +SET @a=des_decrypt(des_encrypt("hello")); +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +flush des_key_file; +select @a = des_decrypt(des_encrypt("hello")); +@a = des_decrypt(des_encrypt("hello")) +NULL +select hex("hello"); +hex("hello") +68656C6C6F +select hex(des_decrypt(des_encrypt("hello",4),'password2')); +hex(des_decrypt(des_encrypt("hello",4),'password2')) +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select hex(des_decrypt(des_encrypt("hello","hidden"))); +hex(des_decrypt(des_encrypt("hello","hidden"))) +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 1c6a4393dfc..ae60daef0ac 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -264,7 +264,7 @@ category int(10) unsigned default NULL, program int(10) unsigned default NULL, bugdesc text, created datetime default NULL, -modified timestamp(14) NOT NULL, +modified timestamp NOT NULL, bugstatus int(10) unsigned default NULL, submitter int(10) unsigned default NULL ) ENGINE=MyISAM; @@ -800,3 +800,79 @@ field(0,NULL,1,0) field("",NULL,"bar","") field(0.0,NULL,1.0,0.0) select field(NULL,1,2,NULL), field(NULL,1,2,0); field(NULL,1,2,NULL) field(NULL,1,2,0) 0 0 +CREATE TABLE t1 (str varchar(20) PRIMARY KEY); +CREATE TABLE t2 (num int primary key); +INSERT INTO t1 VALUES ('notnumber'); +INSERT INTO t2 VALUES (0), (1); +SELECT * FROM t1, t2 WHERE num=str; +str num +notnumber 0 +SELECT * FROM t1, t2 WHERE num=substring(str from 1 for 6); +str num +notnumber 0 +DROP TABLE t1,t2; +CREATE TABLE t1( +id int(11) NOT NULL auto_increment, +pc int(11) NOT NULL default '0', +title varchar(20) default NULL, +PRIMARY KEY (id) +); +INSERT INTO t1 VALUES +(1, 0, 'Main'), +(2, 1, 'Toys'), +(3, 1, 'Games'); +SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1 +FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id +LEFT JOIN t1 AS t3 ON t2.pc=t3.id; +id col1 +1 Main +2 Main->Toys +3 Main->Games +SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1 +FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id +LEFT JOIN t1 AS t3 ON t2.pc=t3.id +WHERE CONCAT_WS('->', t3.title, t2.title, t1.title) LIKE '%Toys%'; +id col1 +2 Main->Toys +DROP TABLE t1; +CREATE TABLE t1( +trackid int(10) unsigned NOT NULL auto_increment, +trackname varchar(100) NOT NULL default '', +PRIMARY KEY (trackid) +); +CREATE TABLE t2( +artistid int(10) unsigned NOT NULL auto_increment, +artistname varchar(100) NOT NULL default '', +PRIMARY KEY (artistid) +); +CREATE TABLE t3( +trackid int(10) unsigned NOT NULL, +artistid int(10) unsigned NOT NULL, +PRIMARY KEY (trackid,artistid) +); +INSERT INTO t1 VALUES (1, 'April In Paris'), (2, 'Autumn In New York'); +INSERT INTO t2 VALUES (1, 'Vernon Duke'); +INSERT INTO t3 VALUES (1,1); +SELECT CONCAT_WS(' ', trackname, artistname) trackname, artistname +FROM t1 LEFT JOIN t3 ON t1.trackid=t3.trackid +LEFT JOIN t2 ON t2.artistid=t3.artistid +WHERE CONCAT_WS(' ', trackname, artistname) LIKE '%In%'; +trackname artistname +April In Paris Vernon Duke Vernon Duke +Autumn In New York NULL +DROP TABLE t1,t2,t3; +create table t1 (b varchar(5)); +insert t1 values ('ab'), ('abc'), ('abcd'), ('abcde'); +select *,substring(b,1),substring(b,-1),substring(b,-2),substring(b,-3),substring(b,-4),substring(b,-5) from t1; +b substring(b,1) substring(b,-1) substring(b,-2) substring(b,-3) substring(b,-4) substring(b,-5) +ab ab b ab +abc abc c bc abc +abcd abcd d cd bcd abcd +abcde abcde e de cde bcde abcde +select * from (select *,substring(b,1),substring(b,-1),substring(b,-2),substring(b,-3),substring(b,-4),substring(b,-5) from t1) t; +b substring(b,1) substring(b,-1) substring(b,-2) substring(b,-3) substring(b,-4) substring(b,-5) +ab ab b ab +abc abc c bc abc +abcd abcd d cd bcd abcd +abcde abcde e de cde bcde abcde +drop table t1; diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index cb51da75368..63da5589c57 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -465,7 +465,7 @@ extract(MONTH FROM "0000-00-00") extract(MONTH FROM d) extract(MONTH FROM dt) ex drop table t1; CREATE TABLE t1 ( start datetime default NULL); INSERT INTO t1 VALUES ('2002-10-21 00:00:00'),('2002-10-28 00:00:00'),('2002-11-04 00:00:00'); -CREATE TABLE t2 ( ctime1 timestamp(14) NOT NULL, ctime2 timestamp(14) NOT NULL); +CREATE TABLE t2 ( ctime1 timestamp NOT NULL, ctime2 timestamp NOT NULL); INSERT INTO t2 VALUES (20021029165106,20021105164731); CREATE TABLE t3 (ctime1 char(19) NOT NULL, ctime2 char(19) NOT NULL); INSERT INTO t3 VALUES ("2002-10-29 16:51:06","2002-11-05 16:47:31"); diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index c8ae8303d99..19982c7bb60 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1,4 +1,5 @@ drop table if exists t1; +drop database if exists mysqltest; SET NAMES binary; delete from mysql.user where user='mysqltest_1'; delete from mysql.db where user='mysqltest_1'; @@ -473,3 +474,120 @@ ERROR 42000: INSERT,CREATE command denied to user 'mysqltest_1'@'localhost' for revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; delete from mysql.user where user=_binary'mysqltest_1'; drop database mysqltest; +CREATE USER dummy@localhost; +CREATE DATABASE mysqltest; +CREATE TABLE mysqltest.dummytable (dummyfield INT); +CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable; +GRANT ALL PRIVILEGES ON mysqltest.dummytable TO dummy@localhost; +GRANT ALL PRIVILEGES ON mysqltest.dummyview TO dummy@localhost; +SHOW GRANTS FOR dummy@localhost; +Grants for dummy@localhost +GRANT USAGE ON *.* TO 'dummy'@'localhost' +GRANT ALL PRIVILEGES ON `mysqltest`.`dummyview` TO 'dummy'@'localhost' +GRANT ALL PRIVILEGES ON `mysqltest`.`dummytable` TO 'dummy'@'localhost' +use INFORMATION_SCHEMA; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +TABLE_SCHEMA TABLE_NAME PRIVILEGES +mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, UPDATE +mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, UPDATE +FLUSH PRIVILEGES; +SHOW GRANTS FOR dummy@localhost; +Grants for dummy@localhost +GRANT USAGE ON *.* TO 'dummy'@'localhost' +GRANT ALL PRIVILEGES ON `mysqltest`.`dummyview` TO 'dummy'@'localhost' +GRANT ALL PRIVILEGES ON `mysqltest`.`dummytable` TO 'dummy'@'localhost' +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +TABLE_SCHEMA TABLE_NAME PRIVILEGES +mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, UPDATE +mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, UPDATE +SHOW FIELDS FROM mysql.tables_priv; +Field Type Null Key Default Extra +Host char(60) NO PRI +Db char(64) NO PRI +User char(16) NO PRI +Table_name char(64) NO PRI +Grantor char(77) NO MUL +Timestamp timestamp YES CURRENT_TIMESTAMP +Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view') NO +Column_priv set('Select','Insert','Update','References') NO +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; +DROP USER dummy@localhost; +DROP DATABASE mysqltest; +CREATE USER dummy@localhost; +CREATE DATABASE mysqltest; +CREATE TABLE mysqltest.dummytable (dummyfield INT); +CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable; +GRANT CREATE VIEW ON mysqltest.dummytable TO dummy@localhost; +GRANT CREATE VIEW ON mysqltest.dummyview TO dummy@localhost; +SHOW GRANTS FOR dummy@localhost; +Grants for dummy@localhost +GRANT USAGE ON *.* TO 'dummy'@'localhost' +GRANT CREATE VIEW ON `mysqltest`.`dummyview` TO 'dummy'@'localhost' +GRANT CREATE VIEW ON `mysqltest`.`dummytable` TO 'dummy'@'localhost' +use INFORMATION_SCHEMA; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +TABLE_SCHEMA TABLE_NAME PRIVILEGES +mysqltest dummytable CREATE VIEW +mysqltest dummyview CREATE VIEW +FLUSH PRIVILEGES; +SHOW GRANTS FOR dummy@localhost; +Grants for dummy@localhost +GRANT USAGE ON *.* TO 'dummy'@'localhost' +GRANT CREATE VIEW ON `mysqltest`.`dummyview` TO 'dummy'@'localhost' +GRANT CREATE VIEW ON `mysqltest`.`dummytable` TO 'dummy'@'localhost' +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +TABLE_SCHEMA TABLE_NAME PRIVILEGES +mysqltest dummytable CREATE VIEW +mysqltest dummyview CREATE VIEW +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; +DROP USER dummy@localhost; +DROP DATABASE mysqltest; +CREATE USER dummy@localhost; +CREATE DATABASE mysqltest; +CREATE TABLE mysqltest.dummytable (dummyfield INT); +CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable; +GRANT SHOW VIEW ON mysqltest.dummytable TO dummy@localhost; +GRANT SHOW VIEW ON mysqltest.dummyview TO dummy@localhost; +SHOW GRANTS FOR dummy@localhost; +Grants for dummy@localhost +GRANT USAGE ON *.* TO 'dummy'@'localhost' +GRANT SHOW VIEW ON `mysqltest`.`dummyview` TO 'dummy'@'localhost' +GRANT SHOW VIEW ON `mysqltest`.`dummytable` TO 'dummy'@'localhost' +use INFORMATION_SCHEMA; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +TABLE_SCHEMA TABLE_NAME PRIVILEGES +mysqltest dummytable SHOW VIEW +mysqltest dummyview SHOW VIEW +FLUSH PRIVILEGES; +SHOW GRANTS FOR dummy@localhost; +Grants for dummy@localhost +GRANT USAGE ON *.* TO 'dummy'@'localhost' +GRANT SHOW VIEW ON `mysqltest`.`dummyview` TO 'dummy'@'localhost' +GRANT SHOW VIEW ON `mysqltest`.`dummytable` TO 'dummy'@'localhost' +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +TABLE_SCHEMA TABLE_NAME PRIVILEGES +mysqltest dummytable SHOW VIEW +mysqltest dummyview SHOW VIEW +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; +DROP USER dummy@localhost; +DROP DATABASE mysqltest; +use mysql; +insert into tables_priv values ('','test_db','mysqltest_1','test_table','test_grantor',CURRENT_TIMESTAMP,'Select','Select'); +flush privileges; +delete from tables_priv where host = '' and user = 'mysqltest_1'; +flush privileges; diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index edad116028f..64446e63e6f 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -117,7 +117,7 @@ bug_file_loc text, bug_severity enum('blocker','critical','major','normal','minor','trivial','enhancement') DEFAULT 'blocker' NOT NULL, bug_status enum('','NEW','ASSIGNED','REOPENED','RESOLVED','VERIFIED','CLOSED') DEFAULT 'NEW' NOT NULL, creation_ts datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, -delta_ts timestamp(14), +delta_ts timestamp, short_desc mediumtext, long_desc mediumtext, op_sys enum('All','Windows 3.1','Windows 95','Windows 98','Windows NT','Windows 2000','Linux','other') DEFAULT 'All' NOT NULL, @@ -751,3 +751,32 @@ COUNT(DISTINCT(t1.id)) comment 1 NULL 1 a problem DROP TABLE t1, t2; +CREATE TABLE t1 (n int); +INSERT INTO t1 VALUES (1); +SELECT n+1 AS n FROM t1 GROUP BY n; +n +2 +Warnings: +Warning 1052 Column 'n' in group statement is ambiguous +DROP TABLE t1; +create table t1 (c1 char(3), c2 char(3)); +create table t2 (c3 char(3), c4 char(3)); +insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2'); +insert into t2 values ('aaa', 'bb1'), ('aaa', 'bb2'); +select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 +group by c2; +c2 +aaa +aaa +Warnings: +Warning 1052 Column 'c2' in group statement is ambiguous +show warnings; +Level Code Message +Warning 1052 Column 'c2' in group statement is ambiguous +select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 +group by t1.c1; +c2 +aaa +show warnings; +Level Code Message +drop table t1, t2; diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result index 22304c4a93d..b905dae3aba 100644 --- a/mysql-test/r/heap.result +++ b/mysql-test/r/heap.result @@ -367,13 +367,13 @@ count(*) 9 explain select count(*) from t1 where v='a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const 9 Using where +1 SIMPLE t1 ref v v 13 const 10 Using where explain select count(*) from t1 where c='a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref c c 11 const 9 Using where +1 SIMPLE t1 ref c c 11 const 10 Using where explain select count(*) from t1 where t='a '; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref t t 13 const 9 Using where +1 SIMPLE t1 ref t t 13 const 10 Using where explain select count(*) from t1 where v like 'a%'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL v NULL NULL NULL 271 Using where @@ -399,7 +399,7 @@ qq *a *a*a * explain select * from t1 where v='a'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const 9 Using where +1 SIMPLE t1 ref v v 13 const 10 Using where select v,count(*) from t1 group by v limit 10; v count(*) a 1 diff --git a/mysql-test/r/heap_hash.result b/mysql-test/r/heap_hash.result index 9720fe4843a..d8d89b786b5 100644 --- a/mysql-test/r/heap_hash.result +++ b/mysql-test/r/heap_hash.result @@ -231,18 +231,19 @@ explain select * from t1 where a='aaad'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref a a 8 const 1 Using where insert into t1 select * from t1; +flush tables; explain select * from t1 where a='aaaa'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where explain select * from t1 where a='aaab'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where explain select * from t1 where a='aaac'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where explain select * from t1 where a='aaad'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where flush tables; explain select * from t1 where a='aaaa'; id select_type table type possible_keys key key_len ref rows Extra @@ -261,16 +262,16 @@ delete from t1; insert into t1 select * from t2; explain select * from t1 where a='aaaa'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where explain select * from t1 where a='aaab'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where explain select * from t1 where a='aaac'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where explain select * from t1 where a='aaad'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a a 8 const 1 Using where +1 SIMPLE t1 ref a a 8 const 2 Using where drop table t1, t2; create table t1 ( id int unsigned not null primary key auto_increment, @@ -345,15 +346,15 @@ insert into t3 select name, name from t1; show index from t3; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t3 1 a 1 a NULL NULL NULL NULL HASH -t3 1 a 2 b NULL 15 NULL NULL HASH +t3 1 a 2 b NULL 13 NULL NULL HASH show index from t3; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t3 1 a 1 a NULL NULL NULL NULL HASH -t3 1 a 2 b NULL 15 NULL NULL HASH +t3 1 a 2 b NULL 13 NULL NULL HASH explain select * from t1 ignore key(btree_idx), t3 where t1.name='matt' and t3.a = concat('',t1.name) and t3.b=t1.name; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 ref a a 44 const,const 6 Using where 1 SIMPLE t1 ref heap_idx heap_idx 22 const 7 Using where +1 SIMPLE t3 ref a a 44 const,const 7 Using where drop table t1, t2, t3; create temporary table t1 ( a int, index (a) ) engine=memory; insert into t1 values (1),(2),(3),(4),(5); diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index c6090bc663d..ffc5f5102a4 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -227,6 +227,9 @@ latin1_bin latin1 latin1_general_ci latin1 latin1_general_cs latin1 latin1_spanish_ci latin1 +drop procedure if exists sel2; +drop function if exists sub1; +drop function if exists sub2; create function sub1(i int) returns int return i+1; create procedure sel2() @@ -735,7 +738,7 @@ x_real NULL NULL x_float NULL NULL x_double_precision NULL NULL drop table t1; -create user mysqltest_4@localhost; +grant select on test.* to mysqltest_4@localhost; SELECT TABLE_NAME, COLUMN_NAME, PRIVILEGES FROM INFORMATION_SCHEMA.COLUMNS where COLUMN_NAME='TABLE_NAME'; TABLE_NAME COLUMN_NAME PRIVILEGES @@ -748,6 +751,7 @@ COLUMN_PRIVILEGES TABLE_NAME select TABLE_CONSTRAINTS TABLE_NAME select KEY_COLUMN_USAGE TABLE_NAME select delete from mysql.user where user='mysqltest_4'; +delete from mysql.db where user='mysqltest_4'; flush privileges; SELECT table_schema, count(*) FROM information_schema.TABLES GROUP BY TABLE_SCHEMA; table_schema count(*) @@ -823,6 +827,8 @@ GRANT SELECT ON *.* TO 'user4'@'localhost' drop user user1@localhost, user2@localhost, user3@localhost, user4@localhost; use test; drop database mysqltest; +drop procedure if exists p1; +drop procedure if exists p2; create procedure p1 () modifies sql data set @a = 5; create procedure p2 () set @a = 5; select sql_data_access from information_schema.routines diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index b07a6b03c8a..aab4eb696d2 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -972,9 +972,9 @@ number bigint(20) NOT NULL default '0', cname char(15) NOT NULL default '', carrier_id smallint(6) NOT NULL default '0', privacy tinyint(4) NOT NULL default '0', -last_mod_date timestamp(14) NOT NULL, +last_mod_date timestamp NOT NULL, last_mod_id smallint(6) NOT NULL default '0', -last_app_date timestamp(14) NOT NULL, +last_app_date timestamp NOT NULL, last_app_id smallint(6) default '-1', version smallint(6) NOT NULL default '0', assigned_scps int(11) default '0', @@ -991,9 +991,9 @@ number bigint(20) NOT NULL default '0', cname char(15) NOT NULL default '', carrier_id smallint(6) NOT NULL default '0', privacy tinyint(4) NOT NULL default '0', -last_mod_date timestamp(14) NOT NULL, +last_mod_date timestamp NOT NULL, last_mod_id smallint(6) NOT NULL default '0', -last_app_date timestamp(14) NOT NULL, +last_app_date timestamp NOT NULL, last_app_id smallint(6) default '-1', version smallint(6) NOT NULL default '0', assigned_scps int(11) default '0', @@ -1721,12 +1721,13 @@ count(*) 0 explain select count(*) from t1 where x > -16; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range PRIMARY PRIMARY 8 NULL 1 Using where; Using index +1 SIMPLE t1 index PRIMARY PRIMARY 8 NULL 2 Using where; Using index select count(*) from t1 where x > -16; count(*) -1 +2 select * from t1 where x > -16; x +18446744073709551600 18446744073709551601 select count(*) from t1 where x = 18446744073709551601; count(*) diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 026dae8381a..f745af182eb 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -1,4 +1,4 @@ -drop table if exists t1,t2; +drop table if exists t1,t2,t3; create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL); insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7,12),(8,12); create table t2 (payoutID SMALLINT UNSIGNED NOT NULL PRIMARY KEY); @@ -636,16 +636,35 @@ ff1 ff2 drop table t1, t2; create table t1 (a int unique); create table t2 (a int, b int); +create table t3 (c int, d int); insert into t1 values (1),(2); insert into t2 values (1,2); +insert into t3 values (1,6),(3,7); select * from t1; a 1 2 -insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b; +insert into t1 select a from t2 on duplicate key update a= t1.a + t2.b; select * from t1; a 2 3 -drop table t1; -drop table t2; +insert into t1 select a+1 from t2 on duplicate key update t1.a= t1.a + t2.b+1; +select * from t1; +a +3 +5 +insert into t1 select t3.c from t3 on duplicate key update a= a + t3.d; +select * from t1; +a +1 +5 +10 +insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= a + 10; +insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b; +ERROR 23000: Column 'a' in field list is ambiguous +insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b; +ERROR 42S02: Unknown table 't2' in field list +insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b; +ERROR 42S02: Unknown table 't2' in field list +drop table t1,t2,t3; diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index 739beea6286..fc157093a7f 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -143,7 +143,7 @@ INSERT t1 VALUES (1,2,10), (3,4,20); CREATE TABLE t2 (a INT, b INT, c INT, d INT); INSERT t2 VALUES (5,6,30,1), (7,4,40,1), (8,9,60,1); INSERT t2 VALUES (2,1,11,2), (7,4,40,2); -INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=c+100; +INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=t1.c+100; SELECT * FROM t1; a b c 1 2 10 @@ -158,6 +158,8 @@ a b c 5 0 30 8 9 60 INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=c+VALUES(a); +ERROR 23000: Column 'c' in field list is ambiguous +INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=t1.c+VALUES(t1.a); SELECT *, VALUES(a) FROM t1; a b c VALUES(a) 1 2 10 NULL @@ -174,7 +176,7 @@ select * from t1; a 1 2 -insert ignore into t1 select a from t1 on duplicate key update a=a+1 ; +insert ignore into t1 select a from t1 as t2 on duplicate key update a=t1.a+1 ; select * from t1; a 1 @@ -185,5 +187,7 @@ a 2 3 insert into t1 select a from t1 on duplicate key update a=a+1 ; -ERROR 23000: Duplicate entry '3' for key 1 +ERROR 23000: Column 'a' in field list is ambiguous +insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ; +ERROR 23000: Column 't1.a' in field list is ambiguous drop table t1; diff --git a/mysql-test/r/lowercase_table2.result b/mysql-test/r/lowercase_table2.result index db833bcd970..44235cbf900 100644 --- a/mysql-test/r/lowercase_table2.result +++ b/mysql-test/r/lowercase_table2.result @@ -1,6 +1,7 @@ -DROP TABLE IF EXISTS t1,t2,t3; +DROP TABLE IF EXISTS t1,t2,t3,t2aA,t1Aa; DROP DATABASE IF EXISTS `TEST_$1`; DROP DATABASE IF EXISTS `test_$1`; +DROP DATABASE IF EXISTS mysqltest_LC2; CREATE TABLE T1 (a int); INSERT INTO T1 VALUES (1); SHOW TABLES LIKE "T1"; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 080bc4d1e0f..be2003bbc67 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1,11 +1,11 @@ DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa; drop database if exists mysqldump_test_db; drop database if exists db1; -drop view if exists v1, v2; +drop view if exists v1, v2, v3; CREATE TABLE t1(a int); INSERT INTO t1 VALUES (1), (2); <?xml version="1.0"?> -<mysqldump> +<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <database name="test"> <table_structure name="t1"> <field Field="a" Type="int(11)" Null="YES" Key="" Extra="" /> @@ -108,7 +108,7 @@ DROP TABLE t1; 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> +<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <database name="test"> <table_structure name="t1"> <field Field="a" Type="int(11)" Null="YES" Key="" Extra="" /> @@ -133,7 +133,7 @@ DROP TABLE t1; CREATE TABLE t1 (`a"b"` char(2)); INSERT INTO t1 VALUES ("1\""), ("\"2"); <?xml version="1.0"?> -<mysqldump> +<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <database name="test"> <table_structure name="t1"> <field Field="a"b"" Type="char(2)" Null="YES" Key="" Extra="" /> @@ -380,6 +380,11 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; DROP TABLE IF EXISTS `v1`; DROP VIEW IF EXISTS `v1`; +CREATE TABLE `v1` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `v1`; +DROP VIEW IF EXISTS `v1`; CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1`; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; @@ -1458,6 +1463,11 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t2` ENABLE KEYS */; DROP TABLE IF EXISTS `v2`; DROP VIEW IF EXISTS `v2`; +CREATE TABLE `v2` ( + `a` varchar(30) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `v2`; +DROP VIEW IF EXISTS `v2`; CREATE ALGORITHM=UNDEFINED VIEW `db1`.`v2` AS select `db1`.`t2`.`a` AS `a` from `db1`.`t2` where (`db1`.`t2`.`a` like _latin1'a%') WITH CASCADED CHECK OPTION; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; @@ -1471,3 +1481,195 @@ CREATE ALGORITHM=UNDEFINED VIEW `db1`.`v2` AS select `db1`.`t2`.`a` AS `a` from drop table t2; drop view v2; drop database db1; +CREATE DATABASE mysqldump_test_db; +USE mysqldump_test_db; +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +<?xml version="1.0"?> +<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<database name="mysqldump_test_db"> + <table_structure name="t1"> + <field Field="a" Type="int(11)" Null="YES" Key="" Extra="" /> + </table_structure> + <table_structure name="t2"> + <field Field="a" Type="int(11)" Null="YES" Key="" Extra="" /> + </table_structure> +</database> +</mysqldump> +<?xml version="1.0"?> +<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<database name="mysqldump_test_db"> + <table_structure name="t1"> + <field Field="a" Type="int(11)" Null="YES" Key="" Extra="" /> + </table_structure> + <table_structure name="t2"> + <field Field="a" Type="int(11)" Null="YES" Key="" Extra="" /> + </table_structure> +</database> +</mysqldump> +DROP TABLE t1, t2; +DROP DATABASE mysqldump_test_db; +create database mysqldump_test_db; +use mysqldump_test_db; +create table t1(a varchar(30) primary key, b int not null); +create table t2(a varchar(30) primary key, b int not null); +create table t3(a varchar(30) primary key, b int not null); +test_sequence +------ Testing with illegal table names ------ +mysqldump: Couldn't find table: "\d-2-1.sql" + +mysqldump: Couldn't find table: "\t1" + +mysqldump: Couldn't find table: "\t1" + +mysqldump: Couldn't find table: "\\t1" + +mysqldump: Couldn't find table: "t\1" + +mysqldump: Couldn't find table: "t\1" + +mysqldump: Couldn't find table: "t/1" + +test_sequence +------ Testing with illegal database names ------ +mysqldump: Got error: 1049: Unknown database 'mysqldump_test_d' when selecting the database +mysqldump: Got error: 1102: Incorrect database name 'mysqld\ump_test_db' when selecting the database +drop table t1, t2, t3; +drop database mysqldump_test_db; +use test; +create table t1 (a int(10)); +create table t2 (pk int primary key auto_increment, +a int(10), b varchar(30), c datetime, d blob, e text); +insert into t1 values (NULL), (10), (20); +insert into t2 (a, b) values (NULL, NULL),(10, NULL),(NULL, "twenty"),(30, "thirty"); +<?xml version="1.0"?> +<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<database name="test"> + <table_data name="t1"> + <row> + <field name="a" xsi:nil="true" /> + </row> + <row> + <field name="a">10</field> + </row> + <row> + <field name="a">20</field> + </row> + </table_data> + <table_data name="t2"> + <row> + <field name="pk">1</field> + <field name="a" xsi:nil="true" /> + <field name="b" xsi:nil="true" /> + <field name="c" xsi:nil="true" /> + <field name="d" xsi:nil="true" /> + <field name="e" xsi:nil="true" /> + </row> + <row> + <field name="pk">2</field> + <field name="a">10</field> + <field name="b" xsi:nil="true" /> + <field name="c" xsi:nil="true" /> + <field name="d" xsi:nil="true" /> + <field name="e" xsi:nil="true" /> + </row> + <row> + <field name="pk">3</field> + <field name="a" xsi:nil="true" /> + <field name="b">twenty</field> + <field name="c" xsi:nil="true" /> + <field name="d" xsi:nil="true" /> + <field name="e" xsi:nil="true" /> + </row> + <row> + <field name="pk">4</field> + <field name="a">30</field> + <field name="b">thirty</field> + <field name="c" xsi:nil="true" /> + <field name="d" xsi:nil="true" /> + <field name="e" xsi:nil="true" /> + </row> + </table_data> +</database> +</mysqldump> +drop table t1, t2; +create table t1(a int, b int, c varchar(30)); +insert into t1 values(1, 2, "one"), (2, 4, "two"), (3, 6, "three"); +create view v3 as +select * from t1; +create view v1 as +select * from v3 where b in (1, 2, 3, 4, 5, 6, 7); +create view v2 as +select v3.a from v3, v1 where v1.a=v3.a and v3.b=3 limit 1; +drop view v1, v2, v3; +drop table t1; +show full tables; +Tables_in_test Table_type +t1 BASE TABLE +v1 VIEW +v2 VIEW +v3 VIEW +show create view v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `v3`.`a` AS `a`,`v3`.`b` AS `b`,`v3`.`c` AS `c` from `test`.`v3` where (`v3`.`b` in (1,2,3,4,5,6,7)) +select * from v1; +a b c +1 2 one +2 4 two +3 6 three +drop view v1, v2, v3; +drop table t1; diff --git a/mysql-test/r/ndb_autodiscover.result b/mysql-test/r/ndb_autodiscover.result index 27ebda36669..0f17160ea99 100644 --- a/mysql-test/r/ndb_autodiscover.result +++ b/mysql-test/r/ndb_autodiscover.result @@ -93,7 +93,7 @@ name char(20), a int, b float, c char(24) ERROR 42S01: Table 't3' already exists show status like 'handler_discover%'; Variable_name Value -Handler_discover 1 +Handler_discover 0 create table IF NOT EXISTS t3( id int not null primary key, id2 int not null, @@ -101,7 +101,7 @@ name char(20) ) engine=ndb; show status like 'handler_discover%'; Variable_name Value -Handler_discover 2 +Handler_discover 0 SHOW CREATE TABLE t3; Table Create Table t3 CREATE TABLE `t3` ( @@ -114,7 +114,7 @@ id name 1 Explorer show status like 'handler_discover%'; Variable_name Value -Handler_discover 2 +Handler_discover 1 drop table t3; flush status; create table t7( diff --git a/mysql-test/r/not_openssl.require b/mysql-test/r/not_openssl.require new file mode 100644 index 00000000000..2b5e423999c --- /dev/null +++ b/mysql-test/r/not_openssl.require @@ -0,0 +1,2 @@ +Variable_name Value +have_openssl NO diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index c37a42d3fa7..a19734d55b5 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -555,3 +555,25 @@ IFNULL(a, 'TEST') COALESCE(b, 'TEST') 4 TEST TEST TEST DROP TABLE t1,t2; +CREATE TABLE t1(id int, type char(1)); +INSERT INTO t1 VALUES +(1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"), +(6,"B"),(7,"A"),(8,"C"),(9,"A"),(10,"C"); +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT type FROM t1 GROUP BY type WITH ROLLUP; +type +A +B +C +NULL +SELECT type FROM v1 GROUP BY type WITH ROLLUP; +type +A +B +C +NULL +EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using filesort +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 290d264174e..bd06be07a8e 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -138,7 +138,7 @@ create table t1 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), -c13 date, c14 datetime, c15 timestamp(14), c16 time, +c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 bit, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index 54c35873201..f2d60ac5025 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -17,7 +17,7 @@ create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), -c13 date, c14 datetime, c15 timestamp(14), c16 time, +c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, @@ -290,11 +290,11 @@ t2 1 t2_idx 1 b A NULL NULL NULL YES BTREE prepare stmt4 from ' show table status from test like ''t2%'' '; execute stmt4; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t2 MyISAM 10 Fixed 0 0 0 4222124650659839 1024 0 NULL # # # latin1_swedish_ci NULL +t2 MyISAM 10 Fixed 0 0 0 # 1024 0 NULL # # # latin1_swedish_ci NULL prepare stmt4 from ' show table status from test like ''t9%'' '; execute stmt4; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t9 MyISAM 10 Dynamic 2 216 432 281474976710655 2048 0 NULL # # # latin1_swedish_ci NULL +t9 MyISAM 10 Dynamic 2 216 432 # 2048 0 NULL # # # latin1_swedish_ci NULL prepare stmt4 from ' show status like ''Threads_running'' '; execute stmt4; Variable_name Value diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 5e839bf4a02..a9342636349 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -10,7 +10,7 @@ create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), -c13 date, c14 datetime, c15 timestamp(14), c16 time, +c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index c5d5895adca..3a470d218d1 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -10,7 +10,7 @@ create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), -c13 date, c14 datetime, c15 timestamp(14), c16 time, +c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index 8d703ec1ea5..beeaff05ece 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -11,7 +11,7 @@ create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), -c13 date, c14 datetime, c15 timestamp(14), c16 time, +c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 varchar(100), c24 varchar(100), c25 varchar(100), c26 varchar(100), c27 varchar(100), c28 varchar(100), diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index 72b0fac4201..fada983a561 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -12,7 +12,7 @@ create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), -c13 date, c14 datetime, c15 timestamp(14), c16 time, +c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, @@ -32,7 +32,7 @@ create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), -c13 date, c14 datetime, c15 timestamp(14), c16 time, +c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, @@ -52,7 +52,7 @@ create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), -c13 date, c14 datetime, c15 timestamp(14), c16 time, +c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, @@ -3064,7 +3064,7 @@ create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), -c13 date, c14 datetime, c15 timestamp(14), c16 time, +c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index 87b1b110f42..404c25c2c37 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -10,7 +10,7 @@ create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), -c13 date, c14 datetime, c15 timestamp(14), c16 time, +c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index c158156d11d..ffddec6d5c2 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -10,7 +10,7 @@ create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), -c13 date, c14 datetime, c15 timestamp(14), c16 time, +c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 506a76579ae..699d81d4cef 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -930,7 +930,7 @@ Variable_name Value Qcache_queries_in_cache 0 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 19 +Qcache_inserts 18 show status like "Qcache_hits"; Variable_name Value Qcache_hits 6 @@ -943,7 +943,7 @@ Variable_name Value Qcache_queries_in_cache 1 show status like "Qcache_inserts"; Variable_name Value -Qcache_inserts 20 +Qcache_inserts 19 show status like "Qcache_hits"; Variable_name Value Qcache_hits 7 @@ -1007,6 +1007,93 @@ abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab zyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcba flush query cache; drop table t1, t2; +flush status; +CREATE TABLE t1 ( +`date` datetime NOT NULL default '0000-00-00 00:00:00', +KEY `date` (`date`) +) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('20050326'); +INSERT INTO t1 VALUES ('20050325'); +SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 0:0:0'; +COUNT(*) +0 +Warnings: +Warning 1292 Incorrect datetime value: '20050327 0:0:0' for column 'date' at row 1 +Warning 1292 Incorrect datetime value: '20050327 0:0:0' for column 'date' at row 1 +SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050328 0:0:0'; +COUNT(*) +0 +Warnings: +Warning 1292 Incorrect datetime value: '20050328 0:0:0' for column 'date' at row 1 +Warning 1292 Incorrect datetime value: '20050328 0:0:0' for column 'date' at row 1 +SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 0:0:0'; +COUNT(*) +0 +Warnings: +Warning 1292 Incorrect datetime value: '20050327 0:0:0' for column 'date' at row 1 +Warning 1292 Incorrect datetime value: '20050327 0:0:0' for column 'date' at row 1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 0 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +drop table t1; +create table t1 (a int); +insert into t1 values (1); +reset query cache; +flush status; +select * from (select * from t1) a; +a +1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from (select * from t1) a; +a +1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +insert into t1 values (2); +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +select * from (select * from t1) a; +a +1 +2 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +drop table t1; create table t1 (a int); insert into t1 values (1),(2); CREATE PROCEDURE `p1`() diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index c7d27a8e60d..6f9b4e41b22 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -549,6 +549,66 @@ select count(*) from t2 where x = 18446744073709551601; count(*) 0 drop table t1,t2; +create table t1 (x bigint unsigned not null primary key) engine=innodb; +insert into t1(x) values (0xfffffffffffffff0); +insert into t1(x) values (0xfffffffffffffff1); +select * from t1; +x +18446744073709551600 +18446744073709551601 +select count(*) from t1 where x>0; +count(*) +2 +select count(*) from t1 where x=0; +count(*) +0 +select count(*) from t1 where x<0; +count(*) +0 +select count(*) from t1 where x < -16; +count(*) +0 +select count(*) from t1 where x = -16; +count(*) +0 +select count(*) from t1 where x > -16; +count(*) +2 +select count(*) from t1 where x = 18446744073709551601; +count(*) +1 +drop table t1; +create table t1 (a bigint unsigned); +create index t1i on t1(a); +insert into t1 select 18446744073709551615; +insert into t1 select 18446744073709551614; +explain select * from t1 where a <> -1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index t1i t1i 9 NULL 2 Using where; Using index +select * from t1 where a <> -1; +a +18446744073709551614 +18446744073709551615 +explain select * from t1 where a > -1 or a < -1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index t1i t1i 9 NULL 2 Using where; Using index +select * from t1 where a > -1 or a < -1; +a +18446744073709551614 +18446744073709551615 +explain select * from t1 where a > -1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index t1i t1i 9 NULL 2 Using where; Using index +select * from t1 where a > -1; +a +18446744073709551614 +18446744073709551615 +explain select * from t1 where a < -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 +select * from t1 where a < -1; +a +drop table t1; set names latin1; create table t1 (a char(10), b text, key (a)) character set latin1; INSERT INTO t1 (a) VALUES @@ -660,3 +720,27 @@ id status 59 C 60 C DROP TABLE t1; +CREATE TABLE t1 (a int, b int, primary key(a,b)); +INSERT INTO t1 VALUES +(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3),(4,1),(4,2),(4,3); +CREATE VIEW v1 as SELECT a,b FROM t1 WHERE b=3; +EXPLAIN SELECT a,b FROM t1 WHERE a < 2 and b=3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index +EXPLAIN SELECT a,b FROM v1 WHERE a < 2 and b=3; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index +EXPLAIN SELECT a,b FROM t1 WHERE a < 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index +EXPLAIN SELECT a,b FROM v1 WHERE a < 2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index +SELECT a,b FROM t1 WHERE a < 2 and b=3; +a b +1 3 +SELECT a,b FROM v1 WHERE a < 2 and b=3; +a b +1 3 +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/r/rpl_innodb.result b/mysql-test/r/rpl_innodb.result new file mode 100644 index 00000000000..ebf1d79c4d0 --- /dev/null +++ b/mysql-test/r/rpl_innodb.result @@ -0,0 +1,37 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TABLE t4 ( +id INT(5) unsigned NOT NULL auto_increment, +name varchar(15) NOT NULL default '', +number varchar(35) NOT NULL default 'default', +PRIMARY KEY (id), +UNIQUE KEY unique_rec (name,number) +) ENGINE=InnoDB; +LOAD DATA +INFILE '../../std_data/loaddata_pair.dat' +REPLACE INTO TABLE t4 +(name,number); +SELECT * FROM t4; +id name number +1 XXX 12345 +2 XXY 12345 +SELECT * FROM t4; +id name number +1 XXX 12345 +2 XXY 12345 +LOAD DATA +INFILE '../../std_data/loaddata_pair.dat' +REPLACE INTO TABLE t4 +(name,number); +SELECT * FROM t4; +id name number +3 XXX 12345 +4 XXY 12345 +SELECT * FROM t4; +id name number +3 XXX 12345 +4 XXY 12345 diff --git a/mysql-test/r/rpl_multi_update3.result b/mysql-test/r/rpl_multi_update3.result index 708b230b19f..1b757b1400c 100644 --- a/mysql-test/r/rpl_multi_update3.result +++ b/mysql-test/r/rpl_multi_update3.result @@ -4,6 +4,8 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; + +-------- Test for BUG#9361 -------- CREATE TABLE t1 ( a int unsigned not null auto_increment primary key, b int unsigned @@ -41,3 +43,82 @@ a b 1 6 2 6 drop table t1,t2; + +-------- Test 1 for BUG#9361 -------- +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +CREATE TABLE t1 ( +a1 char(30), +a2 int, +a3 int, +a4 char(30), +a5 char(30) +); +CREATE TABLE t2 ( +b1 int, +b2 char(30) +); +INSERT INTO t1 VALUES ('Yes', 1, NULL, 'foo', 'bar'); +INSERT INTO t2 VALUES (1, 'baz'); +UPDATE t1 a, t2 +SET a.a1 = 'No' +WHERE a.a2 = +(SELECT b1 +FROM t2 +WHERE b2 = 'baz') +AND a.a3 IS NULL +AND a.a4 = 'foo' +AND a.a5 = 'bar'; +SELECT * FROM t1; +a1 a2 a3 a4 a5 +No 1 NULL foo bar +SELECT * FROM t2; +b1 b2 +1 baz +DROP TABLE t1, t2; + +-------- Test 2 for BUG#9361 -------- +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +CREATE TABLE t1 ( +i INT, +j INT, +x INT, +y INT, +z INT +); +CREATE TABLE t2 ( +i INT, +k INT, +x INT, +y INT, +z INT +); +CREATE TABLE t3 ( +j INT, +k INT, +x INT, +y INT, +z INT +); +INSERT INTO t1 VALUES ( 1, 2,13,14,15); +INSERT INTO t2 VALUES ( 1, 3,23,24,25); +INSERT INTO t3 VALUES ( 2, 3, 1,34,35), ( 2, 3, 1,34,36); +UPDATE t1 AS a +INNER JOIN t2 AS b +ON a.i = b.i +INNER JOIN t3 AS c +ON a.j = c.j AND b.k = c.k +SET a.x = b.x, +a.y = b.y, +a.z = ( +SELECT sum(z) +FROM t3 +WHERE y = 34 +) +WHERE b.x = 23; +SELECT * FROM t1; +i j x y z +1 2 23 24 71 +DROP TABLE t1, t2, t3; diff --git a/mysql-test/r/rpl_trunc_binlog.result b/mysql-test/r/rpl_trunc_binlog.result deleted file mode 100644 index 2663fffe4d4..00000000000 --- a/mysql-test/r/rpl_trunc_binlog.result +++ /dev/null @@ -1,17 +0,0 @@ -stop slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -reset master; -reset slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -start slave; -stop slave; -flush logs; -create table t1 (a int) engine=bdb; -reset slave; -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 # # master-bin.000002 Yes Yes 0 Rolling back unfinished transaction (no COMMIT or ROLLBACK) from relay log. A probable cause is that the master died while writing the transaction to its binary log. 0 4 # None 0 No # -select * from t1; -a -drop table t1; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index bd2825822a1..d02c28a0a97 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2073,7 +2073,7 @@ INSERT INTO t1 (pseudo) VALUES ('test1'); SELECT 1 as rnd1 from t1 where rand() > 2; rnd1 DROP TABLE t1; -CREATE TABLE t1 (gvid int(10) unsigned default NULL, hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, mmid int(10) unsigned default NULL, hdid int(10) unsigned default NULL, fsid int(10) unsigned default NULL, ctid int(10) unsigned default NULL, dtid int(10) unsigned default NULL, cost int(10) unsigned default NULL, performance int(10) unsigned default NULL, serialnumber bigint(20) unsigned default NULL, monitored tinyint(3) unsigned default '1', removed tinyint(3) unsigned default '0', target tinyint(3) unsigned default '0', dt_modified timestamp(14) NOT NULL, name varchar(255) binary default NULL, description varchar(255) default NULL, UNIQUE KEY hmid (hmid,volid)) ENGINE=MyISAM; +CREATE TABLE t1 (gvid int(10) unsigned default NULL, hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, mmid int(10) unsigned default NULL, hdid int(10) unsigned default NULL, fsid int(10) unsigned default NULL, ctid int(10) unsigned default NULL, dtid int(10) unsigned default NULL, cost int(10) unsigned default NULL, performance int(10) unsigned default NULL, serialnumber bigint(20) unsigned default NULL, monitored tinyint(3) unsigned default '1', removed tinyint(3) unsigned default '0', target tinyint(3) unsigned default '0', dt_modified timestamp NOT NULL, name varchar(255) binary default NULL, description varchar(255) default NULL, UNIQUE KEY hmid (hmid,volid)) ENGINE=MyISAM; INSERT INTO t1 VALUES (200001,2,1,1,100,1,1,1,0,0,0,1,0,1,20020425060057,'\\\\ARKIVIO-TESTPDC\\E$',''),(200002,2,2,1,101,1,1,1,0,0,0,1,0,1,20020425060057,'\\\\ARKIVIO-TESTPDC\\C$',''),(200003,1,3,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,0,1,20020425060427,'c:',NULL); CREATE TABLE t2 ( hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, sampletid smallint(5) unsigned default NULL, sampletime datetime default NULL, samplevalue bigint(20) unsigned default NULL, KEY idx1 (hmid,volid,sampletid,sampletime)) ENGINE=MyISAM; INSERT INTO t2 VALUES (1,3,10,'2002-06-01 08:00:00',35),(1,3,1010,'2002-06-01 12:00:01',35); @@ -2423,12 +2423,130 @@ ERROR HY000: Incorrect usage of ALL and DISTINCT select distinct all * from t1; ERROR HY000: Incorrect usage of ALL and DISTINCT drop table t1; +CREATE TABLE t1 ( +kunde_intern_id int(10) unsigned NOT NULL default '0', +kunde_id int(10) unsigned NOT NULL default '0', +FK_firma_id int(10) unsigned NOT NULL default '0', +aktuell enum('Ja','Nein') NOT NULL default 'Ja', +vorname varchar(128) NOT NULL default '', +nachname varchar(128) NOT NULL default '', +geloescht enum('Ja','Nein') NOT NULL default 'Nein', +firma varchar(128) NOT NULL default '' +); +INSERT INTO t1 VALUES +(3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'), +(3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX'); +SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1 +WHERE +( +( +( '' != '' AND firma LIKE CONCAT('%', '', '%')) +OR +(vorname LIKE CONCAT('%', 'Vorname1', '%') AND +nachname LIKE CONCAT('%', '1Nachname', '%') AND +'Vorname1' != '' AND 'xxxx' != '') +) +AND +( +aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 +) +) +; +kunde_id FK_firma_id aktuell vorname nachname geloescht +SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, +geloescht FROM t1 +WHERE +( +( +aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 +) +AND +( +( '' != '' AND firma LIKE CONCAT('%', '', '%') ) +OR +( vorname LIKE CONCAT('%', 'Vorname1', '%') AND +nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND +'xxxx' != '') +) +) +; +kunde_id FK_firma_id aktuell vorname nachname geloescht +SELECT COUNT(*) FROM t1 WHERE +( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1)) +AND FK_firma_id = 2; +COUNT(*) +0 +drop table t1; CREATE TABLE t1 (b BIGINT(20) UNSIGNED NOT NULL, PRIMARY KEY (b)); INSERT INTO t1 VALUES (0x8000000000000000); SELECT b FROM t1 WHERE b=0x8000000000000000; b 9223372036854775808 DROP TABLE t1; +CREATE TABLE `t1` ( `gid` int(11) default NULL, `uid` int(11) default NULL); +CREATE TABLE `t2` ( `ident` int(11) default NULL, `level` char(16) default NULL); +INSERT INTO `t2` VALUES (0,'READ'); +CREATE TABLE `t3` ( `id` int(11) default NULL, `name` char(16) default NULL); +INSERT INTO `t3` VALUES (1,'fs'); +select * from t3 left join t1 on t3.id = t1.uid, t2 where t2.ident in (0, t1.gid, t3.id, 0); +id name gid uid ident level +1 fs NULL NULL 0 READ +drop table t1,t2,t3; +CREATE TABLE t1 ( city char(30) ); +INSERT INTO t1 VALUES ('London'); +INSERT INTO t1 VALUES ('Paris'); +SELECT * FROM t1 WHERE city='London'; +city +London +SELECT * FROM t1 WHERE city='london'; +city +London +EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +SELECT * FROM t1 WHERE city='London' AND city='london'; +city +London +EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; +city +London +DROP TABLE t1; +create table t1 (a int(11) unsigned, b int(11) unsigned); +insert into t1 values (1,0), (1,1), (1,2); +select a-b from t1 order by 1; +a-b +0 +1 +18446744073709551615 +select a-b , (a-b < 0) from t1 order by 1; +a-b (a-b < 0) +0 0 +1 0 +18446744073709551615 0 +select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0; +d (a-b >= 0) b +1 1 0 +0 1 1 +18446744073709551615 1 2 +select cast((a - b) as unsigned) from t1 order by 1; +cast((a - b) as unsigned) +0 +1 +18446744073709551615 +drop table t1; +create table t1 (a int(11)); +select all all * from t1; +a +select distinct distinct * from t1; +a +select all distinct * from t1; +ERROR HY000: Incorrect usage of ALL and DISTINCT +select distinct all * from t1; +ERROR HY000: Incorrect usage of ALL and DISTINCT +drop table t1; CREATE TABLE t1 ( K2C4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '', K4N4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '0000', @@ -2573,115 +2691,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 1 SIMPLE t2 ref a a 23 test.t1.a 2 DROP TABLE t1, t2; -CREATE TABLE t1 ( city char(30) ); -INSERT INTO t1 VALUES ('London'); -INSERT INTO t1 VALUES ('Paris'); -SELECT * FROM t1 WHERE city='London'; -city -London -SELECT * FROM t1 WHERE city='london'; -city -London -EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where -SELECT * FROM t1 WHERE city='London' AND city='london'; -city -London -EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where -SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; -city -London -DROP TABLE t1; -create table t1 (a int(11) unsigned, b int(11) unsigned); -insert into t1 values (1,0), (1,1), (1,2); -select a-b from t1 order by 1; -a-b -0 -1 -18446744073709551615 -select a-b , (a-b < 0) from t1 order by 1; -a-b (a-b < 0) -0 0 -1 0 -18446744073709551615 0 -select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0; -d (a-b >= 0) b -1 1 0 -0 1 1 -18446744073709551615 1 2 -select cast((a - b) as unsigned) from t1 order by 1; -cast((a - b) as unsigned) -0 -1 -18446744073709551615 -drop table t1; -create table t1 (a int(11)); -select all all * from t1; -a -select distinct distinct * from t1; -a -select all distinct * from t1; -ERROR HY000: Incorrect usage of ALL and DISTINCT -select distinct all * from t1; -ERROR HY000: Incorrect usage of ALL and DISTINCT -drop table t1; -CREATE TABLE t1 ( -kunde_intern_id int(10) unsigned NOT NULL default '0', -kunde_id int(10) unsigned NOT NULL default '0', -FK_firma_id int(10) unsigned NOT NULL default '0', -aktuell enum('Ja','Nein') NOT NULL default 'Ja', -vorname varchar(128) NOT NULL default '', -nachname varchar(128) NOT NULL default '', -geloescht enum('Ja','Nein') NOT NULL default 'Nein', -firma varchar(128) NOT NULL default '' -); -INSERT INTO t1 VALUES -(3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'), -(3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX'); -SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1 -WHERE -( -( -( '' != '' AND firma LIKE CONCAT('%', '', '%')) -OR -(vorname LIKE CONCAT('%', 'Vorname1', '%') AND -nachname LIKE CONCAT('%', '1Nachname', '%') AND -'Vorname1' != '' AND 'xxxx' != '') -) -AND -( -aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 -) -) -; -kunde_id FK_firma_id aktuell vorname nachname geloescht -SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, -geloescht FROM t1 -WHERE -( -( -aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 -) -AND -( -( '' != '' AND firma LIKE CONCAT('%', '', '%') ) -OR -( vorname LIKE CONCAT('%', 'Vorname1', '%') AND -nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND -'xxxx' != '') -) -) -; -kunde_id FK_firma_id aktuell vorname nachname geloescht -SELECT COUNT(*) FROM t1 WHERE -( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1)) -AND FK_firma_id = 2; -COUNT(*) -0 -drop table t1; CREATE TABLE t1 (a int); CREATE TABLE t2 (a int); INSERT INTO t1 VALUES (1), (2), (3), (4), (5); diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index dd07e0ba755..f1c536ed1da 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -267,9 +267,9 @@ drop table t1; create table t1 (c decimal(3,3), d double(3,3), f float(3,3)); show columns from t1; Field Type Null Key Default Extra -c decimal(4,3) YES NULL -d double(4,3) YES NULL -f float(4,3) YES NULL +c decimal(3,3) YES NULL +d double(3,3) YES NULL +f float(3,3) YES NULL drop table t1; SET @old_sql_mode= @@sql_mode, sql_mode= ''; SET @old_sql_quote_show_create= @@sql_quote_show_create, sql_quote_show_create= OFF; @@ -497,3 +497,18 @@ def STATISTICS COMMENT Comment 253 16 0 Y 0 0 63 Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 0 PRIMARY 1 field1 A 0 1000 NULL BTREE drop table t1; +create table t1 ( +c1 int NOT NULL, +c2 int NOT NULL, +PRIMARY KEY USING HASH (c1), +INDEX USING BTREE(c2) +); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL, + `c2` int(11) NOT NULL, + PRIMARY KEY USING HASH (`c1`), + KEY `c2` USING BTREE (`c2`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index b6ba737a8ba..18acd2e4c03 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1,3 +1,4 @@ +drop table if exists t1, t2; delete from mysql.proc; create procedure syntaxerror(t int)| 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 '' at line 1 @@ -65,47 +66,6 @@ iterate foo; end| ERROR 42000: ITERATE with no matching label: foo create procedure foo() -begin -goto foo; -end| -ERROR 42000: GOTO with no matching label: foo -create procedure foo() -begin -begin -label foo; -end; -goto foo; -end| -ERROR 42000: GOTO with no matching label: foo -create procedure foo() -begin -goto foo; -begin -label foo; -end; -end| -ERROR 42000: GOTO with no matching label: foo -create procedure foo() -begin -begin -goto foo; -end; -begin -label foo; -end; -end| -ERROR 42000: GOTO with no matching label: foo -create procedure foo() -begin -begin -label foo; -end; -begin -goto foo; -end; -end| -ERROR 42000: GOTO with no matching label: foo -create procedure foo() foo: loop foo: loop set @x=2; @@ -308,16 +268,6 @@ declare continue handler for sqlstate '42S99' set x = 1; declare c cursor for select * from t1; end| ERROR 42000: Cursor declaration after handler declaration -create procedure p() -begin -declare continue handler for sqlexception -begin -goto L1; -end; -select field from t1; -label L1; -end| -ERROR HY000: GOTO is not allowed in a stored procedure handler drop procedure if exists p| create procedure p(in x int, inout y int, out z int) begin @@ -654,10 +604,10 @@ flush tables; return 5; end| ERROR 0A000: FLUSH is not allowed in stored procedures -create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890() +create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123() begin end| -ERROR 42000: Identifier name 'bug9529_90123456789012345678901234567890123456789012345678901234567890' is too long +ERROR 42000: Identifier name 'bug9529_90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890' is too long drop procedure if exists bug10969| create procedure bug10969() begin @@ -686,3 +636,88 @@ ERROR 0A000: EXECUTE is not allowed in stored procedures create function f() returns int begin execute stmt; ERROR 0A000: EXECUTE is not allowed in stored procedures deallocate prepare stmt; +create table t1(f1 int); +create table t2(f1 int); +CREATE PROCEDURE SP001() +P1: BEGIN +DECLARE ENDTABLE INT DEFAULT 0; +DECLARE TEMP_NUM INT; +DECLARE TEMP_SUM INT; +DECLARE C1 CURSOR FOR SELECT F1 FROM t1; +DECLARE C2 CURSOR FOR SELECT F1 FROM t2; +DECLARE CONTINUE HANDLER FOR NOT FOUND SET ENDTABLE = 1; +SET ENDTABLE=0; +SET TEMP_SUM=0; +SET TEMP_NUM=0; +OPEN C1; +FETCH C1 INTO TEMP_NUM; +WHILE ENDTABLE = 0 DO +SET TEMP_SUM=TEMP_NUM+TEMP_SUM; +FETCH C1 INTO TEMP_NUM; +END WHILE; +SELECT TEMP_SUM; +CLOSE C1; +CLOSE C1; +SELECT 'end of proc'; +END P1| +call SP001(); +TEMP_SUM +0 +drop procedure SP001; +drop table t1, t2; +drop function if exists bug11394| +drop function if exists bug11394_1| +drop function if exists bug11394_2| +drop procedure if exists bug11394| +create function bug11394(i int) returns int +begin +if i <= 0 then +return 0; +else +return (i in (100, 200, bug11394(i-1), 400)); +end if; +end| +select bug11394(2)| +ERROR HY000: Recursive stored routines are not allowed. +drop function bug11394| +create function bug11394_1(i int) returns int +begin +if i <= 0 then +return 0; +else +return (select bug11394_1(i-1)); +end if; +end| +select bug11394_1(2)| +ERROR HY000: Recursive stored routines are not allowed. +drop function bug11394_1| +create function bug11394_2(i int) returns int return i| +select bug11394_2(bug11394_2(10))| +bug11394_2(bug11394_2(10)) +10 +drop function bug11394_2| +create procedure bug11394(i int, j int) +begin +if i > 0 then +call bug11394(i - 1,(select 1)); +end if; +end| +call bug11394(2, 1)| +ERROR HY000: Recursive stored routines are not allowed. +drop procedure bug11394| +drop function if exists bug11834_1; +drop function if exists bug11834_2; +create function bug11834_1() returns int return 10; +create function bug11834_2() returns int return bug11834_1(); +prepare stmt from "select bug11834_2()"; +execute stmt; +bug11834_2() +10 +execute stmt; +bug11834_2() +10 +drop function bug11834_1; +execute stmt; +ERROR 42000: FUNCTION test.bug11834_1 does not exist +deallocate prepare stmt; +drop function bug11834_2; diff --git a/mysql-test/r/sp-goto.result b/mysql-test/r/sp-goto.result new file mode 100644 index 00000000000..ca560f62318 --- /dev/null +++ b/mysql-test/r/sp-goto.result @@ -0,0 +1,205 @@ +drop table if exists t1; +create table t1 ( +id char(16) not null default '', +data int not null +); +drop procedure if exists goto1// +create procedure goto1() +begin +declare y int; +label a; +select * from t1; +select count(*) into y from t1; +if y > 2 then +goto b; +end if; +insert into t1 values ("j", y); +goto a; +label b; +end// +call goto1()// +id data +id data +j 0 +id data +j 0 +j 1 +id data +j 0 +j 1 +j 2 +drop procedure goto1// +drop procedure if exists goto2// +create procedure goto2(a int) +begin +declare x int default 0; +declare continue handler for sqlstate '42S98' set x = 1; +label a; +select * from t1; +b: +while x < 2 do +begin +declare continue handler for sqlstate '42S99' set x = 2; +if a = 0 then +set x = x + 1; +iterate b; +elseif a = 1 then +leave b; +elseif a = 2 then +set a = 1; +goto a; +end if; +end; +end while b; +select * from t1; +end// +call goto2(0)// +id data +j 0 +j 1 +j 2 +id data +j 0 +j 1 +j 2 +call goto2(1)// +id data +j 0 +j 1 +j 2 +id data +j 0 +j 1 +j 2 +call goto2(2)// +id data +j 0 +j 1 +j 2 +id data +j 0 +j 1 +j 2 +id data +j 0 +j 1 +j 2 +drop procedure goto2// +delete from t1// +drop procedure if exists goto3// +create procedure goto3() +begin +label L1; +begin +end; +goto L1; +end// +drop procedure goto3// +drop procedure if exists goto4// +create procedure goto4() +begin +begin +label lab1; +begin +goto lab1; +end; +end; +end// +drop procedure goto4// +drop procedure if exists goto5// +create procedure goto5() +begin +begin +begin +goto lab1; +end; +label lab1; +end; +end// +drop procedure goto5// +drop procedure if exists goto6// +create procedure goto6() +begin +label L1; +goto L5; +begin +label L2; +goto L1; +goto L5; +begin +label L3; +goto L1; +goto L2; +goto L3; +goto L4; +goto L5; +end; +goto L2; +goto L4; +label L4; +end; +label L5; +goto L1; +end// +drop procedure goto6// +create procedure foo() +begin +goto foo; +end// +ERROR 42000: GOTO with no matching label: foo +create procedure foo() +begin +begin +label foo; +end; +goto foo; +end// +ERROR 42000: GOTO with no matching label: foo +create procedure foo() +begin +goto foo; +begin +label foo; +end; +end// +ERROR 42000: GOTO with no matching label: foo +create procedure foo() +begin +begin +goto foo; +end; +begin +label foo; +end; +end// +ERROR 42000: GOTO with no matching label: foo +create procedure foo() +begin +begin +label foo; +end; +begin +goto foo; +end; +end// +ERROR 42000: GOTO with no matching label: foo +create procedure p() +begin +declare continue handler for sqlexception +begin +goto L1; +end; +select field from t1; +label L1; +end// +ERROR HY000: GOTO is not allowed in a stored procedure handler +drop procedure if exists bug6898// +create procedure bug6898() +begin +goto label1; +label label1; +begin end; +goto label1; +end// +drop procedure bug6898// +drop table t1; diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result index ee72fde7324..3a0d2aa5f36 100644 --- a/mysql-test/r/sp-security.result +++ b/mysql-test/r/sp-security.result @@ -1,6 +1,7 @@ use test; grant usage on *.* to user1@localhost; flush privileges; +drop table if exists t1; drop database if exists db1_secret; create database db1_secret; create procedure db1_secret.dummy() begin end; @@ -194,3 +195,20 @@ use test; drop database sptest; delete from mysql.user where user='usera' or user='userb' or user='userc'; delete from mysql.procs_priv where user='usera' or user='userb' or user='userc'; +drop function if exists bug_9503; +create database mysqltest// +use mysqltest// +create table t1 (s1 int)// +grant select on t1 to user1@localhost// +create function bug_9503 () returns int sql security invoker begin declare v int; +select min(s1) into v from t1; return v; end// +use mysqltest; +select bug_9503(); +ERROR 42000: execute command denied to user 'user1'@'localhost' for routine 'mysqltest.bug_9503' +grant execute on function bug_9503 to user1@localhost; +do 1; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost; +drop function bug_9503; +use test; +drop database mysqltest; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index ed858ba27ee..74c03987a6a 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -438,145 +438,6 @@ id data i 3 delete from t1| drop procedure i| -drop procedure if exists goto1| -create procedure goto1() -begin -declare y int; -label a; -select * from t1; -select count(*) into y from t1; -if y > 2 then -goto b; -end if; -insert into t1 values ("j", y); -goto a; -label b; -end| -call goto1()| -id data -id data -j 0 -id data -j 0 -j 1 -id data -j 0 -j 1 -j 2 -drop procedure goto1| -drop procedure if exists goto2| -create procedure goto2(a int) -begin -declare x int default 0; -declare continue handler for sqlstate '42S98' set x = 1; -label a; -select * from t1; -b: -while x < 2 do -begin -declare continue handler for sqlstate '42S99' set x = 2; -if a = 0 then -set x = x + 1; -iterate b; -elseif a = 1 then -leave b; -elseif a = 2 then -set a = 1; -goto a; -end if; -end; -end while b; -select * from t1; -end| -call goto2(0)| -id data -j 0 -j 1 -j 2 -id data -j 0 -j 1 -j 2 -call goto2(1)| -id data -j 0 -j 1 -j 2 -id data -j 0 -j 1 -j 2 -call goto2(2)| -id data -j 0 -j 1 -j 2 -id data -j 0 -j 1 -j 2 -id data -j 0 -j 1 -j 2 -drop procedure goto2| -delete from t1| -drop procedure if exists goto3| -create procedure goto3() -begin -label L1; -begin -end; -goto L1; -end| -drop procedure goto3| -drop procedure if exists goto4| -create procedure goto4() -begin -begin -label lab1; -begin -goto lab1; -end; -end; -end| -drop procedure goto4| -drop procedure if exists goto5| -create procedure goto5() -begin -begin -begin -goto lab1; -end; -label lab1; -end; -end| -drop procedure goto5| -drop procedure if exists goto6| -create procedure goto6() -begin -label L1; -goto L5; -begin -label L2; -goto L1; -goto L5; -begin -label L3; -goto L1; -goto L2; -goto L3; -goto L4; -goto L5; -end; -goto L2; -goto L4; -label L4; -end; -label L5; -goto L1; -end| -drop procedure goto6| insert into t1 values ("foo", 3), ("bar", 19)| insert into t2 values ("x", 9, 4.1), ("y", -1, 19.2), ("z", 3, 2.2)| drop procedure if exists sel1| @@ -1227,7 +1088,7 @@ a select * from v1| a 3 -select * from v1, v2| +select * from v1, t1| ERROR HY000: Table 't1' was not locked with LOCK TABLES select f4()| ERROR HY000: Table 't2' was not locked with LOCK TABLES @@ -1396,60 +1257,6 @@ drop procedure opp| drop procedure ip| show procedure status like '%p%'| Db Name Type Definer Modified Created Security_type Comment -drop table if exists fib| -create table fib ( f bigint unsigned not null )| -drop procedure if exists fib| -create procedure fib(n int unsigned) -begin -if n > 1 then -begin -declare x, y bigint unsigned; -declare c cursor for select f from fib order by f desc limit 2; -open c; -fetch c into y; -fetch c into x; -close c; -insert into fib values (x+y); -call fib(n-1); -end; -end if; -end| -insert into fib values (0), (1)| -call fib(3)| -select * from fib order by f asc| -f -0 -1 -1 -2 -delete from fib| -insert into fib values (0), (1)| -call fib(20)| -select * from fib order by f asc| -f -0 -1 -1 -2 -3 -5 -8 -13 -21 -34 -55 -89 -144 -233 -377 -610 -987 -1597 -2584 -4181 -6765 -drop table fib| -drop procedure fib| drop procedure if exists bar| create procedure bar(x char(16), y int) comment "111111111111" sql security invoker @@ -2506,20 +2313,6 @@ s1 1 drop procedure bug4905| drop table t3| -drop function if exists bug6022| -drop function if exists bug6022| -create function bug6022(x int) returns int -begin -if x < 0 then -return 0; -else -return bug6022(x-1); -end if; -end| -select bug6022(5)| -bug6022(5) -0 -drop function bug6022| drop procedure if exists bug6029| drop procedure if exists bug6029| create procedure bug6029() @@ -2971,15 +2764,6 @@ select @x| set global query_cache_size = @qcs1| delete from t1| drop function bug9902| -drop procedure if exists bug6898| -create procedure bug6898() -begin -goto label1; -label label1; -begin end; -goto label1; -end| -drop procedure bug6898| drop function if exists bug9102| create function bug9102() returns blob return 'a'| select bug9102()| @@ -3224,4 +3008,58 @@ bbbbb 2 ccccc 3 drop procedure bug10136| drop table t3| +drop procedure if exists bug11529| +create procedure bug11529() +begin +declare c cursor for select id, data from t1 where data in (10,13); +open c; +begin +declare vid char(16); +declare vdata int; +declare exit handler for not found begin end; +while true do +fetch c into vid, vdata; +end while; +end; +close c; +end| +insert into t1 values +('Name1', 10), +('Name2', 11), +('Name3', 12), +('Name4', 13), +('Name5', 14)| +call bug11529()| +call bug11529()| +delete from t1| +drop procedure bug11529| +drop procedure if exists bug6063| +drop procedure if exists bug7088_1| +drop procedure if exists bug7088_2| +create procedure bug6063() +lâbel: begin end| +call bug6063()| +show create procedure bug6063| +Procedure sql_mode Create Procedure +bug6063 CREATE PROCEDURE `test`.`bug6063`() +l?bel: begin end +set character set utf8| +create procedure bug7088_1() +label1: begin end label1| +create procedure bug7088_2() +läbel1: begin end| +call bug7088_1()| +call bug7088_2()| +set character set default| +show create procedure bug7088_1| +Procedure sql_mode Create Procedure +bug7088_1 CREATE PROCEDURE `test`.`bug7088_1`() +label1: begin end label1 +show create procedure bug7088_2| +Procedure sql_mode Create Procedure +bug7088_2 CREATE PROCEDURE `test`.`bug7088_2`() +läbel1: begin end +drop procedure bug6063| +drop procedure bug7088_1| +drop procedure bug7088_2| drop table t1,t2; diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result index 392bdda32e3..9be5f5bc0d2 100644 --- a/mysql-test/r/sql_mode.result +++ b/mysql-test/r/sql_mode.result @@ -120,7 +120,7 @@ create table t1 ( min_num dec(6,6) default .000001); show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `min_num` decimal(7,6) default '0.000001' + `min_num` decimal(6,6) default '0.000001' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1 ; set session sql_mode = 'IGNORE_SPACE'; @@ -128,14 +128,14 @@ create table t1 ( min_num dec(6,6) default 0.000001); show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `min_num` decimal(7,6) default '0.000001' + `min_num` decimal(6,6) default '0.000001' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1 ; create table t1 ( min_num dec(6,6) default .000001); show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `min_num` decimal(7,6) default '0.000001' + `min_num` decimal(6,6) default '0.000001' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1 ; set @@SQL_MODE=NULL; @@ -420,4 +420,41 @@ t1 CREATE TABLE `t1` ( `a` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +SET @@SQL_MODE=''; +create function `foo` () returns int return 5; +show create function `foo`; +Function sql_mode Create Function +foo CREATE FUNCTION `test`.`foo`() RETURNS int(11) +return 5 +SET @@SQL_MODE='ANSI_QUOTES'; +show create function `foo`; +Function sql_mode Create Function +foo CREATE FUNCTION `test`.`foo`() RETURNS int(11) +return 5 +drop function `foo`; +create function `foo` () returns int return 5; +show create function `foo`; +Function sql_mode Create Function +foo ANSI_QUOTES CREATE FUNCTION "test"."foo"() RETURNS int(11) +return 5 +SET @@SQL_MODE=''; +show create function `foo`; +Function sql_mode Create Function +foo ANSI_QUOTES CREATE FUNCTION "test"."foo"() RETURNS int(11) +return 5 +drop function `foo`; +SET @@SQL_MODE=''; +create table t1 (a int); +create table t2 (a int); +create view v1 as select a from t1; +show create view v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1` +SET @@SQL_MODE='ANSI_QUOTES'; +show create view v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED VIEW "test"."v1" AS select "test"."t1"."a" AS "a" from "test"."t1" +create view v2 as select a from t2 where a in (select a from v1); +drop view v2, v1; +drop table t1, t2; SET @@SQL_MODE=@OLD_SQL_MODE; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 6703147c635..693146c869e 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1025,7 +1025,7 @@ 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 sql_no_cache (select sql_no_cache ecrypt(_latin1'test') AS `ENCRYPT('test')` from `test`.`t1`) AS `(SELECT ENCRYPT('test') FROM t1)` from `test`.`t1` +Note 1003 select sql_no_cache (select sql_no_cache encrypt(_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 @@ -2816,3 +2816,30 @@ select * from t1; EMPNUM E1 DROP TABLE t1,t2; +CREATE TABLE t1(select_id BIGINT, values_id BIGINT); +INSERT INTO t1 VALUES (1, 1); +CREATE TABLE t2 (select_id BIGINT, values_id BIGINT, +PRIMARY KEY(select_id,values_id)); +INSERT INTO t2 VALUES (0, 1), (0, 2), (0, 3), (1, 5); +SELECT values_id FROM t1 +WHERE values_id IN (SELECT values_id FROM t2 +WHERE select_id IN (1, 0)); +values_id +1 +SELECT values_id FROM t1 +WHERE values_id IN (SELECT values_id FROM t2 +WHERE select_id BETWEEN 0 AND 1); +values_id +1 +SELECT values_id FROM t1 +WHERE values_id IN (SELECT values_id FROM t2 +WHERE select_id = 0 OR select_id = 1); +values_id +1 +DROP TABLE t1, t2; +create table t1 (fld enum('0','1')); +insert into t1 values ('1'); +select * from (select max(fld) from t1) as foo; +max(fld) +1 +drop table t1; diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index 409c9db9f47..277115733d4 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -128,7 +128,7 @@ tables_priv CREATE TABLE `tables_priv` ( `Table_name` char(64) collate utf8_bin NOT NULL default '', `Grantor` char(77) collate utf8_bin NOT NULL default '', `Timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, - `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter') character set utf8 NOT NULL default '', + `Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view') character set utf8 NOT NULL default '', `Column_priv` set('Select','Insert','Update','References') character set utf8 NOT NULL default '', PRIMARY KEY (`Host`,`Db`,`User`,`Table_name`), KEY `Grantor` (`Grantor`) @@ -162,7 +162,7 @@ procs_priv CREATE TABLE `procs_priv` ( show create table proc; Table Create Table proc CREATE TABLE `proc` ( - `db` char(64) character set latin1 collate latin1_bin NOT NULL default '', + `db` char(64) character set utf8 collate utf8_bin NOT NULL default '', `name` char(64) NOT NULL default '', `type` enum('FUNCTION','PROCEDURE') NOT NULL, `specific_name` char(64) NOT NULL default '', @@ -173,12 +173,12 @@ proc CREATE TABLE `proc` ( `param_list` blob NOT NULL, `returns` char(64) NOT NULL default '', `body` blob NOT NULL, - `definer` char(77) character set latin1 collate latin1_bin NOT NULL default '', + `definer` char(77) character set utf8 collate utf8_bin NOT NULL default '', `created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, `modified` timestamp NOT NULL default '0000-00-00 00:00:00', `sql_mode` set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE') NOT NULL default '', - `comment` char(64) character set latin1 collate latin1_bin NOT NULL default '', + `comment` char(64) character set utf8 collate utf8_bin NOT NULL default '', PRIMARY KEY (`db`,`name`,`type`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Stored Procedures' +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Stored Procedures' show tables; Tables_in_test diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 996a692d531..746c900d743 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -1,6 +1,7 @@ -drop table if exists t1, t2; +drop table if exists t1, t2, t3; drop view if exists v1; drop database if exists mysqltest; +drop function if exists f1; create table t1 (i int); create trigger trg before insert on t1 for each row set @a:=1; set @a:=0; @@ -182,6 +183,96 @@ select @log; @log (BEFORE_INSERT: new=(id=1, data=5))(BEFORE_UPDATE: old=(id=1, data=4) new=(id=1, data=6))(AFTER_UPDATE: old=(id=1, data=4) new=(id=1, data=6))(BEFORE_INSERT: new=(id=3, data=3))(AFTER_INSERT: new=(id=3, data=3)) drop table t1; +create table t1 (id int primary key, data varchar(10), fk int); +create table t2 (event varchar(100)); +create table t3 (id int primary key); +create trigger t1_ai after insert on t1 for each row +insert into t2 values (concat("INSERT INTO t1 id=", new.id, " data='", new.data, "'")); +insert into t1 (id, data) values (1, "one"), (2, "two"); +select * from t1; +id data fk +1 one NULL +2 two NULL +select * from t2; +event +INSERT INTO t1 id=1 data='one' +INSERT INTO t1 id=2 data='two' +drop trigger t1.t1_ai; +create trigger t1_bi before insert on t1 for each row +begin +if exists (select id from t3 where id=new.fk) then +insert into t2 values (concat("INSERT INTO t1 id=", new.id, " data='", new.data, "' fk=", new.fk)); +else +insert into t2 values (concat("INSERT INTO t1 FAILED id=", new.id, " data='", new.data, "' fk=", new.fk)); +set new.id= NULL; +end if; +end| +insert into t3 values (1); +insert into t1 values (4, "four", 1), (5, "five", 2); +ERROR 23000: Column 'id' cannot be null +select * from t1; +id data fk +1 one NULL +2 two NULL +4 four 1 +select * from t2; +event +INSERT INTO t1 id=1 data='one' +INSERT INTO t1 id=2 data='two' +INSERT INTO t1 id=4 data='four' fk=1 +INSERT INTO t1 FAILED id=5 data='five' fk=2 +drop table t1, t2, t3; +create table t1 (id int primary key, data varchar(10)); +create table t2 (seq int); +insert into t2 values (10); +create function f1 () returns int return (select max(seq) from t2); +create trigger t1_bi before insert on t1 for each row +begin +if new.id > f1() then +set new.id:= f1(); +end if; +end| +select f1(); +f1() +10 +insert into t1 values (1, "first"); +insert into t1 values (f1(), "max"); +select * from t1; +id data +1 first +10 max +drop table t1, t2; +drop function f1; +create table t1 (id int primary key, fk_t2 int); +create table t2 (id int primary key, fk_t3 int); +create table t3 (id int primary key); +insert into t1 values (1,1), (2,1), (3,2); +insert into t2 values (1,1), (2,2); +insert into t3 values (1), (2); +create trigger t3_ad after delete on t3 for each row +delete from t2 where fk_t3=old.id; +create trigger t2_ad after delete on t2 for each row +delete from t1 where fk_t2=old.id; +delete from t3 where id = 1; +select * from t1 left join (t2 left join t3 on t2.fk_t3 = t3.id) on t1.fk_t2 = t2.id; +id fk_t2 id fk_t3 id +3 2 2 2 2 +drop table t1, t2, t3; +create table t1 (id int primary key, copy int); +create table t2 (id int primary key, data int); +insert into t2 values (1,1), (2,2); +create trigger t1_bi before insert on t1 for each row +set new.copy= (select data from t2 where id = new.id); +create trigger t1_bu before update on t1 for each row +set new.copy= (select data from t2 where id = new.id); +insert into t1 values (1,3), (2,4), (3,3); +update t1 set copy= 1 where id = 2; +select * from t1; +id copy +1 1 +2 2 +3 NULL +drop table t1, t2; create table t1 (i int); create trigger trg before insert on t1 for each row set @a:= old.i; ERROR HY000: There is no OLD row in on INSERT trigger diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result index 4d9bc0c7fe1..4aa8587d6e1 100644 --- a/mysql-test/r/type_bit.result +++ b/mysql-test/r/type_bit.result @@ -466,3 +466,90 @@ select a+0 from t1; a+0 255 drop table t1; +create table t1 (a bit(7)); +insert into t1 values (120), (0), (111); +select a+0 from t1 union select a+0 from t1; +a+0 +120 +0 +111 +select a+0 from t1 union select NULL; +a+0 +120 +0 +111 +NULL +select NULL union select a+0 from t1; +NULL +NULL +120 +0 +111 +create table t2 select a from t1 union select a from t1; +select a+0 from t2; +a+0 +120 +0 +111 +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` bit(7) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1, t2; +create table t1 (id1 int(11), b1 bit(1)); +create table t2 (id2 int(11), b2 bit(1)); +insert into t1 values (1, 1), (2, 0), (3, 1); +insert into t2 values (2, 1), (3, 0), (4, 0); +create algorithm=undefined view v1 as +select b1+0, b2+0 from t1, t2 where id1 = id2 and b1 = 0 +union +select b1+0, b2+0 from t1, t2 where id1 = id2 and b2 = 1; +select * from v1; +b1+0 b2+0 +0 1 +drop table t1, t2; +drop view v1; +create table t1(a bit(4)); +insert into t1(a) values (1), (2), (5), (4), (3); +insert into t1 select * from t1; +select a+0 from t1; +a+0 +1 +2 +5 +4 +3 +1 +2 +5 +4 +3 +drop table t1; +create table t1 (a1 int(11), b1 bit(2)); +create table t2 (a2 int(11), b2 bit(2)); +insert into t1 values (1, 1), (2, 0), (3, 1), (4, 2); +insert into t2 values (2, 1), (3, 0), (4, 1), (5, 2); +select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2; +a1 a2 b1+0 b2+0 +2 2 0 1 +3 3 1 0 +4 4 2 1 +select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2 order by a1; +a1 a2 b1+0 b2+0 +2 2 0 1 +3 3 1 0 +4 4 2 1 +select a1, a2, b1+0, b2+0 from t1 join t2 on b1 = b2; +a1 a2 b1+0 b2+0 +1 2 1 1 +3 2 1 1 +2 3 0 0 +1 4 1 1 +3 4 1 1 +4 5 2 2 +select sum(a1), b1+0, b2+0 from t1 join t2 on b1 = b2 group by b1 order by 1; +sum(a1) b1+0 b2+0 +2 0 0 +4 2 2 +8 1 1 diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index 67a011231be..193ed298339 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -703,3 +703,18 @@ select max(i) from t1 where c = ''; max(i) 4 drop table t1; +create table t1 (a int, b int, c tinyblob, d int, e int); +alter table t1 add primary key (a,b,c(255),d); +alter table t1 add key (a,b,d,e); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL default '0', + `b` int(11) NOT NULL default '0', + `c` tinyblob NOT NULL, + `d` int(11) NOT NULL default '0', + `e` int(11) default NULL, + PRIMARY KEY (`a`,`b`,`c`(255),`d`), + KEY `a` (`a`,`b`,`d`,`e`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index 93467d1d7da..15f9b839994 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -476,12 +476,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp CREATE TABLE t1 (a_dec DECIMAL(-1,1)); 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 '-1,1))' at line 1 CREATE TABLE t1 (a_dec DECIMAL(0,11)); -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a_dec` decimal(11,11) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -DROP TABLE t1; +ERROR 42000: Scale may not be larger than the precision (column 'a_dec'). create table t1(a decimal(7,3)); insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000000001'),('10'),('+10'),('-10'),('0000000010'),('+0000000010'),('-0000000010'),('100'),('+100'),('-100'),('0000000100'),('+0000000100'),('-0000000100'),('1000'),('+1000'),('-1000'),('0000001000'),('+0000001000'),('-0000001000'),('10000'),('+10000'),('-10000'),('0000010000'),('+0000010000'),('-0000010000'),('100000'),('+100000'),('-100000'),('0000100000'),('+0000100000'),('-0000100000'),('1000000'),('+1000000'),('-1000000'),('0001000000'),('+0001000000'),('-0001000000'),('10000000'),('+10000000'),('-10000000'),('0010000000'),('+0010000000'),('-0010000000'),('100000000'),('+100000000'),('-100000000'),('0100000000'),('+0100000000'),('-0100000000'),('1000000000'),('+1000000000'),('-1000000000'),('1000000000'),('+1000000000'),('-1000000000'); select * from t1; @@ -699,24 +694,6 @@ select * from t1; d 1 drop table t1; -create table t1 (d decimal(64,99)); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `d` decimal(64,30) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -insert into t1 values (1); -select * from t1; -d -1.000000000000000000000000000000 -drop table t1; -create table t1 (d decimal(10,12)); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `d` decimal(13,12) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -drop table t1; create table t1 (d decimal(5)); show create table t1; Table Create Table @@ -732,7 +709,7 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t1 (d decimal(66,0)); -ERROR 42000: Incorrect column specifier for column 'd' +ERROR 42000: Too big precision 66 specified for column 'd'. Maximum is 65. CREATE TABLE t1 (i INT, d1 DECIMAL(9,2), d2 DECIMAL(9,2)); INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00), (2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40), diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index b0b3ab147b0..d243985332e 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -103,7 +103,7 @@ select max(a),min(a),avg(a) from t1; max(a) min(a) avg(a) 1 1 1 drop table t1; -create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(5,6)); +create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(7,6)); show full columns from t1; Field Type Collation Null Key Default Extra Privileges Comment f float NULL YES NULL # @@ -133,17 +133,7 @@ min(a) -0.010 drop table t1; create table t1 (a float(200,100), b double(200,100)); -insert t1 values (1.0, 2.0); -select * from t1; -a b -1.000000000000000000000000000000 2.000000000000000000000000000000 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` float(200,30) default NULL, - `b` double(200,30) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -drop table t1; +ERROR 42000: Too big scale 100 specified for column 'a'. Maximum is 30. create table t1 (c20 char); insert into t1 values (5000.0); Warnings: diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index b406dbab82f..aed2a478c0e 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -928,3 +928,53 @@ select * from t1 where a = -0.00; a 0.00 drop table t1; +create table t1 (col1 bigint default -9223372036854775808); +insert into t1 values (default); +select * from t1; +col1 +-9223372036854775808 +drop table t1; +select cast('1.00000001335143196001808973960578441619873046875E-10' as decimal(30,15)); +cast('1.00000001335143196001808973960578441619873046875E-10' as decimal(30,15)) +0.000000000100000 +select ln(14000) c1, convert(ln(14000),decimal(2,3)) c2, cast(ln(14000) as decimal(2,3)) c3; +c1 c2 c3 +9.5468126085974 9.547 9.547 +create table t1 (sl decimal(70,30)); +ERROR 42000: Too big precision 70 specified for column 'sl'. Maximum is 65. +create table t1 (sl decimal(32,31)); +ERROR 42000: Too big scale 31 specified for column 'sl'. Maximum is 30. +create table t1 (sl decimal(0,38)); +ERROR 42000: Too big scale 38 specified for column 'sl'. Maximum is 30. +create table t1 (sl decimal(0,30)); +ERROR 42000: Scale may not be larger than the precision (column 'sl'). +create table t1 (sl decimal(5, 5)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `sl` decimal(5,5) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 ( +f1 decimal unsigned not null default 17.49, +f2 decimal unsigned not null default 17.68, +f3 decimal unsigned not null default 99.2, +f4 decimal unsigned not null default 99.7, +f5 decimal unsigned not null default 104.49, +f6 decimal unsigned not null default 199.91, +f7 decimal unsigned not null default 999.9, +f8 decimal unsigned not null default 9999.99); +Warnings: +Note 1265 Data truncated for column 'f1' at row 1 +Note 1265 Data truncated for column 'f2' at row 1 +Note 1265 Data truncated for column 'f3' at row 1 +Note 1265 Data truncated for column 'f4' at row 1 +Note 1265 Data truncated for column 'f5' at row 1 +Note 1265 Data truncated for column 'f6' at row 1 +Note 1265 Data truncated for column 'f7' at row 1 +Note 1265 Data truncated for column 'f8' at row 1 +insert into t1 (f1) values (1); +select * from t1; +f1 f2 f3 f4 f5 f6 f7 f8 +1 18 99 100 104 200 1000 10000 +drop table t1; diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index 9b851d74a12..61ed6bbabf3 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -99,6 +99,14 @@ drop table t1; create table t1 (t2 timestamp(2), t4 timestamp(4), t6 timestamp(6), t8 timestamp(8), t10 timestamp(10), t12 timestamp(12), t14 timestamp(14)); +Warnings: +Warning 1287 'TIMESTAMP(2)' is deprecated; use 'TIMESTAMP' instead +Warning 1287 'TIMESTAMP(4)' is deprecated; use 'TIMESTAMP' instead +Warning 1287 'TIMESTAMP(6)' is deprecated; use 'TIMESTAMP' instead +Warning 1287 'TIMESTAMP(8)' is deprecated; use 'TIMESTAMP' instead +Warning 1287 'TIMESTAMP(10)' is deprecated; use 'TIMESTAMP' instead +Warning 1287 'TIMESTAMP(12)' is deprecated; use 'TIMESTAMP' instead +Warning 1287 'TIMESTAMP(14)' is deprecated; use 'TIMESTAMP' instead insert t1 values (0,0,0,0,0,0,0), ("1997-12-31 23:47:59", "1997-12-31 23:47:59", "1997-12-31 23:47:59", "1997-12-31 23:47:59", "1997-12-31 23:47:59", "1997-12-31 23:47:59", diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index d83952e118b..b0055346d61 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -58,7 +58,7 @@ ushows int(10) unsigned DEFAULT '0' NOT NULL, clicks int(10) unsigned DEFAULT '0' NOT NULL, iclicks int(10) unsigned DEFAULT '0' NOT NULL, uclicks int(10) unsigned DEFAULT '0' NOT NULL, -ts timestamp(14), +ts timestamp, PRIMARY KEY (place_id,ts) ); INSERT INTO t1 (place_id,shows,ishows,ushows,clicks,iclicks,uclicks,ts) @@ -75,7 +75,7 @@ client varchar(255) NOT NULL default '', replyto varchar(255) NOT NULL default '', subject varchar(100) NOT NULL default '', timestamp int(10) unsigned NOT NULL default '0', -tstamp timestamp(14) NOT NULL, +tstamp timestamp NOT NULL, status int(3) NOT NULL default '0', type varchar(15) NOT NULL default '', assignment int(10) unsigned NOT NULL default '0', diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 99b4f0529e6..5468508165c 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -504,10 +504,10 @@ t1 CREATE TABLE `t1` ( `c4` double default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; -SET GLOBAL MYISAM_DATA_POINTER_SIZE= 8; +SET GLOBAL MYISAM_DATA_POINTER_SIZE= 7; SHOW VARIABLES LIKE 'MYISAM_DATA_POINTER_SIZE'; Variable_name Value -myisam_data_pointer_size 8 +myisam_data_pointer_size 7 SET GLOBAL table_cache=-1; SHOW VARIABLES LIKE 'table_cache'; Variable_name Value diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 68cc0c4cb57..3fd85cc883b 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -550,7 +550,7 @@ create table t1 ("a*b" int); create view v1 as select "a*b" from t1; show create view v1; View Create View -v1 CREATE VIEW "test"."v1" AS select `test`.`t1`.`a*b` AS `a*b` from `test`.`t1` +v1 CREATE VIEW "test"."v1" AS select "test"."t1"."a*b" AS "a*b" from "test"."t1" drop view v1; drop table t1; set sql_mode=default; @@ -760,7 +760,7 @@ a b 1 1 show create view v3; View Create View -v3 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v3` AS select `v1`.`col1` AS `a`,`v2`.`col1` AS `b` from `test`.`v1` join `test`.`v2` where (`v1`.`col1` = `v2`.`col1`) +v3 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v3` AS select `v1`.`col1` AS `a`,`v2`.`col1` AS `b` from (`test`.`v1` join `test`.`v2`) where (`v1`.`col1` = `v2`.`col1`) drop view v3, v2, v1; drop table t2, t1; create function `f``1` () returns int return 5; @@ -1561,7 +1561,7 @@ one 1025,2025,3025 two 1050,1050 select col1,group_concat(col2,col3) from v1 group by col1; col1 group_concat(col2,col3) -two 1025,2025,3025 +one 1025,2025,3025 two 1050,1050 drop view v1; drop table t1; @@ -1831,3 +1831,134 @@ select * from v1; t 01:00 drop view v1; +CREATE TABLE t1 (col1 time); +CREATE TABLE t2 (col1 time); +CREATE VIEW v1 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1; +CREATE VIEW v2 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2; +CREATE VIEW v3 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1; +CREATE VIEW v4 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2; +CREATE VIEW v5 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1; +CREATE VIEW v6 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2; +DROP TABLE t1; +CHECK TABLE v1, v2, v3, v4, v5, v6; +Table Op Msg_type Msg_text +test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s) +test.v2 check status OK +test.v3 check error View 'test.v3' references invalid table(s) or column(s) or function(s) +test.v4 check status OK +test.v5 check error View 'test.v5' references invalid table(s) or column(s) or function(s) +test.v6 check status OK +drop view v1, v2, v3, v4, v5, v6; +drop table t2; +CREATE TABLE t1 (col1 time); +CREATE TABLE t2 (col1 time); +CREATE TABLE t3 (col1 time); +create function f1 () returns int return (select max(col1) from t1); +create function f2 () returns int return (select max(col1) from t2); +CREATE VIEW v1 AS SELECT f1() FROM t3; +CREATE VIEW v2 AS SELECT f2() FROM t3; +CREATE VIEW v3 AS SELECT f1() FROM t3; +CREATE VIEW v4 AS SELECT f2() FROM t3; +CREATE VIEW v5 AS SELECT f1() FROM t3; +CREATE VIEW v6 AS SELECT f2() FROM t3; +drop function f1; +CHECK TABLE v1, v2, v3, v4, v5, v6; +Table Op Msg_type Msg_text +test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s) +test.v2 check status OK +test.v3 check error View 'test.v3' references invalid table(s) or column(s) or function(s) +test.v4 check status OK +test.v5 check error View 'test.v5' references invalid table(s) or column(s) or function(s) +test.v6 check status OK +create function f1 () returns int return (select max(col1) from t1); +DROP TABLE t1; +CHECK TABLE v1, v2, v3, v4, v5, v6; +Table Op Msg_type Msg_text +test.v1 check error Table 'test.t1' doesn't exist +test.v2 check status OK +test.v3 check error Table 'test.t1' doesn't exist +test.v4 check status OK +test.v5 check error Table 'test.t1' doesn't exist +test.v6 check status OK +drop function f1; +drop function f2; +drop view v1, v2, v3, v4, v5, v6; +drop table t2,t3; +create table t1 (f1 date); +insert into t1 values ('2005-01-01'),('2005-02-02'); +create view v1 as select * from t1; +select * from v1 where f1='2005.02.02'; +f1 +2005-02-02 +select * from v1 where '2005.02.02'=f1; +f1 +2005-02-02 +drop view v1; +drop table t1; +CREATE VIEW v1 AS SELECT ENCRYPT("dhgdhgd"); +SELECT * FROM v1; +drop view v1; +CREATE VIEW v1 AS SELECT SUBSTRING_INDEX("dkjhgd:kjhdjh", ":", 1); +SELECT * FROM v1; +SUBSTRING_INDEX("dkjhgd:kjhdjh", ":", 1) +dkjhgd +drop view v1; +create table t1 (s1 int); +create view v1 as select var_samp(s1) from t1; +show create view v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select var_samp(`test`.`t1`.`s1`) AS `var_samp(s1)` from `test`.`t1` +drop view v1; +drop table t1; +set sql_mode='strict_all_tables'; +CREATE TABLE t1 (col1 INT NOT NULL, col2 INT NOT NULL) ENGINE = INNODB; +CREATE VIEW v1 (vcol1) AS SELECT col1 FROM t1; +CREATE VIEW v2 (vcol1) AS SELECT col1 FROM t1 WHERE col2 > 2; +INSERT INTO t1 (col1) VALUES(12); +ERROR HY000: Field 'col2' doesn't have a default value +INSERT INTO v1 (vcol1) VALUES(12); +ERROR HY000: Field of view 'test.v1' underlying table doesn't have a default value +INSERT INTO v2 (vcol1) VALUES(12); +ERROR HY000: Field of view 'test.v2' underlying table doesn't have a default value +set sql_mode=default; +drop view v2,v1; +drop table t1; +create table t1 (f1 int); +insert into t1 values (1); +create view v1 as select f1 from t1; +select f1 as alias from v1; +alias +1 +drop view v1; +drop table t1; +CREATE TABLE t1 (s1 int, s2 int); +INSERT INTO t1 VALUES (1,2); +CREATE VIEW v1 AS SELECT s2 AS s1, s1 AS s2 FROM t1; +SELECT * FROM v1; +s1 s2 +2 1 +CREATE PROCEDURE p1 () SELECT * FROM v1; +CALL p1(); +s1 s2 +2 1 +ALTER VIEW v1 AS SELECT s1 AS s1, s2 AS s2 FROM t1; +CALL p1(); +s1 s2 +1 2 +DROP PROCEDURE p1; +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1 (f1 char) ENGINE = innodb; +INSERT INTO t1 VALUES ('A'); +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 VALUES('B'); +SELECT * FROM v1; +f1 +A +B +SELECT * FROM t1; +f1 +A +B +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index df8e2b04f47..b77ee59b3ff 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -284,7 +284,7 @@ create table mysqltest.v3 (b int); grant select(b) on mysqltest.v3 to mysqltest_1@localhost; drop table mysqltest.v3; create view mysqltest.v3 as select b from mysqltest.t2; -ERROR 42000: CREATE VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v3' +ERROR 42000: create view command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 'v3' create view v4 as select b+1 from mysqltest.t2; ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 't2' grant create view,update,select on test.* to mysqltest_1@localhost; diff --git a/mysql-test/std_data/loaddata_pair.dat b/mysql-test/std_data/loaddata_pair.dat new file mode 100644 index 00000000000..5a4f6b57af8 --- /dev/null +++ b/mysql-test/std_data/loaddata_pair.dat @@ -0,0 +1,2 @@ +XXX 12345 +XXY 12345 diff --git a/mysql-test/t/alias.test b/mysql-test/t/alias.test index 646f077217d..cfa8ec7f18a 100644 --- a/mysql-test/t/alias.test +++ b/mysql-test/t/alias.test @@ -30,7 +30,7 @@ CREATE TABLE t1 ( prov_hdl_nr int(11) NOT NULL default '0', auto_wirknetz varchar(50) default NULL, auto_billing varchar(50) default NULL, - touch timestamp(14) NOT NULL, + touch timestamp NOT NULL, kategorie varchar(50) default NULL, kundentyp varchar(20) NOT NULL default '', sammel_rech_msisdn varchar(30) NOT NULL default '', diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index 51334fa62bc..a42a42b2a4e 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1313,6 +1313,11 @@ INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); SELECT * FROM t2; OPTIMIZE TABLE t2; SELECT * FROM t2; +INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W'); +INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring',''); +INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); +OPTIMIZE TABLE t2 EXTENDED; +SELECT * FROM t2; REPAIR TABLE t2; SELECT * FROM t2; diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index f2cfce9085d..e942333d5fe 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -111,6 +111,17 @@ explain extended SELECT SHOW CREATE TABLE t1; DROP TABLE t1; +# Test for BUG#10151 +SELECT 'case+union+test' +UNION +SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END; + +SELECT CASE LOWER('1') WHEN LOWER('2') THEN 'BUG' ELSE 'nobug' END; + +SELECT 'case+union+test' +UNION +SELECT CASE '1' WHEN '2' THEN 'BUG' ELSE 'nobug' END; + # # Tests for bug #9939: conversion of the arguments for COALESCE and IFNULL # diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 2722e8572b0..f4327536795 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -408,6 +408,18 @@ DROP TABLE t1; SET NAMES latin1; # +# Bug#9557 MyISAM utf8 table crash +# +CREATE TABLE t1 ( + a varchar(255) NOT NULL default '', + KEY a (a) +) ENGINE=MyISAM DEFAULT CHARSET=ucs2 COLLATE ucs2_general_ci; +insert into t1 values (0x803d); +insert into t1 values (0x005b); +select hex(a) from t1; +drop table t1; + +# # Conversion from an UCS2 string to a decimal column # CREATE TABLE t1 (a varchar(64) character set ucs2, b decimal(10,3)); diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 343b7c867e7..6bfc8513e23 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -788,3 +788,38 @@ INSERT INTO t2 VALUES ('1234567890',2,'2005-05-24 13:53:25'); SELECT content, t2.msisdn FROM t1, t2 WHERE t1.msisdn = '1234567890'; DROP TABLE t1,t2; + +# +# Bug#11591: CHAR column with utf8 does not work properly +# (more chars than expected) +# +create table t1 (a char(20) character set utf8); +insert into t1 values ('123456'),('андрей'); +alter table t1 modify a char(2) character set utf8; +select char_length(a), length(a), a from t1 order by a; +drop table t1; + +# +# Bug#9557 MyISAM utf8 table crash +# +CREATE TABLE t1 ( + a varchar(255) NOT NULL default '', + KEY a (a) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE utf8_general_ci; +insert into t1 values (_utf8 0xe880bd); +insert into t1 values (_utf8 0x5b); +select hex(a) from t1; +drop table t1; + +# +# Test for bug #11484: wrong results for a DISTINCT varchar column in uft8. +# + +CREATE TABLE t1(id varchar(20) NOT NULL) DEFAULT CHARSET=utf8; +INSERT INTO t1 VALUES ('xxx'), ('aa'), ('yyy'), ('aa'); + +SELECT id FROM t1; +SELECT DISTINCT id FROM t1; +SELECT DISTINCT id FROM t1 ORDER BY id; + +DROP TABLE t1; diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index b6526b67cc8..c5f96ec4201 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -9,3 +9,5 @@ # Don't use any TAB characters for whitespace. # ############################################################################## + +sp-goto:GOTO is currently is disabled - will be fixed in the future diff --git a/mysql-test/t/func_date_add.test b/mysql-test/t/func_date_add.test index 93c77daf86e..29c13793b78 100644 --- a/mysql-test/t/func_date_add.test +++ b/mysql-test/t/func_date_add.test @@ -11,7 +11,7 @@ CREATE TABLE t1 ( group_id int(10) unsigned DEFAULT '0' NOT NULL, hits int(10) unsigned DEFAULT '0' NOT NULL, sessions int(10) unsigned DEFAULT '0' NOT NULL, - ts timestamp(14), + ts timestamp, PRIMARY KEY (visitor_id,group_id) )/*! engine=MyISAM */; INSERT INTO t1 VALUES (465931136,7,2,2,20000318160952); diff --git a/mysql-test/t/func_encrypt.test b/mysql-test/t/func_encrypt.test index fe81a814dda..52aca7f9dcb 100644 --- a/mysql-test/t/func_encrypt.test +++ b/mysql-test/t/func_encrypt.test @@ -59,6 +59,22 @@ select hex(des_encrypt("hello")),hex(des_encrypt("hello",5)),hex(des_encrypt("he select des_decrypt(des_encrypt("hello"),'default_password'); select des_decrypt(des_encrypt("hello",4),'password4'); +# Test use of invalid parameters +select des_encrypt("hello",10); +select des_encrypt(NULL); +select des_encrypt(NULL, 10); +select des_encrypt(NULL, NULL); +select des_encrypt(10, NULL); +select des_encrypt("hello", NULL); + +select des_decrypt("hello",10); +select des_decrypt(NULL); +select des_decrypt(NULL, 10); +select des_decrypt(NULL, NULL); +select des_decrypt(10, NULL); +select des_decrypt("hello", NULL); + + # Test flush SET @a=des_decrypt(des_encrypt("hello")); flush des_key_file; diff --git a/mysql-test/t/func_encrypt_nossl.test b/mysql-test/t/func_encrypt_nossl.test new file mode 100644 index 00000000000..95c104ce046 --- /dev/null +++ b/mysql-test/t/func_encrypt_nossl.test @@ -0,0 +1,37 @@ +-- source include/not_openssl.inc + +# +# Test output from des_encrypt and des_decrypt when server is +# compiled without openssl suuport +# +select des_encrypt("test", 'akeystr'); +select des_encrypt("test", 1); +select des_encrypt("test", 9); +select des_encrypt("test", 100); +select des_encrypt("test", NULL); +select des_encrypt(NULL, NULL); +select des_decrypt("test", 'anotherkeystr'); +select des_decrypt(1, 1); +select des_decrypt(des_encrypt("test", 'thekey')); + + +# +# Test default keys +# +select hex(des_encrypt("hello")),des_decrypt(des_encrypt("hello")); +select des_decrypt(des_encrypt("hello",4)); +select des_decrypt(des_encrypt("hello",'test'),'test'); +select hex(des_encrypt("hello")),hex(des_encrypt("hello",5)),hex(des_encrypt("hello",'default_password')); +select des_decrypt(des_encrypt("hello"),'default_password'); +select des_decrypt(des_encrypt("hello",4),'password4'); + +# Test flush +SET @a=des_decrypt(des_encrypt("hello")); +flush des_key_file; +select @a = des_decrypt(des_encrypt("hello")); + +# Test usage of wrong password +select hex("hello"); +select hex(des_decrypt(des_encrypt("hello",4),'password2')); +select hex(des_decrypt(des_encrypt("hello","hidden"))); + diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 728f0e2c084..9dc6014ec56 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -128,7 +128,7 @@ CREATE TABLE t1 ( program int(10) unsigned default NULL, bugdesc text, created datetime default NULL, - modified timestamp(14) NOT NULL, + modified timestamp NOT NULL, bugstatus int(10) unsigned default NULL, submitter int(10) unsigned default NULL ) ENGINE=MyISAM; @@ -529,3 +529,82 @@ DROP TABLE t1, t2; # select field(0,NULL,1,0), field("",NULL,"bar",""), field(0.0,NULL,1.0,0.0); select field(NULL,1,2,NULL), field(NULL,1,2,0); + +# +# Bug #10124: access by integer index with a string key that is not a number +# + +CREATE TABLE t1 (str varchar(20) PRIMARY KEY); +CREATE TABLE t2 (num int primary key); +INSERT INTO t1 VALUES ('notnumber'); +INSERT INTO t2 VALUES (0), (1); + +SELECT * FROM t1, t2 WHERE num=str; +SELECT * FROM t1, t2 WHERE num=substring(str from 1 for 6); + +DROP TABLE t1,t2; + +# +# Bug #11469: NOT NULL optimization wrongly used for arguments of CONCAT_WS +# + +CREATE TABLE t1( + id int(11) NOT NULL auto_increment, + pc int(11) NOT NULL default '0', + title varchar(20) default NULL, + PRIMARY KEY (id) +); + +INSERT INTO t1 VALUES + (1, 0, 'Main'), + (2, 1, 'Toys'), + (3, 1, 'Games'); + +SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1 + FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id + LEFT JOIN t1 AS t3 ON t2.pc=t3.id; +SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1 + FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id + LEFT JOIN t1 AS t3 ON t2.pc=t3.id + WHERE CONCAT_WS('->', t3.title, t2.title, t1.title) LIKE '%Toys%'; + +DROP TABLE t1; + + +CREATE TABLE t1( + trackid int(10) unsigned NOT NULL auto_increment, + trackname varchar(100) NOT NULL default '', + PRIMARY KEY (trackid) +); + +CREATE TABLE t2( + artistid int(10) unsigned NOT NULL auto_increment, + artistname varchar(100) NOT NULL default '', + PRIMARY KEY (artistid) +); + +CREATE TABLE t3( + trackid int(10) unsigned NOT NULL, + artistid int(10) unsigned NOT NULL, + PRIMARY KEY (trackid,artistid) +); + +INSERT INTO t1 VALUES (1, 'April In Paris'), (2, 'Autumn In New York'); +INSERT INTO t2 VALUES (1, 'Vernon Duke'); +INSERT INTO t3 VALUES (1,1); + +SELECT CONCAT_WS(' ', trackname, artistname) trackname, artistname + FROM t1 LEFT JOIN t3 ON t1.trackid=t3.trackid + LEFT JOIN t2 ON t2.artistid=t3.artistid + WHERE CONCAT_WS(' ', trackname, artistname) LIKE '%In%'; + +DROP TABLE t1,t2,t3; + +# +# Correct length reporting from substring() (BUG#10269) +# +create table t1 (b varchar(5)); +insert t1 values ('ab'), ('abc'), ('abcd'), ('abcde'); +select *,substring(b,1),substring(b,-1),substring(b,-2),substring(b,-3),substring(b,-4),substring(b,-5) from t1; +select * from (select *,substring(b,1),substring(b,-1),substring(b,-2),substring(b,-3),substring(b,-4),substring(b,-5) from t1) t; +drop table t1; diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 6ca29ccded2..66ff460fc61 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -211,7 +211,7 @@ drop table t1; CREATE TABLE t1 ( start datetime default NULL); INSERT INTO t1 VALUES ('2002-10-21 00:00:00'),('2002-10-28 00:00:00'),('2002-11-04 00:00:00'); -CREATE TABLE t2 ( ctime1 timestamp(14) NOT NULL, ctime2 timestamp(14) NOT NULL); +CREATE TABLE t2 ( ctime1 timestamp NOT NULL, ctime2 timestamp NOT NULL); INSERT INTO t2 VALUES (20021029165106,20021105164731); CREATE TABLE t3 (ctime1 char(19) NOT NULL, ctime2 char(19) NOT NULL); INSERT INTO t3 VALUES ("2002-10-29 16:51:06","2002-11-05 16:47:31"); diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index 34d9a09cba7..bb21873a0c4 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -6,6 +6,7 @@ # Cleanup --disable_warnings drop table if exists t1; +drop database if exists mysqltest; --enable_warnings connect (master,localhost,root,,); @@ -403,3 +404,78 @@ connection root; revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; delete from mysql.user where user=_binary'mysqltest_1'; drop database mysqltest; + +# +# check all new table priveleges +# +CREATE USER dummy@localhost; +CREATE DATABASE mysqltest; +CREATE TABLE mysqltest.dummytable (dummyfield INT); +CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable; +GRANT ALL PRIVILEGES ON mysqltest.dummytable TO dummy@localhost; +GRANT ALL PRIVILEGES ON mysqltest.dummyview TO dummy@localhost; +SHOW GRANTS FOR dummy@localhost; +use INFORMATION_SCHEMA; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +FLUSH PRIVILEGES; +SHOW GRANTS FOR dummy@localhost; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +SHOW FIELDS FROM mysql.tables_priv; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; +DROP USER dummy@localhost; +DROP DATABASE mysqltest; +# check view only privileges +CREATE USER dummy@localhost; +CREATE DATABASE mysqltest; +CREATE TABLE mysqltest.dummytable (dummyfield INT); +CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable; +GRANT CREATE VIEW ON mysqltest.dummytable TO dummy@localhost; +GRANT CREATE VIEW ON mysqltest.dummyview TO dummy@localhost; +SHOW GRANTS FOR dummy@localhost; +use INFORMATION_SCHEMA; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +FLUSH PRIVILEGES; +SHOW GRANTS FOR dummy@localhost; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; +DROP USER dummy@localhost; +DROP DATABASE mysqltest; +CREATE USER dummy@localhost; +CREATE DATABASE mysqltest; +CREATE TABLE mysqltest.dummytable (dummyfield INT); +CREATE VIEW mysqltest.dummyview AS SELECT dummyfield FROM mysqltest.dummytable; +GRANT SHOW VIEW ON mysqltest.dummytable TO dummy@localhost; +GRANT SHOW VIEW ON mysqltest.dummyview TO dummy@localhost; +SHOW GRANTS FOR dummy@localhost; +use INFORMATION_SCHEMA; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +FLUSH PRIVILEGES; +SHOW GRANTS FOR dummy@localhost; +SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY +PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE += '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; +use test; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM dummy@localhost; +DROP USER dummy@localhost; +DROP DATABASE mysqltest; +# +# Bug #11330: Entry in tables_priv with host = '' causes crash +# +connection default; +use mysql; +insert into tables_priv values ('','test_db','mysqltest_1','test_table','test_grantor',CURRENT_TIMESTAMP,'Select','Select'); +flush privileges; +delete from tables_priv where host = '' and user = 'mysqltest_1'; +flush privileges; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index be8bdbe892e..6f1880ae8fb 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -135,7 +135,7 @@ CREATE TABLE t1 ( bug_severity enum('blocker','critical','major','normal','minor','trivial','enhancement') DEFAULT 'blocker' NOT NULL, bug_status enum('','NEW','ASSIGNED','REOPENED','RESOLVED','VERIFIED','CLOSED') DEFAULT 'NEW' NOT NULL, creation_ts datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, - delta_ts timestamp(14), + delta_ts timestamp, short_desc mediumtext, long_desc mediumtext, op_sys enum('All','Windows 3.1','Windows 95','Windows 98','Windows NT','Windows 2000','Linux','other') DEFAULT 'All' NOT NULL, @@ -580,3 +580,38 @@ SELECT COUNT(DISTINCT(t1.id)), LEFT(err_comment, 256) AS comment FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY comment; DROP TABLE t1, t2; + +# +# Test for bug #11414: crash on Windows for a simple GROUP BY query +# + +CREATE TABLE t1 (n int); +INSERT INTO t1 VALUES (1); +--disable_ps_protocol +SELECT n+1 AS n FROM t1 GROUP BY n; +--enable_ps_protocol +DROP TABLE t1; + +# +# Bug#11211: Ambiguous column reference in GROUP BY. +# + +create table t1 (c1 char(3), c2 char(3)); +create table t2 (c3 char(3), c4 char(3)); +insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2'); +insert into t2 values ('aaa', 'bb1'), ('aaa', 'bb2'); + +# query with ambiguous column reference 'c2' +--disable_ps_protocol +select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 +group by c2; +show warnings; +--enable_ps_protocol + +# this query has no ambiguity +select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 +group by t1.c1; + +show warnings; +drop table t1, t2; + diff --git a/mysql-test/t/heap_hash.test b/mysql-test/t/heap_hash.test index 46669dd2b8f..21ac69ef3a1 100644 --- a/mysql-test/t/heap_hash.test +++ b/mysql-test/t/heap_hash.test @@ -169,6 +169,8 @@ explain select * from t1 where a='aaac'; explain select * from t1 where a='aaad'; insert into t1 select * from t1; +# avoid statistics differences between normal and ps-protocol tests +flush tables; explain select * from t1 where a='aaaa'; explain select * from t1 where a='aaab'; explain select * from t1 where a='aaac'; diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index e03bea5899a..7c0624b67fd 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -101,6 +101,12 @@ where COLLATION_NAME like 'latin1%'; # Test for information_schema.ROUTINES & # +--disable_warnings +drop procedure if exists sel2; +drop function if exists sub1; +drop function if exists sub2; +--enable_warnings + create function sub1(i int) returns int return i+1; delimiter |; @@ -483,13 +489,14 @@ drop table t1; # Bug#10261 INFORMATION_SCHEMA.COLUMNS, incomplete result for non root user # -create user mysqltest_4@localhost; +grant select on test.* to mysqltest_4@localhost; connect (user4,localhost,mysqltest_4,,); connection user4; SELECT TABLE_NAME, COLUMN_NAME, PRIVILEGES FROM INFORMATION_SCHEMA.COLUMNS where COLUMN_NAME='TABLE_NAME'; connection default; delete from mysql.user where user='mysqltest_4'; +delete from mysql.db where user='mysqltest_4'; flush privileges; # @@ -510,9 +517,9 @@ grant select on mysqltest.t2 to user2@localhost; grant select on mysqltest.* to user3@localhost; grant select on *.* to user4@localhost; -connect (con1,localhost,user1,,); -connect (con2,localhost,user2,,); -connect (con3,localhost,user3,,); +connect (con1,localhost,user1,,mysqltest); +connect (con2,localhost,user2,,mysqltest); +connect (con3,localhost,user3,,mysqltest); connect (con4,localhost,user4,,); connection con1; select * from information_schema.column_privileges; @@ -546,6 +553,11 @@ drop database mysqltest; # # Bug #11055 information_schema: routines.sql_data_access has wrong value # +--disable_warnings +drop procedure if exists p1; +drop procedure if exists p2; +--enable_warnings + create procedure p1 () modifies sql data set @a = 5; create procedure p2 () set @a = 5; select sql_data_access from information_schema.routines diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 06e73d2d32c..485eeec05d9 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -660,9 +660,9 @@ CREATE TABLE t1 ( cname char(15) NOT NULL default '', carrier_id smallint(6) NOT NULL default '0', privacy tinyint(4) NOT NULL default '0', - last_mod_date timestamp(14) NOT NULL, + last_mod_date timestamp NOT NULL, last_mod_id smallint(6) NOT NULL default '0', - last_app_date timestamp(14) NOT NULL, + last_app_date timestamp NOT NULL, last_app_id smallint(6) default '-1', version smallint(6) NOT NULL default '0', assigned_scps int(11) default '0', @@ -679,9 +679,9 @@ CREATE TABLE t2 ( cname char(15) NOT NULL default '', carrier_id smallint(6) NOT NULL default '0', privacy tinyint(4) NOT NULL default '0', - last_mod_date timestamp(14) NOT NULL, + last_mod_date timestamp NOT NULL, last_mod_id smallint(6) NOT NULL default '0', - last_app_date timestamp(14) NOT NULL, + last_app_date timestamp NOT NULL, last_app_id smallint(6) default '-1', version smallint(6) NOT NULL default '0', assigned_scps int(11) default '0', diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index a6468c52645..92e8c7f1231 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -3,7 +3,7 @@ # --disable_warnings -drop table if exists t1,t2; +drop table if exists t1,t2,t3; --enable_warnings create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL); @@ -180,10 +180,24 @@ drop table t1, t2; # create table t1 (a int unique); create table t2 (a int, b int); +create table t3 (c int, d int); insert into t1 values (1),(2); insert into t2 values (1,2); +insert into t3 values (1,6),(3,7); select * from t1; -insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b; +insert into t1 select a from t2 on duplicate key update a= t1.a + t2.b; select * from t1; -drop table t1; -drop table t2; +insert into t1 select a+1 from t2 on duplicate key update t1.a= t1.a + t2.b+1; +select * from t1; +insert into t1 select t3.c from t3 on duplicate key update a= a + t3.d; +select * from t1; +insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= a + 10; + +#Some error cases +--error 1052 +insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b; +--error 1109 +insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b; +--error 1109 +insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b; +drop table t1,t2,t3; diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index 7653fd8dd42..64a76aafa5e 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -72,11 +72,13 @@ CREATE TABLE t2 (a INT, b INT, c INT, d INT); # column names deliberately clash with columns in t1 (Bug#8147) INSERT t2 VALUES (5,6,30,1), (7,4,40,1), (8,9,60,1); INSERT t2 VALUES (2,1,11,2), (7,4,40,2); -INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=c+100; +INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=t1.c+100; SELECT * FROM t1; INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0; SELECT * FROM t1; +--error 1052 INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=c+VALUES(a); +INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=t1.c+VALUES(t1.a); SELECT *, VALUES(a) FROM t1; DROP TABLE t1; DROP TABLE t2; @@ -89,10 +91,12 @@ create table t1 (a int not null unique) engine=myisam; insert into t1 values (1),(2); insert ignore into t1 select 1 on duplicate key update a=2; select * from t1; -insert ignore into t1 select a from t1 on duplicate key update a=a+1 ; +insert ignore into t1 select a from t1 as t2 on duplicate key update a=t1.a+1 ; select * from t1; insert into t1 select 1 on duplicate key update a=2; select * from t1; ---error 1062 +--error 1052 insert into t1 select a from t1 on duplicate key update a=a+1 ; +--error 1052 +insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ; drop table t1; diff --git a/mysql-test/t/lowercase_table2.test b/mysql-test/t/lowercase_table2.test index 51c6f6b5ac3..f5cf292482e 100644 --- a/mysql-test/t/lowercase_table2.test +++ b/mysql-test/t/lowercase_table2.test @@ -10,9 +10,10 @@ show variables like "lower_case_table_names"; enable_query_log; --disable_warnings -DROP TABLE IF EXISTS t1,t2,t3; +DROP TABLE IF EXISTS t1,t2,t3,t2aA,t1Aa; DROP DATABASE IF EXISTS `TEST_$1`; DROP DATABASE IF EXISTS `test_$1`; +DROP DATABASE IF EXISTS mysqltest_LC2; --enable_warnings CREATE TABLE T1 (a int); diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index f842b8f4d0b..811875a36f5 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -5,7 +5,7 @@ DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa; drop database if exists mysqldump_test_db; drop database if exists db1; -drop view if exists v1, v2; +drop view if exists v1, v2, v3; --enable_warnings # XML output @@ -565,7 +565,6 @@ INSERT INTO t1 VALUES (1),(2),(3); --exec $MYSQL_DUMP --add-drop-database --skip-comments --databases test DROP TABLE t1; - # # Bug #10213 mysqldump crashes when dumping VIEWs(on MacOS X) # @@ -588,3 +587,125 @@ create view v2 as select * from t2 where a like 'a%' with check option; drop table t2; drop view v2; drop database db1; +# +# Bug #9558 mysqldump --no-data db t1 t2 format still dumps data +# + +CREATE DATABASE mysqldump_test_db; +USE mysqldump_test_db; +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); +--exec $MYSQL_DUMP --skip-comments --no-data mysqldump_test_db +--exec $MYSQL_DUMP --skip-comments --no-data mysqldump_test_db t1 t2 +--exec $MYSQL_DUMP --skip-comments --skip-create --xml --no-data mysqldump_test_db +--exec $MYSQL_DUMP --skip-comments --skip-create --xml --no-data mysqldump_test_db t1 t2 +DROP TABLE t1, t2; +DROP DATABASE mysqldump_test_db; + +# +# Testing with tables and databases that don't exists +# or contains illegal characters +# (Bug #9358 mysqldump crashes if tablename starts with \) +# +create database mysqldump_test_db; +use mysqldump_test_db; +create table t1(a varchar(30) primary key, b int not null); +create table t2(a varchar(30) primary key, b int not null); +create table t3(a varchar(30) primary key, b int not null); + +--disable_query_log +select '------ Testing with illegal table names ------' as test_sequence ; +--enable_query_log +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\d-2-1.sql" 2>&1 +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\t1" 2>&1 + +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\\t1" 2>&1 + +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\\\\t1" 2>&1 + +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t\1" 2>&1 + +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t\\1" 2>&1 + +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t/1" 2>&1 + +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_1" + +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T%1" + +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T'1" + +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_1" + +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_" + +--disable_query_log +select '------ Testing with illegal database names ------' as test_sequence ; +--enable_query_log +--error 2 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_d 2>&1 + +--error 2 +--exec $MYSQL_DUMP --compact --skip-comments "mysqld\ump_test_db" 2>&1 + +drop table t1, t2, t3; +drop database mysqldump_test_db; +use test; + +# +# Bug #9657 mysqldump xml ( -x ) does not format NULL fields correctly +# + +create table t1 (a int(10)); +create table t2 (pk int primary key auto_increment, +a int(10), b varchar(30), c datetime, d blob, e text); +insert into t1 values (NULL), (10), (20); +insert into t2 (a, b) values (NULL, NULL),(10, NULL),(NULL, "twenty"),(30, "thirty"); +--exec $MYSQL_DUMP --skip-comments --xml --no-create-info test +drop table t1, t2; + +# +# Bug #10927 mysqldump: Can't reload dump with view that consist of other view +# + +create table t1(a int, b int, c varchar(30)); + +insert into t1 values(1, 2, "one"), (2, 4, "two"), (3, 6, "three"); + +create view v3 as +select * from t1; + +create view v1 as +select * from v3 where b in (1, 2, 3, 4, 5, 6, 7); + +create view v2 as +select v3.a from v3, v1 where v1.a=v3.a and v3.b=3 limit 1; + +--exec $MYSQL_DUMP test > var/tmp/bug10927.sql +drop view v1, v2, v3; +drop table t1; +--exec $MYSQL test < var/tmp/bug10927.sql + +# Without dropping the original tables in between +--exec $MYSQL_DUMP test > var/tmp/bug10927.sql +--exec $MYSQL test < var/tmp/bug10927.sql +show full tables; +show create view v1; +select * from v1; + +drop view v1, v2, v3; +drop table t1; diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index 1e5c31da98e..2e5e2293b5c 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -7,6 +7,13 @@ DROP TABLE IF EXISTS t1; drop database if exists mysqltest; --enable_warnings +connect (con1,localhost,root,,test); +connect (con2,localhost,root,,test); + +connection con2; +-- sleep 2 +connection con1; + # # Basic test to show that the ALTER TABLE # is working @@ -92,10 +99,6 @@ CREATE TABLE t1 ( INSERT INTO t1 VALUES (9410,9412); -connect (con1,localhost,,,test); -connect (con2,localhost,,,test); - -connection con1; ALTER TABLE t1 ADD COLUMN c int not null; select * from t1 order by a; diff --git a/mysql-test/t/ndb_autodiscover.test b/mysql-test/t/ndb_autodiscover.test index 80f6f3f35d3..c2068329d41 100644 --- a/mysql-test/t/ndb_autodiscover.test +++ b/mysql-test/t/ndb_autodiscover.test @@ -494,6 +494,28 @@ select * from t1; use test; drop database test_only_ndb_tables; +##################################################### +# Test that it's not possible to create tables +# with same name as NDB internal tables +# This will also test that it's not possible to create +# a table with tha same name as a table that can't be +# discovered( for example a table created via NDBAPI) + +# Test disabled since it doesn't work on case insensitive systems +#--error 1050 +#CREATE TABLE sys.SYSTAB_0 (a int); +#--error 1105 +#select * from sys.SYSTAB_0; + +#CREATE TABLE IF NOT EXISTS sys.SYSTAB_0 (a int); +#show warnings; +#--error 1105 +#select * from sys.SYSTAB_0; + +#--error 1051 +#drop table sys.SYSTAB_0; +#drop table IF EXISTS sys.SYSTAB_0; + ###################################################### # Note! This should always be the last step in this # file, the table t9 will be used and dropped diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index c75cad0b051..26fcc7463d6 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -250,3 +250,19 @@ SELECT IFNULL(a, 'TEST'), COALESCE(b, 'TEST') FROM t2 DROP TABLE t1,t2; +# +# Tests for bug #11639: ROLLUP over view executed through filesort +# + +CREATE TABLE t1(id int, type char(1)); +INSERT INTO t1 VALUES + (1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"), + (6,"B"),(7,"A"),(8,"C"),(9,"A"),(10,"C"); +CREATE VIEW v1 AS SELECT * FROM t1; + +SELECT type FROM t1 GROUP BY type WITH ROLLUP; +SELECT type FROM v1 GROUP BY type WITH ROLLUP; +EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP; + +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 415185d825b..913b6c645af 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -149,7 +149,7 @@ create table t1 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), - c13 date, c14 datetime, c15 timestamp(14), c16 time, + c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 bit, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test index 1c247240eb9..ab133e4c347 100644 --- a/mysql-test/t/ps_1general.test +++ b/mysql-test/t/ps_1general.test @@ -307,15 +307,13 @@ prepare stmt4 from ' show index from t2 from test '; execute stmt4; prepare stmt4 from ' show table status from test like ''t2%'' '; # egalize date and time values ---replace_column 12 # 13 # 14 # ---replace_result 2147483647 64424509439 +--replace_column 8 # 12 # 13 # 14 # # Bug#4288 : prepared statement 'show table status ..', wrong output on execute execute stmt4; # try the same with the big table prepare stmt4 from ' show table status from test like ''t9%'' '; # egalize date and time values ---replace_column 12 # 13 # 14 # ---replace_result 2147483647 4294967295 +--replace_column 8 # 12 # 13 # 14 # # Bug#4288 execute stmt4; prepare stmt4 from ' show status like ''Threads_running'' '; diff --git a/mysql-test/t/ps_4heap.test b/mysql-test/t/ps_4heap.test index 1c9346721ab..3ce3bea8265 100644 --- a/mysql-test/t/ps_4heap.test +++ b/mysql-test/t/ps_4heap.test @@ -31,7 +31,7 @@ eval create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), - c13 date, c14 datetime, c15 timestamp(14), c16 time, + c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 varchar(100), c24 varchar(100), c25 varchar(100), c26 varchar(100), c27 varchar(100), c28 varchar(100), diff --git a/mysql-test/t/ps_5merge.test b/mysql-test/t/ps_5merge.test index 891d1be2c57..7e94ede41d1 100644 --- a/mysql-test/t/ps_5merge.test +++ b/mysql-test/t/ps_5merge.test @@ -31,7 +31,7 @@ create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), - c13 date, c14 datetime, c15 timestamp(14), c16 time, + c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, @@ -62,7 +62,7 @@ create table t9 c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), - c13 date, c14 datetime, c15 timestamp(14), c16 time, + c13 date, c14 datetime, c15 timestamp, c16 time, c17 year, c18 tinyint, c19 bool, c20 char, c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, c25 blob, c26 text, c27 mediumblob, c28 mediumtext, diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 88891bd3881..3a0ac08b1ba 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -757,6 +757,50 @@ flush query cache; drop table t1, t2; # +# Query with warning prohibited to query cache (BUG#9414) +# +flush status; +CREATE TABLE t1 ( + `date` datetime NOT NULL default '0000-00-00 00:00:00', + KEY `date` (`date`) +) ENGINE=MyISAM; + +INSERT INTO t1 VALUES ('20050326'); +INSERT INTO t1 VALUES ('20050325'); +SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 0:0:0'; +SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050328 0:0:0'; +SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 0:0:0'; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +drop table t1; + +# +# queries with subquery in the FROM clause (BUG#11522) +# +create table t1 (a int); +insert into t1 values (1); +reset query cache; +flush status; +select * from (select * from t1) a; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from (select * from t1) a; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +insert into t1 values (2); +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from (select * from t1) a; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +drop table t1; + +# # SP cursors and selects with query cache (BUG#9715) # create table t1 (a int); diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index a5822602b82..3d2285b1633 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -418,6 +418,41 @@ select count(*) from t2 where x > -16; select count(*) from t2 where x = 18446744073709551601; drop table t1,t2; +--disable_warnings +create table t1 (x bigint unsigned not null primary key) engine=innodb; +--enable_warnings +insert into t1(x) values (0xfffffffffffffff0); +insert into t1(x) values (0xfffffffffffffff1); +select * from t1; +select count(*) from t1 where x>0; +select count(*) from t1 where x=0; +select count(*) from t1 where x<0; +select count(*) from t1 where x < -16; +select count(*) from t1 where x = -16; +select count(*) from t1 where x > -16; +select count(*) from t1 where x = 18446744073709551601; + +drop table t1; + +# +# Bug #11185 incorrect comparison of unsigned int to signed constant +# +create table t1 (a bigint unsigned); +create index t1i on t1(a); +insert into t1 select 18446744073709551615; +insert into t1 select 18446744073709551614; + +explain select * from t1 where a <> -1; +select * from t1 where a <> -1; +explain select * from t1 where a > -1 or a < -1; +select * from t1 where a > -1 or a < -1; +explain select * from t1 where a > -1; +select * from t1 where a > -1; +explain select * from t1 where a < -1; +select * from t1 where a < -1; + +drop table t1; + # # Bug #6045: Binary Comparison regression in MySQL 4.1 # Binary searches didn't use a case insensitive index. @@ -495,3 +530,26 @@ SELECT * FROM t1 WHERE status NOT BETWEEN 'A' AND 'B'; SELECT * FROM t1 WHERE status < 'A' OR status > 'B'; DROP TABLE t1; + +# +# Test for bug #10031: range to be used over a view +# + +CREATE TABLE t1 (a int, b int, primary key(a,b)); + +INSERT INTO t1 VALUES + (1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3),(4,1),(4,2),(4,3); + +CREATE VIEW v1 as SELECT a,b FROM t1 WHERE b=3; + +EXPLAIN SELECT a,b FROM t1 WHERE a < 2 and b=3; +EXPLAIN SELECT a,b FROM v1 WHERE a < 2 and b=3; + +EXPLAIN SELECT a,b FROM t1 WHERE a < 2; +EXPLAIN SELECT a,b FROM v1 WHERE a < 2; + +SELECT a,b FROM t1 WHERE a < 2 and b=3; +SELECT a,b FROM v1 WHERE a < 2 and b=3; + +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/rpl_innodb.test b/mysql-test/t/rpl_innodb.test new file mode 100644 index 00000000000..b171dced26e --- /dev/null +++ b/mysql-test/t/rpl_innodb.test @@ -0,0 +1,46 @@ +# File for specialities regarding replication from or to InnoDB +# tables. + +source include/master-slave.inc; +source include/have_innodb.inc; + +# +# Bug#11401: Load data infile 'REPLACE INTO' fails on slave. +# +connection master; +CREATE TABLE t4 ( + id INT(5) unsigned NOT NULL auto_increment, + name varchar(15) NOT NULL default '', + number varchar(35) NOT NULL default 'default', + PRIMARY KEY (id), + UNIQUE KEY unique_rec (name,number) +) ENGINE=InnoDB; + +--disable_warnings +LOAD DATA + INFILE '../../std_data/loaddata_pair.dat' + REPLACE INTO TABLE t4 + (name,number); +--enable_warnings +SELECT * FROM t4; + +sync_slave_with_master; +SELECT * FROM t4; + +connection master; +--disable_warnings +LOAD DATA + INFILE '../../std_data/loaddata_pair.dat' + REPLACE INTO TABLE t4 + (name,number); +--enable_warnings +SELECT * FROM t4; + +sync_slave_with_master; +SELECT * FROM t4; + +connection master; +--disable_query_log +DROP TABLE t4; +--enable_query_log +sync_slave_with_master; diff --git a/mysql-test/t/rpl_multi_update3.test b/mysql-test/t/rpl_multi_update3.test index b8c8ed79532..80b0603eb60 100644 --- a/mysql-test/t/rpl_multi_update3.test +++ b/mysql-test/t/rpl_multi_update3.test @@ -1,7 +1,13 @@ +source include/master-slave.inc; + +############################################################################## +# # Let's verify that multi-update with a subselect does not cause the slave to crash # (BUG#10442) - -source include/master-slave.inc; +# +--disable_query_log +SELECT '-------- Test for BUG#9361 --------' as ""; +--enable_query_log CREATE TABLE t1 ( a int unsigned not null auto_increment primary key, @@ -25,10 +31,129 @@ UPDATE t2, (SELECT a FROM t1) AS t SET t2.b = t.a+5 ; SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; -save_master_pos; +sync_slave_with_master; connection slave; -sync_with_master; SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; +connection master; drop table t1,t2; + +############################################################################## +# +# Test for BUG#9361: +# Subselects should work inside multi-updates +# +--disable_query_log +SELECT '-------- Test 1 for BUG#9361 --------' as ""; +--enable_query_log + +connection master; + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +--enable_warnings + +CREATE TABLE t1 ( + a1 char(30), + a2 int, + a3 int, + a4 char(30), + a5 char(30) +); + +CREATE TABLE t2 ( + b1 int, + b2 char(30) +); + +# Insert one row per table +INSERT INTO t1 VALUES ('Yes', 1, NULL, 'foo', 'bar'); +INSERT INTO t2 VALUES (1, 'baz'); + +# This should update the row in t1 +UPDATE t1 a, t2 + SET a.a1 = 'No' + WHERE a.a2 = + (SELECT b1 + FROM t2 + WHERE b2 = 'baz') + AND a.a3 IS NULL + AND a.a4 = 'foo' + AND a.a5 = 'bar'; + +sync_slave_with_master; +connection slave; +SELECT * FROM t1; +SELECT * FROM t2; + +connection master; +DROP TABLE t1, t2; + +############################################################################## +# +# Second test for BUG#9361 +# + +--disable_query_log +SELECT '-------- Test 2 for BUG#9361 --------' as ""; +--enable_query_log + +connection master; + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP TABLE IF EXISTS t3; +--enable_warnings + +CREATE TABLE t1 ( + i INT, + j INT, + x INT, + y INT, + z INT +); + +CREATE TABLE t2 ( + i INT, + k INT, + x INT, + y INT, + z INT +); + +CREATE TABLE t3 ( + j INT, + k INT, + x INT, + y INT, + z INT +); + +INSERT INTO t1 VALUES ( 1, 2,13,14,15); +INSERT INTO t2 VALUES ( 1, 3,23,24,25); +INSERT INTO t3 VALUES ( 2, 3, 1,34,35), ( 2, 3, 1,34,36); + +UPDATE t1 AS a +INNER JOIN t2 AS b + ON a.i = b.i +INNER JOIN t3 AS c + ON a.j = c.j AND b.k = c.k +SET a.x = b.x, + a.y = b.y, + a.z = ( + SELECT sum(z) + FROM t3 + WHERE y = 34 + ) +WHERE b.x = 23; + +sync_slave_with_master; +connection slave; + +SELECT * FROM t1; + +connection master; +DROP TABLE t1, t2, t3; diff --git a/mysql-test/t/rpl_trunc_binlog.test b/mysql-test/t/rpl_trunc_binlog.test deleted file mode 100644 index eec36532275..00000000000 --- a/mysql-test/t/rpl_trunc_binlog.test +++ /dev/null @@ -1,35 +0,0 @@ -# We are testing if a binlog which contains BEGIN but not COMMIT (the -# master died while writing the transaction to the binlog) triggers a -# rollback on slave. So we use such a truncated binlog and simulate that -# the master restarted after this. - -source include/master-slave.inc; - -connection slave; -# If we are not supporting transactions in the slave, the unfinished -# transaction won't cause any error, so we need to skip the test. In the 4.0 -# testsuite, the slave always runs without InnoDB, so we check for BDB. -source include/have_bdb.inc; -stop slave; - -connection master; -flush logs; -system mv -f var/log/master-bin.000001 var/log/master-bin.000002; -system cp std_data/trunc_binlog.000001 var/log/master-bin.000001; - -connection slave; - -# truncated binlog contains: BEGIN; INSERT t1 VALUES (1); -# so let's create the table t1 on slave - -create table t1 (a int) engine=bdb; -reset slave; -start slave; -# can't sync_with_master so we must sleep -sleep 3; ---replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 8 # 9 # 23 # 33 # -show slave status; -select * from t1; -drop table t1; - diff --git a/mysql-test/t/rpl_until.test b/mysql-test/t/rpl_until.test index 714719f5441..c1aee2cb1db 100644 --- a/mysql-test/t/rpl_until.test +++ b/mysql-test/t/rpl_until.test @@ -26,6 +26,7 @@ show binlog events; connection slave; start slave until master_log_file='master-bin.000001', master_log_pos=319; sleep 2; +wait_for_slave_to_stop; # here table should be still not deleted select * from t1; --replace_result $MASTER_MYPORT MASTER_MYPORT @@ -37,13 +38,15 @@ start slave until master_log_file='master-no-such-bin.000001', master_log_pos=29 # again this table should be still not deleted select * from t1; sleep 2; +wait_for_slave_to_stop; --replace_result $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 9 # 23 # 33 # show slave status; # try replicate all until second insert to t2; start slave until relay_log_file='slave-relay-bin.000004', relay_log_pos=746; -sleep 4; +sleep 2; +wait_for_slave_to_stop; select * from t2; --replace_result $MASTER_MYPORT MASTER_MYPORT --replace_column 1 # 9 # 23 # 33 # @@ -59,8 +62,8 @@ stop slave; # this should stop immediately as we are already there start slave until master_log_file='master-bin.000001', master_log_pos=776; -# 2 is not enough when running with valgrind -real_sleep 4 +sleep 2; +wait_for_slave_to_stop; # here the sql slave thread should be stopped --replace_result $MASTER_MYPORT MASTER_MYPORT bin.000005 bin.000004 bin.000006 bin.000004 bin.000007 bin.000004 --replace_column 1 # 9 # 23 # 33 # diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 2558a3aeaeb..2e4bb3e13ad 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -1789,7 +1789,7 @@ DROP TABLE t1; # Test of bug with SUM(CASE...) # -CREATE TABLE t1 (gvid int(10) unsigned default NULL, hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, mmid int(10) unsigned default NULL, hdid int(10) unsigned default NULL, fsid int(10) unsigned default NULL, ctid int(10) unsigned default NULL, dtid int(10) unsigned default NULL, cost int(10) unsigned default NULL, performance int(10) unsigned default NULL, serialnumber bigint(20) unsigned default NULL, monitored tinyint(3) unsigned default '1', removed tinyint(3) unsigned default '0', target tinyint(3) unsigned default '0', dt_modified timestamp(14) NOT NULL, name varchar(255) binary default NULL, description varchar(255) default NULL, UNIQUE KEY hmid (hmid,volid)) ENGINE=MyISAM; +CREATE TABLE t1 (gvid int(10) unsigned default NULL, hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, mmid int(10) unsigned default NULL, hdid int(10) unsigned default NULL, fsid int(10) unsigned default NULL, ctid int(10) unsigned default NULL, dtid int(10) unsigned default NULL, cost int(10) unsigned default NULL, performance int(10) unsigned default NULL, serialnumber bigint(20) unsigned default NULL, monitored tinyint(3) unsigned default '1', removed tinyint(3) unsigned default '0', target tinyint(3) unsigned default '0', dt_modified timestamp NOT NULL, name varchar(255) binary default NULL, description varchar(255) default NULL, UNIQUE KEY hmid (hmid,volid)) ENGINE=MyISAM; INSERT INTO t1 VALUES (200001,2,1,1,100,1,1,1,0,0,0,1,0,1,20020425060057,'\\\\ARKIVIO-TESTPDC\\E$',''),(200002,2,2,1,101,1,1,1,0,0,0,1,0,1,20020425060057,'\\\\ARKIVIO-TESTPDC\\C$',''),(200003,1,3,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,1,0,1,20020425060427,'c:',NULL); CREATE TABLE t2 ( hmid int(10) unsigned default NULL, volid int(10) unsigned default NULL, sampletid smallint(5) unsigned default NULL, sampletime datetime default NULL, samplevalue bigint(20) unsigned default NULL, KEY idx1 (hmid,volid,sampletid,sampletime)) ENGINE=MyISAM; INSERT INTO t2 VALUES (1,3,10,'2002-06-01 08:00:00',35),(1,3,1010,'2002-06-01 12:00:01',35); @@ -1954,7 +1954,6 @@ EXPLAIN SELECT * FROM t1 LEFT JOIN t2 FORCE INDEX (a) ON t1.a=t2.a; DROP TABLE t1, t2; - # # Test case for bug 7098: substitution of a constant for a string field # @@ -1998,6 +1997,64 @@ select distinct all * from t1; drop table t1; # +# Test for BUG#10095 +# +CREATE TABLE t1 ( + kunde_intern_id int(10) unsigned NOT NULL default '0', + kunde_id int(10) unsigned NOT NULL default '0', + FK_firma_id int(10) unsigned NOT NULL default '0', + aktuell enum('Ja','Nein') NOT NULL default 'Ja', + vorname varchar(128) NOT NULL default '', + nachname varchar(128) NOT NULL default '', + geloescht enum('Ja','Nein') NOT NULL default 'Nein', + firma varchar(128) NOT NULL default '' +); + +INSERT INTO t1 VALUES + (3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'), + (3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX'); + + +SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1 + WHERE + ( + ( + ( '' != '' AND firma LIKE CONCAT('%', '', '%')) + OR + (vorname LIKE CONCAT('%', 'Vorname1', '%') AND + nachname LIKE CONCAT('%', '1Nachname', '%') AND + 'Vorname1' != '' AND 'xxxx' != '') + ) + AND + ( + aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 + ) + ) + ; + +SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, +geloescht FROM t1 + WHERE + ( + ( + aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 + ) + AND + ( + ( '' != '' AND firma LIKE CONCAT('%', '', '%') ) + OR + ( vorname LIKE CONCAT('%', 'Vorname1', '%') AND +nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND +'xxxx' != '') + ) + ) + ; + +SELECT COUNT(*) FROM t1 WHERE +( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1)) +AND FK_firma_id = 2; + +drop table t1; # # Test for Bug#8009, SELECT failed on bigint unsigned when using HEX @@ -2007,6 +2064,65 @@ CREATE TABLE t1 (b BIGINT(20) UNSIGNED NOT NULL, PRIMARY KEY (b)); INSERT INTO t1 VALUES (0x8000000000000000); SELECT b FROM t1 WHERE b=0x8000000000000000; DROP TABLE t1; + +# +# IN with outer join condition (BUG#9393) +# +CREATE TABLE `t1` ( `gid` int(11) default NULL, `uid` int(11) default NULL); + +CREATE TABLE `t2` ( `ident` int(11) default NULL, `level` char(16) default NULL); +INSERT INTO `t2` VALUES (0,'READ'); + +CREATE TABLE `t3` ( `id` int(11) default NULL, `name` char(16) default NULL); +INSERT INTO `t3` VALUES (1,'fs'); + +select * from t3 left join t1 on t3.id = t1.uid, t2 where t2.ident in (0, t1.gid, t3.id, 0); + +drop table t1,t2,t3; + +# +# Test case for bug 7098: substitution of a constant for a string field +# + +CREATE TABLE t1 ( city char(30) ); +INSERT INTO t1 VALUES ('London'); +INSERT INTO t1 VALUES ('Paris'); + +SELECT * FROM t1 WHERE city='London'; +SELECT * FROM t1 WHERE city='london'; +EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london'; +SELECT * FROM t1 WHERE city='London' AND city='london'; +EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; +SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; + +DROP TABLE t1; + +# +# Bug#7425 inconsistent sort order on unsigned columns result of substraction +# + +create table t1 (a int(11) unsigned, b int(11) unsigned); +insert into t1 values (1,0), (1,1), (1,2); +select a-b from t1 order by 1; +select a-b , (a-b < 0) from t1 order by 1; +select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0; +select cast((a - b) as unsigned) from t1 order by 1; +drop table t1; + + +# +# Bug#8733 server accepts malformed query (multiply mentioned distinct) +# +create table t1 (a int(11)); +select all all * from t1; +select distinct distinct * from t1; +--error 1221 +select all distinct * from t1; +--error 1221 +select distinct all * from t1; +drop table t1; + +# # Test for bug #6474 # @@ -2154,108 +2270,6 @@ EXPLAIN SELECT * FROM t1 LEFT JOIN t2 FORCE INDEX (a) ON t1.a=t2.a; DROP TABLE t1, t2; # -# Test case for bug 7098: substitution of a constant for a string field -# - -CREATE TABLE t1 ( city char(30) ); -INSERT INTO t1 VALUES ('London'); -INSERT INTO t1 VALUES ('Paris'); - -SELECT * FROM t1 WHERE city='London'; -SELECT * FROM t1 WHERE city='london'; -EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london'; -SELECT * FROM t1 WHERE city='London' AND city='london'; -EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; -SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; - -DROP TABLE t1; - -# -# Bug#7425 inconsistent sort order on unsigned columns result of substraction -# - -create table t1 (a int(11) unsigned, b int(11) unsigned); -insert into t1 values (1,0), (1,1), (1,2); -select a-b from t1 order by 1; -select a-b , (a-b < 0) from t1 order by 1; -select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0; -select cast((a - b) as unsigned) from t1 order by 1; -drop table t1; - - -# -# Bug#8733 server accepts malformed query (multiply mentioned distinct) -# -create table t1 (a int(11)); -select all all * from t1; -select distinct distinct * from t1; ---error 1221 -select all distinct * from t1; ---error 1221 -select distinct all * from t1; -drop table t1; - -# -# Test for BUG#10095 -# -CREATE TABLE t1 ( - kunde_intern_id int(10) unsigned NOT NULL default '0', - kunde_id int(10) unsigned NOT NULL default '0', - FK_firma_id int(10) unsigned NOT NULL default '0', - aktuell enum('Ja','Nein') NOT NULL default 'Ja', - vorname varchar(128) NOT NULL default '', - nachname varchar(128) NOT NULL default '', - geloescht enum('Ja','Nein') NOT NULL default 'Nein', - firma varchar(128) NOT NULL default '' -); - -INSERT INTO t1 VALUES - (3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'), - (3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX'); - - -SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1 - WHERE - ( - ( - ( '' != '' AND firma LIKE CONCAT('%', '', '%')) - OR - (vorname LIKE CONCAT('%', 'Vorname1', '%') AND - nachname LIKE CONCAT('%', '1Nachname', '%') AND - 'Vorname1' != '' AND 'xxxx' != '') - ) - AND - ( - aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 - ) - ) - ; - -SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, -geloescht FROM t1 - WHERE - ( - ( - aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 - ) - AND - ( - ( '' != '' AND firma LIKE CONCAT('%', '', '%') ) - OR - ( vorname LIKE CONCAT('%', 'Vorname1', '%') AND -nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND -'xxxx' != '') - ) - ) - ; - -SELECT COUNT(*) FROM t1 WHERE -( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1)) -AND FK_firma_id = 2; - -drop table t1; - -# # Test for bug #10084: STRAIGHT_JOIN with ON expression # diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index f74ffc4f4f5..d591f90dd65 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -376,3 +376,12 @@ show index from t1; --disable_metadata drop table t1; +# Test for BUG#11635: mysqldump exports TYPE instead of USING for HASH +create table t1 ( + c1 int NOT NULL, + c2 int NOT NULL, + PRIMARY KEY USING HASH (c1), + INDEX USING BTREE(c2) +); +SHOW CREATE TABLE t1; +DROP TABLE t1; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index faf6d8b4de3..7750071c715 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -2,6 +2,10 @@ # Stored PROCEDURE error tests # +--disable_warnings +drop table if exists t1, t2; +--enable_warnings + # Make sure we don't have any procedures left. delete from mysql.proc; @@ -84,7 +88,7 @@ show create procedure foo| --error 1305 show create function foo| -# LEAVE/ITERATE/GOTO with no match +# LEAVE/ITERATE with no match --error 1308 create procedure foo() foo: loop @@ -100,47 +104,6 @@ create procedure foo() foo: begin iterate foo; end| ---error 1308 -create procedure foo() -begin - goto foo; -end| ---error 1308 -create procedure foo() -begin - begin - label foo; - end; - goto foo; -end| ---error 1308 -create procedure foo() -begin - goto foo; - begin - label foo; - end; -end| ---error 1308 -create procedure foo() -begin - begin - goto foo; - end; - begin - label foo; - end; -end| ---error 1308 -create procedure foo() -begin - begin - label foo; - end; - begin - goto foo; - end; -end| # Redefining label --error 1309 @@ -398,18 +361,6 @@ begin declare c cursor for select * from t1; end| ---error 1358 -create procedure p() -begin - declare continue handler for sqlexception - begin - goto L1; - end; - - select field from t1; - label L1; -end| - # Check in and inout arguments. --disable_warnings drop procedure if exists p| @@ -923,9 +874,9 @@ end| # # BUG#9529: Stored Procedures: No Warning on truncation of procedure name # during creation. -# +# Note: When using utf8 for mysql.proc, this limit is much higher than before --error ER_TOO_LONG_IDENT -create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890() +create procedure bug9529_90123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123() begin end| @@ -986,3 +937,115 @@ create procedure p() execute stmt; create function f() returns int begin execute stmt; deallocate prepare stmt; +# BUG#9814: Closing a cursor that is not open +create table t1(f1 int); +create table t2(f1 int); + +delimiter |; +CREATE PROCEDURE SP001() +P1: BEGIN + DECLARE ENDTABLE INT DEFAULT 0; + DECLARE TEMP_NUM INT; + DECLARE TEMP_SUM INT; + DECLARE C1 CURSOR FOR SELECT F1 FROM t1; + DECLARE C2 CURSOR FOR SELECT F1 FROM t2; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET ENDTABLE = 1; + + SET ENDTABLE=0; + SET TEMP_SUM=0; + SET TEMP_NUM=0; + + OPEN C1; + + FETCH C1 INTO TEMP_NUM; + WHILE ENDTABLE = 0 DO + SET TEMP_SUM=TEMP_NUM+TEMP_SUM; + FETCH C1 INTO TEMP_NUM; + END WHILE; + SELECT TEMP_SUM; + CLOSE C1; + CLOSE C1; + SELECT 'end of proc'; +END P1| +delimiter ;| +call SP001(); +drop procedure SP001; +drop table t1, t2; + +# Bug #11394 "Recursion in SP crash server" and bug #11600 "Stored +# procedures: crash with function calling itself". +# We have to disable recursion since in many cases LEX and many +# Item's can't be used in reentrant way nowdays. +delimiter |; +--disable_warnings +drop function if exists bug11394| +drop function if exists bug11394_1| +drop function if exists bug11394_2| +drop procedure if exists bug11394| +--enable_warnings +create function bug11394(i int) returns int +begin + if i <= 0 then + return 0; + else + return (i in (100, 200, bug11394(i-1), 400)); + end if; +end| +# If we allow recursive functions without additional modifications +# this will crash server since Item for "IN" is not reenterable. +--error 1424 +select bug11394(2)| +drop function bug11394| +create function bug11394_1(i int) returns int +begin + if i <= 0 then + return 0; + else + return (select bug11394_1(i-1)); + end if; +end| +# The following statement will crash because some LEX members responsible +# for selects cannot be used in reentrant fashion. +--error 1424 +select bug11394_1(2)| +drop function bug11394_1| +# Note that the following should be allowed since it does not contains +# recursion +create function bug11394_2(i int) returns int return i| +select bug11394_2(bug11394_2(10))| +drop function bug11394_2| +create procedure bug11394(i int, j int) +begin + if i > 0 then + call bug11394(i - 1,(select 1)); + end if; +end| +# Again if we allow recursion for stored procedures (without +# additional efforts) the following statement will crash the server. +--error 1424 +call bug11394(2, 1)| +drop procedure bug11394| +delimiter ;| + +# +# Bug#11834 "Re-execution of prepared statement with dropped function +# crashes server". Also tests handling of prepared stmts which use +# stored functions but does not require prelocking. +# +--disable_warnings +drop function if exists bug11834_1; +drop function if exists bug11834_2; +--enable_warnings +create function bug11834_1() returns int return 10; +create function bug11834_2() returns int return bug11834_1(); +prepare stmt from "select bug11834_2()"; +execute stmt; +# Re-execution of statement should not crash server. +execute stmt; +drop function bug11834_1; +# Attempt to execute statement should return proper error and +# should not crash server. +--error ER_SP_DOES_NOT_EXIST +execute stmt; +deallocate prepare stmt; +drop function bug11834_2; diff --git a/mysql-test/t/sp-goto.test b/mysql-test/t/sp-goto.test new file mode 100644 index 00000000000..e770dd285ff --- /dev/null +++ b/mysql-test/t/sp-goto.test @@ -0,0 +1,238 @@ +# +# The non-standard GOTO, for compatibility +# +# QQQ The "label" syntax is temporary, it will (hopefully) +# change to the more common "L:" syntax soon. +# For the time being, this feature is disabled, until +# the syntax (and some other known bugs) can be fixed. +# +# Test cases for bugs are added at the end. See template there. +# + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 ( + id char(16) not null default '', + data int not null +); + +delimiter //; + +--disable_warnings +drop procedure if exists goto1// +--enable_warnings +create procedure goto1() +begin + declare y int; + +label a; + select * from t1; + select count(*) into y from t1; + if y > 2 then + goto b; + end if; + insert into t1 values ("j", y); + goto a; +label b; +end// + +call goto1()// +drop procedure goto1// + +# With dummy handlers, just to test restore of contexts with jumps +--disable_warnings +drop procedure if exists goto2// +--enable_warnings +create procedure goto2(a int) +begin + declare x int default 0; + declare continue handler for sqlstate '42S98' set x = 1; + +label a; + select * from t1; +b: + while x < 2 do + begin + declare continue handler for sqlstate '42S99' set x = 2; + + if a = 0 then + set x = x + 1; + iterate b; + elseif a = 1 then + leave b; + elseif a = 2 then + set a = 1; + goto a; + end if; + end; + end while b; + + select * from t1; +end// + +call goto2(0)// +call goto2(1)// +call goto2(2)// + +drop procedure goto2// +delete from t1// + +# Check label visibility for some more cases. We don't call these. +--disable_warnings +drop procedure if exists goto3// +--enable_warnings +create procedure goto3() +begin + label L1; + begin + end; + goto L1; +end// +drop procedure goto3// + +--disable_warnings +drop procedure if exists goto4// +--enable_warnings +create procedure goto4() +begin + begin + label lab1; + begin + goto lab1; + end; + end; +end// +drop procedure goto4// + +--disable_warnings +drop procedure if exists goto5// +--enable_warnings +create procedure goto5() +begin + begin + begin + goto lab1; + end; + label lab1; + end; +end// +drop procedure goto5// + +--disable_warnings +drop procedure if exists goto6// +--enable_warnings +create procedure goto6() +begin + label L1; + goto L5; + begin + label L2; + goto L1; + goto L5; + begin + label L3; + goto L1; + goto L2; + goto L3; + goto L4; + goto L5; + end; + goto L2; + goto L4; + label L4; + end; + label L5; + goto L1; +end// +drop procedure goto6// + +# Mismatching labels +--error 1308 +create procedure foo() +begin + goto foo; +end// +--error 1308 +create procedure foo() +begin + begin + label foo; + end; + goto foo; +end// +--error 1308 +create procedure foo() +begin + goto foo; + begin + label foo; + end; +end// +--error 1308 +create procedure foo() +begin + begin + goto foo; + end; + begin + label foo; + end; +end// +--error 1308 +create procedure foo() +begin + begin + label foo; + end; + begin + goto foo; + end; +end// + +# No goto in a handler +--error 1358 +create procedure p() +begin + declare continue handler for sqlexception + begin + goto L1; + end; + + select field from t1; + label L1; +end// + + +# +# Test cases for old bugs +# + +# +# BUG#6898: Stored procedure crash if GOTO statements exist +# +--disable_warnings +drop procedure if exists bug6898// +--enable_warnings +create procedure bug6898() +begin + goto label1; + label label1; + begin end; + goto label1; +end// +drop procedure bug6898// + +# +# BUG#NNNN: New bug synopsis +# +#--disable_warnings +#drop procedure if exists bugNNNN// +#--enable_warnings +#create procedure bugNNNN... + + +# Add bugs above this line. Use existing tables t1 and t2 when +# practical, or create table t3, t4 etc temporarily (and drop them). +delimiter ;// +drop table t1; diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test index e1d8043ccda..3dc6b9d07ab 100644 --- a/mysql-test/t/sp-security.test +++ b/mysql-test/t/sp-security.test @@ -15,6 +15,7 @@ grant usage on *.* to user1@localhost; flush privileges; --disable_warnings +drop table if exists t1; drop database if exists db1_secret; --enable_warnings # Create our secret database @@ -304,3 +305,39 @@ drop database sptest; delete from mysql.user where user='usera' or user='userb' or user='userc'; delete from mysql.procs_priv where user='usera' or user='userb' or user='userc'; +# +# BUG#9503: reseting correct parameters of thread after error in SP function +# +connect (root,localhost,root,,test); +connection root; + +--disable_warnings +drop function if exists bug_9503; +--enable_warnings +delimiter //; +create database mysqltest// +use mysqltest// +create table t1 (s1 int)// +grant select on t1 to user1@localhost// +create function bug_9503 () returns int sql security invoker begin declare v int; +select min(s1) into v from t1; return v; end// +delimiter ;// + +connect (user1,localhost,user1,,test); +connection user1; +use mysqltest; +-- error 1370 +select bug_9503(); + +connection root; +grant execute on function bug_9503 to user1@localhost; + +connection user1; +do 1; +use test; + +connection root; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost; +drop function bug_9503; +use test; +drop database mysqltest; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index e7ee4b134ba..4df49c5f934 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -12,6 +12,7 @@ # Tests that check privilege and security issues go to sp-security.test. # Tests that require multiple connections, except security/privilege tests, # go to sp-thread. +# Tests that uses 'goto' to into sp-goto.test (currently disabled) use test; @@ -585,139 +586,6 @@ delete from t1| drop procedure i| -# The non-standard GOTO, for compatibility -# -# QQQ The "label" syntax is temporary, it will (hopefully) -# change to the more common "L:" syntax soon. -# ---disable_warnings -drop procedure if exists goto1| ---enable_warnings -create procedure goto1() -begin - declare y int; - -label a; - select * from t1; - select count(*) into y from t1; - if y > 2 then - goto b; - end if; - insert into t1 values ("j", y); - goto a; -label b; -end| - -call goto1()| -drop procedure goto1| - -# With dummy handlers, just to test restore of contexts with jumps ---disable_warnings -drop procedure if exists goto2| ---enable_warnings -create procedure goto2(a int) -begin - declare x int default 0; - declare continue handler for sqlstate '42S98' set x = 1; - -label a; - select * from t1; -b: - while x < 2 do - begin - declare continue handler for sqlstate '42S99' set x = 2; - - if a = 0 then - set x = x + 1; - iterate b; - elseif a = 1 then - leave b; - elseif a = 2 then - set a = 1; - goto a; - end if; - end; - end while b; - - select * from t1; -end| - -call goto2(0)| -call goto2(1)| -call goto2(2)| - -drop procedure goto2| -delete from t1| - -# Check label visibility for some more cases. We don't call these. ---disable_warnings -drop procedure if exists goto3| ---enable_warnings -create procedure goto3() -begin - label L1; - begin - end; - goto L1; -end| -drop procedure goto3| - ---disable_warnings -drop procedure if exists goto4| ---enable_warnings -create procedure goto4() -begin - begin - label lab1; - begin - goto lab1; - end; - end; -end| -drop procedure goto4| - ---disable_warnings -drop procedure if exists goto5| ---enable_warnings -create procedure goto5() -begin - begin - begin - goto lab1; - end; - label lab1; - end; -end| -drop procedure goto5| - ---disable_warnings -drop procedure if exists goto6| ---enable_warnings -create procedure goto6() -begin - label L1; - goto L5; - begin - label L2; - goto L1; - goto L5; - begin - label L3; - goto L1; - goto L2; - goto L3; - goto L4; - goto L5; - end; - goto L2; - goto L4; - label L4; - end; - label L5; - goto L1; -end| -drop procedure goto6| - # SELECT with one of more result set sent back to the clinet insert into t1 values ("foo", 3), ("bar", 19)| insert into t2 values ("x", 9, 4.1), ("y", -1, 19.2), ("z", 3, 2.2)| @@ -1415,7 +1283,8 @@ select * from v1| # views and functions ? create function f1() returns int return (select sum(data) from t1) + (select sum(data) from v1)| -# FIXME All these just exceed file limit for me :) +# This queries will crash server because we can't use LEX in +# reenterable fashion yet. Patch disabling recursion will heal this. #select f1()| #select * from v1| #select * from v2| @@ -1460,15 +1329,12 @@ select * from v2| select * from v1| # These should not work as we have too little instances of tables locked --error 1100 -select * from v1, v2| +select * from v1, t1| --error 1100 select f4()| unlock tables| -# TODO We also should test integration with triggers - - # Cleanup drop function f0| drop function f1| @@ -1630,54 +1496,56 @@ show procedure status like '%p%'| # Fibonacci, for recursion test. (Yet Another Numerical series :) - ---disable_warnings -drop table if exists fib| ---enable_warnings -create table fib ( f bigint unsigned not null )| - -# We deliberately do it the awkward way, fetching the last two -# values from the table, in order to exercise various statements -# and table accesses at each turn. ---disable_warnings -drop procedure if exists fib| ---enable_warnings -create procedure fib(n int unsigned) -begin - if n > 1 then - begin - declare x, y bigint unsigned; - declare c cursor for select f from fib order by f desc limit 2; - - open c; - fetch c into y; - fetch c into x; - close c; - insert into fib values (x+y); - call fib(n-1); - end; - end if; -end| - -# Minimum test: recursion of 3 levels - -insert into fib values (0), (1)| - -call fib(3)| - -select * from fib order by f asc| - -delete from fib| - -# Original test: 20 levels (may run into memory limits!) - -insert into fib values (0), (1)| - -call fib(20)| - -select * from fib order by f asc| -drop table fib| -drop procedure fib| +# +# This part of test is disabled until we implement support for +# recursive stored procedures. +#--disable_warnings +#drop table if exists fib| +#--enable_warnings +#create table fib ( f bigint unsigned not null )| +# +## We deliberately do it the awkward way, fetching the last two +## values from the table, in order to exercise various statements +## and table accesses at each turn. +#--disable_warnings +#drop procedure if exists fib| +#--enable_warnings +#create procedure fib(n int unsigned) +#begin +# if n > 1 then +# begin +# declare x, y bigint unsigned; +# declare c cursor for select f from fib order by f desc limit 2; +# +# open c; +# fetch c into y; +# fetch c into x; +# close c; +# insert into fib values (x+y); +# call fib(n-1); +# end; +# end if; +#end| +# +## Minimum test: recursion of 3 levels +# +#insert into fib values (0), (1)| +# +#call fib(3)| +# +#select * from fib order by f asc| +# +#delete from fib| +# +## Original test: 20 levels (may run into memory limits!) +# +#insert into fib values (0), (1)| +# +#call fib(20)| +# +#select * from fib order by f asc| +#drop table fib| +#drop procedure fib| # @@ -3011,24 +2879,26 @@ drop table t3| # # BUG#6022: Stored procedure shutdown problem with self-calling function. # ---disable_warnings -drop function if exists bug6022| ---enable_warnings - ---disable_warnings -drop function if exists bug6022| ---enable_warnings -create function bug6022(x int) returns int -begin - if x < 0 then - return 0; - else - return bug6022(x-1); - end if; -end| - -select bug6022(5)| -drop function bug6022| +# This part of test is disabled until we implement support for +# recursive stored functions. +#--disable_warnings +#drop function if exists bug6022| +#--enable_warnings +# +#--disable_warnings +#drop function if exists bug6022| +#--enable_warnings +#create function bug6022(x int) returns int +#begin +# if x < 0 then +# return 0; +# else +# return bug6022(x-1); +# end if; +#end| +# +#select bug6022(5)| +#drop function bug6022| # # BUG#6029: Stored procedure specific handlers should have priority @@ -3635,22 +3505,6 @@ drop function bug9902| # -# BUG#6898: Stored procedure crash if GOTO statements exist -# ---disable_warnings -drop procedure if exists bug6898| ---enable_warnings -create procedure bug6898() -begin - goto label1; - label label1; - begin end; - goto label1; -end| -drop procedure bug6898| - - -# # BUG#9102: Stored proccedures: function which returns blob causes crash # --disable_warnings @@ -3912,6 +3766,74 @@ drop procedure bug10136| drop table t3| # +# BUG#11529: crash server after use stored procedure +# +--disable_warnings +drop procedure if exists bug11529| +--enable_warnings +create procedure bug11529() +begin + declare c cursor for select id, data from t1 where data in (10,13); + + open c; + begin + declare vid char(16); + declare vdata int; + declare exit handler for not found begin end; + + while true do + fetch c into vid, vdata; + end while; + end; + close c; +end| + +insert into t1 values + ('Name1', 10), + ('Name2', 11), + ('Name3', 12), + ('Name4', 13), + ('Name5', 14)| + +call bug11529()| +call bug11529()| +delete from t1| +drop procedure bug11529| + + +# +# BUG#6063: Stored procedure labels are subject to restrictions (partial) +# BUG#7088: Stored procedures: labels won't work if character set is utf8 +# +--disable_warnings +drop procedure if exists bug6063| +drop procedure if exists bug7088_1| +drop procedure if exists bug7088_2| +--enable_warnings + +create procedure bug6063() + lâbel: begin end| +call bug6063()| +# QQ Known bug: this will not show the label correctly. +show create procedure bug6063| + +set character set utf8| +create procedure bug7088_1() + label1: begin end label1| +create procedure bug7088_2() + läbel1: begin end| +call bug7088_1()| +call bug7088_2()| +set character set default| +show create procedure bug7088_1| +show create procedure bug7088_2| + +drop procedure bug6063| +drop procedure bug7088_1| +drop procedure bug7088_2| + + +# # BUG#NNNN: New bug synopsis # #--disable_warnings @@ -3921,7 +3843,6 @@ drop table t3| # Add bugs above this line. Use existing tables t1 and t2 when -# practical, or create table t3, t3 etc temporarily (and drop them). +# practical, or create table t3, t4 etc temporarily (and drop them). delimiter ;| drop table t1,t2; - diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test index 26cb0944e3a..f8ab521e665 100644 --- a/mysql-test/t/sql_mode.test +++ b/mysql-test/t/sql_mode.test @@ -189,7 +189,6 @@ SET @@SQL_MODE=''; SELECT 'a\\b', 'a\\\"b', 'a''\\b', 'a''\\\"b'; SELECT "a\\b", "a\\\'b", "a""\\b", "a""\\\'b"; - # # Bug#6877: MySQL should give an error if the requested table type # is not available @@ -208,5 +207,37 @@ create table t1 (a int) engine=isam; show create table t1; drop table t1; +# +# Bug #6903: ANSI_QUOTES does not come into play with SHOW CREATE FUNCTION +# or PROCEDURE because it displays the SQL_MODE used to create the routine. +# +SET @@SQL_MODE=''; +create function `foo` () returns int return 5; +show create function `foo`; +SET @@SQL_MODE='ANSI_QUOTES'; +show create function `foo`; +drop function `foo`; + +create function `foo` () returns int return 5; +show create function `foo`; +SET @@SQL_MODE=''; +show create function `foo`; +drop function `foo`; + +# +# Bug #6903: ANSI_QUOTES should have effect for SHOW CREATE VIEW (Bug #6903) +# +SET @@SQL_MODE=''; +create table t1 (a int); +create table t2 (a int); +create view v1 as select a from t1; +show create view v1; +SET @@SQL_MODE='ANSI_QUOTES'; +show create view v1; +# Test a view with a subselect, which will get shown incorrectly without +# thd->lex->view_prepare_mode set properly. +create view v2 as select a from t2 where a in (select a from v1); +drop view v2, v1; +drop table t1, t2; SET @@SQL_MODE=@OLD_SQL_MODE; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 2e6cea8468b..ecb3432753d 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1837,3 +1837,33 @@ WHERE t1.EMPNUM NOT IN WHERE t1.EMPNUM = t2.EMPNUM); select * from t1; DROP TABLE t1,t2; + +# +# Test for bug #11487: range access in a subquery +# + +CREATE TABLE t1(select_id BIGINT, values_id BIGINT); +INSERT INTO t1 VALUES (1, 1); +CREATE TABLE t2 (select_id BIGINT, values_id BIGINT, + PRIMARY KEY(select_id,values_id)); +INSERT INTO t2 VALUES (0, 1), (0, 2), (0, 3), (1, 5); + +SELECT values_id FROM t1 +WHERE values_id IN (SELECT values_id FROM t2 + WHERE select_id IN (1, 0)); +SELECT values_id FROM t1 +WHERE values_id IN (SELECT values_id FROM t2 + WHERE select_id BETWEEN 0 AND 1); +SELECT values_id FROM t1 +WHERE values_id IN (SELECT values_id FROM t2 + WHERE select_id = 0 OR select_id = 1); + +DROP TABLE t1, t2; + +# BUG#11821 : Select from subselect using aggregate function on an enum +# segfaults: +create table t1 (fld enum('0','1')); +insert into t1 values ('1'); +select * from (select max(fld) from t1) as foo; +drop table t1; + diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 0c5ef077159..229cbd3c79c 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -3,9 +3,10 @@ # --disable_warnings -drop table if exists t1, t2; +drop table if exists t1, t2, t3; drop view if exists v1; drop database if exists mysqltest; +drop function if exists f1; --enable_warnings create table t1 (i int); @@ -200,6 +201,86 @@ drop table t1; # +# Let us test triggers which access other tables. +# +# Trivial trigger which inserts data into another table +create table t1 (id int primary key, data varchar(10), fk int); +create table t2 (event varchar(100)); +create table t3 (id int primary key); +create trigger t1_ai after insert on t1 for each row + insert into t2 values (concat("INSERT INTO t1 id=", new.id, " data='", new.data, "'")); +insert into t1 (id, data) values (1, "one"), (2, "two"); +select * from t1; +select * from t2; +drop trigger t1.t1_ai; +# Trigger which uses couple of tables (and partially emulates FK constraint) +delimiter |; +create trigger t1_bi before insert on t1 for each row +begin + if exists (select id from t3 where id=new.fk) then + insert into t2 values (concat("INSERT INTO t1 id=", new.id, " data='", new.data, "' fk=", new.fk)); + else + insert into t2 values (concat("INSERT INTO t1 FAILED id=", new.id, " data='", new.data, "' fk=", new.fk)); + set new.id= NULL; + end if; +end| +delimiter ;| +insert into t3 values (1); +--error 1048 +insert into t1 values (4, "four", 1), (5, "five", 2); +select * from t1; +select * from t2; +drop table t1, t2, t3; +# Trigger which invokes function +create table t1 (id int primary key, data varchar(10)); +create table t2 (seq int); +insert into t2 values (10); +create function f1 () returns int return (select max(seq) from t2); +delimiter |; +create trigger t1_bi before insert on t1 for each row +begin + if new.id > f1() then + set new.id:= f1(); + end if; +end| +delimiter ;| +# Remove this once bug #11554 will be fixed. +select f1(); +insert into t1 values (1, "first"); +insert into t1 values (f1(), "max"); +select * from t1; +drop table t1, t2; +drop function f1; +# Trigger which forces invocation of another trigger +# (emulation of FK on delete cascade policy) +create table t1 (id int primary key, fk_t2 int); +create table t2 (id int primary key, fk_t3 int); +create table t3 (id int primary key); +insert into t1 values (1,1), (2,1), (3,2); +insert into t2 values (1,1), (2,2); +insert into t3 values (1), (2); +create trigger t3_ad after delete on t3 for each row + delete from t2 where fk_t3=old.id; +create trigger t2_ad after delete on t2 for each row + delete from t1 where fk_t2=old.id; +delete from t3 where id = 1; +select * from t1 left join (t2 left join t3 on t2.fk_t3 = t3.id) on t1.fk_t2 = t2.id; +drop table t1, t2, t3; +# Trigger which assigns value selected from table to field of row +# being inserted/updated. +create table t1 (id int primary key, copy int); +create table t2 (id int primary key, data int); +insert into t2 values (1,1), (2,2); +create trigger t1_bi before insert on t1 for each row + set new.copy= (select data from t2 where id = new.id); +create trigger t1_bu before update on t1 for each row + set new.copy= (select data from t2 where id = new.id); +insert into t1 values (1,3), (2,4), (3,3); +update t1 set copy= 1 where id = 2; +select * from t1; +drop table t1, t2; + +# # Test of wrong column specifiers in triggers # create table t1 (i int); @@ -494,3 +575,18 @@ replace into t1 (i, k) values (2, 11); select * from t1; # Also drops all triggers drop table t1, t2; + +# Test for bug #5893 "Triggers with dropped functions cause crashes" +# Appropriate error should be reported instead of crash. +# Had to disable this test until bug #11554 will be fixed. +#--disable_warnings +#drop function if exists bug5893; +#--enable_warnings +#create table t1 (col1 int, col2 int); +#insert into t1 values (1, 2); +#create function bug5893 () returns int return 5; +#create trigger t1_bu before update on t1 for each row set new.col1= bug5893(); +#drop function bug5893; +#--error 1305 +#update t1 set col2 = 4; +#drop table t1; diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test index 2df5f0ed05d..fd5eb49858c 100644 --- a/mysql-test/t/type_bit.test +++ b/mysql-test/t/type_bit.test @@ -171,3 +171,56 @@ create table t1 (a bit(8)) engine=heap; insert into t1 values ('1111100000'); select a+0 from t1; drop table t1; + +# +# Bug #11091: union +# + +create table t1 (a bit(7)); +insert into t1 values (120), (0), (111); +select a+0 from t1 union select a+0 from t1; +select a+0 from t1 union select NULL; +select NULL union select a+0 from t1; +create table t2 select a from t1 union select a from t1; +select a+0 from t2; +show create table t2; +drop table t1, t2; + +# +# Bug #11572: view +# + +create table t1 (id1 int(11), b1 bit(1)); +create table t2 (id2 int(11), b2 bit(1)); +insert into t1 values (1, 1), (2, 0), (3, 1); +insert into t2 values (2, 1), (3, 0), (4, 0); +create algorithm=undefined view v1 as + select b1+0, b2+0 from t1, t2 where id1 = id2 and b1 = 0 + union + select b1+0, b2+0 from t1, t2 where id1 = id2 and b2 = 1; +select * from v1; +drop table t1, t2; +drop view v1; + +# +# Bug #10617: bulk-insert +# + +create table t1(a bit(4)); +insert into t1(a) values (1), (2), (5), (4), (3); +insert into t1 select * from t1; +select a+0 from t1; +drop table t1; + +# +# join +# + +create table t1 (a1 int(11), b1 bit(2)); +create table t2 (a2 int(11), b2 bit(2)); +insert into t1 values (1, 1), (2, 0), (3, 1), (4, 2); +insert into t2 values (2, 1), (3, 0), (4, 1), (5, 2); +select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2; +select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2 order by a1; +select a1, a2, b1+0, b2+0 from t1 join t2 on b1 = b2; +select sum(a1), b1+0, b2+0 from t1 join t2 on b1 = b2 group by b1 order by 1; diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test index c33ea3f435d..80aabf6c5e0 100644 --- a/mysql-test/t/type_blob.test +++ b/mysql-test/t/type_blob.test @@ -394,4 +394,11 @@ INSERT t1 (i, c) VALUES (1,''),(2,''),(3,'asdfh'),(4,''); select max(i) from t1 where c = ''; drop table t1; - +# +# Bug#11657: Creation of secondary index fails +# +create table t1 (a int, b int, c tinyblob, d int, e int); +alter table t1 add primary key (a,b,c(255),d); +alter table t1 add key (a,b,d,e); +show create table t1; +drop table t1; diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 7ce54847506..2901592fd9e 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -247,9 +247,8 @@ CREATE TABLE t1 (a_dec DECIMAL(-1,0)); CREATE TABLE t1 (a_dec DECIMAL(-2,1)); --error 1064 CREATE TABLE t1 (a_dec DECIMAL(-1,1)); +--error 1427 CREATE TABLE t1 (a_dec DECIMAL(0,11)); -SHOW CREATE TABLE t1; -DROP TABLE t1; # # Zero prepend overflow bug @@ -293,21 +292,13 @@ create table t1 (d decimal(64,0)); insert into t1 values (1); select * from t1; drop table t1; -create table t1 (d decimal(64,99)); -show create table t1; -insert into t1 values (1); -select * from t1; -drop table t1; -create table t1 (d decimal(10,12)); -show create table t1; -drop table t1; create table t1 (d decimal(5)); show create table t1; drop table t1; create table t1 (d decimal); show create table t1; drop table t1; ---error 1063 +--error 1426 create table t1 (d decimal(66,0)); # diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index 41812ef2652..a27fd4c58b4 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -67,7 +67,7 @@ drop table t1; # FLOAT/DOUBLE/DECIMAL handling # -create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(5,6)); +create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(7,6)); # We mask out Privileges column because it differs for embedded server --replace_column 8 # show full columns from t1; @@ -79,11 +79,8 @@ select a from t1 order by a; select min(a) from t1; drop table t1; +--error 1425 create table t1 (a float(200,100), b double(200,100)); -insert t1 values (1.0, 2.0); -select * from t1; -show create table t1; -drop table t1; # # float in a char(1) field diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index 6199bd34fa9..f54c8d80f09 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -964,3 +964,54 @@ insert into t1 values (0.00); select * from t1 where a > -0.00; select * from t1 where a = -0.00; drop table t1; + +# +# Bug #11215: a problem with LONGLONG_MIN +# + +create table t1 (col1 bigint default -9223372036854775808); +insert into t1 values (default); +select * from t1; +drop table t1; + +# +# Bug #10891 (converting to decimal crashes server) +# +select cast('1.00000001335143196001808973960578441619873046875E-10' as decimal(30,15)); + +# +# Bug #11708 (conversion to decimal fails in decimal part) +# +select ln(14000) c1, convert(ln(14000),decimal(2,3)) c2, cast(ln(14000) as decimal(2,3)) c3; + +# +# Bug #8449 (Silent column changes) +# +--error 1426 +create table t1 (sl decimal(70,30)); +--error 1425 +create table t1 (sl decimal(32,31)); +--error 1425 +create table t1 (sl decimal(0,38)); +--error 1427 +create table t1 (sl decimal(0,30)); +create table t1 (sl decimal(5, 5)); +show create table t1; +drop table t1; + +# +# Bug 11557 (DEFAULT values rounded improperly +# +create table t1 ( + f1 decimal unsigned not null default 17.49, + f2 decimal unsigned not null default 17.68, + f3 decimal unsigned not null default 99.2, + f4 decimal unsigned not null default 99.7, + f5 decimal unsigned not null default 104.49, + f6 decimal unsigned not null default 199.91, + f7 decimal unsigned not null default 999.9, + f8 decimal unsigned not null default 9999.99); +insert into t1 (f1) values (1); +select * from t1; +drop table t1; + diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 6a90fb95760..21789a550b9 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -31,7 +31,7 @@ CREATE TABLE t1 clicks int(10) unsigned DEFAULT '0' NOT NULL, iclicks int(10) unsigned DEFAULT '0' NOT NULL, uclicks int(10) unsigned DEFAULT '0' NOT NULL, - ts timestamp(14), + ts timestamp, PRIMARY KEY (place_id,ts) ); @@ -52,7 +52,7 @@ CREATE TABLE t1 ( replyto varchar(255) NOT NULL default '', subject varchar(100) NOT NULL default '', timestamp int(10) unsigned NOT NULL default '0', - tstamp timestamp(14) NOT NULL, + tstamp timestamp NOT NULL, status int(3) NOT NULL default '0', type varchar(15) NOT NULL default '', assignment int(10) unsigned NOT NULL default '0', diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index f8d833b6b73..c3ffdc79c16 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -373,9 +373,13 @@ drop table t1; # # Bug #6993: myisam_data_pointer_size +# Wrong bug report, data pointer size must be restricted to 7, +# setting to 8 will not work on all computers, myisamchk and +# the server may see a wrong value, such as 0 or negative number +# if 8 bytes is set. # -SET GLOBAL MYISAM_DATA_POINTER_SIZE= 8; +SET GLOBAL MYISAM_DATA_POINTER_SIZE= 7; SHOW VARIABLES LIKE 'MYISAM_DATA_POINTER_SIZE'; # diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 13a5f8cef1f..2ccac059724 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1673,3 +1673,133 @@ create view v1(k, K) as select 1,2; create view v1 as SELECT TIME_FORMAT(SEC_TO_TIME(3600),'%H:%i') as t; select * from v1; drop view v1; + +# +# checking views after some view with error (BUG#11337) +# +CREATE TABLE t1 (col1 time); +CREATE TABLE t2 (col1 time); +CREATE VIEW v1 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1; +CREATE VIEW v2 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2; +CREATE VIEW v3 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1; +CREATE VIEW v4 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2; +CREATE VIEW v5 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t1; +CREATE VIEW v6 AS SELECT CONVERT_TZ(col1,'GMT','MET') FROM t2; +DROP TABLE t1; +CHECK TABLE v1, v2, v3, v4, v5, v6; +drop view v1, v2, v3, v4, v5, v6; +drop table t2; + +CREATE TABLE t1 (col1 time); +CREATE TABLE t2 (col1 time); +CREATE TABLE t3 (col1 time); +create function f1 () returns int return (select max(col1) from t1); +create function f2 () returns int return (select max(col1) from t2); +CREATE VIEW v1 AS SELECT f1() FROM t3; +CREATE VIEW v2 AS SELECT f2() FROM t3; +CREATE VIEW v3 AS SELECT f1() FROM t3; +CREATE VIEW v4 AS SELECT f2() FROM t3; +CREATE VIEW v5 AS SELECT f1() FROM t3; +CREATE VIEW v6 AS SELECT f2() FROM t3; +drop function f1; +CHECK TABLE v1, v2, v3, v4, v5, v6; +create function f1 () returns int return (select max(col1) from t1); +DROP TABLE t1; +# following will show underlying table until BUG#11555 fix +CHECK TABLE v1, v2, v3, v4, v5, v6; +drop function f1; +drop function f2; +drop view v1, v2, v3, v4, v5, v6; +drop table t2,t3; + +# +# bug #11325 Wrong date comparison in views +# +create table t1 (f1 date); +insert into t1 values ('2005-01-01'),('2005-02-02'); +create view v1 as select * from t1; +select * from v1 where f1='2005.02.02'; +select * from v1 where '2005.02.02'=f1; +drop view v1; +drop table t1; + +# +# using encrypt & substring_index in view (BUG#7024) +# +CREATE VIEW v1 AS SELECT ENCRYPT("dhgdhgd"); +disable_result_log; +SELECT * FROM v1; +enable_result_log; +drop view v1; +CREATE VIEW v1 AS SELECT SUBSTRING_INDEX("dkjhgd:kjhdjh", ":", 1); +SELECT * FROM v1; +drop view v1; + +# +# Using var_samp with view (BUG#10651) +# +create table t1 (s1 int); +create view v1 as select var_samp(s1) from t1; +show create view v1; +drop view v1; +drop table t1; + +# +# Correct inserting data check (absence of default value) for view +# underlying tables (BUG#6443) +# +set sql_mode='strict_all_tables'; +CREATE TABLE t1 (col1 INT NOT NULL, col2 INT NOT NULL) ENGINE = INNODB; +CREATE VIEW v1 (vcol1) AS SELECT col1 FROM t1; +CREATE VIEW v2 (vcol1) AS SELECT col1 FROM t1 WHERE col2 > 2; +-- error 1364 +INSERT INTO t1 (col1) VALUES(12); +-- error 1423 +INSERT INTO v1 (vcol1) VALUES(12); +-- error 1423 +INSERT INTO v2 (vcol1) VALUES(12); +set sql_mode=default; +drop view v2,v1; +drop table t1; + +# +# Bug#11399 Use an alias in a select statement on a view +# +create table t1 (f1 int); +insert into t1 values (1); +create view v1 as select f1 from t1; +select f1 as alias from v1; +drop view v1; +drop table t1; + +# +# Test for bug #6120: SP cache to be invalidated when altering a view +# + +CREATE TABLE t1 (s1 int, s2 int); +INSERT INTO t1 VALUES (1,2); +CREATE VIEW v1 AS SELECT s2 AS s1, s1 AS s2 FROM t1; +SELECT * FROM v1; +CREATE PROCEDURE p1 () SELECT * FROM v1; +CALL p1(); +ALTER VIEW v1 AS SELECT s1 AS s1, s2 AS s2 FROM t1; +CALL p1(); + +DROP PROCEDURE p1; +DROP VIEW v1; +DROP TABLE t1; + +# +# Test for bug #11771: wrong query_id in SELECT * FROM <view> +# + +CREATE TABLE t1 (f1 char) ENGINE = innodb; +INSERT INTO t1 VALUES ('A'); +CREATE VIEW v1 AS SELECT * FROM t1; + +INSERT INTO t1 VALUES('B'); +SELECT * FROM v1; +SELECT * FROM t1; + +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index bb603b75daa..6283a1abf11 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -360,7 +360,7 @@ create table mysqltest.v3 (b int); grant select(b) on mysqltest.v3 to mysqltest_1@localhost; drop table mysqltest.v3; connection user1; --- error 1142 +-- error 1143 create view mysqltest.v3 as select b from mysqltest.t2; # Expression need select privileges diff --git a/mysys/Makefile.am b/mysys/Makefile.am index f61c95f523a..41a8a3e647a 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -17,7 +17,8 @@ MYSQLDATAdir = $(localstatedir) MYSQLSHAREdir = $(pkgdatadir) MYSQLBASEdir= $(prefix) -INCLUDES = @ZLIB_INCLUDES@ -I$(top_srcdir)/include -I$(srcdir) +INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \ + -I$(top_srcdir)/include -I$(srcdir) pkglib_LIBRARIES = libmysys.a LDADD = libmysys.a ../dbug/libdbug.a \ ../strings/libmystrings.a diff --git a/mysys/charset.c b/mysys/charset.c index cbd9ba16b4c..4920e7806a2 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -561,11 +561,30 @@ CHARSET_INFO *get_charset_by_csname(const char *cs_name, DBUG_RETURN(cs); } + /* + Escape string with backslashes (\) + + SYNOPSIS + escape_string_for_mysql() + charset_info Charset of the strings + to Buffer for escaped string + to_length Length of destination buffer, or 0 + from The string to escape + length The length of the string to escape + + DESCRIPTION + This escapes the contents of a string by adding backslashes before special + characters, and turning others into specific escape sequences, such as + turning newlines into \n and null bytes into \0. + NOTE - to keep old C API, to_length may be 0 to mean "big enough" - RETURN - the length of the escaped string or ~0 if it did not fit. + To maintain compatibility with the old C API, to_length may be 0 to mean + "big enough" + + RETURN VALUES + ~0 The escaped string did not fit in the to buffer + >=0 The length of the escaped string */ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to, ulong to_length, @@ -573,20 +592,20 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, { const char *to_start= to; const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length); - my_bool overflow=0; + my_bool overflow= FALSE; #ifdef USE_MB my_bool use_mb_flag= use_mb(charset_info); #endif for (end= from + length; from < end; from++) { - char escape=0; + char escape= 0; #ifdef USE_MB int tmp_length; if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end))) { if (to + tmp_length > to_end) { - overflow=1; + overflow= TRUE; break; } while (tmp_length--) @@ -636,7 +655,7 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, { if (to + 2 > to_end) { - overflow=1; + overflow= TRUE; break; } *to++= '\\'; @@ -646,7 +665,7 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, { if (to + 1 > to_end) { - overflow=1; + overflow= TRUE; break; } *to++= *from; @@ -656,3 +675,84 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, return overflow ? (ulong)~0 : (ulong) (to - to_start); } + +/* + Escape apostrophes by doubling them up + + SYNOPSIS + escape_quotes_for_mysql() + charset_info Charset of the strings + to Buffer for escaped string + to_length Length of destination buffer, or 0 + from The string to escape + length The length of the string to escape + + DESCRIPTION + This escapes the contents of a string by doubling up any apostrophes that + it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in + effect on the server. + + NOTE + To be consistent with escape_string_for_mysql(), to_length may be 0 to + mean "big enough" + + RETURN VALUES + ~0 The escaped string did not fit in the to buffer + >=0 The length of the escaped string +*/ +ulong escape_quotes_for_mysql(CHARSET_INFO *charset_info, + char *to, ulong to_length, + const char *from, ulong length) +{ + const char *to_start= to; + const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length); + my_bool overflow= FALSE; +#ifdef USE_MB + my_bool use_mb_flag= use_mb(charset_info); +#endif + for (end= from + length; from < end; from++) + { + char escape= 0; +#ifdef USE_MB + int tmp_length; + if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end))) + { + if (to + tmp_length > to_end) + { + overflow= TRUE; + break; + } + while (tmp_length--) + *to++= *from++; + from--; + continue; + } + /* + We don't have the same issue here with a non-multi-byte character being + turned into a multi-byte character by the addition of an escaping + character, because we are only escaping the ' character with itself. + */ +#endif + if (*from == '\'') + { + if (to + 2 > to_end) + { + overflow= TRUE; + break; + } + *to++= '\''; + *to++= '\''; + } + else + { + if (to + 1 > to_end) + { + overflow= TRUE; + break; + } + *to++= *from; + } + } + *to= 0; + return overflow ? (ulong)~0 : (ulong) (to - to_start); +} diff --git a/mysys/default.c b/mysys/default.c index 1fa8deaa65c..15c92e816a6 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -48,13 +48,14 @@ char *defaults_extra_file=0; /* Which directories are searched for options (and in which order) */ -#define MAX_DEFAULT_DIRS 5 +#define MAX_DEFAULT_DIRS 6 const char *default_directories[MAX_DEFAULT_DIRS + 1]; #ifdef __WIN__ static const char *f_extensions[]= { ".ini", ".cnf", 0 }; #define NEWLINE "\r\n" -static char system_dir[FN_REFLEN], shared_system_dir[FN_REFLEN]; +static char system_dir[FN_REFLEN], shared_system_dir[FN_REFLEN], + config_dir[FN_REFLEN]; #else static const char *f_extensions[]= { ".cnf", 0 }; #define NEWLINE "\n" @@ -286,8 +287,8 @@ int load_defaults(const char *conf_file, const char **groups, { DYNAMIC_ARRAY args; TYPELIB group; - my_bool found_print_defaults=0; - uint args_used=0; + my_bool found_print_defaults= 0; + uint args_used= 0; int error= 0; MEM_ROOT alloc; char *ptr,**res; @@ -328,8 +329,8 @@ int load_defaults(const char *conf_file, const char **groups, ctx.args= &args; ctx.group= &group; - if (*argc >= 2 + args_used && - is_prefix(argv[0][1+args_used], instance_option)) + if (*argc >= 2 && + is_prefix(argv[0][1], instance_option)) { args_used++; defaults_instance= argv[0][args_used]+sizeof(instance_option)-1; @@ -870,6 +871,45 @@ void print_defaults(const char *conf_file, const char **groups) #include <help_end.h> +#ifdef __WIN__ +/* + This wrapper for GetSystemWindowsDirectory() will dynamically bind to the + function if it is available, emulate it on NT4 Terminal Server by stripping + the \SYSTEM32 from the end of the results of GetSystemDirectory(), or just + return GetSystemDirectory(). + */ + +typedef UINT (WINAPI *GET_SYSTEM_WINDOWS_DIRECTORY)(LPSTR, UINT); + +static uint my_get_system_windows_directory(char *buffer, uint size) +{ + GET_SYSTEM_WINDOWS_DIRECTORY + func_ptr= (GET_SYSTEM_WINDOWS_DIRECTORY) + GetProcAddress(GetModuleHandle("kernel32.dll"), + "GetSystemWindowsDirectoryA"); + + if (func_ptr) + return func_ptr(buffer, size); + else + { + /* + Windows NT 4.0 Terminal Server Edition: + To retrieve the shared Windows directory, call GetSystemDirectory and + trim the "System32" element from the end of the returned path. + */ + UINT count= GetSystemDirectory(buffer, size); + + if (count > 8 && stricmp(buffer+(count-8), "\\System32") == 0) + { + count-= 8; + buffer[count] = '\0'; + } + return count; + } +} +#endif + + /* Create the list of default directories. @@ -878,7 +918,8 @@ void print_defaults(const char *conf_file, const char **groups) 2. GetWindowsDirectory() 3. GetSystemWindowsDirectory() 4. getenv(DEFAULT_HOME_ENV) - 5. "" + 5. Direcotry above where the executable is located + 6. "" On Novell NetWare, this is: 1. sys:/etc/ @@ -909,13 +950,10 @@ static void init_default_directories() if (GetWindowsDirectory(system_dir,sizeof(system_dir))) *ptr++= (char*)&system_dir; -#if defined(_MSC_VER) && (_MSC_VER >= 1300) - /* Only VC7 and up */ - /* Only add shared system directory if different from default. */ - if (GetSystemWindowsDirectory(shared_system_dir,sizeof(shared_system_dir)) && + if (my_get_system_windows_directory(shared_system_dir, + sizeof(shared_system_dir)) && strcmp(system_dir, shared_system_dir)) *ptr++= (char *)&shared_system_dir; -#endif #elif defined(__NETWARE__) *ptr++= "sys:/etc/"; @@ -931,6 +969,36 @@ static void init_default_directories() *ptr++= ""; /* Place for defaults_extra_file */ #if !defined(__WIN__) && !defined(__NETWARE__) *ptr++= "~/";; +#elif defined(__WIN__) + if (GetModuleFileName(NULL, config_dir, sizeof(config_dir))) + { + char *last= NULL, *end= strend(config_dir); + /* + Look for the second-to-last \ in the filename, but hang on + to a pointer after the last \ in case we're in the root of + a drive. + */ + for ( ; end > config_dir; end--) + { + if (*end == FN_LIBCHAR) + { + if (last) + break; + last= end; + } + } + + if (last) + { + if (end != config_dir && end[-1] == FN_DEVCHAR) /* Ended up with D:\ */ + end[1]= 0; /* Keep one \ */ + else if (end != config_dir) + end[0]= 0; + else + last[1]= 0; + } + *ptr++= (char *)&config_dir; + } #endif *ptr= 0; /* end marker */ } diff --git a/mysys/default_modify.c b/mysys/default_modify.c index 00caa7beed6..ea384f9f27a 100644 --- a/mysys/default_modify.c +++ b/mysys/default_modify.c @@ -20,6 +20,8 @@ #include <my_dir.h> #define BUFF_SIZE 1024 +/* should be big enough to handle at least one line */ +#define RESERVE 1024 #ifdef __WIN__ #define NEWLINE "\r\n" @@ -66,8 +68,11 @@ int modify_defaults_file(const char *file_location, const char *option, FILE *cnf_file; MY_STAT file_stat; char linebuff[BUFF_SIZE], *src_ptr, *dst_ptr, *file_buffer; - uint opt_len, optval_len, sect_len, nr_newlines= 0; + uint opt_len, optval_len, sect_len, nr_newlines= 0, buffer_size; my_bool in_section= FALSE, opt_applied= 0; + uint reserve_extended= 1, old_opt_len= 0; + uint new_opt_len; + int reserve_occupied= 0; DBUG_ENTER("modify_defaults_file"); if (!(cnf_file= my_fopen(file_location, O_RDWR | O_BINARY, MYF(0)))) @@ -75,28 +80,33 @@ int modify_defaults_file(const char *file_location, const char *option, /* my_fstat doesn't use the flag parameter */ if (my_fstat(fileno(cnf_file), &file_stat, MYF(0))) - goto err; + goto malloc_err; opt_len= (uint) strlen(option); optval_len= (uint) strlen(option_value); + new_opt_len= opt_len + 1 + optval_len + NEWLINE_LEN; + + /* calculate the size of the buffer we need */ + buffer_size= sizeof(char) * (file_stat.st_size + + /* option name len */ + opt_len + + /* reserve for '=' char */ + 1 + + /* option value len */ + optval_len + + /* reserve space for newline */ + NEWLINE_LEN + + /* The ending zero */ + 1 + + /* reserve some additional space */ + RESERVE); + /* Reserve space to read the contents of the file and some more for the option we want to add. */ - if (!(file_buffer= (char*) my_malloc(sizeof(char) * - (file_stat.st_size + - /* option name len */ - opt_len + - /* reserve space for newline */ - NEWLINE_LEN + - /* reserve for '=' char */ - 1 + - /* option value len */ - optval_len + - /* The ending zero */ - 1), MYF(MY_WME)))) - + if (!(file_buffer= (char*) my_malloc(buffer_size, MYF(MY_WME)))) goto malloc_err; sect_len= (uint) strlen(section_name); @@ -115,13 +125,37 @@ int modify_defaults_file(const char *file_location, const char *option, } /* correct the option */ - if (!opt_applied && in_section && !strncmp(src_ptr, option, opt_len) && + if (in_section && !strncmp(src_ptr, option, opt_len) && (*(src_ptr + opt_len) == '=' || my_isspace(&my_charset_latin1, *(src_ptr + opt_len)) || *(src_ptr + opt_len) == '\0')) { + /* + we should change all options. If opt_applied is set, we are running + into reserved memory area. Hence we should check for overruns. + */ + if (opt_applied) + { + src_ptr+= opt_len; /* If we correct an option, we know it's name */ + old_opt_len= opt_len; + + while (*src_ptr++) /* Find the end of the line */ + old_opt_len++; + + /* could be negative */ + reserve_occupied+= (int) new_opt_len - (int) old_opt_len; + if ((int) reserve_occupied > (int) (RESERVE*reserve_extended)) + { + if (!(file_buffer= (char*) my_realloc(file_buffer, buffer_size + + RESERVE*reserve_extended, + MYF(MY_WME|MY_FREE_ON_ERROR)))) + goto malloc_err; + reserve_extended++; + } + } + else + opt_applied= 1; dst_ptr= add_option(dst_ptr, option_value, option, remove_option); - opt_applied= 1; } else { diff --git a/mysys/hash.c b/mysys/hash.c index 28f8797288c..45cf7d5ff1d 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -277,9 +277,8 @@ static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink) record being compared against. RETURN - < 0 key of record < key = 0 key of record == key - > 0 key of record > key + != 0 key of record != key */ static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length) diff --git a/mysys/my_access.c b/mysys/my_access.c index c01031827c0..256749ed447 100644 --- a/mysys/my_access.c +++ b/mysys/my_access.c @@ -98,17 +98,16 @@ int check_if_legal_filename(const char *path) for (reserved_name= reserved_names; *reserved_name; reserved_name++) { + const char *reserved= *reserved_name; /* never empty */ const char *name= path; - const char *current_reserved_name= *reserved_name; - while (name != end && *current_reserved_name) + do { - if (*current_reserved_name != my_toupper(&my_charset_latin1, *name)) + if (*reserved != my_toupper(&my_charset_latin1, *name)) break; - current_reserved_name++; if (++name == end) DBUG_RETURN(1); /* Found wrong path */ - } + } while (*++reserved); } DBUG_RETURN(0); } diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index 0260bc2ee41..6cfabad1d3b 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -159,6 +159,51 @@ void bitmap_free(MY_BITMAP *map) } +/* + test if bit already set and set it if it was not (thread unsafe method) + + SYNOPSIS + bitmap_fast_test_and_set() + MAP bit map struct + BIT bit number + + RETURN + 0 bit was not set + !=0 bit was set +*/ + +my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit) +{ + uchar *byte= map->bitmap + (bitmap_bit / 8); + uchar bit= 1 << ((bitmap_bit) & 7); + uchar res= (*byte) & bit; + *byte|= bit; + return res; +} + + +/* + test if bit already set and set it if it was not (thread safe method) + + SYNOPSIS + bitmap_fast_test_and_set() + map bit map struct + bitmap_bit bit number + + RETURN + 0 bit was not set + !=0 bit was set +*/ + +my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit) +{ + my_bool res; + DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8); + bitmap_lock(map); + res= bitmap_fast_test_and_set(map, bitmap_bit); + bitmap_unlock(map); +} + uint bitmap_set_next(MY_BITMAP *map) { uint bit_found; diff --git a/mysys/my_copy.c b/mysys/my_copy.c index 03f3feb54d3..072492172e3 100644 --- a/mysys/my_copy.c +++ b/mysys/my_copy.c @@ -16,7 +16,7 @@ #define USES_TYPES /* sys/types is included */ #include "mysys_priv.h" -#include <sys/stat.h> +#include <my_dir.h> /* for stat */ #include <m_string.h> #if defined(HAVE_UTIME_H) #include <utime.h> @@ -53,26 +53,28 @@ struct utimbuf { int my_copy(const char *from, const char *to, myf MyFlags) { uint Count; - int new_file_stat, create_flag; + my_bool new_file_stat; /* 1 if we could stat "to" */ + int create_flag; File from_file,to_file; char buff[IO_SIZE]; - struct stat stat_buff,new_stat_buff; + MY_STAT stat_buff,new_stat_buff; DBUG_ENTER("my_copy"); DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags)); from_file=to_file= -1; - new_file_stat=0; + LINT_INIT(new_file_stat); + DBUG_ASSERT(!(MyFlags & (MY_FNABP | MY_NABP))); /* for my_read/my_write */ if (MyFlags & MY_HOLD_ORIGINAL_MODES) /* Copy stat if possible */ - new_file_stat=stat((char*) to, &new_stat_buff); + new_file_stat= test(my_stat((char*) to, &new_stat_buff, MYF(0))); if ((from_file=my_open(from,O_RDONLY | O_SHARE,MyFlags)) >= 0) { - if (stat(from,&stat_buff)) + if (!my_stat(from, &stat_buff, MyFlags)) { my_errno=errno; goto err; } - if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat) + if (MyFlags & MY_HOLD_ORIGINAL_MODES && new_file_stat) stat_buff=new_stat_buff; create_flag= (MyFlags & MY_DONT_OVERWRITE_FILE) ? O_EXCL : O_TRUNC; @@ -91,7 +93,7 @@ int my_copy(const char *from, const char *to, myf MyFlags) /* Copy modes if possible */ - if (MyFlags & MY_HOLD_ORIGINAL_MODES && new_file_stat) + if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat) DBUG_RETURN(0); /* File copyed but not stat */ VOID(chmod(to, stat_buff.st_mode & 07777)); /* Copy modes */ #if !defined(MSDOS) && !defined(__WIN__) && !defined(__EMX__) && !defined(OS2) && !defined(__NETWARE__) diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c index 002e5ca0f06..f07beec9f39 100644 --- a/mysys/my_fopen.c +++ b/mysys/my_fopen.c @@ -19,27 +19,36 @@ #include <errno.h> #include "mysys_err.h" -static void make_ftype(my_string to,int flag); +static void make_ftype(my_string to,int flag); - /* Open a file as stream */ +/* + Open a file as stream -FILE *my_fopen(const char *FileName, int Flags, myf MyFlags) - /* Path-name of file */ - /* Read | write .. */ - /* Special flags */ + SYNOPSIS + my_fopen() + FileName Path-name of file + Flags Read | write | append | trunc (like for open()) + MyFlags Flags for handling errors + + RETURN + 0 Error + # File handler +*/ + +FILE *my_fopen(const char *filename, int flags, myf MyFlags) { FILE *fd; char type[5]; DBUG_ENTER("my_fopen"); - DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d", - FileName, Flags, MyFlags)); + DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %d", + filename, flags, MyFlags)); /* if we are not creating, then we need to use my_access to make sure the file exists since Windows doesn't handle files like "com1.sym" very well */ #ifdef __WIN__ - if (check_if_legal_filename(FileName)) + if (check_if_legal_filename(filename)) { errno= EACCES; fd= 0; @@ -47,8 +56,8 @@ FILE *my_fopen(const char *FileName, int Flags, myf MyFlags) else #endif { - make_ftype(type,Flags); - fd = fopen(FileName, type); + make_ftype(type,flags); + fd = fopen(filename, type); } if (fd != 0) @@ -65,7 +74,7 @@ FILE *my_fopen(const char *FileName, int Flags, myf MyFlags) } pthread_mutex_lock(&THR_LOCK_open); if ((my_file_info[fileno(fd)].name = (char*) - my_strdup(FileName,MyFlags))) + my_strdup(filename,MyFlags))) { my_stream_opened++; my_file_info[fileno(fd)].type = STREAM_BY_FOPEN; @@ -81,9 +90,9 @@ FILE *my_fopen(const char *FileName, int Flags, myf MyFlags) my_errno=errno; DBUG_PRINT("error",("Got error %d on open",my_errno)); if (MyFlags & (MY_FFNF | MY_FAE | MY_WME)) - my_error((Flags & O_RDONLY) || (Flags == O_RDONLY ) ? EE_FILENOTFOUND : + my_error((flags & O_RDONLY) || (flags == O_RDONLY ) ? EE_FILENOTFOUND : EE_CANTCREATEFILE, - MYF(ME_BELL+ME_WAITTANG), FileName,my_errno); + MYF(ME_BELL+ME_WAITTANG), filename, my_errno); DBUG_RETURN((FILE*) 0); } /* my_fopen */ @@ -158,33 +167,39 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags) DBUG_RETURN(fd); } /* my_fdopen */ + /* - make_ftype - Make a filehandler-open-typestring from ordinary inputflags + Make a fopen() typestring from a open() type bitmap + + SYNOPSIS + make_ftype() + to String for fopen() is stored here + flag Flag used by open() - Note: This routine attempts to find the best possible match - between a numeric option and a string option that could be - fed to fopen. There is not a 1 to 1 mapping between the two. + IMPLEMENTATION + This routine attempts to find the best possible match + between a numeric option and a string option that could be + fed to fopen. There is not a 1 to 1 mapping between the two. - r == O_RDONLY - w == O_WRONLY|O_TRUNC|O_CREAT - a == O_WRONLY|O_APPEND|O_CREAT - r+ == O_RDWR - w+ == O_RDWR|O_TRUNC|O_CREAT - a+ == O_RDWR|O_APPEND|O_CREAT + NOTE + On Unix, O_RDONLY is usually 0 + + MAPPING + r == O_RDONLY + w == O_WRONLY|O_TRUNC|O_CREAT + a == O_WRONLY|O_APPEND|O_CREAT + r+ == O_RDWR + w+ == O_RDWR|O_TRUNC|O_CREAT + a+ == O_RDWR|O_APPEND|O_CREAT */ + static void make_ftype(register my_string to, register int flag) { -#if FILE_BINARY - /* If we have binary-files */ - reg3 int org_flag=flag; -#endif - flag&= ~FILE_BINARY; /* remove binary bit */ - /* check some possible invalid combinations */ - DBUG_ASSERT(flag & (O_TRUNC|O_APPEND) != O_TRUNC|O_APPEND); + DBUG_ASSERT((flag & (O_TRUNC | O_APPEND)) != (O_TRUNC | O_APPEND)); + DBUG_ASSERT((flag & (O_WRONLY | O_RDWR)) != (O_WRONLY | O_RDWR)); - if (flag & (O_RDONLY|O_WRONLY) == O_WRONLY) + if ((flag & (O_RDONLY|O_WRONLY)) == O_WRONLY) *to++= (flag & O_APPEND) ? 'a' : 'w'; else if (flag & O_RDWR) { @@ -201,9 +216,8 @@ static void make_ftype(register my_string to, register int flag) *to++= 'r'; #if FILE_BINARY /* If we have binary-files */ - if (org_flag & FILE_BINARY) + if (flag & FILE_BINARY) *to++='b'; #endif *to='\0'; } /* make_ftype */ - diff --git a/mysys/tree.c b/mysys/tree.c index bec1ec680f1..1780913961e 100644 --- a/mysys/tree.c +++ b/mysys/tree.c @@ -263,6 +263,9 @@ TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size, if (tree->flag & TREE_NO_DUPS) return(NULL); element->count++; + /* Avoid a wrap over of the count. */ + if (! element->count) + element->count--; } DBUG_EXECUTE("check_tree", test_rb_tree(tree->root);); return element; diff --git a/netware/Makefile.am b/netware/Makefile.am index 92c8afba896..be59efd1deb 100644 --- a/netware/Makefile.am +++ b/netware/Makefile.am @@ -15,7 +15,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA if HAVE_NETWARE -INCLUDES = -I$(srcdir)/../include -I../include -I.. +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I.. LDADD = @CLIENT_EXTRA_LDFLAGS@ ../mysys/libmysys.a \ ../dbug/libdbug.a ../strings/libmystrings.a bin_PROGRAMS = mysqld_safe mysql_install_db mysql_test_run libmysql diff --git a/netware/my_print_defaults.def b/netware/my_print_defaults.def index 826981256b5..d88c5adf4cc 100644 --- a/netware/my_print_defaults.def +++ b/netware/my_print_defaults.def @@ -4,7 +4,8 @@ MODULE libc.nlm COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Print Defaults Tool" -VERSION 4, 0 +VERSION 5, 0, 8 +STACKSIZE 32767 XDCDATA ../netware/mysql.xdc #DEBUG diff --git a/regex/Makefile.am b/regex/Makefile.am index 07d7a03635d..3b161287d36 100644 --- a/regex/Makefile.am +++ b/regex/Makefile.am @@ -15,7 +15,7 @@ # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, # MA 02111-1307, USA -INCLUDES = -I$(top_srcdir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include noinst_LIBRARIES = libregex.a LDADD= libregex.a $(top_builddir)/strings/libmystrings.a noinst_HEADERS = cclass.h cname.h regex2.h utils.h engine.c regex.h diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index 74734f4dd5f..fbdbd998138 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -27,7 +27,7 @@ parse_arguments() { --tmp=*) TMP=`echo "$arg" | sed -e "s;--tmp=;;"` ;; --suffix=*) SUFFIX=`echo "$arg" | sed -e "s;--suffix=;;"` ;; --no-strip) STRIP=0 ;; - --machine) MACHINE=`echo "$arg" | sed -e "s;--machine=;;"` ;; + --machine=*) MACHINE=`echo "$arg" | sed -e "s;--machine=;;"` ;; --silent) SILENT=1 ;; --with-ndbcluster) NDBCLUSTER=1 ;; *) @@ -221,6 +221,7 @@ done $CP mysql-test/lib/*.pl $BASE/mysql-test/lib $CP mysql-test/lib/*.sql $BASE/mysql-test/lib $CP mysql-test/include/*.inc $BASE/mysql-test/include +$CP mysql-test/t/*.def $BASE/mysql-test/t $CP mysql-test/std_data/*.dat mysql-test/std_data/*.frm \ mysql-test/std_data/*.pem mysql-test/std_data/Moscow_leap \ mysql-test/std_data/des_key_file mysql-test/std_data/*.*001 \ diff --git a/scripts/make_win_src_distribution.sh b/scripts/make_win_src_distribution.sh index 6165a31fac2..c79433f97c1 100644 --- a/scripts/make_win_src_distribution.sh +++ b/scripts/make_win_src_distribution.sh @@ -361,6 +361,9 @@ if [ -d $BASE/SSL/SCCS ] then find $BASE/ -type d -name SCCS -printf " \"%p\"" | xargs rm -r -f fi +find $BASE/ -type d -name .deps -printf " \"%p\"" | xargs rm -r -f +find $BASE/ -type d -name .libs -printf " \"%p\"" | xargs rm -r -f +rm -r -f "$BASE/mysql-test/var" # # Initialize the initial data directory diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh index a5c8af5ecb2..16e50c044ca 100644 --- a/scripts/mysql_config.sh +++ b/scripts/mysql_config.sh @@ -60,11 +60,19 @@ fix_path () get_full_path () { - case $1 in - /*) echo "$1";; - ./*) tmp=`pwd`/$1; echo $tmp | sed -e 's;/\./;/;' ;; - *) which $1 ;; - esac + file=$1 + + # if the file is a symlink, try to resolve it + if [ -h $file ]; + then + file=`ls -l $file | awk '{ print $NF }'` + fi + + case $file in + /*) echo "$file";; + */*) tmp=`pwd`/$file; echo $tmp | sed -e 's;/\./;/;' ;; + *) which $file ;; + esac } me=`get_full_path $0` diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh index a8f6c02b057..a3036b5c10b 100644 --- a/scripts/mysql_create_system_tables.sh +++ b/scripts/mysql_create_system_tables.sh @@ -215,7 +215,7 @@ then c_t="$c_t Table_name char(64) binary DEFAULT '' NOT NULL," c_t="$c_t Grantor char(77) DEFAULT '' NOT NULL," c_t="$c_t Timestamp timestamp(14)," - c_t="$c_t Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter') COLLATE utf8_general_ci DEFAULT '' NOT NULL," + c_t="$c_t Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view') COLLATE utf8_general_ci DEFAULT '' NOT NULL," c_t="$c_t Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL," c_t="$c_t PRIMARY KEY (Host,Db,User,Table_name)," c_t="$c_t KEY Grantor (Grantor)" @@ -669,7 +669,7 @@ fi if test ! -f $mdata/proc.frm then c_p="$c_p CREATE TABLE proc (" - c_p="$c_p db char(64) binary DEFAULT '' NOT NULL," + c_p="$c_p db char(64) collate utf8_bin DEFAULT '' NOT NULL," c_p="$c_p name char(64) DEFAULT '' NOT NULL," c_p="$c_p type enum('FUNCTION','PROCEDURE') NOT NULL," c_p="$c_p specific_name char(64) DEFAULT '' NOT NULL," @@ -684,7 +684,7 @@ then c_p="$c_p param_list blob DEFAULT '' NOT NULL," c_p="$c_p returns char(64) DEFAULT '' NOT NULL," c_p="$c_p body blob DEFAULT '' NOT NULL," - c_p="$c_p definer char(77) binary DEFAULT '' NOT NULL," + c_p="$c_p definer char(77) collate utf8_bin DEFAULT '' NOT NULL," c_p="$c_p created timestamp," c_p="$c_p modified timestamp," c_p="$c_p sql_mode set(" @@ -718,10 +718,12 @@ then c_p="$c_p 'TRADITIONAL'," c_p="$c_p 'NO_AUTO_CREATE_USER'," c_p="$c_p 'HIGH_NOT_PRECEDENCE'" - c_p="$c_p ) DEFAULT 0 NOT NULL," - c_p="$c_p comment char(64) binary DEFAULT '' NOT NULL," + c_p="$c_p ) DEFAULT '' NOT NULL," + c_p="$c_p comment char(64) collate utf8_bin DEFAULT '' NOT NULL," c_p="$c_p PRIMARY KEY (db,name,type)" - c_p="$c_p ) comment='Stored Procedures';" + c_p="$c_p ) engine=MyISAM" + c_p="$c_p character set utf8" + c_p="$c_p comment='Stored Procedures';" fi cat << END_OF_DATA diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index 7956287b6c2..bc9da056758 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -260,6 +260,11 @@ ALTER TABLE host ADD Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAUL ALTER TABLE user ADD Show_view_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Create_view_priv; # +# Show/Create views table privileges (v5.0) +# +ALTER TABLE tables_priv MODIFY Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view') COLLATE utf8_general_ci DEFAULT '' NOT NULL; + +# # Assign create/show view privileges to people who have create provileges # UPDATE user SET Create_view_priv=Create_priv, Show_view_priv=Create_priv where user<>"" AND @hadCreateViewPriv = 0; @@ -406,22 +411,22 @@ PRIMARY KEY TranTime (Transition_time) # CREATE TABLE IF NOT EXISTS proc ( - db char(64) binary DEFAULT '' NOT NULL, + db char(64) collate utf8_bin DEFAULT '' NOT NULL, name char(64) DEFAULT '' NOT NULL, type enum('FUNCTION','PROCEDURE') NOT NULL, specific_name char(64) DEFAULT '' NOT NULL, language enum('SQL') DEFAULT 'SQL' NOT NULL, sql_data_access enum('CONTAINS_SQL', - 'NO_SQL', - 'READS_SQL_DATA', - 'MODIFIES_SQL_DATA' - ) DEFAULT 'CONTAINS_SQL' NOT NULL, + 'NO_SQL', + 'READS_SQL_DATA', + 'MODIFIES_SQL_DATA' + ) DEFAULT 'CONTAINS_SQL' NOT NULL, is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL, security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, param_list blob DEFAULT '' NOT NULL, returns char(64) DEFAULT '' NOT NULL, body blob DEFAULT '' NOT NULL, - definer char(77) binary DEFAULT '' NOT NULL, + definer char(77) collate utf8_bin DEFAULT '' NOT NULL, created timestamp, modified timestamp, sql_mode set( @@ -455,20 +460,22 @@ CREATE TABLE IF NOT EXISTS proc ( 'TRADITIONAL', 'NO_AUTO_CREATE_USER', 'HIGH_NOT_PRECEDENCE' - ) DEFAULT 0 NOT NULL, - comment char(64) binary DEFAULT '' NOT NULL, + ) DEFAULT '' NOT NULL, + comment char(64) collate utf8_bin DEFAULT '' NOT NULL, PRIMARY KEY (db,name,type) -) comment='Stored Procedures'; +) engine=MyISAM + character set utf8 + comment='Stored Procedures'; # Correct the name fields to not binary, and expand sql_data_access ALTER TABLE proc MODIFY name char(64) DEFAULT '' NOT NULL, MODIFY specific_name char(64) DEFAULT '' NOT NULL, - MODIFY sql_data_access - enum('CONTAINS_SQL', - 'NO_SQL', - 'READS_SQL_DATA', - 'MODIFIES_SQL_DATA' - ) DEFAULT 'CONTAINS_SQL' NOT NULL, + MODIFY sql_data_access + enum('CONTAINS_SQL', + 'NO_SQL', + 'READS_SQL_DATA', + 'MODIFIES_SQL_DATA' + ) DEFAULT 'CONTAINS_SQL' NOT NULL, MODIFY sql_mode set('REAL_AS_FLOAT', 'PIPES_AS_CONCAT', @@ -500,4 +507,15 @@ ALTER TABLE proc MODIFY name char(64) DEFAULT '' NOT NULL, 'TRADITIONAL', 'NO_AUTO_CREATE_USER', 'HIGH_NOT_PRECEDENCE' - ) DEFAULT 0 NOT NULL; + ) DEFAULT '' NOT NULL + DEFAULT CHARACTER SET utf8; + +# Correct the character set and collation +ALTER TABLE proc CONVERT TO CHARACTER SET utf8; +# Reset some fields after the conversion +ALTER TABLE proc MODIFY db + char(64) collate utf8_bin DEFAULT '' NOT NULL, + MODIFY definer + char(77) collate utf8_bin DEFAULT '' NOT NULL, + MODIFY comment + char(64) collate utf8_bin DEFAULT '' NOT NULL; diff --git a/sql/Makefile.am b/sql/Makefile.am index 0b6610fab55..b1b14db4cb7 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -21,8 +21,8 @@ MYSQLSHAREdir = $(pkgdatadir) MYSQLBASEdir= $(prefix) INCLUDES = @ZLIB_INCLUDES@ \ @bdb_includes@ @innodb_includes@ @ndbcluster_includes@ \ - -I$(top_srcdir)/include -I$(top_srcdir)/regex \ - -I$(srcdir) $(openssl_includes) -I$(top_builddir)/include + -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/regex -I$(srcdir) $(openssl_includes) WRAPLIBS= @WRAPLIBS@ SUBDIRS = share libexec_PROGRAMS = mysqld diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index 93cedcbf251..c362985f565 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -259,7 +259,7 @@ error: This method reads the header of a meta file and returns whether or not it was successful. *rows will contain the current number of rows in the data file upon success. */ -int ha_archive::read_meta_file(File meta_file, ulonglong *rows) +int ha_archive::read_meta_file(File meta_file, ha_rows *rows) { uchar meta_buffer[META_BUFFER_SIZE]; ulonglong check_point; @@ -273,7 +273,7 @@ int ha_archive::read_meta_file(File meta_file, ulonglong *rows) /* Parse out the meta data, we ignore version at the moment */ - *rows= uint8korr(meta_buffer + 2); + *rows= (ha_rows)uint8korr(meta_buffer + 2); check_point= uint8korr(meta_buffer + 10); DBUG_PRINT("ha_archive::read_meta_file", ("Check %d", (uint)meta_buffer[0])); @@ -296,7 +296,7 @@ int ha_archive::read_meta_file(File meta_file, ulonglong *rows) By setting dirty you say whether or not the file represents the actual state of the data file. Upon ::open() we set to dirty, and upon ::close() we set to clean. */ -int ha_archive::write_meta_file(File meta_file, ulonglong rows, bool dirty) +int ha_archive::write_meta_file(File meta_file, ha_rows rows, bool dirty) { uchar meta_buffer[META_BUFFER_SIZE]; ulonglong check_point= 0; //Reserved for the future @@ -305,12 +305,12 @@ int ha_archive::write_meta_file(File meta_file, ulonglong rows, bool dirty) meta_buffer[0]= (uchar)ARCHIVE_CHECK_HEADER; meta_buffer[1]= (uchar)ARCHIVE_VERSION; - int8store(meta_buffer + 2, rows); + int8store(meta_buffer + 2, (ulonglong)rows); int8store(meta_buffer + 10, check_point); *(meta_buffer + 18)= (uchar)dirty; DBUG_PRINT("ha_archive::write_meta_file", ("Check %d", (uint)ARCHIVE_CHECK_HEADER)); DBUG_PRINT("ha_archive::write_meta_file", ("Version %d", (uint)ARCHIVE_VERSION)); - DBUG_PRINT("ha_archive::write_meta_file", ("Rows %llu", rows)); + DBUG_PRINT("ha_archive::write_meta_file", ("Rows %llu", (ulonglong)rows)); DBUG_PRINT("ha_archive::write_meta_file", ("Checkpoint %llu", check_point)); DBUG_PRINT("ha_archive::write_meta_file", ("Dirty %d", (uint)dirty)); @@ -326,6 +326,9 @@ int ha_archive::write_meta_file(File meta_file, ulonglong rows, bool dirty) /* We create the shared memory space that we will use for the open table. + No matter what we try to get or create a share. This is so that a repair + table operation can occur. + See ha_example.cc for a longer description. */ ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, TABLE *table) @@ -363,7 +366,7 @@ ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, TABLE *table) */ VOID(pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST)); if ((share->meta_file= my_open(meta_file_name, O_RDWR, MYF(0))) == -1) - goto error; + share->crashed= TRUE; /* After we read, we set the file to dirty. When we close, we will do the @@ -381,27 +384,14 @@ ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, TABLE *table) that is shared amoung all open tables. */ if ((share->archive_write= gzopen(share->data_file_name, "ab")) == NULL) - goto error2; - if (my_hash_insert(&archive_open_tables, (byte*) share)) - goto error3; + share->crashed= TRUE; + VOID(my_hash_insert(&archive_open_tables, (byte*) share)); thr_lock_init(&share->lock); } share->use_count++; pthread_mutex_unlock(&archive_mutex); return share; - -error3: - /* We close, but ignore errors since we already have errors */ - (void)gzclose(share->archive_write); -error2: - my_close(share->meta_file,MYF(0)); -error: - pthread_mutex_unlock(&archive_mutex); - VOID(pthread_mutex_destroy(&share->mutex)); - my_free((gptr) share, MYF(0)); - - return NULL; } @@ -458,13 +448,14 @@ int ha_archive::open(const char *name, int mode, uint test_if_locked) DBUG_ENTER("ha_archive::open"); if (!(share= get_share(name, table))) - DBUG_RETURN(-1); + DBUG_RETURN(HA_ERR_OUT_OF_MEM); // Not handled well by calling code! thr_lock_data_init(&share->lock,&lock,NULL); if ((archive= gzopen(share->data_file_name, "rb")) == NULL) { - (void)free_share(share); //We void since we already have an error - DBUG_RETURN(errno ? errno : -1); + if (errno == EROFS || errno == EACCES) + DBUG_RETURN(my_errno= errno); + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); } DBUG_RETURN(0); @@ -572,36 +563,22 @@ error: DBUG_RETURN(error ? error : -1); } - -/* - Look at ha_archive::open() for an explanation of the row format. - Here we just write out the row. - - Wondering about start_bulk_insert()? We don't implement it for - archive since it optimizes for lots of writes. The only save - for implementing start_bulk_insert() is that we could skip - setting dirty to true each time. +/* + This is where the actual row is written out. */ -int ha_archive::write_row(byte * buf) +int ha_archive::real_write_row(byte *buf, gzFile writer) { z_off_t written; uint *ptr, *end; - DBUG_ENTER("ha_archive::write_row"); + DBUG_ENTER("ha_archive::real_write_row"); - if (share->crashed) - DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); - - statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status); - if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) - table->timestamp_field->set_time(); - pthread_mutex_lock(&share->mutex); - written= gzwrite(share->archive_write, buf, table->s->reclength); - DBUG_PRINT("ha_archive::write_row", ("Wrote %d bytes expected %d", written, table->s->reclength)); + written= gzwrite(writer, buf, table->s->reclength); + DBUG_PRINT("ha_archive::real_write_row", ("Wrote %d bytes expected %d", written, table->s->reclength)); if (!delayed_insert || !bulk_insert) share->dirty= TRUE; if (written != (z_off_t)table->s->reclength) - goto error; + DBUG_RETURN(errno ? errno : -1); /* We should probably mark the table as damagaged if the record is written but the blob fails. @@ -616,21 +593,43 @@ int ha_archive::write_row(byte * buf) if (size) { ((Field_blob*) table->field[*ptr])->get_ptr(&data_ptr); - written= gzwrite(share->archive_write, data_ptr, (unsigned)size); + written= gzwrite(writer, data_ptr, (unsigned)size); if (written != (z_off_t)size) - goto error; + DBUG_RETURN(errno ? errno : -1); } } + DBUG_RETURN(0); +} + + +/* + Look at ha_archive::open() for an explanation of the row format. + Here we just write out the row. + + Wondering about start_bulk_insert()? We don't implement it for + archive since it optimizes for lots of writes. The only save + for implementing start_bulk_insert() is that we could skip + setting dirty to true each time. +*/ +int ha_archive::write_row(byte *buf) +{ + int rc; + DBUG_ENTER("ha_archive::write_row"); + + if (share->crashed) + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); + + statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status); + if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) + table->timestamp_field->set_time(); + pthread_mutex_lock(&share->mutex); share->rows_recorded++; + rc= real_write_row(buf, share->archive_write); pthread_mutex_unlock(&share->mutex); - DBUG_RETURN(0); -error: - pthread_mutex_unlock(&share->mutex); - DBUG_RETURN(errno ? errno : -1); + DBUG_RETURN(rc); } - /* All calls that need to scan the table start with this method. If we are told that it is a table scan we rewind the file to the beginning, otherwise @@ -787,7 +786,7 @@ int ha_archive::rnd_pos(byte * buf, byte *pos) DBUG_ENTER("ha_archive::rnd_pos"); statistic_increment(table->in_use->status_var.ha_read_rnd_next_count, &LOCK_status); - current_position= my_get_ptr(pos, ref_length); + current_position= (z_off_t)my_get_ptr(pos, ref_length); (void)gzseek(archive, current_position, SEEK_SET); DBUG_RETURN(get_row(archive, buf)); @@ -795,68 +794,20 @@ int ha_archive::rnd_pos(byte * buf, byte *pos) /* This method repairs the meta file. It does this by walking the datafile and - rewriting the meta file. + rewriting the meta file. Currently it does this by calling optimize with + the extended flag. */ int ha_archive::repair(THD* thd, HA_CHECK_OPT* check_opt) { - int rc; - byte *buf; - ulonglong rows_recorded= 0; - gzFile rebuild_file; // Archive file we are working with - File meta_file; // Meta file we use - char data_file_name[FN_REFLEN]; DBUG_ENTER("ha_archive::repair"); + check_opt->flags= T_EXTEND; + int rc= optimize(thd, check_opt); - /* - Open up the meta file to recreate it. - */ - fn_format(data_file_name, share->table_name, "", ARZ, - MY_REPLACE_EXT|MY_UNPACK_FILENAME); - if ((rebuild_file= gzopen(data_file_name, "rb")) == NULL) - DBUG_RETURN(errno ? errno : -1); + if (rc) + DBUG_RETURN(HA_ERR_CRASHED_ON_REPAIR); - if ((rc= read_data_header(rebuild_file))) - goto error; - - /* - We malloc up the buffer we will use for counting the rows. - I know, this malloc'ing memory but this should be a very - rare event. - */ - if (!(buf= (byte*) my_malloc(table->s->rec_buff_length > sizeof(ulonglong) +1 ? - table->s->rec_buff_length : sizeof(ulonglong) +1 , - MYF(MY_WME)))) - { - rc= HA_ERR_CRASHED_ON_USAGE; - goto error; - } - - while (!(rc= get_row(rebuild_file, buf))) - rows_recorded++; - - /* - Only if we reach the end of the file do we assume we can rewrite. - At this point we reset rc to a non-message state. - */ - if (rc == HA_ERR_END_OF_FILE) - { - fn_format(data_file_name,share->table_name,"",ARM,MY_REPLACE_EXT|MY_UNPACK_FILENAME); - if ((meta_file= my_open(data_file_name, O_RDWR, MYF(0))) == -1) - { - rc= HA_ERR_CRASHED_ON_USAGE; - goto error; - } - (void)write_meta_file(meta_file, rows_recorded, TRUE); - my_close(meta_file,MYF(0)); - rc= 0; - } - - my_free((gptr) buf, MYF(0)); share->crashed= FALSE; -error: - gzclose(rebuild_file); - - DBUG_RETURN(rc); + DBUG_RETURN(0); } /* @@ -866,39 +817,100 @@ error: int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt) { DBUG_ENTER("ha_archive::optimize"); - int read; // Bytes read, gzread() returns int - gzFile reader, writer; - char block[IO_SIZE]; + int rc; + gzFile writer; char writer_filename[FN_REFLEN]; - /* Closing will cause all data waiting to be flushed */ - gzclose(share->archive_write); - share->archive_write= NULL; + /* Flush any waiting data */ + gzflush(share->archive_write, Z_SYNC_FLUSH); /* Lets create a file to contain the new data */ fn_format(writer_filename, share->table_name, "", ARN, MY_REPLACE_EXT|MY_UNPACK_FILENAME); - if ((reader= gzopen(share->data_file_name, "rb")) == NULL) - DBUG_RETURN(-1); - if ((writer= gzopen(writer_filename, "wb")) == NULL) + DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); + + /* + An extended rebuild is a lot more effort. We open up each row and re-record it. + Any dead rows are removed (aka rows that may have been partially recorded). + */ + + if (check_opt->flags == T_EXTEND) { - gzclose(reader); - DBUG_RETURN(-1); - } + byte *buf; - while ((read= gzread(reader, block, IO_SIZE))) - gzwrite(writer, block, read); + /* + First we create a buffer that we can use for reading rows, and can pass + to get_row(). + */ + if (!(buf= (byte*) my_malloc(table->s->reclength, MYF(MY_WME)))) + { + rc= HA_ERR_OUT_OF_MEM; + goto error; + } - gzclose(reader); - gzclose(writer); + /* + Now we will rewind the archive file so that we are positioned at the + start of the file. + */ + rc= read_data_header(archive); + + /* + Assuming now error from rewinding the archive file, we now write out the + new header for out data file. + */ + if (!rc) + rc= write_data_header(writer); + + /* + On success of writing out the new header, we now fetch each row and + insert it into the new archive file. + */ + if (!rc) + { + share->rows_recorded= 0; + while (!(rc= get_row(archive, buf))) + { + real_write_row(buf, writer); + share->rows_recorded++; + } + } + + my_free((char*)buf, MYF(0)); + if (rc && rc != HA_ERR_END_OF_FILE) + goto error; + } + else + { + /* + The quick method is to just read the data raw, and then compress it directly. + */ + int read; // Bytes read, gzread() returns int + char block[IO_SIZE]; + if (gzrewind(archive) == -1) + { + rc= HA_ERR_CRASHED_ON_USAGE; + goto error; + } + + while ((read= gzread(archive, block, IO_SIZE))) + gzwrite(writer, block, read); + } + + gzflush(writer, Z_SYNC_FLUSH); + gzclose(share->archive_write); + share->archive_write= writer; my_rename(writer_filename,share->data_file_name,MYF(0)); DBUG_RETURN(0); -} +error: + gzclose(writer); + + DBUG_RETURN(rc); +} /* Below is an example of how to setup row level locking. diff --git a/sql/examples/ha_archive.h b/sql/examples/ha_archive.h index 2f310d8c69b..3932b62980c 100644 --- a/sql/examples/ha_archive.h +++ b/sql/examples/ha_archive.h @@ -36,7 +36,7 @@ typedef struct st_archive_share { gzFile archive_write; /* Archive file we are working with */ bool dirty; /* Flag for if a flush should occur */ bool crashed; /* Meta file is crashed */ - ulonglong rows_recorded; /* Number of rows in tables */ + ha_rows rows_recorded; /* Number of rows in tables */ } ARCHIVE_SHARE; /* @@ -53,7 +53,7 @@ class ha_archive: public handler z_off_t current_position; /* The position of the row we just read */ byte byte_buffer[IO_SIZE]; /* Initial buffer for our string */ String buffer; /* Buffer used for blob storage */ - ulonglong scan_rows; /* Number of rows left in scan */ + ha_rows scan_rows; /* Number of rows left in scan */ bool delayed_insert; /* If the insert is delayed */ bool bulk_insert; /* If we are performing a bulk insert */ @@ -84,12 +84,13 @@ public: int open(const char *name, int mode, uint test_if_locked); int close(void); int write_row(byte * buf); + int real_write_row(byte *buf, gzFile writer); int rnd_init(bool scan=1); int rnd_next(byte *buf); int rnd_pos(byte * buf, byte *pos); int get_row(gzFile file_to_read, byte *buf); - int read_meta_file(File meta_file, ulonglong *rows); - int write_meta_file(File meta_file, ulonglong rows, bool dirty); + int read_meta_file(File meta_file, ha_rows *rows); + int write_meta_file(File meta_file, ha_rows rows, bool dirty); ARCHIVE_SHARE *get_share(const char *table_name, TABLE *table); int free_share(ARCHIVE_SHARE *share); bool auto_repair() const { return 1; } // For the moment we just do this @@ -102,6 +103,10 @@ public: int repair(THD* thd, HA_CHECK_OPT* check_opt); void start_bulk_insert(ha_rows rows); int end_bulk_insert(); + enum row_type get_row_type() const + { + return ROW_TYPE_COMPRESSED; + } THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); }; diff --git a/sql/field.cc b/sql/field.cc index 16bf63e96fc..fef4195c46d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1445,6 +1445,7 @@ my_decimal *Field_str::val_decimal(my_decimal *decimal_value) uint Field::fill_cache_field(CACHE_FIELD *copy) { + uint store_length; copy->str=ptr; copy->length=pack_length(); copy->blob_field=0; @@ -1458,10 +1459,16 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) else if (!zero_pack() && (type() == MYSQL_TYPE_STRING && copy->length >= 4 && copy->length < 256)) + { copy->strip=1; /* Remove end space */ + store_length= 2; + } else + { copy->strip=0; - return copy->length+(int) copy->strip; + store_length= 0; + } + return copy->length+ store_length; } @@ -2480,7 +2487,7 @@ int Field_new_decimal::store(longlong nr) int err; if ((err= int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, - nr, false, &decimal_value))) + nr, FALSE, &decimal_value))) { if (check_overflow(err)) set_value_on_overflow(&decimal_value, decimal_value.sign()); @@ -3318,12 +3325,12 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) } if (error) { - error= 1; + error= error != MY_ERRNO_EDOM ? 1 : 2; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); } else if (from+len != end && table->in_use->count_cuted_fields && check_int(from,len,end,cs)) - error= 1; + error= 2; store_tmp= (long) tmp; #ifdef WORDS_BIGENDIAN @@ -3585,7 +3592,7 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) } else if (from+len != end && table->in_use->count_cuted_fields && check_int(from,len,end,cs)) - error= 1; + error= 2; #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) { @@ -3807,7 +3814,7 @@ int Field_float::store(const char *from,uint len,CHARSET_INFO *cs) { set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, (error ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED), 1); - error= 1; + error= error ? 1 : 2; } Field_float::store(nr); return error; @@ -4094,7 +4101,7 @@ int Field_double::store(const char *from,uint len,CHARSET_INFO *cs) { set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, (error ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED), 1); - error= 1; + error= error ? 1 : 2; } Field_double::store(nr); return error; @@ -4496,6 +4503,8 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) error= 1; } } + if (error > 1) + error= 2; #ifdef WORDS_BIGENDIAN if (table->s->db_low_byte_first) @@ -4792,7 +4801,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) if (str_to_time(from, len, <ime, &error)) { tmp=0L; - error= 1; + error= 2; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, from, len, MYSQL_TIMESTAMP_TIME, 1); } @@ -4814,6 +4823,8 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) from, len, MYSQL_TIMESTAMP_TIME, !error); error= 1; } + if (error > 1) + error= 2; } if (ltime.neg) @@ -5150,7 +5161,7 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs) &error) <= MYSQL_TIMESTAMP_ERROR) { tmp=0; - error= 1; + error= 2; } else tmp=(uint32) l_time.year*10000L + (uint32) (l_time.month*100+l_time.day); @@ -5354,7 +5365,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs) &error) <= MYSQL_TIMESTAMP_ERROR) { tmp=0L; - error= 1; + error= 2; } else tmp= l_time.day + l_time.month*32 + l_time.year*16*32; @@ -5837,7 +5848,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) from= tmpstr.ptr(); length= tmpstr.length(); if (conv_errors) - error= 1; + error= 2; } /* @@ -5861,7 +5872,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) from+= field_charset->cset->scan(field_charset, from, end, MY_SEQ_SPACES); if (from != end) - error= 1; + error= 2; } if (error) { @@ -6243,7 +6254,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) table->in_use->abort_on_warning) error_code= ER_DATA_TOO_LONG; set_warning(level, error_code, 1); - return 1; + return 2; } return 0; } @@ -6819,11 +6830,16 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) ¬_used))) { uint conv_errors; - tmpstr.copy(from, length, cs, field_charset, &conv_errors); + if (tmpstr.copy(from, length, cs, field_charset, &conv_errors)) + { + /* Fatal OOM error */ + bzero(ptr,Field_blob::pack_length()); + return -1; + } from= tmpstr.ptr(); length= tmpstr.length(); if (conv_errors) - error= 1; + error= 2; } copy_length= max_data_length(); @@ -6838,7 +6854,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) copy_length, &well_formed_error); if (copy_length < length) - error= 1; + error= 2; Field_blob::store_length(copy_length); if (was_conversion || table->copy_blobs || copy_length <= MAX_FIELD_WIDTH) { // Must make a copy diff --git a/sql/field.h b/sql/field.h index f297b17fd67..3f6b88198db 100644 --- a/sql/field.h +++ b/sql/field.h @@ -86,6 +86,7 @@ public: utype unireg_check; uint32 field_length; // Length of field + uint field_index; // field number in fields array uint16 flags; /* fieldnr is the id of the field (first field = 1) as is also used in key_part. @@ -1292,7 +1293,7 @@ public: enum_field_types type() const { return FIELD_TYPE_BIT; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; } uint32 key_length() const { return (uint32) field_length + (bit_len > 0); } - uint32 max_length() { return (uint32) field_length + (bit_len > 0); } + uint32 max_length() { return (uint32) field_length * 8 + bit_len; } uint size_of() const { return sizeof(*this); } Item_result result_type () const { return INT_RESULT; } void reset(void) { bzero(ptr, field_length); } @@ -1324,6 +1325,11 @@ public: Field *new_key_field(MEM_ROOT *root, struct st_table *new_table, char *new_ptr, uchar *new_null_ptr, uint new_null_bit); + void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg) + { + bit_ptr= bit_ptr_arg; + bit_ofs= bit_ofs_arg; + } }; @@ -1335,6 +1341,7 @@ public: enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg); enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + uint32 max_length() { return (uint32) create_length; } uint size_of() const { return sizeof(*this); } int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr) { return Field_bit::store(nr); } diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 15598e59bb9..0dc82666f52 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -324,21 +324,28 @@ static void do_field_real(Copy_field *copy) static void do_cut_string(Copy_field *copy) { // Shorter string field - memcpy(copy->to_ptr,copy->from_ptr,copy->to_length); - - /* Check if we loosed any important characters */ - char *ptr,*end; - for (ptr=copy->from_ptr+copy->to_length,end=copy->from_ptr+copy->from_length ; - ptr != end ; - ptr++) + int well_formed_error; + CHARSET_INFO *cs= copy->from_field->charset(); + const char *from_end= copy->from_ptr + copy->from_length; + uint copy_length= cs->cset->well_formed_len(cs, copy->from_ptr, from_end, + copy->to_length / cs->mbmaxlen, + &well_formed_error); + if (copy->to_length < copy_length) + copy_length= copy->to_length; + memcpy(copy->to_ptr, copy->from_ptr, copy_length); + + /* Check if we lost any important characters */ + if (well_formed_error || + cs->cset->scan(cs, copy->from_ptr + copy_length, from_end, + MY_SEQ_SPACES) < (copy->from_length - copy_length)) { - if (!my_isspace(system_charset_info, *ptr)) // QQ: ucs incompatible - { - copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, - WARN_DATA_TRUNCATED, 1); - break; - } + copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_DATA_TRUNCATED, 1); } + + if (copy_length < copy->to_length) + cs->cset->fill(cs, copy->to_ptr + copy_length, + copy->to_length - copy_length, ' '); } diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index c18ca5d7915..bbcae0613e7 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -848,7 +848,7 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) query.length(0); uint table_name_length, table_base_name_length; - char *tmp_table_name, *tmp_table_base_name, *table_base_name, *select_query; + char *tmp_table_name, *table_base_name, *select_query; /* share->table_name has the file location - we want the table's name! */ table_base_name= (char*) table->s->table_name; @@ -969,7 +969,6 @@ const char **ha_federated::bas_ext() const int ha_federated::open(const char *name, int mode, uint test_if_locked) { - int rc; DBUG_ENTER("ha_federated::open"); if (!(share= get_share(name, table))) @@ -1370,27 +1369,25 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) int ha_federated::delete_row(const byte *buf) { - uint x= 0; char delete_buffer[IO_SIZE]; char data_buffer[IO_SIZE]; - String delete_string(delete_buffer, sizeof(delete_buffer), &my_charset_bin); - delete_string.length(0); String data_string(data_buffer, sizeof(data_buffer), &my_charset_bin); - data_string.length(0); - DBUG_ENTER("ha_federated::delete_row"); + delete_string.length(0); delete_string.append("DELETE FROM `"); delete_string.append(share->table_base_name); delete_string.append("`"); delete_string.append(" WHERE "); - for (Field **field= table->field; *field; field++, x++) + for (Field **field= table->field; *field; field++) { - delete_string.append((*field)->field_name); + Field *cur_field= *field; + data_string.length(0); + delete_string.append(cur_field->field_name); - if ((*field)->is_null()) + if (cur_field->is_null_in_record((const uchar*) buf)) { delete_string.append(" IS "); data_string.append("NULL"); @@ -1398,17 +1395,15 @@ int ha_federated::delete_row(const byte *buf) else { delete_string.append("="); - (*field)->val_str(&data_string); - (*field)->quote_data(&data_string); + cur_field->val_str(&data_string, (char*) buf+ cur_field->offset()); + cur_field->quote_data(&data_string); } delete_string.append(data_string); - data_string.length(0); - - if (x + 1 < table->s->fields) - delete_string.append(" AND "); + delete_string.append(" AND "); } + delete_string.length(delete_string.length()-5); // Remove AND delete_string.append(" LIMIT 1"); DBUG_PRINT("info", ("Delete sql: %s", delete_string.c_ptr_quick())); @@ -1454,8 +1449,6 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key, __attribute__ ((unused))) { char index_value[IO_SIZE]; - char key_value[IO_SIZE]; - char test_value[IO_SIZE]; String index_string(index_value, sizeof(index_value), &my_charset_bin); index_string.length(0); uint keylen; @@ -1521,7 +1514,6 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key, /* Initialized at each key walk (called multiple times unlike rnd_init()) */ int ha_federated::index_init(uint keynr) { - int error; DBUG_ENTER("ha_federated::index_init"); DBUG_PRINT("info", ("table: '%s' key: %d", table->s->table_name, keynr)); @@ -1553,7 +1545,6 @@ int ha_federated::index_next(byte *buf) int ha_federated::rnd_init(bool scan) { DBUG_ENTER("ha_federated::rnd_init"); - int num_fields, rows; /* This 'scan' flag is incredibly important for this handler to work diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index cd655eeb0a9..6e609a94be3 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -65,7 +65,15 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked) { /* Initialize variables for the opened table */ set_keys_for_scanning(); - update_key_stats(); + /* + We cannot run update_key_stats() here because we do not have a + lock on the table. The 'records' count might just be changed + temporarily at this moment and we might get wrong statistics (Bug + #10178). Instead we request for update. This will be done in + ha_heap::info(), which is always called before key statistics are + used. + */ + key_stats_ok= FALSE; } return (file ? 0 : 1); } @@ -118,6 +126,8 @@ void ha_heap::update_key_stats() } } records_changed= 0; + /* At the end of update_key_stats() we can proudly claim they are OK. */ + key_stats_ok= TRUE; } @@ -132,7 +142,7 @@ int ha_heap::write_row(byte * buf) res= heap_write(file,buf); if (!res && (++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records)) - update_key_stats(); + key_stats_ok= FALSE; return res; } @@ -145,7 +155,7 @@ int ha_heap::update_row(const byte * old_data, byte * new_data) res= heap_update(file,old_data,new_data); if (!res && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records) - update_key_stats(); + key_stats_ok= FALSE; return res; } @@ -156,7 +166,7 @@ int ha_heap::delete_row(const byte * buf) res= heap_delete(file,buf); if (!res && table->s->tmp_table == NO_TMP_TABLE && ++records_changed*HEAP_STATS_UPDATE_THRESHOLD > file->s->records) - update_key_stats(); + key_stats_ok= FALSE; return res; } @@ -278,6 +288,13 @@ void ha_heap::info(uint flag) delete_length= info.deleted * info.reclength; if (flag & HA_STATUS_AUTO) auto_increment_value= info.auto_increment; + /* + If info() is called for the first time after open(), we will still + have to update the key statistics. Hoping that a table lock is now + in place. + */ + if (! key_stats_ok) + update_key_stats(); } int ha_heap::extra(enum ha_extra_function operation) @@ -289,7 +306,7 @@ int ha_heap::delete_all_rows() { heap_clear(file); if (table->s->tmp_table == NO_TMP_TABLE) - update_key_stats(); + key_stats_ok= FALSE; return 0; } @@ -448,6 +465,9 @@ ha_rows ha_heap::records_in_range(uint inx, key_range *min_key, min_key->flag != HA_READ_KEY_EXACT || max_key->flag != HA_READ_AFTER_KEY) return HA_POS_ERROR; // Can only use exact keys + + /* Assert that info() did run. We need current statistics here. */ + DBUG_ASSERT(key_stats_ok); return key->rec_per_key[key->key_parts-1]; } diff --git a/sql/ha_heap.h b/sql/ha_heap.h index 2aa065e0d96..7a97c727049 100644 --- a/sql/ha_heap.h +++ b/sql/ha_heap.h @@ -29,8 +29,10 @@ class ha_heap: public handler key_map btree_keys; /* number of records changed since last statistics update */ uint records_changed; + bool key_stats_ok; public: - ha_heap(TABLE *table): handler(table), file(0), records_changed(0) {} + ha_heap(TABLE *table): handler(table), file(0), records_changed(0), + key_stats_ok(0) {} ~ha_heap() {} const char *table_type() const { diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 78b70d9876a..4167b7c2dde 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -326,7 +326,7 @@ innodb_srv_conc_enter_innodb( /*=========================*/ trx_t* trx) /* in: transaction handle */ { - if (UNIV_LIKELY(srv_thread_concurrency >= 20)) { + if (UNIV_LIKELY(srv_thread_concurrency >= SRV_CONCURRENCY_THRESHOLD)) { return; } @@ -343,7 +343,7 @@ innodb_srv_conc_exit_innodb( /*========================*/ trx_t* trx) /* in: transaction handle */ { - if (UNIV_LIKELY(srv_thread_concurrency >= 20)) { + if (UNIV_LIKELY(srv_thread_concurrency >= SRV_CONCURRENCY_THRESHOLD)) { return; } @@ -1496,8 +1496,8 @@ innobase_start_trx_and_assign_read_view( /********************************************************************* Commits a transaction in an InnoDB database or marks an SQL statement ended. */ - -static int +static +int innobase_commit( /*============*/ /* out: 0 */ @@ -2955,22 +2955,45 @@ build_template( templ = prebuilt->mysql_template + n_requested_fields; field = table->field[i]; - ibool index_contains_field= - dict_index_contains_col_or_prefix(index, i); + if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) { + /* Decide which columns we should fetch + and which we can skip. */ + register const ibool index_contains_field = + dict_index_contains_col_or_prefix(index, i); + + if (!index_contains_field && prebuilt->read_just_key) { + /* If this is a 'key read', we do not need + columns that are not in the key */ + + goto skip_field; + } + + if (index_contains_field && fetch_all_in_key) { + /* This field is needed in the query */ + + goto include_field; + } + + if (table->file->ha_get_bit_in_read_set(i+1) || + table->file->ha_get_bit_in_write_set(i+1)) { + /* This field is needed in the query */ + + goto include_field; + } - if (templ_type == ROW_MYSQL_REC_FIELDS && - ((prebuilt->read_just_key && !index_contains_field) || - (!(fetch_all_in_key && index_contains_field) && - !(fetch_primary_key_cols && - dict_table_col_in_clustered_key(index->table, i)) && - (!(table->file->ha_get_bit_in_read_set(i+1) || - table->file->ha_get_bit_in_write_set(i+1)))))) { + if (fetch_primary_key_cols + && dict_table_col_in_clustered_key(index->table, + i)) { + /* This field is needed in the query */ + + goto include_field; + } /* This field is not needed in the query, skip it */ goto skip_field; } - +include_field: n_requested_fields++; templ->col_no = i; @@ -3539,7 +3562,9 @@ ha_innobase::delete_row( } /************************************************************************** -Deletes a lock set to a row */ +Removes a new lock set on a row. This can be called after a row has been read +in the processing of an UPDATE or a DELETE query, if the option +innodb_locks_unsafe_for_binlog is set. */ void ha_innobase::unlock_row(void) @@ -3557,8 +3582,10 @@ ha_innobase::unlock_row(void) mem_analyze_corruption((byte *) prebuilt->trx); ut_error; } - - row_unlock_for_mysql(prebuilt); + + if (srv_locks_unsafe_for_binlog) { + row_unlock_for_mysql(prebuilt, FALSE); + } } /********************************************************************** @@ -5992,6 +6019,7 @@ ha_innobase::external_lock( reads. */ prebuilt->select_lock_type = LOCK_S; + prebuilt->stored_select_lock_type = LOCK_S; } /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK @@ -6031,7 +6059,6 @@ ha_innobase::external_lock( trx->n_mysql_tables_in_use--; prebuilt->mysql_has_locked = FALSE; - /* If the MySQL lock count drops to zero we know that the current SQL statement has ended */ @@ -6564,12 +6591,14 @@ the value of the auto-inc counter. */ int ha_innobase::innobase_read_and_init_auto_inc( /*=========================================*/ - /* out: 0 or error code: deadlock or - lock wait timeout */ + /* out: 0 or error code: deadlock or lock wait + timeout */ longlong* ret) /* out: auto-inc value */ { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; longlong auto_inc; + ulint old_select_lock_type; + ibool trx_was_not_started = FALSE; int error; ut_a(prebuilt); @@ -6577,6 +6606,10 @@ ha_innobase::innobase_read_and_init_auto_inc( (trx_t*) current_thd->ha_data[innobase_hton.slot]); ut_a(prebuilt->table); + if (prebuilt->trx->conc_state == TRX_NOT_STARTED) { + trx_was_not_started = TRUE; + } + /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads */ @@ -6588,7 +6621,9 @@ ha_innobase::innobase_read_and_init_auto_inc( /* Already initialized */ *ret = auto_inc; - return(0); + error = 0; + + goto func_exit_early; } error = row_lock_table_autoinc_for_mysql(prebuilt); @@ -6596,7 +6631,7 @@ ha_innobase::innobase_read_and_init_auto_inc( if (error != DB_SUCCESS) { error = convert_error_code_to_mysql(error, user_thd); - goto func_exit; + goto func_exit_early; } /* Check again if someone has initialized the counter meanwhile */ @@ -6605,30 +6640,37 @@ ha_innobase::innobase_read_and_init_auto_inc( if (auto_inc != 0) { *ret = auto_inc; - return(0); + error = 0; + + goto func_exit_early; } (void) extra(HA_EXTRA_KEYREAD); index_init(table->s->next_number_index); - /* We use an exclusive lock when we read the max key value from the - auto-increment column index. This is because then build_template will - advise InnoDB to fetch all columns. In SHOW TABLE STATUS the query - id of the auto-increment column is not changed, and previously InnoDB - did not fetch it, causing SHOW TABLE STATUS to show wrong values - for the autoinc column. */ - - prebuilt->select_lock_type = LOCK_X; + /* Starting from 5.0.9, we use a consistent read to read the auto-inc + column maximum value. This eliminates the spurious deadlocks caused + by the row X-lock that we previously used. Note the following flaw + in our algorithm: if some other user meanwhile UPDATEs the auto-inc + column, our consistent read will not return the largest value. We + accept this flaw, since the deadlocks were a bigger trouble. */ - /* Play safe and also give in another way the hint to fetch - all columns in the key: */ + /* Fetch all the columns in the key */ prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS; - prebuilt->trx->mysql_n_tables_locked += 1; - + old_select_lock_type = prebuilt->select_lock_type; + prebuilt->select_lock_type = LOCK_NONE; + + /* Eliminate an InnoDB error print that happens when we try to SELECT + from a table when no table has been locked in ::external_lock(). */ + prebuilt->trx->n_mysql_tables_in_use++; + error = index_last(table->record[1]); + prebuilt->trx->n_mysql_tables_in_use--; + prebuilt->select_lock_type = old_select_lock_type; + if (error) { if (error == HA_ERR_END_OF_FILE) { /* The table was empty, initialize to 1 */ @@ -6636,7 +6678,10 @@ ha_innobase::innobase_read_and_init_auto_inc( error = 0; } else { - /* Deadlock or a lock wait timeout */ + /* This should not happen in a consistent read */ + fprintf(stderr, +"InnoDB: Error: consistent read of auto-inc column returned %lu\n", + (ulong)error); auto_inc = -1; goto func_exit; @@ -6656,7 +6701,18 @@ func_exit: *ret = auto_inc; - return(error); +func_exit_early: + /* Since MySQL does not seem to call autocommit after SHOW TABLE + STATUS (even if we would register the trx here), we must commit our + transaction here if it was started here. This is to eliminate a + dangling transaction. */ + + if (trx_was_not_started) { + + innobase_commit_low(prebuilt->trx); + } + + return(error); } /*********************************************************************** diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index f1dbedc1af1..7d182d07087 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -341,7 +341,7 @@ void ha_ndbcluster::records_update() { Ndb *ndb= get_ndb(); struct Ndb_statistics stat; - if(ndb_get_table_statistics(ndb, m_tabname, &stat) == 0){ + if (ndb_get_table_statistics(ndb, m_tabname, &stat) == 0){ mean_rec_length= stat.row_size; data_file_length= stat.fragment_memory; info->records= stat.row_count; @@ -448,27 +448,27 @@ void ha_ndbcluster::invalidate_dictionary_cache(bool global) NDBINDEX *unique_index = (NDBINDEX *) m_index[i].unique_index; NDB_INDEX_TYPE idx_type= m_index[i].type; - switch(idx_type) { - case(PRIMARY_KEY_ORDERED_INDEX): - case(ORDERED_INDEX): + switch (idx_type) { + case PRIMARY_KEY_ORDERED_INDEX: + case ORDERED_INDEX: if (global) dict->invalidateIndex(index->getName(), m_tabname); else dict->removeCachedIndex(index->getName(), m_tabname); break; - case(UNIQUE_ORDERED_INDEX): + case UNIQUE_ORDERED_INDEX: if (global) dict->invalidateIndex(index->getName(), m_tabname); else dict->removeCachedIndex(index->getName(), m_tabname); - case(UNIQUE_INDEX): + case UNIQUE_INDEX: if (global) dict->invalidateIndex(unique_index->getName(), m_tabname); else dict->removeCachedIndex(unique_index->getName(), m_tabname); break; - case(PRIMARY_KEY_INDEX): - case(UNDEFINED_INDEX): + case PRIMARY_KEY_INDEX: + case UNDEFINED_INDEX: break; } } @@ -515,8 +515,10 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) if (m_rows_to_insert == 1) m_dupkey= table->s->primary_key; else - // We are batching inserts, offending key is not available + { + /* We are batching inserts, offending key is not available */ m_dupkey= (uint) -1; + } } DBUG_RETURN(res); } @@ -1246,36 +1248,18 @@ int ha_ndbcluster::set_primary_key(NdbOperation *op, const byte *key) } -int ha_ndbcluster::set_primary_key_from_old_data(NdbOperation *op, const byte *old_data) +int ha_ndbcluster::set_primary_key_from_record(NdbOperation *op, const byte *record) { KEY* key_info= table->key_info + table->s->primary_key; KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; - DBUG_ENTER("set_primary_key_from_old_data"); + DBUG_ENTER("set_primary_key_from_record"); for (; key_part != end; key_part++) { Field* field= key_part->field; if (set_ndb_key(op, field, - key_part->fieldnr-1, old_data+key_part->offset)) - ERR_RETURN(op->getNdbError()); - } - DBUG_RETURN(0); -} - - -int ha_ndbcluster::set_primary_key(NdbOperation *op) -{ - DBUG_ENTER("set_primary_key"); - KEY* key_info= table->key_info + table->s->primary_key; - KEY_PART_INFO* key_part= key_info->key_part; - KEY_PART_INFO* end= key_part+key_info->key_parts; - - for (; key_part != end; key_part++) - { - Field* field= key_part->field; - if (set_ndb_key(op, field, - key_part->fieldnr-1, field->ptr)) + key_part->fieldnr-1, record+key_part->offset)) ERR_RETURN(op->getNdbError()); } DBUG_RETURN(0); @@ -1344,6 +1328,7 @@ int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op) DBUG_RETURN(0); } + /* Read one record from NDB using primary key */ @@ -1384,7 +1369,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf) return res; } - if((res= define_read_attrs(buf, op))) + if ((res= define_read_attrs(buf, op))) DBUG_RETURN(res); if (execute_no_commit_ie(this,trans) != 0) @@ -1423,11 +1408,9 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data) if (!(op= trans->getNdbOperation((const NDBTAB *) m_table)) || op->readTuple(lm) != 0) ERR_RETURN(trans->getNdbError()); - int res; - if ((res= set_primary_key_from_old_data(op, old_data))) + if ((res= set_primary_key_from_record(op, old_data))) ERR_RETURN(trans->getNdbError()); - // Read all unreferenced non-key field(s) for (i= 0; i < no_fields; i++) { @@ -1470,7 +1453,7 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data) Peek to check if a particular row already exists */ -int ha_ndbcluster::peek_row() +int ha_ndbcluster::peek_row(const byte *record) { NdbTransaction *trans= m_active_trans; NdbOperation *op; @@ -1483,7 +1466,7 @@ int ha_ndbcluster::peek_row() ERR_RETURN(trans->getNdbError()); int res; - if ((res= set_primary_key(op))) + if ((res= set_primary_key_from_record(op, record))) ERR_RETURN(trans->getNdbError()); if (execute_no_commit_ie(this,trans) != 0) @@ -1517,10 +1500,10 @@ int ha_ndbcluster::unique_index_read(const byte *key, ERR_RETURN(trans->getNdbError()); // Set secondary index key(s) - if((res= set_index_key(op, table->key_info + active_index, key))) + if ((res= set_index_key(op, table->key_info + active_index, key))) DBUG_RETURN(res); - if((res= define_read_attrs(buf, op))) + if ((res= define_read_attrs(buf, op))) DBUG_RETURN(res); if (execute_no_commit_ie(this,trans) != 0) @@ -1580,7 +1563,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) { if (execute_commit(this,trans) != 0) DBUG_RETURN(-1); - if(trans->restart() != 0) + if (trans->restart() != 0) { DBUG_ASSERT(0); DBUG_RETURN(-1); @@ -1618,7 +1601,7 @@ inline int ha_ndbcluster::next_result(byte *buf) if (!m_active_cursor) DBUG_RETURN(HA_ERR_END_OF_FILE); - if((res= fetch_next(m_active_cursor)) == 0) + if ((res= fetch_next(m_active_cursor)) == 0) { DBUG_PRINT("info", ("One more record found")); @@ -1626,7 +1609,7 @@ inline int ha_ndbcluster::next_result(byte *buf) table->status= 0; DBUG_RETURN(0); } - else if(res == 1) + else if (res == 1) { // No more records table->status= STATUS_NOT_FOUND; @@ -1858,7 +1841,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, DBUG_ASSERT(op->getSorted() == sorted); DBUG_ASSERT(op->getLockMode() == (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type)); - if(op->reset_bounds(m_force_send)) + if (op->reset_bounds(m_force_send)) DBUG_RETURN(ndb_err(m_active_trans)); } @@ -1905,7 +1888,7 @@ int ha_ndbcluster::full_table_scan(byte *buf) m_active_cursor= op; if (generate_scan_filter(m_cond_stack, op)) DBUG_RETURN(ndb_err(trans)); - if((res= define_read_attrs(buf, op))) + if ((res= define_read_attrs(buf, op))) DBUG_RETURN(res); if (execute_no_commit(this,trans) != 0) @@ -1931,7 +1914,7 @@ int ha_ndbcluster::write_row(byte *record) if (m_ignore_dup_key && table->s->primary_key != MAX_KEY) { - int peek_res= peek_row(); + int peek_res= peek_row(record); if (!peek_res) { @@ -1985,9 +1968,7 @@ int ha_ndbcluster::write_row(byte *record) m_skip_auto_increment= !auto_increment_column_changed; } - if ((res= (m_primary_key_update ? - set_primary_key_from_old_data(op, record) - : set_primary_key(op)))) + if ((res= set_primary_key_from_record(op, record))) return res; } @@ -2044,7 +2025,7 @@ int ha_ndbcluster::write_row(byte *record) no_uncommitted_rows_execute_failure(); DBUG_RETURN(ndb_err(trans)); } - if(trans->restart() != 0) + if (trans->restart() != 0) { DBUG_ASSERT(0); DBUG_RETURN(-1); @@ -2127,7 +2108,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) if ((table->s->primary_key != MAX_KEY) && (key_cmp(table->s->primary_key, old_data, new_data))) { - int read_res, insert_res, delete_res; + int read_res, insert_res, delete_res, undo_res; DBUG_PRINT("info", ("primary key update, doing pk read+delete+insert")); // Get all old fields, since we optimize away fields not in query @@ -2156,9 +2137,14 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) DBUG_PRINT("info", ("insert failed")); if (trans->commitStatus() == NdbConnection::Started) { - // Undo write_row(new_data) + // Undo delete_row(old_data) m_primary_key_update= TRUE; - insert_res= write_row((byte *)old_data); + undo_res= write_row((byte *)old_data); + if (undo_res) + push_warning(current_thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + undo_res, + "NDB failed undoing delete at primary key update"); m_primary_key_update= FALSE; } DBUG_RETURN(insert_res); @@ -2207,7 +2193,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) else { int res; - if ((res= set_primary_key_from_old_data(op, old_data))) + if ((res= set_primary_key_from_record(op, old_data))) DBUG_RETURN(res); } } @@ -2293,10 +2279,8 @@ int ha_ndbcluster::delete_row(const byte *record) else { int res; - if ((res= (m_primary_key_update ? - set_primary_key_from_old_data(op, record) - : set_primary_key(op)))) - return res; + if ((res= set_primary_key_from_record(op, record))) + return res; } } @@ -2424,7 +2408,7 @@ void ha_ndbcluster::print_results() field= table->field[f]; if (!(value= m_value[f]).ptr) { - my_snprintf(buf, sizeof(buf), "not read"); + strmov(buf, "not read"); goto print_value; } @@ -2434,7 +2418,7 @@ void ha_ndbcluster::print_results() { if (value.rec->isNULL()) { - my_snprintf(buf, sizeof(buf), "NULL"); + strmov(buf, "NULL"); goto print_value; } type.length(0); @@ -2448,10 +2432,8 @@ void ha_ndbcluster::print_results() NdbBlob *ndb_blob= value.blob; bool isNull= TRUE; ndb_blob->getNull(isNull); - if (isNull) { - my_snprintf(buf, sizeof(buf), "NULL"); - goto print_value; - } + if (isNull) + strmov(buf, "NULL"); } print_value: @@ -2491,7 +2473,7 @@ check_null_in_key(const KEY* key_info, const byte *key, uint key_len) for (; curr_part != end_part && key < end_ptr; curr_part++) { - if(curr_part->null_bit && *key) + if (curr_part->null_bit && *key) return 1; key += curr_part->store_length; @@ -2516,7 +2498,7 @@ int ha_ndbcluster::index_read(byte *buf, case PRIMARY_KEY_INDEX: if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len) { - if(m_active_cursor && (error= close_scan())) + if (m_active_cursor && (error= close_scan())) DBUG_RETURN(error); DBUG_RETURN(pk_read(key, key_len, buf)); } @@ -2530,7 +2512,7 @@ int ha_ndbcluster::index_read(byte *buf, if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len && !check_null_in_key(key_info, key, key_len)) { - if(m_active_cursor && (error= close_scan())) + if (m_active_cursor && (error= close_scan())) DBUG_RETURN(error); DBUG_RETURN(unique_index_read(key, key_len, buf)); } @@ -2642,7 +2624,7 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, start_key->length == key_info->key_length && start_key->flag == HA_READ_KEY_EXACT) { - if(m_active_cursor && (error= close_scan())) + if (m_active_cursor && (error= close_scan())) DBUG_RETURN(error); error= pk_read(start_key->key, start_key->length, buf); DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error); @@ -2655,7 +2637,7 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, start_key->flag == HA_READ_KEY_EXACT && !check_null_in_key(key_info, start_key->key, start_key->length)) { - if(m_active_cursor && (error= close_scan())) + if (m_active_cursor && (error= close_scan())) DBUG_RETURN(error); error= unique_index_read(start_key->key, start_key->length, buf); DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error); @@ -2703,7 +2685,7 @@ int ha_ndbcluster::rnd_init(bool scan) { if (!scan) DBUG_RETURN(1); - if(cursor->restart(m_force_send) != 0) + if (cursor->restart(m_force_send) != 0) { DBUG_ASSERT(0); DBUG_RETURN(-1); @@ -3369,7 +3351,7 @@ int ndbcluster_commit(THD *thd, bool all) } ndb->closeTransaction(trans); - if(all) + if (all) thd_ndb->all= NULL; else thd_ndb->stmt= NULL; @@ -3419,7 +3401,7 @@ int ndbcluster_rollback(THD *thd, bool all) } ndb->closeTransaction(trans); - if(all) + if (all) thd_ndb->all= NULL; else thd_ndb->stmt= NULL; @@ -3675,7 +3657,8 @@ static int create_ndb_column(NDBCOL &col, col.setType(NDBCOL::Char); col.setLength(field->pack_length()); break; - case MYSQL_TYPE_BIT: { + case MYSQL_TYPE_BIT: + { int no_of_bits= field->field_length*8 + ((Field_bit *) field)->bit_len; col.setType(NDBCOL::Bit); if (!no_of_bits) @@ -3810,7 +3793,7 @@ int ha_ndbcluster::create(const char *name, if ((my_errno= create_ndb_column(col, field, info))) DBUG_RETURN(my_errno); tab.addColumn(col); - if(col.getPrimaryKey()) + if (col.getPrimaryKey()) pk_length += (field->pack_length() + 3) / 4; } @@ -3843,7 +3826,7 @@ int ha_ndbcluster::create(const char *name, { NdbDictionary::Column * col= tab.getColumn(i); int size= pk_length + (col->getPartSize()+3)/4 + 7; - if(size > NDB_MAX_TUPLE_SIZE_IN_WORDS && + if (size > NDB_MAX_TUPLE_SIZE_IN_WORDS && (pk_length+7) < NDB_MAX_TUPLE_SIZE_IN_WORDS) { size= NDB_MAX_TUPLE_SIZE_IN_WORDS - pk_length - 7; @@ -4071,12 +4054,10 @@ ulonglong ha_ndbcluster::get_auto_increment() m_rows_to_insert+= m_autoincrement_prefetch; } cache_size= - (int) - (m_rows_to_insert - m_rows_inserted < m_autoincrement_prefetch) ? - m_rows_to_insert - m_rows_inserted - : (m_rows_to_insert > m_autoincrement_prefetch) ? - m_rows_to_insert - : m_autoincrement_prefetch; + (int) ((m_rows_to_insert - m_rows_inserted < m_autoincrement_prefetch) ? + m_rows_to_insert - m_rows_inserted : + ((m_rows_to_insert > m_autoincrement_prefetch) ? + m_rows_to_insert : m_autoincrement_prefetch)); auto_value= NDB_FAILED_AUTO_INCREMENT; uint retries= NDB_AUTO_INCREMENT_RETRIES; do { @@ -4347,7 +4328,7 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name, { const NdbError err= dict->getNdbError(); if (err.code == 709) - DBUG_RETURN(1); + DBUG_RETURN(-1); ERR_RETURN(err); } DBUG_PRINT("info", ("Found table %s", tab->getName())); @@ -4355,13 +4336,15 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name, len= tab->getFrmLength(); if (len == 0 || tab->getFrmData() == NULL) { - DBUG_PRINT("No frm data found", - ("Table is probably created via NdbApi")); - DBUG_RETURN(2); + DBUG_PRINT("error", ("No frm data found.")); + DBUG_RETURN(1); } if (unpackfrm(&data, &len, tab->getFrmData())) - DBUG_RETURN(3); + { + DBUG_PRINT("error", ("Could not unpack table")); + DBUG_RETURN(1); + } *frmlen= len; *frmblob= data; @@ -4374,11 +4357,11 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name, */ -int ndbcluster_table_exists(THD* thd, const char *db, const char *name) +int ndbcluster_table_exists_in_engine(THD* thd, const char *db, const char *name) { const NDBTAB* tab; Ndb* ndb; - DBUG_ENTER("ndbcluster_table_exists"); + DBUG_ENTER("ndbcluster_table_exists_in_engine"); DBUG_PRINT("enter", ("db: %s, name: %s", db, name)); if (!(ndb= check_ndb_in_thd(thd))) @@ -4557,7 +4540,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, DBUG_PRINT("info", ("%s existed on disk", name)); // The .ndb file exists on disk, but it's not in list of tables in ndb // Verify that handler agrees table is gone. - if (ndbcluster_table_exists(thd, db, file_name) == 0) + if (ndbcluster_table_exists_in_engine(thd, db, file_name) == 0) { DBUG_PRINT("info", ("NDB says %s does not exists", file_name)); it.remove(); @@ -4611,7 +4594,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, while ((file_name=it2++)) { DBUG_PRINT("info", ("Table %s need discovery", file_name)); - if (ha_create_table_from_engine(thd, db, file_name, TRUE) == 0) + if (ha_create_table_from_engine(thd, db, file_name) == 0) files->push_back(thd->strdup(file_name)); } @@ -4676,7 +4659,7 @@ ndbcluster_init() g_ndb_cluster_connection->get_connected_port())); g_ndb_cluster_connection->wait_until_ready(10,3); } - else if(res == 1) + else if (res == 1) { if (g_ndb_cluster_connection->start_connect_thread(connect_callback)) { @@ -4724,7 +4707,7 @@ ndbcluster_init() DBUG_RETURN(&ndbcluster_hton); ndbcluster_init_error: - if(g_ndb) + if (g_ndb) delete g_ndb; g_ndb= NULL; if (g_ndb_cluster_connection) @@ -4753,7 +4736,7 @@ bool ndbcluster_end() (void) pthread_cond_signal(&COND_ndb_util_thread); (void) pthread_mutex_unlock(&LOCK_ndb_util_thread); - if(g_ndb) + if (g_ndb) delete g_ndb; g_ndb= NULL; if (g_ndb_cluster_connection) @@ -5003,7 +4986,7 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname, } pthread_mutex_lock(&share->mutex); - if(share->commit_count_lock == lock) + if (share->commit_count_lock == lock) { DBUG_PRINT("info", ("Setting commit_count to %llu", stat.commit_count)); share->commit_count= stat.commit_count; @@ -5495,9 +5478,13 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, for (; multi_range_curr<multi_range_end && curr+reclength <= end_of_buffer; multi_range_curr++) { - switch(index_type){ + switch (index_type){ + case PRIMARY_KEY_ORDERED_INDEX: + if (!(multi_range_curr->start_key.length == key_info->key_length && + multi_range_curr->start_key.flag == HA_READ_KEY_EXACT)) + goto range; + /* fall through */ case PRIMARY_KEY_INDEX: - pk: { multi_range_curr->range_flag |= UNIQUE_RANGE; if ((op= m_active_trans->getNdbOperation(tab)) && @@ -5511,8 +5498,14 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, break; } break; + case UNIQUE_ORDERED_INDEX: + if (!(multi_range_curr->start_key.length == key_info->key_length && + multi_range_curr->start_key.flag == HA_READ_KEY_EXACT && + !check_null_in_key(key_info, multi_range_curr->start_key.key, + multi_range_curr->start_key.length))) + goto range; + /* fall through */ case UNIQUE_INDEX: - sk: { multi_range_curr->range_flag |= UNIQUE_RANGE; if ((op= m_active_trans->getNdbIndexOperation(unique_idx, tab)) && @@ -5525,19 +5518,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError()); break; } - case PRIMARY_KEY_ORDERED_INDEX: - if (multi_range_curr->start_key.length == key_info->key_length && - multi_range_curr->start_key.flag == HA_READ_KEY_EXACT) - goto pk; - goto range; - case UNIQUE_ORDERED_INDEX: - if (multi_range_curr->start_key.length == key_info->key_length && - multi_range_curr->start_key.flag == HA_READ_KEY_EXACT && - !check_null_in_key(key_info, multi_range_curr->start_key.key, - multi_range_curr->start_key.length)) - goto sk; - goto range; - case ORDERED_INDEX: { + case ORDERED_INDEX: + { range: multi_range_curr->range_flag &= ~(uint)UNIQUE_RANGE; if (scanOp == 0) @@ -5548,7 +5530,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, DBUG_ASSERT(scanOp->getSorted() == sorted); DBUG_ASSERT(scanOp->getLockMode() == (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type)); - if(scanOp->reset_bounds(m_force_send)) + if (scanOp->reset_bounds(m_force_send)) DBUG_RETURN(ndb_err(m_active_trans)); end_of_buffer -= reclength; @@ -5574,7 +5556,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, DBUG_RETURN(res); break; } - case(UNDEFINED_INDEX): + case UNDEFINED_INDEX: DBUG_ASSERT(FALSE); DBUG_RETURN(1); break; @@ -5683,7 +5665,7 @@ ha_ndbcluster::read_multi_range_next(KEY_MULTI_RANGE ** multi_range_found_p) DBUG_MULTI_RANGE(6); // First fetch from cursor DBUG_ASSERT(range_no == -1); - if((res= m_multi_cursor->nextResult(true))) + if ((res= m_multi_cursor->nextResult(true))) { goto close_scan; } @@ -5786,7 +5768,7 @@ ha_ndbcluster::update_table_comment( const char* comment)/* in: table comment defined by user */ { uint length= strlen(comment); - if(length > 64000 - 3) + if (length > 64000 - 3) { return((char*)comment); /* string too long */ } @@ -5813,9 +5795,9 @@ ha_ndbcluster::update_table_comment( return (char*)comment; } - snprintf(str,fmt_len_plus_extra,fmt,comment, - length > 0 ? " ":"", - tab->getReplicaCount()); + my_snprintf(str,fmt_len_plus_extra,fmt,comment, + length > 0 ? " ":"", + tab->getReplicaCount()); return str; } @@ -5914,7 +5896,7 @@ extern "C" pthread_handler_decl(ndb_util_thread_func, lock= share->commit_count_lock; pthread_mutex_unlock(&share->mutex); - if(ndb_get_table_statistics(ndb, tabname, &stat) == 0) + if (ndb_get_table_statistics(ndb, tabname, &stat) == 0) { DBUG_PRINT("ndb_util_thread", ("Table: %s, commit_count: %llu, rows: %llu", @@ -5949,7 +5931,7 @@ extern "C" pthread_handler_decl(ndb_util_thread_func, abstime.tv_sec= tick_time.tv_sec; abstime.tv_nsec= tick_time.tv_usec * 1000; - if(msecs >= 1000){ + if (msecs >= 1000){ secs= msecs / 1000; msecs= msecs % 1000; } @@ -6058,17 +6040,18 @@ void ndb_serialize_cond(const Item *item, void *arg) { DBUG_PRINT("info", ("Skiping argument %d", context->skip)); context->skip--; - switch(item->type()) { - case (Item::FUNC_ITEM): { + switch (item->type()) { + case Item::FUNC_ITEM: + { Item_func *func_item= (Item_func *) item; context->skip+= func_item->argument_count(); break; } - case(Item::INT_ITEM): - case(Item::REAL_ITEM): - case(Item::STRING_ITEM): - case(Item::VARBIN_ITEM): - case(Item::DECIMAL_ITEM): + case Item::INT_ITEM: + case Item::REAL_ITEM: + case Item::STRING_ITEM: + case Item::VARBIN_ITEM: + case Item::DECIMAL_ITEM: break; default: context->supported= FALSE; @@ -6087,8 +6070,8 @@ void ndb_serialize_cond(const Item *item, void *arg) (func_item= rewrite_context->func_item) && rewrite_context->count++ == 0) { - switch(func_item->functype()) { - case(Item_func::BETWEEN): + switch (func_item->functype()) { + case Item_func::BETWEEN: /* Rewrite <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2> @@ -6098,7 +6081,8 @@ void ndb_serialize_cond(const Item *item, void *arg) BEGIN(AND) GT(<field>|<const>, <const1>|<field1>), LT(<field>|<const>, <const2>|<field2>), END() */ - case(Item_func::IN_FUNC): { + case Item_func::IN_FUNC: + { /* Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..) to <field>|<const> = <const1>|<field1> OR @@ -6163,17 +6147,18 @@ void ndb_serialize_cond(const Item *item, void *arg) { Ndb_rewrite_context *rewrite_context= context->rewrite_stack; const Item_func *func_item= rewrite_context->func_item; - switch(func_item->functype()) { - case(Item_func::BETWEEN): { - /* - Rewrite - <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2> - to <field>|<const> > <const1>|<field1> AND - <field>|<const> < <const2>|<field2> - or actually in prefix format - BEGIN(AND) GT(<field>|<const>, <const1>|<field1>), - LT(<field>|<const>, <const2>|<field2>), END() - */ + switch (func_item->functype()) { + case Item_func::BETWEEN: + { + /* + Rewrite + <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2> + to <field>|<const> > <const1>|<field1> AND + <field>|<const> < <const2>|<field2> + or actually in prefix format + BEGIN(AND) GT(<field>|<const>, <const1>|<field1>), + LT(<field>|<const>, <const2>|<field2>), END() + */ if (rewrite_context->count == 2) { // Lower limit of BETWEEN @@ -6195,7 +6180,8 @@ void ndb_serialize_cond(const Item *item, void *arg) } break; } - case(Item_func::IN_FUNC): { + case Item_func::IN_FUNC: + { /* Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..) to <field>|<const> = <const1>|<field1> OR @@ -6244,8 +6230,10 @@ void ndb_serialize_cond(const Item *item, void *arg) curr_cond->ndb_item= new Ndb_item(NDB_END_COND); } else - switch(item->type()) { - case(Item::FIELD_ITEM): { + { + switch (item->type()) { + case Item::FIELD_ITEM: + { Item_field *field_item= (Item_field *) item; Field *field= field_item->field; enum_field_types type= field->type(); @@ -6291,23 +6279,23 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::INT_ITEM); } else - switch(field->result_type()) { - case(STRING_RESULT): + switch (field->result_type()) { + case STRING_RESULT: // Expect char string or binary string context->expect_only(Item::STRING_ITEM); context->expect(Item::VARBIN_ITEM); context->expect_collation(field_item->collation.collation); break; - case(REAL_RESULT): + case REAL_RESULT: context->expect_only(Item::REAL_ITEM); context->expect(Item::DECIMAL_ITEM); context->expect(Item::INT_ITEM); break; - case(INT_RESULT): + case INT_RESULT: context->expect_only(Item::INT_ITEM); context->expect(Item::VARBIN_ITEM); break; - case(DECIMAL_RESULT): + case DECIMAL_RESULT: context->expect_only(Item::DECIMAL_ITEM); context->expect(Item::REAL_ITEM); context->expect(Item::INT_ITEM); @@ -6352,7 +6340,8 @@ void ndb_serialize_cond(const Item *item, void *arg) } break; } - case(Item::FUNC_ITEM): { + case Item::FUNC_ITEM: + { Item_func *func_item= (Item_func *) item; // Check that we expect a function or functional expression here if (context->expecting(Item::FUNC_ITEM) || @@ -6365,8 +6354,9 @@ void ndb_serialize_cond(const Item *item, void *arg) break; } - switch(func_item->functype()) { - case(Item_func::EQ_FUNC): { + switch (func_item->functype()) { + case Item_func::EQ_FUNC: + { DBUG_PRINT("info", ("EQ_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6382,7 +6372,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::NE_FUNC): { + case Item_func::NE_FUNC: + { DBUG_PRINT("info", ("NE_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6398,7 +6389,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::LT_FUNC): { + case Item_func::LT_FUNC: + { DBUG_PRINT("info", ("LT_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6414,7 +6406,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::LE_FUNC): { + case Item_func::LE_FUNC: + { DBUG_PRINT("info", ("LE_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6430,7 +6423,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::GE_FUNC): { + case Item_func::GE_FUNC: + { DBUG_PRINT("info", ("GE_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6446,7 +6440,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::GT_FUNC): { + case Item_func::GT_FUNC: + { DBUG_PRINT("info", ("GT_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6462,7 +6457,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::LIKE_FUNC): { + case Item_func::LIKE_FUNC: + { DBUG_PRINT("info", ("LIKE_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6472,7 +6468,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::FUNC_ITEM); break; } - case(Item_func::NOTLIKE_FUNC): { + case Item_func::NOTLIKE_FUNC: + { DBUG_PRINT("info", ("NOTLIKE_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6482,7 +6479,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::FUNC_ITEM); break; } - case(Item_func::ISNULL_FUNC): { + case Item_func::ISNULL_FUNC: + { DBUG_PRINT("info", ("ISNULL_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6493,7 +6491,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::ISNOTNULL_FUNC): { + case Item_func::ISNOTNULL_FUNC: + { DBUG_PRINT("info", ("ISNOTNULL_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6504,7 +6503,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::NOT_FUNC): { + case Item_func::NOT_FUNC: + { DBUG_PRINT("info", ("NOT_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6512,7 +6512,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::COND_ITEM); break; } - case(Item_func::BETWEEN) : { + case Item_func::BETWEEN: + { DBUG_PRINT("info", ("BETWEEN, rewriting using AND")); Ndb_rewrite_context *rewrite_context= new Ndb_rewrite_context(func_item); @@ -6528,7 +6529,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::FUNC_ITEM); break; } - case(Item_func::IN_FUNC) : { + case Item_func::IN_FUNC: + { DBUG_PRINT("info", ("IN_FUNC, rewriting using OR")); Ndb_rewrite_context *rewrite_context= new Ndb_rewrite_context(func_item); @@ -6544,13 +6546,16 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::FUNC_ITEM); break; } - case(Item_func::UNKNOWN_FUNC): { + case Item_func::UNKNOWN_FUNC: + { DBUG_PRINT("info", ("UNKNOWN_FUNC %s", func_item->const_item()?"const":"")); DBUG_PRINT("info", ("result type %d", func_item->result_type())); if (func_item->const_item()) - switch(func_item->result_type()) { - case(STRING_RESULT): { + { + switch (func_item->result_type()) { + case STRING_RESULT: + { NDB_ITEM_QUALIFICATION q; q.value_type= Item::STRING_ITEM; curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); @@ -6579,7 +6584,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->skip= func_item->argument_count(); break; } - case(REAL_RESULT): { + case REAL_RESULT: + { NDB_ITEM_QUALIFICATION q; q.value_type= Item::REAL_ITEM; curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); @@ -6601,7 +6607,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->skip= func_item->argument_count(); break; } - case(INT_RESULT): { + case INT_RESULT: + { NDB_ITEM_QUALIFICATION q; q.value_type= Item::INT_ITEM; curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); @@ -6623,7 +6630,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->skip= func_item->argument_count(); break; } - case(DECIMAL_RESULT): { + case DECIMAL_RESULT: + { NDB_ITEM_QUALIFICATION q; q.value_type= Item::DECIMAL_ITEM; curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); @@ -6647,12 +6655,14 @@ void ndb_serialize_cond(const Item *item, void *arg) default: break; } + } else // Function does not return constant expression context->supported= FALSE; break; } - default: { + default: + { DBUG_PRINT("info", ("Found func_item of type %d", func_item->functype())); context->supported= FALSE; @@ -6660,7 +6670,7 @@ void ndb_serialize_cond(const Item *item, void *arg) } break; } - case(Item::STRING_ITEM): + case Item::STRING_ITEM: DBUG_PRINT("info", ("STRING_ITEM")); if (context->expecting(Item::STRING_ITEM)) { @@ -6699,7 +6709,7 @@ void ndb_serialize_cond(const Item *item, void *arg) else context->supported= FALSE; break; - case(Item::INT_ITEM): + case Item::INT_ITEM: DBUG_PRINT("info", ("INT_ITEM")); if (context->expecting(Item::INT_ITEM)) { @@ -6726,7 +6736,7 @@ void ndb_serialize_cond(const Item *item, void *arg) else context->supported= FALSE; break; - case(Item::REAL_ITEM): + case Item::REAL_ITEM: DBUG_PRINT("info", ("REAL_ITEM %s")); if (context->expecting(Item::REAL_ITEM)) { @@ -6751,7 +6761,7 @@ void ndb_serialize_cond(const Item *item, void *arg) else context->supported= FALSE; break; - case(Item::VARBIN_ITEM): + case Item::VARBIN_ITEM: DBUG_PRINT("info", ("VARBIN_ITEM")); if (context->expecting(Item::VARBIN_ITEM)) { @@ -6774,7 +6784,7 @@ void ndb_serialize_cond(const Item *item, void *arg) else context->supported= FALSE; break; - case(Item::DECIMAL_ITEM): + case Item::DECIMAL_ITEM: DBUG_PRINT("info", ("DECIMAL_ITEM %s")); if (context->expecting(Item::DECIMAL_ITEM)) { @@ -6800,17 +6810,19 @@ void ndb_serialize_cond(const Item *item, void *arg) else context->supported= FALSE; break; - case(Item::COND_ITEM): { + case Item::COND_ITEM: + { Item_cond *cond_item= (Item_cond *) item; if (context->expecting(Item::COND_ITEM)) - switch(cond_item->functype()) { - case(Item_func::COND_AND_FUNC): + { + switch (cond_item->functype()) { + case Item_func::COND_AND_FUNC: DBUG_PRINT("info", ("COND_AND_FUNC")); curr_cond->ndb_item= new Ndb_item(cond_item->functype(), cond_item); break; - case(Item_func::COND_OR_FUNC): + case Item_func::COND_OR_FUNC: DBUG_PRINT("info", ("COND_OR_FUNC")); curr_cond->ndb_item= new Ndb_item(cond_item->functype(), cond_item); @@ -6820,17 +6832,21 @@ void ndb_serialize_cond(const Item *item, void *arg) context->supported= FALSE; break; } + } else - // Did not expect condition + { + /* Did not expect condition */ context->supported= FALSE; + } break; } - default: { + default: + { DBUG_PRINT("info", ("Found item of type %d", item->type())); context->supported= FALSE; } } - + } if (context->supported && context->rewrite_stack) { Ndb_rewrite_context *rewrite_context= context->rewrite_stack; @@ -6874,18 +6890,19 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, bool negated) { DBUG_ENTER("build_scan_filter_predicate"); - switch(cond->ndb_item->type) { - case(NDB_FUNCTION): { + switch (cond->ndb_item->type) { + case NDB_FUNCTION: + { if (!cond->next) break; Ndb_item *a= cond->next->ndb_item; Ndb_item *b, *field, *value= NULL; - switch(cond->ndb_item->argument_count()) { - case(1): + switch (cond->ndb_item->argument_count()) { + case 1: field= (a->type == NDB_FIELD)? a : NULL; break; - case(2): + case 2: if (!cond->next->next) break; b= cond->next->next->ndb_item; @@ -6901,11 +6918,11 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, default: break; } - switch((negated) ? - Ndb_item::negate(cond->ndb_item->qualification.function_type) - : cond->ndb_item->qualification.function_type) + switch ((negated) ? + Ndb_item::negate(cond->ndb_item->qualification.function_type) + : cond->ndb_item->qualification.function_type) { + case Item_func::EQ_FUNC: { - case(Item_func::EQ_FUNC): { if (!value || !field) break; // Save value in right format for the field type value->save_in_field(field); @@ -6918,7 +6935,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::NE_FUNC): { + case Item_func::NE_FUNC: + { if (!value || !field) break; // Save value in right format for the field type value->save_in_field(field); @@ -6931,7 +6949,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::LT_FUNC): { + case Item_func::LT_FUNC: + { if (!value || !field) break; // Save value in right format for the field type value->save_in_field(field); @@ -6956,7 +6975,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::LE_FUNC): { + case Item_func::LE_FUNC: + { if (!value || !field) break; // Save value in right format for the field type value->save_in_field(field); @@ -6981,7 +7001,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::GE_FUNC): { + case Item_func::GE_FUNC: + { if (!value || !field) break; // Save value in right format for the field type value->save_in_field(field); @@ -7006,7 +7027,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::GT_FUNC): { + case Item_func::GT_FUNC: + { if (!value || !field) break; // Save value in right format for the field type value->save_in_field(field); @@ -7031,7 +7053,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::LIKE_FUNC): { + case Item_func::LIKE_FUNC: + { if (!value || !field) break; if ((value->qualification.value_type != Item::STRING_ITEM) && (value->qualification.value_type != Item::VARBIN_ITEM)) @@ -7049,7 +7072,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::NOTLIKE_FUNC): { + case Item_func::NOTLIKE_FUNC: + { if (!value || !field) break; if ((value->qualification.value_type != Item::STRING_ITEM) && (value->qualification.value_type != Item::VARBIN_ITEM)) @@ -7067,7 +7091,7 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::ISNULL_FUNC): + case Item_func::ISNULL_FUNC: if (!field) break; DBUG_PRINT("info", ("Generating ISNULL filter")); @@ -7075,7 +7099,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, DBUG_RETURN(1); cond= cond->next->next; DBUG_RETURN(0); - case(Item_func::ISNOTNULL_FUNC): { + case Item_func::ISNOTNULL_FUNC: + { if (!field) break; DBUG_PRINT("info", ("Generating ISNOTNULL filter")); @@ -7101,15 +7126,18 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) { uint level=0; bool negated= FALSE; - DBUG_ENTER("build_scan_filter_group"); + do { - if (!cond) DBUG_RETURN(1); - switch(cond->ndb_item->type) { - case(NDB_FUNCTION): - switch(cond->ndb_item->qualification.function_type) { - case(Item_func::COND_AND_FUNC): { + if (!cond) + DBUG_RETURN(1); + switch (cond->ndb_item->type) { + case NDB_FUNCTION: + { + switch (cond->ndb_item->qualification.function_type) { + case Item_func::COND_AND_FUNC: + { level++; DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NAND":"AND", level)); @@ -7120,7 +7148,8 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) cond= cond->next; break; } - case(Item_func::COND_OR_FUNC): { + case Item_func::COND_OR_FUNC: + { level++; DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NOR":"OR", level)); @@ -7131,11 +7160,11 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) cond= cond->next; break; } - case(Item_func::NOT_FUNC): { + case Item_func::NOT_FUNC: + { DBUG_PRINT("info", ("Generating negated query")); cond= cond->next; negated= TRUE; - break; } default: @@ -7145,7 +7174,8 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) break; } break; - case(NDB_END_COND): + } + case NDB_END_COND: DBUG_PRINT("info", ("End of group %u", level)); level--; if (cond) cond= cond->next; @@ -7154,7 +7184,8 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) if (!negated) break; // else fall through (NOT END is an illegal condition) - default: { + default: + { DBUG_PRINT("info", ("Illegal scan filter")); } } @@ -7169,11 +7200,11 @@ ha_ndbcluster::build_scan_filter(Ndb_cond * &cond, NdbScanFilter *filter) bool simple_cond= TRUE; DBUG_ENTER("build_scan_filter"); - switch(cond->ndb_item->type) { - case(NDB_FUNCTION): - switch(cond->ndb_item->qualification.function_type) { - case(Item_func::COND_AND_FUNC): - case(Item_func::COND_OR_FUNC): + switch (cond->ndb_item->type) { + case NDB_FUNCTION: + switch (cond->ndb_item->qualification.function_type) { + case Item_func::COND_AND_FUNC: + case Item_func::COND_OR_FUNC: simple_cond= FALSE; break; default: diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index f73ca8a974e..6efc18f2f6a 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -551,7 +551,7 @@ private: int pk_read(const byte *key, uint key_len, byte *buf); int complemented_pk_read(const byte *old_data, byte *new_data); - int peek_row(); + int peek_row(const byte *record); int unique_index_read(const byte *key, uint key_len, byte *buf); int ordered_index_scan(const key_range *start_key, @@ -580,8 +580,7 @@ private: friend int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg); int get_ndb_blobs_value(NdbBlob *last_ndb_blob); int set_primary_key(NdbOperation *op, const byte *key); - int set_primary_key(NdbOperation *op); - int set_primary_key_from_old_data(NdbOperation *op, const byte *old_data); + int set_primary_key_from_record(NdbOperation *op, const byte *record); int set_bounds(NdbIndexScanOperation*, const key_range *keys[2], uint= 0); int key_cmp(uint keynr, const byte * old_row, const byte * new_row); int set_index_key(NdbOperation *, const KEY *key_info, const byte *key_ptr); @@ -680,7 +679,8 @@ int ndbcluster_discover(THD* thd, const char* dbname, const char* name, const void** frmblob, uint* frmlen); int ndbcluster_find_files(THD *thd,const char *db,const char *path, const char *wild, bool dir, List<char> *files); -int ndbcluster_table_exists(THD* thd, const char *db, const char *name); +int ndbcluster_table_exists_in_engine(THD* thd, + const char *db, const char *name); int ndbcluster_drop_database(const char* path); void ndbcluster_print_error(int error, const NdbOperation *error_op); diff --git a/sql/handler.cc b/sql/handler.cc index 06a1c09fcc8..bf2ce0dad4e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2041,21 +2041,19 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info, } /* - Try to discover table from engine and + Try to discover table from engine and if found, write the frm file to disk. - + RETURN VALUES: - 0 : Table existed in engine and created - on disk if so requested - 1 : Table does not exist - >1 : error + -1 : Table did not exists + 0 : Table created ok + > 0 : Error, table existed but could not be created */ -int ha_create_table_from_engine(THD* thd, - const char *db, - const char *name, - bool create_if_found) +int ha_create_table_from_engine(THD* thd, + const char *db, + const char *name) { int error; const void *frmblob; @@ -2064,45 +2062,43 @@ int ha_create_table_from_engine(THD* thd, HA_CREATE_INFO create_info; TABLE table; DBUG_ENTER("ha_create_table_from_engine"); - DBUG_PRINT("enter", ("name '%s'.'%s' create_if_found: %d", - db, name, create_if_found)); + DBUG_PRINT("enter", ("name '%s'.'%s'", db, name)); bzero((char*) &create_info,sizeof(create_info)); - if ((error= ha_discover(thd, db, name, &frmblob, &frmlen))) - DBUG_RETURN(error); + { + /* Table could not be discovered and thus not created */ + DBUG_RETURN(error); + } + /* - Table exists in handler - frmblob and frmlen are set + Table exists in handler and could be discovered + frmblob and frmlen are set, write the frm to disk */ - if (create_if_found) - { - (void)strxnmov(path,FN_REFLEN,mysql_data_home,"/",db,"/",name,NullS); - // Save the frm file - if ((error = writefrm(path, frmblob, frmlen))) - goto err_end; + (void)strxnmov(path,FN_REFLEN,mysql_data_home,"/",db,"/",name,NullS); + // Save the frm file + error= writefrm(path, frmblob, frmlen); + my_free((char*) frmblob, MYF(0)); + if (error) + DBUG_RETURN(2); - if (openfrm(thd, path,"",0,(uint) READ_ALL, 0, &table)) - DBUG_RETURN(1); + if (openfrm(thd, path,"",0,(uint) READ_ALL, 0, &table)) + DBUG_RETURN(3); - update_create_info_from_table(&create_info, &table); - create_info.table_options|= HA_CREATE_FROM_ENGINE; + update_create_info_from_table(&create_info, &table); + create_info.table_options|= HA_CREATE_FROM_ENGINE; - if (lower_case_table_names == 2 && - !(table.file->table_flags() & HA_FILE_BASED)) - { - /* Ensure that handler gets name in lower case */ - my_casedn_str(files_charset_info, path); - } - - error=table.file->create(path,&table,&create_info); - VOID(closefrm(&table)); + if (lower_case_table_names == 2 && + !(table.file->table_flags() & HA_FILE_BASED)) + { + /* Ensure that handler gets name in lower case */ + my_casedn_str(files_charset_info, path); } + error=table.file->create(path,&table,&create_info); + VOID(closefrm(&table)); -err_end: - my_free((char*) frmblob, MYF(MY_ALLOW_ZERO_PTR)); - DBUG_RETURN(error); + DBUG_RETURN(error != 0); } void st_ha_check_opt::init() @@ -2205,14 +2201,15 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, Try to discover one table from handler(s) RETURN - 0 ok. In this case *frmblob and *frmlen are set - 1 error. frmblob and frmlen may not be set + -1 : Table did not exists + 0 : OK. In this case *frmblob and *frmlen are set + >0 : error. frmblob and frmlen may not be set */ int ha_discover(THD *thd, const char *db, const char *name, const void **frmblob, uint *frmlen) { - int error= 1; // Table does not exist in any handler + int error= -1; // Table does not exist in any handler DBUG_ENTER("ha_discover"); DBUG_PRINT("enter", ("db: %s, name: %s", db, name)); #ifdef HAVE_NDBCLUSTER_DB @@ -2244,11 +2241,8 @@ ha_find_files(THD *thd,const char *db,const char *path, error= ndbcluster_find_files(thd, db, path, wild, dir, files); #endif DBUG_RETURN(error); - - } -#ifdef NOT_YET_USED /* Ask handler if the table exists in engine @@ -2259,20 +2253,19 @@ ha_find_files(THD *thd,const char *db,const char *path, # Error code */ -int ha_table_exists(THD* thd, const char* db, const char* name) +int ha_table_exists_in_engine(THD* thd, const char* db, const char* name) { - int error= 2; - DBUG_ENTER("ha_table_exists"); + int error= 0; + DBUG_ENTER("ha_table_exists_in_engine"); DBUG_PRINT("enter", ("db: %s, name: %s", db, name)); #ifdef HAVE_NDBCLUSTER_DB if (have_ndbcluster == SHOW_OPTION_YES) - error= ndbcluster_table_exists(thd, db, name); + error= ndbcluster_table_exists_in_engine(thd, db, name); #endif + DBUG_PRINT("exit", ("error: %d", error)); DBUG_RETURN(error); } -#endif - /* Read the first row of a multi-range set. diff --git a/sql/handler.h b/sql/handler.h index f4efdd0ed8a..d7fe19ad884 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1047,13 +1047,12 @@ int ha_delete_table(THD *thd, enum db_type db_type, const char *path, const char *alias, bool generate_warning); /* discovery */ -int ha_create_table_from_engine(THD* thd, const char *db, const char *name, - bool create_if_found); +int ha_create_table_from_engine(THD* thd, const char *db, const char *name); int ha_discover(THD* thd, const char* dbname, const char* name, const void** frmblob, uint* frmlen); int ha_find_files(THD *thd,const char *db,const char *path, const char *wild, bool dir,List<char>* files); -int ha_table_exists(THD* thd, const char* db, const char* name); +int ha_table_exists_in_engine(THD* thd, const char* db, const char* name); /* key cache */ int ha_init_key_cache(const char *name, KEY_CACHE *key_cache); diff --git a/sql/item.cc b/sql/item.cc index ec685982304..c210ea3ca45 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -338,7 +338,6 @@ Item::Item(): place == IN_HAVING) thd->lex->current_select->select_n_having_items++; } - item_flags= 0; } /* @@ -359,8 +358,7 @@ Item::Item(THD *thd, Item *item): unsigned_flag(item->unsigned_flag), with_sum_func(item->with_sum_func), fixed(item->fixed), - collation(item->collation), - item_flags(item->item_flags) + collation(item->collation) { next= thd->free_list; // Put in free list thd->free_list= this; @@ -440,16 +438,17 @@ void Item::rename(char *new_name) } -Item_ident::Item_ident(const char *db_name_par,const char *table_name_par, - const char *field_name_par) - :orig_db_name(db_name_par), orig_table_name(table_name_par), - orig_field_name(field_name_par), - db_name(db_name_par), table_name(table_name_par), - field_name(field_name_par), +Item_ident::Item_ident(Name_resolution_context *context_arg, + const char *db_name_arg,const char *table_name_arg, + const char *field_name_arg) + :orig_db_name(db_name_arg), orig_table_name(table_name_arg), + orig_field_name(field_name_arg), context(context_arg), + db_name(db_name_arg), table_name(table_name_arg), + field_name(field_name_arg), alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX), cached_table(0), depended_from(0) { - name = (char*) field_name_par; + name = (char*) field_name_arg; } @@ -460,6 +459,7 @@ Item_ident::Item_ident(THD *thd, Item_ident *item) orig_db_name(item->orig_db_name), orig_table_name(item->orig_table_name), orig_field_name(item->orig_field_name), + context(item->context), db_name(item->db_name), table_name(item->table_name), field_name(item->field_name), @@ -785,7 +785,7 @@ Item_splocal::type() const } -bool Item_splocal::fix_fields(THD *, struct st_table_list *, Item **) +bool Item_splocal::fix_fields(THD *, Item **) { Item *it= this_item(); DBUG_ASSERT(it->fixed); @@ -855,7 +855,8 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, uint el= fields.elements; Item *new_item; ref_pointer_array[el]= this; - if (!(new_item= new Item_ref(ref_pointer_array + el, 0, name))) + if (!(new_item= new Item_ref(&thd->lex->current_select->context, + ref_pointer_array + el, 0, name))) return; // fatal_error is set fields.push_front(this); ref_pointer_array[el]= this; @@ -995,7 +996,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags) } Item_field::Item_field(Field *f) - :Item_ident(NullS, *f->table_name, f->field_name), + :Item_ident(0, NullS, *f->table_name, f->field_name), item_equal(0), no_const_subst(0), have_privileges(0), any_privileges(0) { @@ -1007,8 +1008,9 @@ Item_field::Item_field(Field *f) orig_table_name= orig_field_name= ""; } -Item_field::Item_field(THD *thd, Field *f) - :Item_ident(f->table->s->db, *f->table_name, f->field_name), +Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, + Field *f) + :Item_ident(context_arg, f->table->s->db, *f->table_name, f->field_name), item_equal(0), no_const_subst(0), have_privileges(0), any_privileges(0) { @@ -1043,6 +1045,17 @@ Item_field::Item_field(THD *thd, Field *f) set_field(f); } + +Item_field::Item_field(Name_resolution_context *context_arg, + const char *db_arg,const char *table_name_arg, + const char *field_name_arg) + :Item_ident(context_arg, db_arg,table_name_arg,field_name_arg), + field(0), result_field(0), item_equal(0), no_const_subst(0), + have_privileges(0), any_privileges(0) +{ + collation.set(DERIVATION_IMPLICIT); +} + // Constructor need to process subselect with temporary tables (see Item) Item_field::Item_field(THD *thd, Item_field *item) :Item_ident(thd, item), @@ -2233,7 +2246,7 @@ bool Item_param::convert_str_value(THD *thd) return rc; } -bool Item_param::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +bool Item_param::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); SELECT_LEX *cursel= (SELECT_LEX *) thd->lex->current_select; @@ -2393,9 +2406,7 @@ int Item_copy_string::save_in_field(Field *field, bool no_conversions) */ /* ARGSUSED */ -bool Item::fix_fields(THD *thd, - struct st_table_list *list, - Item ** ref) +bool Item::fix_fields(THD *thd, Item ** ref) { // We do not check fields which are fixed during construction @@ -2762,7 +2773,6 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) SYNOPSIS Item_field::fix_fields() thd [in] current thread - tables [in] the tables in a FROM clause reference [in/out] view column if this item was resolved to a view column DESCRIPTION @@ -2808,7 +2818,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) FALSE on success */ -bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) +bool Item_field::fix_fields(THD *thd, Item **reference) { enum_parsing_place place= NO_MATTER; DBUG_ASSERT(fixed == 0); @@ -2821,135 +2831,131 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) expression to 'reference', i.e. it substitute that expression instead of this Item_field */ - if ((from_field= find_field_in_tables(thd, this, tables, reference, - IGNORE_EXCEPT_NON_UNIQUE, - !any_privileges)) == + if ((from_field= find_field_in_tables(thd, this, context->table_list, + reference, + IGNORE_EXCEPT_NON_UNIQUE, + !any_privileges && + context->check_privileges, + TRUE)) == not_found_field) { - SELECT_LEX *last= 0; - TABLE_LIST *table_list; - Item **ref= (Item **) not_found_item; - SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select; /* - If there is an outer select, and it is not a derived table (which do - not support the use of outer fields for now), try to resolve this - reference in the outer select(s). - + If there is an outer contexts (outer selects, but current select is + not derived table or view) try to resolve this reference in the + outer contexts. + We treat each subselect as a separate namespace, so that different subselects may contain columns with the same names. The subselects are - searched starting from the innermost. + searched starting from the innermost. */ - if (current_sel->master_unit()->first_select()->linkage != - DERIVED_TABLE_TYPE) + Name_resolution_context *last_checked_context= context; + Item **ref= (Item **) not_found_item; + Name_resolution_context *outer_context= context->outer_context; + for (; + outer_context; + outer_context= outer_context->outer_context) { - SELECT_LEX_UNIT *prev_unit= current_sel->master_unit(); - SELECT_LEX *outer_sel= prev_unit->outer_select(); - for ( ; outer_sel ; - outer_sel= (prev_unit= outer_sel->master_unit())->outer_select()) - { - last= outer_sel; - Item_subselect *prev_subselect_item= prev_unit->item; - upward_lookup= TRUE; - - /* Search in the tables of the FROM clause of the outer select. */ - table_list= outer_sel->get_table_list(); - if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list) - { - /* - It is a primary INSERT st_select_lex => do not resolve against the - first table. - */ - table_list= table_list->next_local; - } - place= prev_subselect_item->parsing_place; - /* - Check table fields only if the subquery is used somewhere out of - HAVING, or the outer SELECT does not use grouping (i.e. tables are - accessible). + SELECT_LEX *select= outer_context->select_lex; + Item_subselect *prev_subselect_item= + last_checked_context->select_lex->master_unit()->item; + last_checked_context= outer_context; + upward_lookup= TRUE; - In case of view, find_field_in_tables() write pointer to view - field expression to 'reference', i.e. it substitute that - expression instead of this Item_field - */ - if ((place != IN_HAVING || - (outer_sel->with_sum_func == 0 && - outer_sel->group_list.elements == 0)) && - (from_field= find_field_in_tables(thd, this, table_list, - reference, - IGNORE_EXCEPT_NON_UNIQUE, - TRUE)) != - not_found_field) - { - if (from_field) - { - if (from_field != view_ref_found) - { - prev_subselect_item->used_tables_cache|= from_field->table->map; - prev_subselect_item->const_item_cache= 0; - } - else - { - Item::Type type= (*reference)->type(); - prev_subselect_item->used_tables_cache|= - (*reference)->used_tables(); - prev_subselect_item->const_item_cache&= - (*reference)->const_item(); - mark_as_dependent(thd, last, current_sel, this, - ((type == REF_ITEM || type == FIELD_ITEM) ? - (Item_ident*) (*reference) : - 0)); - /* - view reference found, we substituted it instead of this - Item (find_field_in_tables do it by assigning new value to - *reference), so can quit - */ - return FALSE; - } - } - break; - } + place= prev_subselect_item->parsing_place; + /* + Check table fields only if the subquery is used somewhere out of + HAVING, or the outer SELECT does not use grouping (i.e. tables are + accessible). - /* Search in the SELECT and GROUP lists of the outer select. */ - if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE) + In case of a view, find_field_in_tables() writes the pointer to + the found view field into '*reference', in other words, it + substitutes this Item_field with the found expression. + */ + if ((place != IN_HAVING || + (!select->with_sum_func && + select->group_list.elements == 0)) && + (from_field= find_field_in_tables(thd, this, + outer_context->table_list, + reference, + IGNORE_EXCEPT_NON_UNIQUE, + outer_context-> + check_privileges, + TRUE)) != + not_found_field) + { + if (from_field) { - if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel))) - return TRUE; /* Some error occurred (e.g. ambiguous names). */ - if (ref != not_found_item) + if (from_field != view_ref_found) + { + prev_subselect_item->used_tables_cache|= from_field->table->map; + prev_subselect_item->const_item_cache= 0; + } + else { - DBUG_ASSERT(*ref && (*ref)->fixed); - prev_subselect_item->used_tables_cache|= (*ref)->used_tables(); - prev_subselect_item->const_item_cache&= (*ref)->const_item(); - break; + Item::Type type= (*reference)->type(); + prev_subselect_item->used_tables_cache|= + (*reference)->used_tables(); + prev_subselect_item->const_item_cache&= + (*reference)->const_item(); + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, + ((type == REF_ITEM || type == FIELD_ITEM) ? + (Item_ident*) (*reference) : + 0)); + /* + A reference to a view field had been found and we + substituted it instead of this Item (find_field_in_tables + does it by assigning the new value to *reference), so now + we can return from this function. + */ + return FALSE; } - } + } + break; + } - // Reference is not found => depend from outer (or just error) - prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; - prev_subselect_item->const_item_cache= 0; + /* Search in SELECT and GROUP lists of the outer select. */ + if (outer_context->resolve_in_select_list) + { + if (!(ref= resolve_ref_in_select_and_group(thd, this, select))) + goto error; /* Some error occurred (e.g. ambiguous names). */ + if (ref != not_found_item) + { + DBUG_ASSERT(*ref && (*ref)->fixed); + prev_subselect_item->used_tables_cache|= (*ref)->used_tables(); + prev_subselect_item->const_item_cache&= (*ref)->const_item(); + break; + } + } - if (outer_sel->master_unit()->first_select()->linkage == - DERIVED_TABLE_TYPE) - break; // do not look over derived table - } + /* + Reference is not found in this select => this subquery depend on + outer select (or we just trying to find wrong identifier, in this + case it does not matter which used tables bits we set) + */ + prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; + prev_subselect_item->const_item_cache= 0; } DBUG_ASSERT(ref != 0); if (!from_field) - return TRUE; + goto error; if (ref == not_found_item && from_field == not_found_field) { if (upward_lookup) { - // We can't say exactly what absent table or field + // We can't say exactly what absent table or field my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where); } else { - // Call to report error - find_field_in_tables(thd, this, tables, reference, REPORT_ALL_ERRORS, - TRUE); + /* Call find_field_in_tables only to report the error */ + find_field_in_tables(thd, this, context->table_list, + reference, REPORT_ALL_ERRORS, + !any_privileges && + context->check_privileges, TRUE); } - return TRUE; + goto error; } else if (ref != not_found_item) { @@ -2967,45 +2973,54 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) save= *ref; *ref= NULL; // Don't call set_properties() rf= (place == IN_HAVING ? - new Item_ref(ref, (char*) table_name, (char*) field_name) : - new Item_direct_ref(ref, (char*) table_name, (char*) field_name)); + new Item_ref(context, ref, (char*) table_name, + (char*) field_name) : + new Item_direct_ref(context, ref, (char*) table_name, + (char*) field_name)); *ref= save; if (!rf) - return TRUE; + goto error; thd->change_item_tree(reference, rf); /* rf is Item_ref => never substitute other items (in this case) during fix_fields() => we can use rf after fix_fields() */ DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() - if (rf->fix_fields(thd, tables, reference) || rf->check_cols(1)) - return TRUE; + if (rf->fix_fields(thd, reference) || rf->check_cols(1)) + goto error; - mark_as_dependent(thd, last, current_sel, this, rf); + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, + rf); return FALSE; } else { - mark_as_dependent(thd, last, current_sel, this, this); - if (last->having_fix_field) + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, + this, this); + if (last_checked_context->select_lex->having_fix_field) { Item_ref *rf; - rf= new Item_ref((cached_table->db[0] ? cached_table->db : 0), + rf= new Item_ref(context, + (cached_table->db[0] ? cached_table->db : 0), (char*) cached_table->alias, (char*) field_name); if (!rf) - return TRUE; + goto error; thd->change_item_tree(reference, rf); /* rf is Item_ref => never substitute other items (in this case) during fix_fields() => we can use rf after fix_fields() */ DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() - return (rf->fix_fields(thd, tables, reference) || rf->check_cols(1)); + if (rf->fix_fields(thd, reference) || rf->check_cols(1)) + goto error; + return FALSE; } } } else if (!from_field) - return TRUE; + goto error; /* if it is not expression from merged VIEW we will set this field. @@ -3058,12 +3073,16 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY", thd->priv_user, thd->host_or_ip, field_name, tab); - return TRUE; + goto error; } } #endif fixed= 1; return FALSE; + +error: + context->process_error(thd); + return TRUE; } @@ -3352,6 +3371,9 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) case MYSQL_TYPE_YEAR: return new Field_year((char*) 0, max_length, null_ptr, 0, Field::NONE, name, table); + case MYSQL_TYPE_BIT: + return new Field_bit_as_char(NULL, max_length, null_ptr, 0, NULL, 0, + Field::NONE, name, table); default: /* This case should never be chosen */ DBUG_ASSERT(0); @@ -3578,7 +3600,7 @@ Item *Item_int_with_ref::new_item() Item_num *Item_uint::neg() { - Item_decimal *item= new Item_decimal(value, 0); + Item_decimal *item= new Item_decimal(value, 1); return item->neg(); } @@ -3924,16 +3946,17 @@ bool Item_field::send(Protocol *protocol, String *buffer) } -Item_ref::Item_ref(Item **item, const char *table_name_par, - const char *field_name_par) - :Item_ident(NullS, table_name_par, field_name_par), result_field(0), - ref(item) +Item_ref::Item_ref(Name_resolution_context *context_arg, + Item **item, const char *table_name_arg, + const char *field_name_arg) + :Item_ident(context_arg, NullS, table_name_arg, field_name_arg), + result_field(0), ref(item) { /* This constructor used to create some internals references over fixed items */ DBUG_ASSERT(ref != 0); - if (*ref) + if (*ref && (*ref)->fixed) set_properties(); } @@ -3944,7 +3967,6 @@ Item_ref::Item_ref(Item **item, const char *table_name_par, SYNOPSIS Item_ref::fix_fields() thd [in] current thread - tables [in] the tables in a FROM clause reference [in/out] view column if this item was resolved to a view column DESCRIPTION @@ -3996,59 +4018,56 @@ Item_ref::Item_ref(Item **item, const char *table_name_par, FALSE on success */ -bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) +bool Item_ref::fix_fields(THD *thd, Item **reference) { - DBUG_ASSERT(fixed == 0); enum_parsing_place place= NO_MATTER; + DBUG_ASSERT(fixed == 0); SELECT_LEX *current_sel= thd->lex->current_select; if (!ref || ref == not_found_item) { - SELECT_LEX_UNIT *prev_unit= current_sel->master_unit(); - SELECT_LEX *outer_sel= prev_unit->outer_select(); - - if (!(ref= resolve_ref_in_select_and_group(thd, this, current_sel))) - return TRUE; /* Some error occurred (e.g. ambiguous names). */ + if (!(ref= resolve_ref_in_select_and_group(thd, this, + context->select_lex))) + goto error; /* Some error occurred (e.g. ambiguous names). */ if (ref == not_found_item) /* This reference was not resolved. */ { - TABLE_LIST *table_list; + Name_resolution_context *last_checked_context= context; + Name_resolution_context *outer_context= context->outer_context; Field *from_field; - SELECT_LEX *last; ref= 0; - if (!outer_sel || (current_sel->master_unit()->first_select()->linkage == - DERIVED_TABLE_TYPE)) + if (!outer_context) { /* The current reference cannot be resolved in this query. */ my_error(ER_BAD_FIELD_ERROR,MYF(0), this->full_name(), current_thd->where); - return TRUE; + goto error; } + /* - If there is an outer select, and it is not a derived table (which do - not support the use of outer fields for now), try to resolve this - reference in the outer select(s). + If there is an outer context (select), and it is not a derived table + (which do not support the use of outer fields for now), try to + resolve this reference in the outer select(s). We treat each subselect as a separate namespace, so that different subselects may contain columns with the same names. The subselects are searched starting from the innermost. */ from_field= (Field*) not_found_field; - last= 0; - /* The following loop will always be excuted at least once */ - for ( ; outer_sel ; - outer_sel= (prev_unit= outer_sel->master_unit())->outer_select()) + do { - last= outer_sel; - Item_subselect *prev_subselect_item= prev_unit->item; + SELECT_LEX *select= outer_context->select_lex; + Item_subselect *prev_subselect_item= + last_checked_context->select_lex->master_unit()->item; + last_checked_context= outer_context; /* Search in the SELECT and GROUP lists of the outer select. */ - if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE) + if (outer_context->resolve_in_select_list) { - if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel))) - return TRUE; /* Some error occurred (e.g. ambiguous names). */ + if (!(ref= resolve_ref_in_select_and_group(thd, this, select))) + goto error; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { DBUG_ASSERT(*ref && (*ref)->fixed); @@ -4064,43 +4083,34 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) ref= 0; } - /* Search in the tables of the FROM clause of the outer select. */ - table_list= outer_sel->get_table_list(); - if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list) - { - /* - It is a primary INSERT st_select_lex => do not resolve against - the first table. - */ - table_list= table_list->next_local; - } - place= prev_subselect_item->parsing_place; /* Check table fields only if the subquery is used somewhere out of HAVING or the outer SELECT does not use grouping (i.e. tables are accessible). - TODO: + TODO: Here we could first find the field anyway, and then test this condition, so that we can give a better error message - ER_WRONG_FIELD_WITH_GROUP, instead of the less informative ER_BAD_FIELD_ERROR which we produce now. */ if ((place != IN_HAVING || - (!outer_sel->with_sum_func && - outer_sel->group_list.elements == 0))) + (!select->with_sum_func && + select->group_list.elements == 0))) { /* In case of view, find_field_in_tables() write pointer to view field expression to 'reference', i.e. it substitute that expression instead of this Item_ref */ - from_field= find_field_in_tables(thd, this, table_list, + from_field= find_field_in_tables(thd, this, + outer_context->table_list, reference, IGNORE_EXCEPT_NON_UNIQUE, + outer_context->check_privileges, TRUE); if (! from_field) - return TRUE; + goto error; if (from_field == view_ref_found) { Item::Type type= (*reference)->type(); @@ -4109,7 +4119,8 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) prev_subselect_item->const_item_cache&= (*reference)->const_item(); DBUG_ASSERT((*reference)->type() == REF_ITEM); - mark_as_dependent(thd, last, current_sel, this, + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, ((type == REF_ITEM || type == FIELD_ITEM) ? (Item_ident*) (*reference) : 0)); @@ -4132,19 +4143,18 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; prev_subselect_item->const_item_cache= 0; - if (outer_sel->master_unit()->first_select()->linkage == - DERIVED_TABLE_TYPE) - break; /* Do not consider derived tables. */ - } + outer_context= outer_context->outer_context; + } while (outer_context); DBUG_ASSERT(from_field != 0 && from_field != view_ref_found); if (from_field != not_found_field) { Item_field* fld; if (!(fld= new Item_field(from_field))) - return TRUE; + goto error; thd->change_item_tree(reference, fld); - mark_as_dependent(thd, last, thd->lex->current_select, this, fld); + mark_as_dependent(thd, last_checked_context->select_lex, + thd->lex->current_select, this, fld); return FALSE; } if (ref == 0) @@ -4152,11 +4162,12 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) /* The item was not a table field and not a reference */ my_error(ER_BAD_FIELD_ERROR, MYF(0), this->full_name(), current_thd->where); - return TRUE; + goto error; } /* Should be checked in resolve_ref_in_select_and_group(). */ DBUG_ASSERT(*ref && (*ref)->fixed); - mark_as_dependent(thd, last, current_sel, this, this); + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, this); } } @@ -4176,14 +4187,18 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) name, ((*ref)->with_sum_func? "reference to group function": "forward reference in item list")); - return TRUE; + goto error; } set_properties(); if ((*ref)->check_cols(1)) - return TRUE; + goto error; return FALSE; + +error: + context->process_error(thd); + return TRUE; } @@ -4371,18 +4386,16 @@ my_decimal *Item_ref::val_decimal(my_decimal *decimal_value) int Item_ref::save_in_field(Field *to, bool no_conversions) { int res; - if(result_field){ + if (result_field) + { if (result_field->is_null()) { null_value= 1; return set_field_to_null_with_conversions(to, no_conversions); } - else - { - to->set_notnull(); - field_conv(to, result_field); - null_value= 0; - } + to->set_notnull(); + field_conv(to, result_field); + null_value= 0; return 0; } res= (*ref)->save_in_field(to, no_conversions); @@ -4391,6 +4404,19 @@ int Item_ref::save_in_field(Field *to, bool no_conversions) } +void Item_ref::make_field(Send_field *field) +{ + (*ref)->make_field(field); + /* Non-zero in case of a view */ + if (name) + field->col_name= name; + if (table_name) + field->table_name= table_name; + if (db_name) + field->db_name= db_name; +} + + void Item_ref_null_helper::print(String *str) { str->append("<ref_null_helper>(", 18); @@ -4454,6 +4480,31 @@ bool Item_direct_ref::get_date(TIME *ltime,uint fuzzydate) } +/* + Prepare referenced view viewld then call usual Item_direct_ref::fix_fields + + SYNOPSIS + Item_direct_view_ref::fix_fields() + thd thread handler + reference reference on reference where this item stored + + RETURN + FALSE OK + TRUE Error +*/ + +bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) +{ + /* view fild reference must be defined */ + DBUG_ASSERT(*ref); + /* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */ + if (!(*ref)->fixed && + ((*ref)->fix_fields(thd, ref))) + return TRUE; + return Item_direct_ref::fix_fields(thd, reference); +} + + void Item_null_helper::print(String *str) { str->append("<null_helper>(", 14); @@ -4469,9 +4520,7 @@ bool Item_default_value::eq(const Item *item, bool binary_cmp) const } -bool Item_default_value::fix_fields(THD *thd, - struct st_table_list *table_list, - Item **items) +bool Item_default_value::fix_fields(THD *thd, Item **items) { Item *real_arg; Item_field *field_arg; @@ -4483,29 +4532,34 @@ bool Item_default_value::fix_fields(THD *thd, fixed= 1; return FALSE; } - if (!arg->fixed && arg->fix_fields(thd, table_list, &arg)) - return TRUE; + if (!arg->fixed && arg->fix_fields(thd, &arg)) + goto error; + real_arg= arg->real_item(); if (real_arg->type() != FIELD_ITEM) { my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name); - return TRUE; + goto error; } field_arg= (Item_field *)real_arg; if (field_arg->field->flags & NO_DEFAULT_VALUE_FLAG) { my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), field_arg->field->field_name); - return TRUE; + goto error; } if (!(def_field= (Field*) sql_alloc(field_arg->field->size_of()))) - return TRUE; + goto error; memcpy(def_field, field_arg->field, field_arg->field->size_of()); def_field->move_field(def_field->table->s->default_values - def_field->table->record[0]); set_field(def_field); return FALSE; + +error: + context->process_error(thd); + return TRUE; } @@ -4528,11 +4582,27 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) { if (field_arg->flags & NO_DEFAULT_VALUE_FLAG) { - push_warning_printf(field_arg->table->in_use, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_NO_DEFAULT_FOR_FIELD, - ER(ER_NO_DEFAULT_FOR_FIELD), - field_arg->field_name); + if (context->error_processor == &view_error_processor) + { + TABLE_LIST *view= (cached_table->belong_to_view ? + cached_table->belong_to_view : + cached_table); + // TODO: make correct error message + push_warning_printf(field_arg->table->in_use, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_VIEW_FIELD, + ER(ER_NO_DEFAULT_FOR_VIEW_FIELD), + view->view_db.str, + view->view_name.str); + } + else + { + push_warning_printf(field_arg->table->in_use, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_FIELD, + ER(ER_NO_DEFAULT_FOR_FIELD), + field_arg->field_name); + } return 1; } field_arg->set_default(); @@ -4549,12 +4619,10 @@ bool Item_insert_value::eq(const Item *item, bool binary_cmp) const } -bool Item_insert_value::fix_fields(THD *thd, - struct st_table_list *table_list, - Item **items) +bool Item_insert_value::fix_fields(THD *thd, Item **items) { DBUG_ASSERT(fixed == 0); - if (!arg->fixed && arg->fix_fields(thd, table_list, &arg)) + if (!arg->fixed && arg->fix_fields(thd, &arg)) return TRUE; if (arg->type() == REF_ITEM) @@ -4643,9 +4711,7 @@ bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const } -bool Item_trigger_field::fix_fields(THD *thd, - TABLE_LIST *table_list, - Item **items) +bool Item_trigger_field::fix_fields(THD *thd, Item **items) { /* Since trigger is object tightly associated with TABLE object most @@ -5158,8 +5224,7 @@ enum_field_types Item_type_holder::get_real_type(Item *item) acceptable information for client in send_field, so we make field type from expression type. */ - switch (item->result_type()) - { + switch (item->result_type()) { case STRING_RESULT: return MYSQL_TYPE_VAR_STRING; case INT_RESULT: @@ -5361,9 +5426,13 @@ void Item_type_holder::get_full_info(Item *item) if (fld_type == MYSQL_TYPE_ENUM || fld_type == MYSQL_TYPE_SET) { + if (item->type() == Item::SUM_FUNC_ITEM && + (((Item_sum*)item)->sum_func() == Item_sum::MAX_FUNC || + ((Item_sum*)item)->sum_func() == Item_sum::MIN_FUNC)) + item = ((Item_sum*)item)->args[0]; /* - We can have enum/set type after merging only if we have one enum/set - field and number of NULL fields + We can have enum/set type after merging only if we have one enum|set + field (or MIN|MAX(enum|set field)) and number of NULL fields */ DBUG_ASSERT((enum_set_typelib && get_real_type(item) == MYSQL_TYPE_NULL) || @@ -5413,6 +5482,34 @@ void Item_result_field::cleanup() DBUG_VOID_RETURN; } +/* + Dummy error processor used by default by Name_resolution_context + + SYNOPSIS + dummy_error_processor() + + NOTE + do nothing +*/ + +void dummy_error_processor(THD *thd, void *data) +{} + +/* + Wrapper of hide_view_error call for Name_resolution_context error processor + + SYNOPSIS + view_error_processor() + + NOTE + hide view underlying tables details in error messages +*/ + +void view_error_processor(THD *thd, void *data) +{ + ((TABLE_LIST *)data)->hide_view_error(thd); +} + /***************************************************************************** ** Instantiate templates *****************************************************************************/ diff --git a/sql/item.h b/sql/item.h index c8180b4932a..12acb8dd28d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -24,7 +24,6 @@ struct st_table_list; void item_init(void); /* Init item functions */ class Item_field; - /* "Declared Type Collation" A combination of collation and its derivation. @@ -218,23 +217,110 @@ struct Hybrid_type_traits_integer: public Hybrid_type_traits static const Hybrid_type_traits_integer *instance(); }; + +void dummy_error_processor(THD *thd, void *data); + +void view_error_processor(THD *thd, void *data); + +/* + Instances of Name_resolution_context store the information necesary for + name resolution of Items and other context analysis of a query made in + fix_fields(). + + This structure is a part of SELECT_LEX, a pointer to this structure is + assigned when an item is created (which happens mostly during parsing + (sql_yacc.yy)), but the structure itself will be initialized after parsing + is complete + + TODO: move subquery of INSERT ... SELECT and CREATE ... SELECT to + separate SELECT_LEX which allow to remove tricks of changing this + structure before and after INSERT/CREATE and its SELECT to make correct + field name resolution. +*/ +struct Name_resolution_context +{ + /* + The name resolution context to search in when an Item cannot be + resolved in this context (the context of an outer select) + */ + Name_resolution_context *outer_context; + + /* + List of tables used to resolve the items of this context. Usually these + are tables from the FROM clause of SELECT statement. The exceptions are + INSERT ... SELECT and CREATE ... SELECT statements, where SELECT + subquery is not moved to a separate SELECT_LEX. For these types of + statements we have to change this member dynamically to ensure correct + name resolution of different parts of the statement. + */ + TABLE_LIST *table_list; + + /* + SELECT_LEX item belong to, in case of merged VIEW it can differ from + SELECT_LEX where item was created, so we can't use table_list/field_list + from there + */ + st_select_lex *select_lex; + + /* + Processor of errors caused during Item name resolving, now used only to + hide underlying tables in errors about views (i.e. it substitute some + errors for views) + */ + void (*error_processor)(THD *, void *); + void *error_processor_data; + + /* + When TRUE items are resolved in this context both against the + SELECT list and this->table_list. If FALSE, items are resolved + only against this->table_list. + */ + bool resolve_in_select_list; + + /* + When FALSE we do not check columns right of resolving items, used to + prevent rights check on underlying tables of view + */ + bool check_privileges; + + Name_resolution_context() + :outer_context(0), table_list(0), select_lex(0), + error_processor_data(0), + check_privileges(TRUE) + {} + + void init() + { + resolve_in_select_list= FALSE; + error_processor= &dummy_error_processor; + } + + void resolve_in_table_list_only(TABLE_LIST *tables) + { + table_list= tables; + resolve_in_select_list= FALSE; + } + + void process_error(THD *thd) + { + (*error_processor)(thd, error_processor_data); + } +}; + + /*************************************************************************/ typedef bool (Item::*Item_processor)(byte *arg); typedef Item* (Item::*Item_transformer) (byte *arg); - typedef void (*Cond_traverser) (const Item *item, void *arg); -/* - See comments for sql_yacc.yy: insert_update_elem rule - */ -#define MY_ITEM_PREFER_1ST_TABLE 1 class Item { Item(const Item &); /* Prevent use of these */ void operator=(Item &); public: - static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } + static void *operator new(size_t size) + { return (void*) sql_alloc((uint) size); } static void *operator new(size_t size, MEM_ROOT *mem_root) { return (void*) alloc_root(mem_root, (uint) size); } /* Special for SP local variable assignment - reusing slots */ @@ -248,7 +334,8 @@ public: PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, - PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM}; + PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM, + VIEW_FIXER_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; @@ -277,7 +364,6 @@ public: my_bool is_autogenerated_name; /* indicate was name of this Item autogenerated or set by user */ DTCollation collation; - uint8 item_flags; /* Flags on how item should be processed */ // alloc & destruct is done as start of select using sql_alloc Item(); @@ -302,7 +388,7 @@ public: virtual void cleanup(); virtual void make_field(Send_field *field); Field *make_string_field(TABLE *table); - virtual bool fix_fields(THD *, struct st_table_list *, Item **); + virtual bool fix_fields(THD *, Item **); /* should be used in case where we are sure that we do not need complete fix_fields() procedure. @@ -554,6 +640,9 @@ public: virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; } virtual bool cleanup_processor(byte *arg); virtual bool collect_item_field_processor(byte * arg) { return 0; } + virtual bool change_context_processor(byte *context) { return 0; } + virtual bool reset_query_id_processor(byte *query_id) { return 0; } + virtual Item *equal_fields_propagator(byte * arg) { return this; } virtual Item *set_no_const_sub(byte *arg) { return this; } virtual Item *replace_equal_field(byte * arg) { return this; } @@ -590,11 +679,6 @@ public: cleanup(); delete this; } - virtual bool set_flags_processor(byte *args) - { - this->item_flags|= *((uint8*)args); - return false; - } virtual bool is_splocal() { return 0; } /* Needed for error checking */ }; @@ -631,7 +715,7 @@ public: Item **this_item_addr(THD *thd, Item **); Item *this_const_item() const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void cleanup(); inline uint get_offset() @@ -704,7 +788,9 @@ protected: const char *orig_db_name; const char *orig_table_name; const char *orig_field_name; + public: + Name_resolution_context *context; const char *db_name; const char *table_name; const char *field_name; @@ -722,13 +808,16 @@ public: */ TABLE_LIST *cached_table; st_select_lex *depended_from; - Item_ident(const char *db_name_par,const char *table_name_par, - const char *field_name_par); + Item_ident(Name_resolution_context *context_arg, + const char *db_name_arg, const char *table_name_arg, + const char *field_name_arg); Item_ident(THD *thd, Item_ident *item); const char *full_name() const; void cleanup(); bool remove_dependence_processor(byte * arg); void print(String *str); + virtual bool change_context_processor(byte *cntx) + { context= (Name_resolution_context *)cntx; return FALSE; } }; class Item_equal; @@ -750,12 +839,9 @@ public: /* field need any privileges (for VIEW creation) */ bool any_privileges; - Item_field(const char *db_par,const char *table_name_par, - const char *field_name_par) - :Item_ident(db_par,table_name_par,field_name_par), - field(0), result_field(0), item_equal(0), no_const_subst(0), - have_privileges(0), any_privileges(0) - { collation.set(DERIVATION_IMPLICIT); } + Item_field(Name_resolution_context *context_arg, + const char *db_arg,const char *table_name_arg, + const char *field_name_arg); /* Constructor needed to process subselect with temporary tables (see Item) */ @@ -765,7 +851,7 @@ public: and database names will live as long as Item_field (this is important in prepared statements). */ - Item_field(THD *thd, Field *field); + Item_field(THD *thd, Name_resolution_context *context_arg, Field *field); /* If this constructor is used, fix_fields() won't work, because db_name, table_name and column_name are unknown. It's necessary to call @@ -785,7 +871,7 @@ public: bool val_bool_result(); bool send(Protocol *protocol, String *str_arg); void reset_field(Field *f); - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void make_field(Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); void save_org_in_field(Field *field); @@ -810,6 +896,13 @@ public: bool is_null() { return field->is_null(); } Item *get_tmp_table_item(THD *thd); bool collect_item_field_processor(byte * arg); + bool reset_query_id_processor(byte *arg) + { + field->query_id= *((query_id_t *) arg); + if (result_field) + result_field->query_id= field->query_id; + return 0; + } void cleanup(); Item_equal *find_item_equal(COND_EQUAL *cond_equal); Item *equal_fields_propagator(byte *arg); @@ -946,7 +1039,7 @@ public: bool get_time(TIME *tm); bool get_date(TIME *tm, uint fuzzydate); int save_in_field(Field *field, bool no_conversions); - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void set_null(); void set_int(longlong i, uint32 max_length_arg); @@ -1317,9 +1410,11 @@ protected: public: Field *result_field; /* Save result here */ Item **ref; - Item_ref(const char *db_par, const char *table_name_par, - const char *field_name_par) - :Item_ident(db_par, table_name_par, field_name_par), result_field(0), ref(0) {} + Item_ref(Name_resolution_context *context_arg, + const char *db_arg, const char *table_name_arg, + const char *field_name_arg) + :Item_ident(context_arg, db_arg, table_name_arg, field_name_arg), + result_field(0), ref(0) {} /* This constructor is used in two scenarios: A) *item = NULL @@ -1334,13 +1429,18 @@ public: TODO we probably fix a superset of problems like in BUG#6658. Check this with Bar, and if we have a more broader set of problems like this. */ - Item_ref(Item **item, const char *table_name_par, const char *field_name_par); + Item_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, const char *field_name_arg); /* Constructor need to process subselect with temporary tables (see Item) */ - Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {} + Item_ref(THD *thd, Item_ref *item) + :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {} enum Type type() const { return REF_ITEM; } bool eq(const Item *item, bool binary_cmp) const - { return ref && (*ref)->eq(item, binary_cmp); } + { + Item *it= ((Item *) item)->real_item(); + return ref && (*ref)->eq(it, binary_cmp); + } double val_real(); longlong val_int(); my_decimal *val_decimal(my_decimal *); @@ -1354,8 +1454,8 @@ public: my_decimal *val_decimal_result(my_decimal *); bool val_bool_result(); bool send(Protocol *prot, String *tmp); - void make_field(Send_field *field) { (*ref)->make_field(field); } - bool fix_fields(THD *, struct st_table_list *, Item **); + void make_field(Send_field *field); + bool fix_fields(THD *, Item **); int save_in_field(Field *field, bool no_conversions); void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } @@ -1380,6 +1480,8 @@ public: { return (*ref)->walk(processor, arg); } void print(String *str); void cleanup(); + Item_field *filed_for_view_update() + { return (*ref)->filed_for_view_update(); } }; @@ -1390,9 +1492,10 @@ public: class Item_direct_ref :public Item_ref { public: - Item_direct_ref(Item **item, const char *table_name_par, - const char *field_name_par) - :Item_ref(item, table_name_par, field_name_par) {} + Item_direct_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, + const char *field_name_arg) + :Item_ref(context_arg, item, table_name_arg, field_name_arg) {} /* Constructor need to process subselect with temporary tables (see Item) */ Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {} @@ -1405,6 +1508,24 @@ public: bool get_date(TIME *ltime,uint fuzzydate); }; +/* + Class for view fields, the same as Item_direct_ref, but call fix_fields + of reference if it is not called yet +*/ +class Item_direct_view_ref :public Item_direct_ref +{ +public: + Item_direct_view_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, + const char *field_name_arg) + :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg) {} + /* Constructor need to process subselect with temporary tables (see Item) */ + Item_direct_view_ref(THD *thd, Item_direct_ref *item) + :Item_direct_ref(thd, item) {} + + bool fix_fields(THD *, Item **); +}; + class Item_in_subselect; @@ -1413,9 +1534,11 @@ class Item_ref_null_helper: public Item_ref protected: Item_in_subselect* owner; public: - Item_ref_null_helper(Item_in_subselect* master, Item **item, - const char *table_name_par, const char *field_name_par): - Item_ref(item, table_name_par, field_name_par), owner(master) {} + Item_ref_null_helper(Name_resolution_context *context_arg, + Item_in_subselect* master, Item **item, + const char *table_name_arg, const char *field_name_arg) + :Item_ref(context_arg, item, table_name_arg, field_name_arg), + owner(master) {} double val_real(); longlong val_int(); String* val_str(String* s); @@ -1429,10 +1552,11 @@ class Item_null_helper :public Item_ref_null_helper { Item *store; public: - Item_null_helper(Item_in_subselect* master, Item *item, - const char *table_name_par, const char *field_name_par) - :Item_ref_null_helper(master, (store= 0, &store), table_name_par, - field_name_par), + Item_null_helper(Name_resolution_context *context_arg, + Item_in_subselect* master, Item *item, + const char *table_name_arg, const char *field_name_arg) + :Item_ref_null_helper(context_arg, master, (store= 0, &store), + table_name_arg, field_name_arg), store(item) { ref= &store; } void print(String *str); @@ -1583,13 +1707,17 @@ class Item_default_value : public Item_field { public: Item *arg; - Item_default_value() : - Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(NULL) {} - Item_default_value(Item *a) : - Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {} + Item_default_value(Name_resolution_context *context_arg) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(NULL) {} + Item_default_value(Name_resolution_context *context_arg, Item *a) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(a) {} enum Type type() const { return DEFAULT_VALUE_ITEM; } bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void print(String *str); int save_in_field(Field *field_arg, bool no_conversions); table_map used_tables() const { return (table_map)0L; } @@ -1618,10 +1746,12 @@ class Item_insert_value : public Item_field { public: Item *arg; - Item_insert_value(Item *a) : - Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {} + Item_insert_value(Name_resolution_context *context_arg, Item *a) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(a) {} bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void print(String *str); int save_in_field(Field *field_arg, bool no_conversions) { @@ -1683,15 +1813,17 @@ public: /* Pointer to Table_trigger_list object for table of this trigger */ Table_triggers_list *triggers; - Item_trigger_field(row_version_type row_ver_par, - const char *field_name_par): - Item_field((const char *)NULL, (const char *)NULL, field_name_par), - row_version(row_ver_par), field_idx((uint)-1) + Item_trigger_field(Name_resolution_context *context_arg, + row_version_type row_ver_arg, + const char *field_name_arg) + :Item_field(context_arg, + (const char *)NULL, (const char *)NULL, field_name_arg), + row_version(row_ver_arg), field_idx((uint)-1) {} void setup_field(THD *thd, TABLE *table); enum Type type() const { return TRIGGER_FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void print(String *str); table_map used_tables() const { return (table_map)0L; } void cleanup(); @@ -1880,7 +2012,7 @@ public: Item_type_holder(THD*, Item*); Item_result result_type() const; - virtual enum_field_types field_type() const { return fld_type; }; + enum_field_types field_type() const { return fld_type; }; enum Type type() const { return TYPE_HOLDER; } double val_real(); longlong val_int(); @@ -1892,6 +2024,7 @@ public: static enum_field_types get_real_type(Item *); }; + class st_select_lex; void mark_select_range_as_dependent(THD *thd, st_select_lex *last_select, diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 5a2e14eef2e..5ed857319be 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -238,9 +238,10 @@ void Item_bool_func2::fix_length_and_dec() return; } - if (args[0]->type() == FIELD_ITEM) + Item *real_item= args[0]->real_item(); + if (real_item->type() == FIELD_ITEM) { - Field *field=((Item_field*) args[0])->field; + Field *field= ((Item_field*) real_item)->field; if (field->can_be_compared_as_longlong()) { if (convert_constant_item(thd, field,&args[1])) @@ -251,9 +252,10 @@ void Item_bool_func2::fix_length_and_dec() } } } - if (args[1]->type() == FIELD_ITEM /* && !args[1]->const_item() */) + real_item= args[1]->real_item(); + if (real_item->type() == FIELD_ITEM) { - Field *field=((Item_field*) args[1])->field; + Field *field= ((Item_field*) real_item)->field; if (field->can_be_compared_as_longlong()) { if (convert_constant_item(thd, field,&args[0])) @@ -273,7 +275,7 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) owner= item; func= comparator_matrix[type] [test(owner->functype() == Item_func::EQUAL_FUNC)]; - switch(type) { + switch (type) { case ROW_RESULT: { uint n= (*a)->cols(); @@ -636,11 +638,9 @@ int Arg_comparator::compare_e_row() } -bool Item_in_optimizer::fix_left(THD *thd, - struct st_table_list *tables, - Item **ref) +bool Item_in_optimizer::fix_left(THD *thd, Item **ref) { - if (!args[0]->fixed && args[0]->fix_fields(thd, tables, args) || + if (!args[0]->fixed && args[0]->fix_fields(thd, args) || !cache && !(cache= Item_cache::get_cache(args[0]->result_type()))) return 1; @@ -677,16 +677,15 @@ bool Item_in_optimizer::fix_left(THD *thd, } -bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, - Item ** ref) +bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - if (fix_left(thd, tables, ref)) + if (fix_left(thd, ref)) return TRUE; if (args[0]->maybe_null) maybe_null=1; - if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args+1)) + if (!args[1]->fixed && args[1]->fix_fields(thd, args+1)) return TRUE; Item_in_subselect * sub= (Item_in_subselect *)args[1]; if (args[0]->cols() != sub->engine->cols()) @@ -1420,6 +1419,8 @@ Item *Item_func_case::find_item(String *str) my_decimal *first_expr_dec, first_expr_dec_val; longlong first_expr_int; double first_expr_real; + char buff[MAX_FIELD_WIDTH]; + String buff_str(buff,sizeof(buff),default_charset()); /* These will be initialized later */ LINT_INIT(first_expr_str); @@ -1433,7 +1434,7 @@ Item *Item_func_case::find_item(String *str) { case STRING_RESULT: // We can't use 'str' here as this may be overwritten - if (!(first_expr_str= args[first_expr_num]->val_str(&str_value))) + if (!(first_expr_str= args[first_expr_num]->val_str(&buff_str))) return else_expr_num != -1 ? args[else_expr_num] : 0; // Impossible break; case INT_RESULT: @@ -1577,6 +1578,25 @@ my_decimal *Item_func_case::val_decimal(my_decimal *decimal_value) } +bool Item_func_case::fix_fields(THD *thd, Item **ref) +{ + /* + buff should match stack usage from + Item_func_case::val_int() -> Item_func_case::find_item() + */ + char buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2]; + bool res= Item_func::fix_fields(thd, ref); + /* + Call check_stack_overrun after fix_fields to be sure that stack variable + is not optimized away + */ + if (check_stack_overrun(thd, STACK_MIN_SIZE, buff)) + return TRUE; // Fatal error flag is set! + return res; +} + + + void Item_func_case::fix_length_and_dec() { Item **agg; @@ -2308,7 +2328,7 @@ void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item) bool -Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_cond::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); List_iterator<Item> li(list); @@ -2356,7 +2376,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) // item can be substituted in fix_fields if ((!item->fixed && - item->fix_fields(thd, tables, li.ref())) || + item->fix_fields(thd, li.ref())) || (item= *li.ref())->check_cols(1)) return TRUE; /* purecov: inspected */ used_tables_cache|= item->used_tables(); @@ -2743,11 +2763,11 @@ Item_func::optimize_type Item_func_like::select_optimize() const } -bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) +bool Item_func_like::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - if (Item_bool_func2::fix_fields(thd, tlist, ref) || - escape_item->fix_fields(thd, tlist, &escape_item)) + if (Item_bool_func2::fix_fields(thd, ref) || + escape_item->fix_fields(thd, &escape_item)) return TRUE; if (!escape_item->const_during_execution()) @@ -2811,13 +2831,13 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) #ifdef USE_REGEX bool -Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_func_regex::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); if ((!args[0]->fixed && - args[0]->fix_fields(thd, tables, args)) || args[0]->check_cols(1) || + args[0]->fix_fields(thd, args)) || args[0]->check_cols(1) || (!args[1]->fixed && - args[1]->fix_fields(thd,tables, args + 1)) || args[1]->check_cols(1)) + args[1]->fix_fields(thd, args + 1)) || args[1]->check_cols(1)) return TRUE; /* purecov: inspected */ with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func; max_length= 1; @@ -3477,7 +3497,7 @@ void Item_equal::sort(Item_field_cmpfunc cmp, void *arg) } while (swap); } -bool Item_equal::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +bool Item_equal::fix_fields(THD *thd, Item **ref) { List_iterator_fast<Item_field> li(fields); Item *item; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 7a22e76b217..75c8411b844 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -108,8 +108,8 @@ public: Item_in_optimizer(Item *a, Item_in_subselect *b): Item_bool_func(a, my_reinterpret_cast(Item *)(b)), cache(0), save_cache(0) {} - bool fix_fields(THD *, struct st_table_list *, Item **); - bool fix_left(THD *thd, struct st_table_list *tables, Item **ref); + bool fix_fields(THD *, Item **); + bool fix_left(THD *thd, Item **ref); bool is_null(); /* Item_in_optimizer item is special boolean function. On value request @@ -502,11 +502,11 @@ public: String *val_str(String *str); my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return cached_result_type; } - bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); args[0]->top_level_item(); - return Item_func::fix_fields(thd, tlist, ref); + return Item_func::fix_fields(thd, ref); } void fix_length_and_dec(); uint decimal_precision() const; @@ -566,6 +566,7 @@ public: longlong val_int(); String *val_str(String *); my_decimal *val_decimal(my_decimal *); + bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); uint decimal_precision() const; table_map not_null_tables() const { return 0; } @@ -849,6 +850,12 @@ class Item_func_in :public Item_int_func bool nulls_in_row(); bool is_bool_func() { return 1; } CHARSET_INFO *compare_collation() { return cmp_collation.collation; } + /* + IN() protect from NULL only first argument, if construction like + "expression IN ()" will be allowed, we will need to check number of + argument here, because "NOT(NULL IN ())" is TRUE. + */ + table_map not_null_tables() const { return args[0]->not_null_tables(); } }; /* Functions used by where clause */ @@ -961,7 +968,7 @@ public: optimize_type select_optimize() const; cond_result eq_cmp_result() const { return COND_TRUE; } const char *func_name() const { return "like"; } - bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); + bool fix_fields(THD *thd, Item **ref); }; #ifdef USE_REGEX @@ -980,7 +987,7 @@ public: regex_compiled(0),regex_is_const(0) {} void cleanup(); longlong val_int(); - bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); + bool fix_fields(THD *thd, Item **ref); const char *func_name() const { return "regexp"; } void print(String *str) { print_op(str); } CHARSET_INFO *compare_collation() { return cmp_collation.collation; } @@ -1024,7 +1031,7 @@ public: :Item_bool_func(), list(nlist), abort_on_null(0) {} bool add(Item *item) { return list.push_back(item); } void add_at_head(List<Item> *nlist) { list.prepand(nlist); } - bool fix_fields(THD *, struct st_table_list *, Item **ref); + bool fix_fields(THD *, Item **ref); enum Type type() const { return COND_ITEM; } List<Item>* argument_list() { return &list; } @@ -1033,7 +1040,7 @@ public: void print(String *str); void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, - COND **conds); + COND **conds); void top_level_item() { abort_on_null=1; } void copy_andor_arguments(THD *thd, Item_cond *item); bool walk(Item_processor processor, byte *arg); @@ -1141,7 +1148,7 @@ public: void sort(Item_field_cmpfunc cmp, void *arg); friend class Item_equal_iterator; void fix_length_and_dec(); - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); void update_used_tables(); bool walk(Item_processor processor, byte *arg); Item *transform(Item_transformer transformer, byte *arg); diff --git a/sql/item_func.cc b/sql/item_func.cc index 57f68bbc2a0..7576bca6701 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -194,11 +194,10 @@ bool Item_func::agg_arg_charsets(DTCollation &coll, ((Item_field *)(*arg))->no_const_subst= 1; /* We do not check conv->fixed, because Item_func_conv_charset which can - be return by safe_charset_converter can't be fixed at creation, also - it do not need tables (second argument) for name resolving + be return by safe_charset_converter can't be fixed at creation */ *arg= conv; - conv->fix_fields(thd, 0, arg); + conv->fix_fields(thd, arg); } if (arena) thd->restore_backup_item_arena(arena, &backup); @@ -261,7 +260,6 @@ Item_func::Item_func(THD *thd, Item_func *item) SYNOPSIS: fix_fields() thd Thread object - tables List of all open tables involved in the query ref Pointer to where this object is used. This reference is used if we want to replace this object with another one (for example in the summary functions). @@ -290,7 +288,7 @@ Item_func::Item_func(THD *thd, Item_func *item) */ bool -Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_func::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); Item **arg,**arg_end; @@ -312,7 +310,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) We can't yet set item to *arg as fix_fields may change *arg We shouldn't call fix_fields() twice, so check 'fixed' field first */ - if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg))) + if ((!(*arg)->fixed && (*arg)->fix_fields(thd, arg))) return TRUE; /* purecov: inspected */ item= *arg; @@ -568,6 +566,17 @@ String *Item_real_func::val_str(String *str) } +my_decimal *Item_real_func::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed); + double nr= val_real(); + if (null_value) + return 0; /* purecov: inspected */ + double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value); + return decimal_value; +} + + void Item_func::fix_num_length_and_dec() { decimals= 0; @@ -1882,8 +1891,7 @@ void Item_func_round::fix_length_and_dec() return; } - switch (args[0]->result_type()) - { + switch (args[0]->result_type()) { case REAL_RESULT: case STRING_RESULT: hybrid_type= REAL_RESULT; @@ -1891,16 +1899,17 @@ void Item_func_round::fix_length_and_dec() max_length= float_length(decimals); break; case INT_RESULT: - if ((decimals_to_set==0) && + if (!decimals_to_set && (truncate || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS))) { + int length_can_increase= test(!truncate && (args[1]->val_int() < 0)); + max_length= args[0]->max_length + length_can_increase; /* Here we can keep INT_RESULT */ hybrid_type= INT_RESULT; - int length_can_increase= !truncate && (args[1]->val_int() < 0); - max_length= args[0]->max_length + length_can_increase; decimals= 0; break; } + /* fall through */ case DECIMAL_RESULT: { hybrid_type= DECIMAL_RESULT; @@ -2010,10 +2019,9 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) } -bool Item_func_rand::fix_fields(THD *thd, struct st_table_list *tables, - Item **ref) +bool Item_func_rand::fix_fields(THD *thd,Item **ref) { - if (Item_real_func::fix_fields(thd, tables, ref)) + if (Item_real_func::fix_fields(thd, ref)) return TRUE; used_tables_cache|= RAND_TABLE_BIT; if (arg_count) @@ -2604,7 +2612,7 @@ void udf_handler::cleanup() bool -udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, +udf_handler::fix_fields(THD *thd, Item_result_field *func, uint arg_count, Item **arguments) { #ifndef EMBEDDED_LIBRARY // Avoid compiler warning @@ -2646,7 +2654,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, arg++,i++) { if (!(*arg)->fixed && - (*arg)->fix_fields(thd, tables, arg)) + (*arg)->fix_fields(thd, arg)) DBUG_RETURN(1); // we can't assign 'item' before, because fix_fields() can change arg Item *item= *arg; @@ -3458,12 +3466,11 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, SELECT @a:= ). */ -bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, - Item **ref) +bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); /* fix_fields will call Item_func_set_user_var::fix_length_and_dec */ - if (Item_func::fix_fields(thd, tables, ref) || + if (Item_func::fix_fields(thd, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return TRUE; /* @@ -4127,11 +4134,10 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const } -bool Item_user_var_as_out_param::fix_fields(THD *thd, TABLE_LIST *tables, - Item **ref) +bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - if (Item::fix_fields(thd, tables, ref) || + if (Item::fix_fields(thd, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return TRUE; entry->type= STRING_RESULT; @@ -4314,7 +4320,7 @@ void Item_func_match::init_search(bool no_order) } -bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) +bool Item_func_match::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); Item *item; @@ -4329,7 +4335,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) modifications to find_best and auto_close as complement to auto_init code above. */ - if (Item_func::fix_fields(thd, tlist, ref) || + if (Item_func::fix_fields(thd, ref) || !args[0]->const_during_execution()) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST"); @@ -4451,7 +4457,8 @@ err: bool Item_func_match::eq(const Item *item, bool binary_cmp) const { - if (item->type() != FUNC_ITEM || ((Item_func*)item)->functype() != FT_FUNC || + if (item->type() != FUNC_ITEM || + ((Item_func*)item)->functype() != FT_FUNC || flags != ((Item_func_match*)item)->flags) return 0; @@ -4690,8 +4697,9 @@ longlong Item_func_row_count::val_int() } -Item_func_sp::Item_func_sp(sp_name *name) - :Item_func(), m_name(name), m_sp(NULL), result_field(NULL) +Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name) + :Item_func(), context(context_arg), m_name(name), m_sp(NULL), + result_field(NULL) { maybe_null= 1; m_name->init_qname(current_thd); @@ -4699,8 +4707,10 @@ Item_func_sp::Item_func_sp(sp_name *name) } -Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list) - :Item_func(list), m_name(name), m_sp(NULL), result_field(NULL) +Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, + sp_name *name, List<Item> &list) + :Item_func(list), context(context_arg), m_name(name), m_sp(NULL), + result_field(NULL) { maybe_null= 1; m_name->init_qname(current_thd); @@ -4715,6 +4725,7 @@ Item_func_sp::cleanup() delete result_field; result_field= NULL; } + m_sp= NULL; Item_func::cleanup(); } @@ -4807,42 +4818,36 @@ Item_func_sp::execute(Item **itp) DBUG_ENTER("Item_func_sp::execute"); THD *thd= current_thd; ulong old_client_capabilites; - int res; + int res= -1; bool save_in_sub_stmt= thd->transaction.in_sub_stmt; + my_bool save_no_send_ok; #ifndef NO_EMBEDDED_ACCESS_CHECKS st_sp_security_context save_ctx; #endif - if (! m_sp) + if (! m_sp && ! (m_sp= sp_find_function(thd, m_name, TRUE))) { - if (!(m_sp= sp_find_function(thd, m_name, TRUE))) - { - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); - DBUG_RETURN(-1); - } + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); + goto error; } old_client_capabilites= thd->client_capabilities; thd->client_capabilities &= ~CLIENT_MULTI_RESULTS; #ifndef EMBEDDED_LIBRARY - my_bool nsok= thd->net.no_send_ok; + save_no_send_ok= thd->net.no_send_ok; thd->net.no_send_ok= TRUE; #endif #ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_routine_access(thd, EXECUTE_ACL, m_sp->m_db.str, m_sp->m_name.str, 0, 0)) - DBUG_RETURN(-1); + goto error_check; sp_change_security_context(thd, m_sp, &save_ctx); if (save_ctx.changed && check_routine_access(thd, EXECUTE_ACL, m_sp->m_db.str, m_sp->m_name.str, 0, 0)) - { - sp_restore_security_context(thd, m_sp, &save_ctx); - thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS; - DBUG_RETURN(-1); - } + goto error_check_ctx; #endif /* Like for SPs, we don't binlog the substatements. If the statement which @@ -4850,6 +4855,7 @@ Item_func_sp::execute(Item **itp) it's not (e.g. SELECT myfunc()) it won't be binlogged (documented known problem). */ + tmp_disable_binlog(thd); /* don't binlog the substatements */ thd->transaction.in_sub_stmt= TRUE; @@ -4865,15 +4871,20 @@ Item_func_sp::execute(Item **itp) ER(ER_FAILED_ROUTINE_BREAK_BINLOG)); #ifndef NO_EMBEDDED_ACCESS_CHECKS +error_check_ctx: sp_restore_security_context(thd, m_sp, &save_ctx); #endif + thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS; + +error_check: #ifndef EMBEDDED_LIBRARY - thd->net.no_send_ok= nsok; + thd->net.no_send_ok= save_no_send_ok; #endif thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS; +error: DBUG_RETURN(res); } @@ -4944,7 +4955,10 @@ Item_func_sp::fix_length_and_dec() } if (!(field= sp_result_field())) + { + context->process_error(current_thd); DBUG_VOID_RETURN; + } decimals= field->decimals(); max_length= field->field_length; maybe_null= 1; diff --git a/sql/item_func.h b/sql/item_func.h index e0f14ceac75..3ca37b1961f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -116,7 +116,7 @@ public: Item_func(List<Item> &list); // Constructor used for Item_cond_and/or (see Item comment) Item_func(THD *thd, Item_func *item); - bool fix_fields(THD *,struct st_table_list *, Item **ref); + bool fix_fields(THD *, Item **ref); table_map used_tables() const; table_map not_null_tables() const; void update_used_tables(); @@ -187,6 +187,7 @@ public: Item_real_func(Item *a,Item *b) :Item_func(a,b) {} Item_real_func(List<Item> &list) :Item_func(list) {} String *val_str(String*str); + my_decimal *val_decimal(my_decimal *decimal_value); longlong val_int() { DBUG_ASSERT(fixed == 1); return (longlong) val_real(); } enum Item_result result_type () const { return REAL_RESULT; } @@ -630,7 +631,7 @@ public: const char *func_name() const { return "rand"; } bool const_item() const { return 0; } void update_used_tables(); - bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); }; @@ -885,14 +886,15 @@ protected: udf_handler udf; public: - Item_udf_func(udf_func *udf_arg) :Item_func(), udf(udf_arg) {} + Item_udf_func(udf_func *udf_arg) + :Item_func(), udf(udf_arg) {} Item_udf_func(udf_func *udf_arg, List<Item> &list) :Item_func(list), udf(udf_arg) {} const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - bool res= udf.fix_fields(thd, tables, this, arg_count, args); + bool res= udf.fix_fields(thd, this, arg_count, args); used_tables_cache= udf.used_tables_cache; const_item_cache= udf.const_item_cache; fixed= 1; @@ -907,9 +909,11 @@ public: class Item_func_udf_float :public Item_udf_func { public: - Item_func_udf_float(udf_func *udf_arg) :Item_udf_func(udf_arg) {} - Item_func_udf_float(udf_func *udf_arg, List<Item> &list) - :Item_udf_func(udf_arg,list) {} + Item_func_udf_float(udf_func *udf_arg) + :Item_udf_func(udf_arg) {} + Item_func_udf_float(udf_func *udf_arg, + List<Item> &list) + :Item_udf_func(udf_arg, list) {} longlong val_int() { DBUG_ASSERT(fixed == 1); @@ -932,9 +936,11 @@ class Item_func_udf_float :public Item_udf_func class Item_func_udf_int :public Item_udf_func { public: - Item_func_udf_int(udf_func *udf_arg) :Item_udf_func(udf_arg) {} - Item_func_udf_int(udf_func *udf_arg, List<Item> &list) - :Item_udf_func(udf_arg,list) {} + Item_func_udf_int(udf_func *udf_arg) + :Item_udf_func(udf_arg) {} + Item_func_udf_int(udf_func *udf_arg, + List<Item> &list) + :Item_udf_func(udf_arg, list) {} longlong val_int(); double val_real() { return (double) Item_func_udf_int::val_int(); } String *val_str(String *str); @@ -946,9 +952,10 @@ public: class Item_func_udf_decimal :public Item_udf_func { public: - Item_func_udf_decimal(udf_func *udf_arg) :Item_udf_func(udf_arg) {} + Item_func_udf_decimal(udf_func *udf_arg) + :Item_udf_func(udf_arg) {} Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) - :Item_udf_func(udf_arg,list) {} + :Item_udf_func(udf_arg, list) {} longlong val_int(); double val_real(); my_decimal *val_decimal(my_decimal *); @@ -961,9 +968,10 @@ public: class Item_func_udf_str :public Item_udf_func { public: - Item_func_udf_str(udf_func *udf_arg) :Item_udf_func(udf_arg) {} + Item_func_udf_str(udf_func *udf_arg) + :Item_udf_func(udf_arg) {} Item_func_udf_str(udf_func *udf_arg, List<Item> &list) - :Item_udf_func(udf_arg,list) {} + :Item_udf_func(udf_arg, list) {} String *val_str(String *); double val_real() { @@ -998,8 +1006,10 @@ public: class Item_func_udf_float :public Item_real_func { public: - Item_func_udf_float(udf_func *udf_arg) :Item_real_func() {} - Item_func_udf_float(udf_func *udf_arg, List<Item> &list) :Item_real_func(list) {} + Item_func_udf_float(udf_func *udf_arg) + :Item_real_func() {} + Item_func_udf_float(udf_func *udf_arg, List<Item> &list) + :Item_real_func(list) {} double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } }; @@ -1007,8 +1017,10 @@ class Item_func_udf_float :public Item_real_func class Item_func_udf_int :public Item_int_func { public: - Item_func_udf_int(udf_func *udf_arg) :Item_int_func() {} - Item_func_udf_int(udf_func *udf_arg, List<Item> &list) :Item_int_func(list) {} + Item_func_udf_int(udf_func *udf_arg) + :Item_int_func() {} + Item_func_udf_int(udf_func *udf_arg, List<Item> &list) + :Item_int_func(list) {} longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; } }; @@ -1016,8 +1028,10 @@ public: class Item_func_udf_decimal :public Item_int_func { public: - Item_func_udf_decimal(udf_func *udf_arg) :Item_int_func() {} - Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) :Item_int_func(list) {} + Item_func_udf_decimal(udf_func *udf_arg) + :Item_int_func() {} + Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) + :Item_int_func(list) {} my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } }; @@ -1025,8 +1039,10 @@ public: class Item_func_udf_str :public Item_func { public: - Item_func_udf_str(udf_func *udf_arg) :Item_func() {} - Item_func_udf_str(udf_func *udf_arg, List<Item> &list) :Item_func(list) {} + Item_func_udf_str(udf_func *udf_arg) + :Item_func() {} + Item_func_udf_str(udf_func *udf_arg, List<Item> &list) + :Item_func(list) {} String *val_str(String *) { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } double val_real() { DBUG_ASSERT(fixed == 1); null_value= 1; return 0.0; } @@ -1116,7 +1132,7 @@ public: bool check(); bool update(); enum Item_result result_type () const { return cached_result_type; } - bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); void print(String *str); void print_as_stmt(String *str); @@ -1176,7 +1192,7 @@ public: String *val_str(String *str); my_decimal *val_decimal(my_decimal *decimal_buffer); /* fix_fields() binds variable name with its entry structure */ - bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); void print(String *str); void set_null_value(CHARSET_INFO* cs); void set_value(const char *str, uint length, CHARSET_INFO* cs); @@ -1230,7 +1246,7 @@ public: const char *func_name() const { return "match"; } void update_used_tables() {} table_map not_null_tables() const { return 0; } - bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); + bool fix_fields(THD *thd, Item **ref); bool eq(const Item *, bool binary_cmp) const; /* The following should be safe, even if we compare doubles */ longlong val_int() { DBUG_ASSERT(fixed == 1); return val_real() != 0.0; } @@ -1302,6 +1318,7 @@ class sp_name; class Item_func_sp :public Item_func { private: + Name_resolution_context *context; sp_name *m_name; mutable sp_head *m_sp; TABLE *dummy_table; @@ -1314,9 +1331,10 @@ private: public: - Item_func_sp(sp_name *name); + Item_func_sp(Name_resolution_context *context_arg, sp_name *name); - Item_func_sp(sp_name *name, List<Item> &list); + Item_func_sp(Name_resolution_context *context_arg, + sp_name *name, List<Item> &list); virtual ~Item_func_sp() {} @@ -1361,6 +1379,9 @@ public: return result_field->val_str(str); } + virtual bool change_context_processor(byte *cntx) + { context= (Name_resolution_context *)cntx; return FALSE; } + void fix_length_and_dec(); }; diff --git a/sql/item_row.cc b/sql/item_row.cc index 0c8baa332ca..9362518e6ef 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -53,7 +53,7 @@ void Item_row::illegal_method_call(const char *method) DBUG_VOID_RETURN; } -bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) +bool Item_row::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); null_value= 0; @@ -61,7 +61,7 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) Item **arg, **arg_end; for (arg= items, arg_end= items+arg_count; arg != arg_end ; arg++) { - if ((*arg)->fix_fields(thd, tabl, arg)) + if ((*arg)->fix_fields(thd, arg)) return TRUE; // we can't assign 'item' before, because fix_fields() can change arg Item *item= *arg; diff --git a/sql/item_row.h b/sql/item_row.h index e6b23eebb49..6fbe7436b72 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -61,7 +61,7 @@ public: illegal_method_call((const char*)"val_decimal"); return 0; }; - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); table_map used_tables() const { return used_tables_cache; }; bool const_item() const { return const_item_cache; }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 9f7a44f6f47..ccc56adf007 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -363,6 +363,7 @@ String *Item_func_des_encrypt::val_str(String *str) { DBUG_ASSERT(fixed == 1); #ifdef HAVE_OPENSSL + uint code= ER_WRONG_PARAMETERS_TO_PROCEDURE; DES_cblock ivec; struct st_des_keyblock keyblock; struct st_des_keyschedule keyschedule; @@ -370,8 +371,8 @@ String *Item_func_des_encrypt::val_str(String *str) uint key_number, res_length, tail; String *res= args[0]->val_str(str); - if ((null_value=args[0]->null_value)) - return 0; + if ((null_value= args[0]->null_value)) + return 0; // ENCRYPT(NULL) == NULL if ((res_length=res->length()) == 0) return &my_empty_string; @@ -419,6 +420,7 @@ String *Item_func_des_encrypt::val_str(String *str) tail= (8-(res_length) % 8); // 1..8 marking extra length res_length+=tail; + code= ER_OUT_OF_RESOURCES; if (tail && res->append(append_str, tail) || tmp_value.alloc(res_length+1)) goto error; (*res)[res_length-1]=tail; // save extra length @@ -436,6 +438,13 @@ String *Item_func_des_encrypt::val_str(String *str) return &tmp_value; error: + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + code, ER(code), + "des_encrypt"); +#else + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED), + "des_encrypt","--with-openssl"); #endif /* HAVE_OPENSSL */ null_value=1; return 0; @@ -446,12 +455,12 @@ String *Item_func_des_decrypt::val_str(String *str) { DBUG_ASSERT(fixed == 1); #ifdef HAVE_OPENSSL - DES_key_schedule ks1, ks2, ks3; + uint code= ER_WRONG_PARAMETERS_TO_PROCEDURE; DES_cblock ivec; struct st_des_keyblock keyblock; struct st_des_keyschedule keyschedule; String *res= args[0]->val_str(str); - uint length=res->length(),tail; + uint length= 0, tail; if ((null_value=args[0]->null_value)) return 0; @@ -485,6 +494,7 @@ String *Item_func_des_decrypt::val_str(String *str) DES_set_key_unchecked(&keyblock.key2,&keyschedule.ks2); DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3); } + code= ER_OUT_OF_RESOURCES; if (tmp_value.alloc(length-1)) goto error; @@ -498,11 +508,19 @@ String *Item_func_des_decrypt::val_str(String *str) &ivec, FALSE); /* Restore old length of key */ if ((tail=(uint) (uchar) tmp_value[length-2]) > 8) - goto error; // Wrong key + goto wrong_key; // Wrong key tmp_value.length(length-1-tail); return &tmp_value; error: + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + code, ER(code), + "des_decrypt"); +wrong_key: +#else + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED), + "des_decrypt","--with-openssl"); #endif /* HAVE_OPENSSL */ null_value=1; return 0; @@ -1037,7 +1055,8 @@ void Item_func_substr::fix_length_and_dec() collation.set(args[0]->collation); if (args[1]->const_item()) { - int32 start=(int32) args[1]->val_int()-1; + int32 start= (int32) args[1]->val_int(); + start= (int32)((start < 0) ? max_length + start : start - 1); if (start < 0 || start >= (int32) max_length) max_length=0; /* purecov: inspected */ else diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 8d2eb269915..d85210984d9 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -95,6 +95,7 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "concat_ws"; } + table_map not_null_tables() const { return 0; } }; class Item_func_reverse :public Item_str_func @@ -322,7 +323,7 @@ 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"; } + const char *func_name() const { return "encrypt"; } }; #include "sql_crypt.h" @@ -415,12 +416,12 @@ class Item_func_make_set :public Item_str_func public: Item_func_make_set(Item *a,List<Item> &list) :Item_str_func(list),item(a) {} String *val_str(String *str); - bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - return ((!item->fixed && item->fix_fields(thd, tlist, &item)) || + return ((!item->fixed && item->fix_fields(thd, &item)) || item->check_cols(1) || - Item_func::fix_fields(thd, tlist, ref)); + Item_func::fix_fields(thd, ref)); } void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); void fix_length_and_dec(); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 393cb87c113..ad1c9977e5b 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -130,7 +130,7 @@ Item_subselect::select_transformer(JOIN *join) } -bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) +bool Item_subselect::fix_fields(THD *thd_param, Item **ref) { char const *save_where= thd_param->where; bool res; @@ -165,7 +165,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) substitution= 0; thd->where= "checking transformed subquery"; if (!(*ref)->fixed) - ret= (*ref)->fix_fields(thd, tables, ref); + ret= (*ref)->fix_fields(thd, ref); thd->where= save_where; return ret; } @@ -194,15 +194,8 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) bool Item_subselect::exec() { int res; - MEM_ROOT *old_root= thd->mem_root; - /* - As this is execution, all objects should be allocated through the main - mem root - */ - thd->mem_root= &thd->main_mem_root; res= engine->exec(); - thd->mem_root= old_root; if (engine_changed) { @@ -840,7 +833,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, reference, also Item_sum_(max|min) can't be fixed after creation, so we do not check item->fixed */ - if (item->fix_fields(thd, join->tables_list, 0)) + if (item->fix_fields(thd, 0)) DBUG_RETURN(RES_ERROR); /* we added aggregate function => we have to change statistic */ count_field_types(&join->tmp_table_param, join->all_fields, 0); @@ -869,7 +862,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, thd->lex->current_select= up= current->return_after_parsing(); //optimizer never use Item **ref => we can pass 0 as parameter - if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0)) + if (!optimizer || optimizer->fix_left(thd, 0)) { thd->lex->current_select= current; DBUG_RETURN(RES_ERROR); @@ -880,7 +873,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, As far as Item_ref_in_optimizer do not substitute itself on fix_fields we can use same item for all selects. */ - expr= new Item_direct_ref((Item**)optimizer->get_cache(), + expr= new Item_direct_ref(&select_lex->context, + (Item**)optimizer->get_cache(), (char *)"<no matter>", (char *)in_left_expr_name); @@ -900,7 +894,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, { bool tmp; Item *item= func->create(expr, - new Item_ref_null_helper(this, + new Item_ref_null_helper(&select_lex->context, + this, select_lex-> ref_pointer_array, (char *)"<ref>", @@ -920,7 +915,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, we do not check join->having->fixed, because Item_and (from and_items) or comparison function (from func->create) can't be fixed after creation */ - tmp= join->having->fix_fields(thd, join->tables_list, 0); + tmp= join->having->fix_fields(thd, 0); select_lex->having_fix_field= 0; if (tmp) DBUG_RETURN(RES_ERROR); @@ -956,7 +951,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, and_items) or comparison function (from func->create) can't be fixed after creation */ - tmp= join->having->fix_fields(thd, join->tables_list, 0); + tmp= join->having->fix_fields(thd, 0); select_lex->having_fix_field= 0; if (tmp) DBUG_RETURN(RES_ERROR); @@ -978,7 +973,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, we do not check join->conds->fixed, because Item_and can't be fixed after creation */ - if (join->conds->fix_fields(thd, join->tables_list, 0)) + if (join->conds->fix_fields(thd, 0)) DBUG_RETURN(RES_ERROR); } else @@ -990,22 +985,23 @@ Item_in_subselect::single_value_transformer(JOIN *join, comparison functions can't be changed during fix_fields() we can assign select_lex->having here, and pass 0 as last argument (reference) to fix_fields() - */ - item= func->create(expr, - new Item_null_helper(this, item, - (char *)"<no matter>", - (char *)"<result>")); + */ + item= func->create(expr, + new Item_null_helper(&select_lex->context, + this, item, + (char *)"<no matter>", + (char *)"<result>")); #ifdef CORRECT_BUT_TOO_SLOW_TO_BE_USABLE if (!abort_on_null && left_expr->maybe_null) item= new Item_cond_or(new Item_func_isnull(left_expr), item); #endif - select_lex->having= join->having= item; + select_lex->having= join->having= item; select_lex->having_fix_field= 1; /* we do not check join->having->fixed, because comparison function (from func->create) can't be fixed after creation */ - tmp= join->having->fix_fields(thd, join->tables_list, 0); + tmp= join->having->fix_fields(thd, 0); select_lex->having_fix_field= 0; if (tmp) DBUG_RETURN(RES_ERROR); @@ -1055,7 +1051,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) SELECT_LEX *current= thd->lex->current_select, *up; thd->lex->current_select= up= current->return_after_parsing(); //optimizer never use Item **ref => we can pass 0 as parameter - if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0)) + if (!optimizer || optimizer->fix_left(thd, 0)) { thd->lex->current_select= current; DBUG_RETURN(RES_ERROR); @@ -1078,12 +1074,14 @@ Item_in_subselect::row_value_transformer(JOIN *join) if (select_lex->ref_pointer_array[i]-> check_cols(left_expr->el(i)->cols())) DBUG_RETURN(RES_ERROR); - Item *func= new Item_ref_null_helper(this, + Item *func= new Item_ref_null_helper(&select_lex->context, + this, select_lex->ref_pointer_array+i, (char *) "<no matter>", (char *) "<list ref>"); func= - eq_creator.create(new Item_direct_ref((*optimizer->get_cache())-> + eq_creator.create(new Item_direct_ref(&select_lex->context, + (*optimizer->get_cache())-> addr(i), (char *)"<no matter>", (char *)in_left_expr_name), @@ -1106,7 +1104,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) join->having can't be fixed after creation, so we do not check join->having->fixed */ - if (join->having->fix_fields(thd, join->tables_list, 0)) + if (join->having->fix_fields(thd, 0)) { select_lex->having_fix_field= 0; DBUG_RETURN(RES_ERROR); @@ -1125,7 +1123,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) join->conds can't be fixed after creation, so we do not check join->conds->fixed */ - if (join->conds->fix_fields(thd, join->tables_list, 0)) + if (join->conds->fix_fields(thd, 0)) DBUG_RETURN(RES_ERROR); } @@ -1196,8 +1194,7 @@ Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func) thd->lex->current_select= up= current->return_after_parsing(); result= (!left_expr->fixed && - left_expr->fix_fields(thd, up->get_table_list(), - optimizer->arguments())); + left_expr->fix_fields(thd, optimizer->arguments())); /* fix_fields can change reference to left_expr, we need reassign it */ left_expr= optimizer->arguments()[0]; @@ -1487,7 +1484,7 @@ int subselect_uniquesubquery_engine::exec() TABLE *table= tab->table; for (store_key **copy=tab->ref.key_copy ; *copy ; copy++) { - if (tab->ref.key_err= (*copy)->copy()) + if ((tab->ref.key_err= (*copy)->copy()) & 1) { table->status= STATUS_NOT_FOUND; DBUG_RETURN(1); @@ -1540,7 +1537,7 @@ int subselect_indexsubquery_engine::exec() for (store_key **copy=tab->ref.key_copy ; *copy ; copy++) { - if (tab->ref.key_err= (*copy)->copy()) + if ((tab->ref.key_err= (*copy)->copy()) & 1) { table->status= STATUS_NOT_FOUND; DBUG_RETURN(1); diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 84935429353..e05db4a00cc 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -92,7 +92,7 @@ public: val_int(); return null_value; } - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); virtual bool exec(); virtual void fix_length_and_dec(); table_map used_tables() const; @@ -119,9 +119,9 @@ public: friend class select_subselect; friend class Item_in_optimizer; - friend bool Item_field::fix_fields(THD *, TABLE_LIST *, Item **); - friend bool Item_ref::fix_fields(THD *, TABLE_LIST *, Item **); - friend bool Item_param::fix_fields(THD *, TABLE_LIST *, Item **); + friend bool Item_field::fix_fields(THD *, Item **); + friend bool Item_ref::fix_fields(THD *, Item **); + friend bool Item_param::fix_fields(THD *, Item **); friend void mark_select_range_as_dependent(THD*, st_select_lex*, st_select_lex*, Field*, Item*, Item_ident*); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 76f94801b49..d2f1016891b 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -193,7 +193,7 @@ my_decimal *Item_sum_int::val_decimal(my_decimal *decimal_value) bool -Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_sum_num::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); @@ -208,7 +208,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) maybe_null=0; for (uint i=0 ; i < arg_count ; i++) { - if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1)) + if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1)) return TRUE; set_if_bigger(decimals, args[i]->decimals); maybe_null |= args[i]->maybe_null; @@ -253,7 +253,7 @@ Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) } bool -Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_sum_hybrid::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); @@ -268,7 +268,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) // 'item' can be changed during fix_fields if (!item->fixed && - item->fix_fields(thd, tables, args) || + item->fix_fields(thd, args) || (item= args[0])->check_cols(1)) return TRUE; decimals=item->decimals; @@ -2766,11 +2766,12 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)), */ Item_func_group_concat:: -Item_func_group_concat(bool distinct_arg, List<Item> *select_list, +Item_func_group_concat(Name_resolution_context *context_arg, + bool distinct_arg, List<Item> *select_list, SQL_LIST *order_list, String *separator_arg) :tmp_table_param(0), warning(0), separator(separator_arg), tree(0), table(0), - order(0), tables_list(0), + order(0), context(context_arg), arg_count_order(order_list ? order_list->elements : 0), arg_count_field(select_list->elements), count_cut_values(0), @@ -2826,7 +2827,7 @@ Item_func_group_concat::Item_func_group_concat(THD *thd, tree(item->tree), table(item->table), order(item->order), - tables_list(item->tables_list), + context(item->context), arg_count_order(item->arg_count_order), arg_count_field(item->arg_count_field), count_cut_values(item->count_cut_values), @@ -2946,7 +2947,7 @@ bool Item_func_group_concat::add() bool -Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_func_group_concat::fix_fields(THD *thd, Item **ref) { uint i; /* for loop variable */ DBUG_ASSERT(fixed == 0); @@ -2968,7 +2969,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) for (i=0 ; i < arg_count ; i++) { if ((!args[i]->fixed && - args[i]->fix_fields(thd, tables, args + i)) || + args[i]->fix_fields(thd, args + i)) || args[i]->check_cols(1)) return TRUE; if (i < arg_count_field) @@ -2979,7 +2980,6 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) null_value= 1; thd->allow_sum_func= 1; max_length= thd->variables.group_concat_max_len; - tables_list= tables; fixed= 1; return FALSE; } @@ -3029,7 +3029,7 @@ bool Item_func_group_concat::setup(THD *thd) tmp table columns. */ if (arg_count_order && - setup_order(thd, args, tables_list, list, all_fields, *order)) + setup_order(thd, args, context->table_list, list, all_fields, *order)) DBUG_RETURN(TRUE); count_field_types(tmp_table_param,all_fields,0); diff --git a/sql/item_sum.h b/sql/item_sum.h index b9a90ee5de5..32a1d8dd923 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -98,7 +98,7 @@ public: */ virtual const char *func_name() const= 0; virtual Item *result_item(Field *field) - { return new Item_field(field);} + { return new Item_field(field); } table_map used_tables() const { return ~(table_map) 0; } /* Not used */ bool const_item() const { return 0; } bool is_null() { return null_value; } @@ -124,7 +124,7 @@ public: Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {} Item_sum_num(List<Item> &list) :Item_sum(list) {} Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item) {} - bool fix_fields(THD *, TABLE_LIST *, Item **); + bool fix_fields(THD *, Item **); longlong val_int() { DBUG_ASSERT(fixed == 1); @@ -479,7 +479,8 @@ public: Item *result_item(Field *field) { return new Item_variance_field(this); } void no_rows_in_result() {} - const char *func_name() const { return "variance("; } + const char *func_name() const + { return sample ? "var_samp(" : "variance("; } Item *copy_or_same(THD* thd); Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); enum Item_result result_type () const { return hybrid_type; } @@ -543,7 +544,7 @@ protected: was_values(TRUE) { collation.set(&my_charset_bin); } Item_sum_hybrid(THD *thd, Item_sum_hybrid *item); - bool fix_fields(THD *, TABLE_LIST *, Item **); + bool fix_fields(THD *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } @@ -660,18 +661,21 @@ protected: udf_handler udf; public: - Item_udf_sum(udf_func *udf_arg) :Item_sum(), udf(udf_arg) { quick_group=0;} - Item_udf_sum( udf_func *udf_arg, List<Item> &list ) - :Item_sum( list ), udf(udf_arg) + Item_udf_sum(udf_func *udf_arg) + :Item_sum(), udf(udf_arg) + { quick_group=0; } + Item_udf_sum(udf_func *udf_arg, List<Item> &list) + :Item_sum(list), udf(udf_arg) { quick_group=0;} Item_udf_sum(THD *thd, Item_udf_sum *item) - :Item_sum(thd, item), udf(item->udf) { udf.not_original= TRUE; } + :Item_sum(thd, item), udf(item->udf) + { udf.not_original= TRUE; } const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); fixed= 1; - return udf.fix_fields(thd,tables,this,this->arg_count,this->args); + return udf.fix_fields(thd, this, this->arg_count, this->args); } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } virtual bool have_field_update(void) const { return 0; } @@ -688,9 +692,10 @@ public: class Item_sum_udf_float :public Item_udf_sum { public: - Item_sum_udf_float(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_float(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_float(udf_func *udf_arg, List<Item> &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) :Item_udf_sum(thd, item) {} longlong val_int() @@ -709,9 +714,10 @@ class Item_sum_udf_float :public Item_udf_sum class Item_sum_udf_int :public Item_udf_sum { public: - Item_sum_udf_int(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_int(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_int(udf_func *udf_arg, List<Item> &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) :Item_udf_sum(thd, item) {} longlong val_int(); @@ -728,7 +734,8 @@ public: class Item_sum_udf_str :public Item_udf_sum { public: - Item_sum_udf_str(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_str(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) :Item_udf_sum(udf_arg,list) {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) @@ -766,9 +773,10 @@ public: class Item_sum_udf_decimal :public Item_udf_sum { public: - Item_sum_udf_decimal(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_decimal(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item) :Item_udf_sum(thd, item) {} String *val_str(String *); @@ -785,7 +793,8 @@ public: class Item_sum_udf_float :public Item_sum_num { public: - Item_sum_udf_float(udf_func *udf_arg) :Item_sum_num() {} + Item_sum_udf_float(udf_func *udf_arg) + :Item_sum_num() {} Item_sum_udf_float(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) :Item_sum_num(thd, item) {} @@ -800,7 +809,8 @@ class Item_sum_udf_float :public Item_sum_num class Item_sum_udf_int :public Item_sum_num { public: - Item_sum_udf_int(udf_func *udf_arg) :Item_sum_num() {} + Item_sum_udf_int(udf_func *udf_arg) + :Item_sum_num() {} Item_sum_udf_int(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) :Item_sum_num(thd, item) {} @@ -816,15 +826,17 @@ public: class Item_sum_udf_decimal :public Item_sum_num { public: - Item_sum_udf_decimal(udf_func *udf_arg) :Item_sum_num() {} - Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} + Item_sum_udf_decimal(udf_func *udf_arg) + :Item_sum_num() {} + Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) + :Item_sum_num() {} Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item) :Item_sum_num(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } void clear() {} - bool add() { return 0; } + bool add() { return 0; } void update_field() {} }; @@ -832,8 +844,10 @@ class Item_sum_udf_decimal :public Item_sum_num class Item_sum_udf_str :public Item_sum_num { public: - Item_sum_udf_str(udf_func *udf_arg) :Item_sum_num() {} - Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} + Item_sum_udf_str(udf_func *udf_arg) + :Item_sum_num() {} + Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) + :Item_sum_num() {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) :Item_sum_num(thd, item) {} String *val_str(String *) @@ -862,7 +876,7 @@ class Item_func_group_concat : public Item_sum TREE *tree; TABLE *table; ORDER **order; - TABLE_LIST *tables_list; + Name_resolution_context *context; uint arg_count_order; // total count of ORDER BY items uint arg_count_field; // count of arguments uint count_cut_values; @@ -887,8 +901,9 @@ class Item_func_group_concat : public Item_sum Item_func_group_concat *group_concat_item); public: - Item_func_group_concat(bool is_distinct,List<Item> *is_select, - SQL_LIST *is_order,String *is_separator); + Item_func_group_concat(Name_resolution_context *context_arg, + bool is_distinct, List<Item> *is_select, + SQL_LIST *is_order, String *is_separator); Item_func_group_concat(THD *thd, Item_func_group_concat *item); ~Item_func_group_concat() {} @@ -901,7 +916,7 @@ public: bool add(); void reset_field() {} // not used void update_field() {} // not used - bool fix_fields(THD *, TABLE_LIST *, Item **); + bool fix_fields(THD *,Item **); bool setup(THD *thd); void make_unique(); double val_real() @@ -927,4 +942,6 @@ public: Item *copy_or_same(THD* thd); void no_rows_in_result() {} void print(String *str); + virtual bool change_context_processor(byte *cntx) + { context= (Name_resolution_context *)cntx; return FALSE; } }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 19386c15835..cac9613f1ad 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1753,10 +1753,10 @@ void Item_func_convert_tz::fix_length_and_dec() bool -Item_func_convert_tz::fix_fields(THD *thd_arg, TABLE_LIST *tables_arg, Item **ref) +Item_func_convert_tz::fix_fields(THD *thd_arg, Item **ref) { String str; - if (Item_date_func::fix_fields(thd_arg, tables_arg, ref)) + if (Item_date_func::fix_fields(thd_arg, ref)) return TRUE; tz_tables= thd_arg->lex->time_zone_tables_used; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index a6dd9f7da91..107d12e6da2 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -561,7 +561,7 @@ class Item_func_convert_tz :public Item_date_func double val_real() { return (double) val_int(); } String *val_str(String *str); const char *func_name() const { return "convert_tz"; } - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void fix_length_and_dec(); bool get_date(TIME *res, uint fuzzy_date); void cleanup(); diff --git a/sql/item_uniq.h b/sql/item_uniq.h index e95aa35101e..c884c454dac 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -47,7 +47,7 @@ public: bool add() { return 0; } void reset_field() {} void update_field() {} - bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); fixed= 1; diff --git a/sql/lex.h b/sql/lex.h index d0dc287775e..aa10328ced0 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -214,7 +214,9 @@ static SYMBOL symbols[] = { { "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION)}, { "GET_FORMAT", SYM(GET_FORMAT)}, { "GLOBAL", SYM(GLOBAL_SYM)}, +#ifdef SP_GOTO { "GOTO", SYM(GOTO_SYM)}, +#endif { "GRANT", SYM(GRANT)}, { "GRANTS", SYM(GRANTS)}, { "GROUP", SYM(GROUP)}, @@ -262,7 +264,10 @@ static SYMBOL symbols[] = { { "KEY", SYM(KEY_SYM)}, { "KEYS", SYM(KEYS)}, { "KILL", SYM(KILL_SYM)}, +#ifdef SP_GOTO + /* QQ This will go away when the GOTO label syntax is fixed */ { "LABEL", SYM(LABEL_SYM)}, +#endif { "LANGUAGE", SYM(LANGUAGE_SYM)}, { "LAST", SYM(LAST_SYM)}, { "LEADING", SYM(LEADING)}, diff --git a/sql/log_event.cc b/sql/log_event.cc index 08aedfb3f63..1519cfb6630 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2619,13 +2619,15 @@ void Load_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_ev #ifndef MYSQL_CLIENT void Load_log_event::set_fields(const char* affected_db, - List<Item> &field_list) + List<Item> &field_list, + Name_resolution_context *context) { uint i; const char* field = fields; for (i= 0; i < num_fields; i++) { - field_list.push_back(new Item_field(affected_db, table_name, field)); + field_list.push_back(new Item_field(context, + affected_db, table_name, field)); field+= field_lens[i] + 1; } } @@ -2748,7 +2750,9 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, thd->query= load_data_query; if (sql_ex.opt_flags & REPLACE_FLAG) + { handle_dup= DUP_REPLACE; + } else if (sql_ex.opt_flags & IGNORE_FLAG) { ignore= 1; @@ -2790,7 +2794,8 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, ex.skip_lines = skip_lines; List<Item> field_list; - set_fields(thd->db,field_list); + thd->main_lex.select_lex.context.resolve_in_table_list_only(&tables); + set_fields(thd->db, field_list, &thd->main_lex.select_lex.context); thd->variables.pseudo_thread_id= thread_id; List<Item> set_fields; if (net) @@ -3618,7 +3623,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) */ - e.fix_fields(thd, 0, 0); + e.fix_fields(thd, 0); /* A variable can just be considered as a table with a single record and with a single column. Thus, like diff --git a/sql/log_event.h b/sql/log_event.h index b163a37e7cc..9f4681ae2c5 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -877,7 +877,8 @@ public: const char* table_name_arg, List<Item>& fields_arg, enum enum_duplicates handle_dup, bool ignore, bool using_trans); - void set_fields(const char* db, List<Item> &fields_arg); + void set_fields(const char* db, List<Item> &fields_arg, + Name_resolution_context *context); const char* get_db() { return db; } #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2b185dbc13b..122ac08c389 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -667,6 +667,7 @@ int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t); Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Item ***copy_func, Field **from_field, bool group, bool modify_item, + bool table_cant_handle_bit_fields, uint convert_blob_length); void sp_prepare_create_field(THD *thd, create_field *sql_field); int prepare_create_field(create_field *sql_field, @@ -725,7 +726,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields, List<List_item> &values, List<Item> &update_fields, List<Item> &update_values, enum_duplicates flag, bool ignore); -int check_that_all_fields_are_given_values(THD *thd, TABLE *entry); +int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, + TABLE_LIST *table_list); bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds); bool mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, SQL_LIST *order, ha_rows rows, ulong options); @@ -756,7 +758,8 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, Item **ref, find_item_error_report_type report_error, - bool check_privileges); + bool check_privileges, + bool register_tree_change); Field * find_field_in_table(THD *thd, TABLE_LIST *table_list, const char *name, const char *item_name, @@ -892,16 +895,29 @@ Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter, bool *unaliased); bool get_key_map_from_key_list(key_map *map, TABLE *table, List<String> *index_list); -bool insert_fields(THD *thd,TABLE_LIST *tables, +bool insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, - List_iterator<Item> *it, bool any_privileges); -bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, + List_iterator<Item> *it, bool any_privileges); +bool setup_tables(THD *thd, Name_resolution_context *context, + TABLE_LIST *tables, Item **conds, TABLE_LIST **leaves, bool select_insert); int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, List<Item> *sum_func_list, uint wild_num); -bool setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables, +bool setup_fields(THD *thd, Item** ref_pointer_array, List<Item> &item, ulong set_query_id, List<Item> *sum_func_list, bool allow_sum_func); +inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array, + List<Item> &item, bool set_query_id, + List<Item> *sum_func_list, + bool allow_sum_func) +{ + bool res; + thd->lex->select_lex.no_wrap_view_item= TRUE; + res= setup_fields(thd, ref_pointer_array, item, set_query_id, sum_func_list, + allow_sum_func); + thd->lex->select_lex.no_wrap_view_item= FALSE; + return res; +} int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds); int setup_ftfuncs(SELECT_LEX* select); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 6a1d04fa69a..30bb84a3cb4 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -141,6 +141,7 @@ int deny_severity = LOG_WARNING; #define zVOLSTATE_DEACTIVE 2 #define zVOLSTATE_MAINTENANCE 3 +#include <nks/netware.h> #include <nks/vm.h> #include <library.h> #include <monitor.h> @@ -3008,14 +3009,15 @@ int main(int argc, char **argv) #endif #ifdef __WIN__ -/* Before performing any socket operation (like retrieving hostname */ -/* in init_common_variables we have to call WSAStartup */ - if (!opt_disable_networking) + /* + Before performing any socket operation (like retrieving hostname + in init_common_variables we have to call WSAStartup + */ { WSADATA WsaData; if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData)) { - /* errors are not read yet, so we use test here */ + /* errors are not read yet, so we use english text here */ my_message(ER_WSAS_FAILED, "WSAStartup Failed", MYF(0)); unireg_abort(1); } @@ -4460,7 +4462,7 @@ Disable with --skip-bdb (will save memory).", (gptr*) &default_collation_name, (gptr*) &default_collation_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, {"default-storage-engine", OPT_STORAGE_ENGINE, - "Set the default storage engine (table tyoe) for tables.", 0, 0, + "Set the default storage engine (table type) for tables.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"default-table-type", OPT_STORAGE_ENGINE, "(deprecated) Use --default-storage-engine.", 0, 0, @@ -5389,7 +5391,7 @@ The minimum value for this variable is 4096.", "Default pointer size to be used for MyISAM tables.", (gptr*) &myisam_data_pointer_size, (gptr*) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG, - 6, 2, 8, 0, 1, 0}, + 6, 2, 7, 0, 1, 0}, {"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, "Deprecated option", (gptr*) &global_system_variables.myisam_max_extra_sort_file_size, @@ -6335,9 +6337,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case (int) OPT_SLOW_QUERY_LOG: opt_slow_log=1; break; - case (int) OPT_LOG_SLOW_ADMIN_STATEMENTS: - opt_log_slow_admin_statements= 1; - break; case (int) OPT_SKIP_NEW: opt_specialflag|= SPECIAL_NO_NEW_FUNC; delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7645ce39eea..e04e15788fa 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -325,7 +325,7 @@ typedef struct st_qsel_param { TABLE *table; KEY_PART *key_parts,*key_parts_end; KEY_PART *key[MAX_KEY]; /* First key parts of keys used in the query */ - MEM_ROOT *mem_root; + MEM_ROOT *mem_root, *old_root; table_map prev_tables,read_tables,current_table; uint baseflag, max_key_part, range_count; @@ -1669,7 +1669,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, keys_to_use.intersect(head->keys_in_use_for_query); if (!keys_to_use.is_clear_all()) { - MEM_ROOT *old_root,alloc; + MEM_ROOT alloc; SEL_TREE *tree= NULL; KEY_PART *key_parts; KEY *key_info; @@ -1684,6 +1684,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, param.table=head; param.keys=0; param.mem_root= &alloc; + param.old_root= thd->mem_root; param.needed_reg= &needed_reg; param.imerge_cost_buff_size= 0; @@ -1699,7 +1700,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, DBUG_RETURN(0); // Can't use range } key_parts= param.key_parts; - old_root= thd->mem_root; thd->mem_root= &alloc; /* @@ -1849,7 +1849,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, } } - thd->mem_root= old_root; + thd->mem_root= param.old_root; /* If we got a read plan, create a quick select from it. */ if (best_trp) @@ -1864,7 +1864,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, free_mem: free_root(&alloc,MYF(0)); // Return memory & allocator - thd->mem_root= old_root; + thd->mem_root= param.old_root; thd->no_errors=0; } @@ -3533,15 +3533,12 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) { /* Optimize NOT BETWEEN and NOT IN */ Item *arg= cond_func->arguments()[0]; - if (arg->type() == Item::FUNC_ITEM) - { - cond_func= (Item_func*) arg; - if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) - DBUG_RETURN(0); - inv= TRUE; - } - else + if (arg->type() != Item::FUNC_ITEM) DBUG_RETURN(0); + cond_func= (Item_func*) arg; + if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) + DBUG_RETURN(0); + inv= TRUE; } else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) DBUG_RETURN(0); @@ -3586,15 +3583,16 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) DBUG_RETURN(ftree); } default: - if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM) + if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM) { - field_item= (Item_field*) (cond_func->arguments()[0]); + field_item= (Item_field*) (cond_func->arguments()[0]->real_item()); value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : 0; } else if (cond_func->have_rev_func() && - cond_func->arguments()[1]->type() == Item::FIELD_ITEM) + cond_func->arguments()[1]->real_item()->type() == + Item::FIELD_ITEM) { - field_item= (Item_field*) (cond_func->arguments()[1]); + field_item= (Item_field*) (cond_func->arguments()[1]->real_item()); value= cond_func->arguments()[0]; } else @@ -3615,7 +3613,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) for (uint i= 0; i < cond_func->arg_count; i++) { - Item *arg= cond_func->arguments()[i]; + Item *arg= cond_func->arguments()[i]->real_item(); if (arg != field_item) ref_tables|= arg->used_tables(); } @@ -3700,24 +3698,38 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, { uint maybe_null=(uint) field->real_maybe_null(); bool optimize_range; - SEL_ARG *tree; + SEL_ARG *tree= 0; + MEM_ROOT *alloc= param->mem_root; char *str; DBUG_ENTER("get_mm_leaf"); + /* + We need to restore the runtime mem_root of the thread in this + function because it evaluates the value of its argument, while + the argument can be any, e.g. a subselect. The subselect + items, in turn, assume that all the memory allocated during + the evaluation has the same life span as the item itself. + TODO: opt_range.cc should not reset thd->mem_root at all. + */ + param->thd->mem_root= param->old_root; if (!value) // IS NULL or IS NOT NULL { if (field->table->maybe_null) // Can't use a key on this - DBUG_RETURN(0); + goto end; if (!maybe_null) // Not null field - DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0); - if (!(tree=new SEL_ARG(field,is_null_string,is_null_string))) - DBUG_RETURN(0); // out of memory + { + if (type == Item_func::ISNULL_FUNC) + tree= &null_element; + goto end; + } + if (!(tree= new (alloc) SEL_ARG(field,is_null_string,is_null_string))) + goto end; // out of memory if (type == Item_func::ISNOTNULL_FUNC) { tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */ tree->max_flag=NO_MAX_RANGE; } - DBUG_RETURN(tree); + goto end; } /* @@ -3737,7 +3749,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, key_part->image_type == Field::itRAW && ((Field_str*)field)->charset() != conf_func->compare_collation() && !(conf_func->compare_collation()->state & MY_CS_BINSORT)) - DBUG_RETURN(0); + goto end; optimize_range= field->optimize_range(param->real_keynr[key_part->key], key_part->part); @@ -3751,9 +3763,12 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, uint field_length= field->pack_length()+maybe_null; if (!optimize_range) - DBUG_RETURN(0); // Can't optimize this + goto end; if (!(res= value->val_str(&tmp))) - DBUG_RETURN(&null_element); + { + tree= &null_element; + goto end; + } /* TODO: @@ -3766,7 +3781,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, res= &tmp; } if (field->cmp_type() != STRING_RESULT) - DBUG_RETURN(0); // Can only optimize strings + goto end; // Can only optimize strings offset=maybe_null; length=key_part->store_length; @@ -3791,8 +3806,8 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, field_length= length; } length+=offset; - if (!(min_str= (char*) alloc_root(param->mem_root, length*2))) - DBUG_RETURN(0); + if (!(min_str= (char*) alloc_root(alloc, length*2))) + goto end; max_str=min_str+length; if (maybe_null) @@ -3807,20 +3822,21 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, min_str+offset, max_str+offset, &min_length, &max_length); if (like_error) // Can't optimize with LIKE - DBUG_RETURN(0); + goto end; if (offset != maybe_null) // BLOB or VARCHAR { int2store(min_str+maybe_null,min_length); int2store(max_str+maybe_null,max_length); } - DBUG_RETURN(new SEL_ARG(field,min_str,max_str)); + tree= new (alloc) SEL_ARG(field, min_str, max_str); + goto end; } if (!optimize_range && type != Item_func::EQ_FUNC && type != Item_func::EQUAL_FUNC) - DBUG_RETURN(0); // Can't optimize this + goto end; // Can't optimize this /* We can't always use indexes when comparing a string index to a number @@ -3829,21 +3845,53 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, if (field->result_type() == STRING_RESULT && value->result_type() != STRING_RESULT && field->cmp_type() != value->result_type()) - DBUG_RETURN(0); + goto end; if (value->save_in_field_no_warnings(field, 1) < 0) { /* This happens when we try to insert a NULL field in a not null column */ - DBUG_RETURN(&null_element); // cmp with NULL is never TRUE + tree= &null_element; // cmp with NULL is never TRUE + goto end; } - str= (char*) alloc_root(param->mem_root, key_part->store_length+1); + str= (char*) alloc_root(alloc, key_part->store_length+1); if (!str) - DBUG_RETURN(0); + goto end; if (maybe_null) *str= (char) field->is_real_null(); // Set to 1 if null field->get_key_image(str+maybe_null, key_part->length, key_part->image_type); - if (!(tree=new SEL_ARG(field,str,str))) - DBUG_RETURN(0); // out of memory + if (!(tree= new (alloc) SEL_ARG(field, str, str))) + goto end; // out of memory + + /* + Check if we are comparing an UNSIGNED integer with a negative constant. + In this case we know that: + (a) (unsigned_int [< | <=] negative_constant) == FALSE + (b) (unsigned_int [> | >=] negative_constant) == TRUE + In case (a) the condition is false for all values, and in case (b) it + is true for all values, so we can avoid unnecessary retrieval and condition + testing, and we also get correct comparison of unsinged integers with + negative integers (which otherwise fails because at query execution time + negative integers are cast to unsigned if compared with unsigned). + */ + if (field->result_type() == INT_RESULT && + value->result_type() == INT_RESULT && + ((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag) + { + longlong item_val= value->val_int(); + if (item_val < 0) + { + if (type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) + { + tree->type= SEL_ARG::IMPOSSIBLE; + goto end; + } + if (type == Item_func::GT_FUNC || type == Item_func::GE_FUNC) + { + tree= 0; + goto end; + } + } + } switch (type) { case Item_func::LT_FUNC: @@ -3904,6 +3952,9 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, default: break; } + +end: + param->thd->mem_root= alloc; DBUG_RETURN(tree); } @@ -5997,7 +6048,10 @@ int QUICK_RANGE_SELECT::reset() next=0; range= NULL; cur_range= (QUICK_RANGE**) ranges.buffer; - + + if (file->inited == handler::NONE && (error= file->ha_index_init(index))) + DBUG_RETURN(error); + /* Do not allocate the buffers twice. */ if (multi_range_length) { @@ -8126,7 +8180,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next() (have_max && have_min && (max_res == 0))); } /* - If this is a just a GROUP BY or DISTINCT without MIN or MAX and there + If this is just a GROUP BY or DISTINCT without MIN or MAX and there are equality predicates for the key parts after the group, find the first sub-group with the extended prefix. */ @@ -8529,23 +8583,21 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range() if ((result == HA_ERR_KEY_NOT_FOUND) && (cur_range->flag & EQ_RANGE)) continue; /* Check the next range. */ - else if (result) + if (result) + { /* In no key was found with this upper bound, there certainly are no keys in the ranges to the left. */ return result; - + } /* A key was found. */ if (cur_range->flag & EQ_RANGE) - return result; /* No need to perform the checks below for equal keys. */ + return 0; /* No need to perform the checks below for equal keys. */ /* Check if record belongs to the current group. */ if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) - { - result = HA_ERR_KEY_NOT_FOUND; - continue; - } + continue; // Row not found /* If there is a lower limit, check if the found key is in the range. */ if ( !(cur_range->flag & NO_MIN_RANGE) ) diff --git a/sql/protocol.cc b/sql/protocol.cc index 57922cdc677..ade94a483a8 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -28,6 +28,7 @@ #include <stdarg.h> static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024; +static void write_eof_packet(THD *thd, NET *net); #ifndef EMBEDDED_LIBRARY bool Protocol::net_store_data(const char *from, uint length) @@ -294,7 +295,12 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) DBUG_ENTER("send_ok"); if (net->no_send_ok || !net->vio) // hack for re-parsing queries + { + DBUG_PRINT("info", ("no send ok: %s, vio present: %s", + (net->no_send_ok ? "YES" : "NO"), + (net->vio ? "YES" : "NO"))); DBUG_VOID_RETURN; + } buff[0]=0; // No fields pos=net_store_length(buff+1,(ulonglong) affected_rows); @@ -357,43 +363,52 @@ static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ */ void -send_eof(THD *thd, bool no_flush) +send_eof(THD *thd) { NET *net= &thd->net; DBUG_ENTER("send_eof"); if (net->vio != 0 && !net->no_send_eof) { - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - uchar buff[5]; - /* Don't send warn count during SP execution, as the warn_list - is cleared between substatements, and mysqltest gets confused */ - uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535)); - buff[0]=254; - int2store(buff+1, tmp); - /* - The following test should never be true, but it's better to do it - because if 'is_fatal_error' is set the server is not going to execute - other queries (see the if test in dispatch_command / COM_QUERY) - */ - if (thd->is_fatal_error) - thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; - int2store(buff+3, thd->server_status); - VOID(my_net_write(net,(char*) buff,5)); - VOID(net_flush(net)); - } - else - { - VOID(my_net_write(net,eof_buff,1)); - if (!no_flush) - VOID(net_flush(net)); - } + write_eof_packet(thd, net); + VOID(net_flush(net)); thd->net.no_send_error= 1; DBUG_PRINT("info", ("EOF sent, so no more error sending allowed")); } DBUG_VOID_RETURN; } + +/* + Format EOF packet according to the current protocol and + write it to the network output buffer. +*/ + +static void write_eof_packet(THD *thd, NET *net) +{ + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + uchar buff[5]; + /* + Don't send warn count during SP execution, as the warn_list + is cleared between substatements, and mysqltest gets confused + */ + uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535)); + buff[0]= 254; + int2store(buff+1, tmp); + /* + The following test should never be true, but it's better to do it + because if 'is_fatal_error' is set the server is not going to execute + other queries (see the if test in dispatch_command / COM_QUERY) + */ + if (thd->is_fatal_error) + thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; + int2store(buff+3, thd->server_status); + VOID(my_net_write(net, (char*) buff, 5)); + } + else + VOID(my_net_write(net, eof_buff, 1)); +} + /* Please client to send scrambled_password in old format. SYNOPSYS @@ -635,7 +650,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) } if (flags & SEND_EOF) - my_net_write(&thd->net, eof_buff, 1); + write_eof_packet(thd, &thd->net); DBUG_RETURN(prepare_for_send(list)); err: diff --git a/sql/protocol.h b/sql/protocol.h index 5b402cb2669..2717d2258fa 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -179,7 +179,7 @@ void net_printf_error(THD *thd, uint sql_errno, ...); void net_send_error(THD *thd, uint sql_errno=0, const char *err=0); void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, const char *info=0); -void send_eof(THD *thd, bool no_flush=0); +void send_eof(THD *thd); bool send_old_password_request(THD *thd); char *net_store_length(char *packet,uint length); char *net_store_data(char *to,const char *from, uint length); diff --git a/sql/set_var.cc b/sql/set_var.cc index 1c0de702e4e..ae7e4bd844b 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1617,7 +1617,7 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) { if (!(res= var->value->val_str(&str))) { - strmake(buff, "NULL", 4); + strmov(buff, "NULL"); goto err; } var->save_result.ulong_value= ((ulong) @@ -2983,7 +2983,7 @@ int set_var::check(THD *thd) } if ((!value->fixed && - value->fix_fields(thd, 0, &value)) || value->check_cols(1)) + value->fix_fields(thd, &value)) || value->check_cols(1)) return -1; if (var->check_update_type(value->result_type())) { @@ -3017,7 +3017,7 @@ int set_var::light_check(THD *thd) if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)) return 1; - if (value && ((!value->fixed && value->fix_fields(thd, 0, &value)) || + if (value && ((!value->fixed && value->fix_fields(thd, &value)) || value->check_cols(1))) return -1; return 0; @@ -3046,7 +3046,7 @@ int set_var_user::check(THD *thd) Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) */ - return (user_var_item->fix_fields(thd, 0, (Item**) 0) || + return (user_var_item->fix_fields(thd, (Item**) 0) || user_var_item->check()) ? -1 : 0; } @@ -3069,7 +3069,7 @@ int set_var_user::light_check(THD *thd) Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) */ - return (user_var_item->fix_fields(thd, 0, (Item**) 0)); + return (user_var_item->fix_fields(thd, (Item**) 0)); } @@ -3238,7 +3238,16 @@ void fix_sql_mode_var(THD *thd, enum_var_type type) global_system_variables.sql_mode= fix_sql_mode(global_system_variables.sql_mode); else + { thd->variables.sql_mode= fix_sql_mode(thd->variables.sql_mode); + /* + Update thd->server_status + */ + if (thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) + thd->server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES; + else + thd->server_status&= ~SERVER_STATUS_NO_BACKSLASH_ESCAPES; + } } /* Map database specific bits to function bits */ diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index fcc04c950aa..622c570fa9a 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5021,7 +5021,7 @@ ER_NON_UPDATABLE_TABLE por "A tabela destino %-.100s do %s não é atualizável" rus "ôÁÂÌÉÃÁ %-.100s × %s ÎÅ ÍÏÖÅÔ ÉÚÍÅÎÑÔÓÑ" spa "La tabla destino %-.100s del %s no es actualizable" - swe "Tabel %-.100s använd med '%s' är inte uppdateringsbar" + swe "Tabell %-.100s använd med '%s' är inte uppdateringsbar" ukr "ôÁÂÌÉÃÑ %-.100s Õ %s ÎÅ ÍÏÖÅ ÏÎÏ×ÌÀ×ÁÔÉÓØ" ER_FEATURE_DISABLED eng "The '%s' feature is disabled; you need MySQL built with '%s' to have it working" @@ -5358,3 +5358,13 @@ ER_STMT_HAS_NO_OPEN_CURSOR eng "The statement (%lu) has no open cursor." ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG eng "Explicit or implicit commit is not allowed in stored function or trigger." +ER_NO_DEFAULT_FOR_VIEW_FIELD + eng "Field of view '%-.64s.%-.64s' underlying table doesn't have a default value" +ER_SP_NO_RECURSION + eng "Recursive stored routines are not allowed." +ER_TOO_BIG_SCALE 42000 S1009 + eng "Too big scale %d specified for column '%-.64s'. Maximum is %d." +ER_TOO_BIG_PRECISION 42000 S1009 + eng "Too big precision %d specified for column '%-.64s'. Maximum is %d." +ER_SCALE_BIGGER_THAN_PRECISION 42000 S1009 + eng "Scale may not be larger than the precision (column '%-.64s')." diff --git a/sql/sp.cc b/sql/sp.cc index 4f89d6ba6da..cf842803c01 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -19,6 +19,7 @@ #include "sp.h" #include "sp_head.h" #include "sp_cache.h" +#include "sql_trigger.h" static bool create_string(THD *thd, String *buf, @@ -67,7 +68,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, enum thr_lock_type ltype, TABLE **tablep, bool *opened) { TABLE *table; - byte key[NAME_LEN*2+4+1]; // db, name, optional key length type + byte key[MAX_KEY_LENGTH]; // db, name, optional key length type DBUG_ENTER("db_find_routine_aux"); DBUG_PRINT("enter", ("type: %d name: %*s", type, name->m_name.length, name->m_name.str)); @@ -676,15 +677,20 @@ db_show_routine_status(THD *thd, int type, const char *wild) tables is not VIEW for sure => we can pass 0 as condition */ - setup_tables(thd, &tables, 0, &leaves, FALSE); + thd->lex->select_lex.context.resolve_in_table_list_only(&tables); + setup_tables(thd, &thd->lex->select_lex.context, + &tables, 0, &leaves, FALSE); for (used_field= &used_fields[0]; used_field->field_name; used_field++) { - Item_field *field= new Item_field("mysql", "proc", + Item_field *field= new Item_field(&thd->lex->select_lex.context, + "mysql", "proc", used_field->field_name); - if (!(used_field->field= find_field_in_tables(thd, field, &tables, - 0, REPORT_ALL_ERRORS, 1))) + if (!field || + !(used_field->field= find_field_in_tables(thd, field, &tables, + 0, REPORT_ALL_ERRORS, 1, + TRUE))) { res= SP_INTERNAL_ERROR; goto err_case1; @@ -1072,145 +1078,317 @@ sp_function_exists(THD *thd, sp_name *name) } -byte * -sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first) +/* + Structure that represents element in the set of stored routines + used by statement or routine. +*/ +struct Sroutine_hash_entry; + +struct Sroutine_hash_entry { - LEX_STRING *lsp= (LEX_STRING *)ptr; - *plen= lsp->length; - return (byte *)lsp->str; + /* Set key consisting of one-byte routine type and quoted routine name. */ + LEX_STRING key; + /* + Next element in list linking all routines in set. See also comments + for LEX::sroutine/sroutine_list and sp_head::m_sroutines. + */ + Sroutine_hash_entry *next; +}; + + +extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first) +{ + Sroutine_hash_entry *rn= (Sroutine_hash_entry *)ptr; + *plen= rn->key.length; + return (byte *)rn->key.str; } -void -sp_add_to_hash(HASH *h, sp_name *fun) +/* + Auxilary function that adds new element to the set of stored routines + used by statement. + + SYNOPSIS + add_used_routine() + lex - LEX representing statement + arena - arena in which memory for new element will be allocated + key - key for the hash representing set + + NOTES + Will also add element to end of 'LEX::sroutines_list' list. + + In case when statement uses stored routines but does not need + prelocking (i.e. it does not use any tables) we will access the + elements of LEX::sroutines set on prepared statement re-execution. + Because of this we have to allocate memory for both hash element + and copy of its key in persistent arena. + + TODO + When we will got rid of these accesses on re-executions we will be + able to allocate memory for hash elements in non-persitent arena + and directly use key values from sp_head::m_sroutines sets instead + of making their copies. + + RETURN VALUE + TRUE - new element was added. + FALSE - element was not added (because it is already present in the set). +*/ + +static bool add_used_routine(LEX *lex, Query_arena *arena, + const LEX_STRING *key) { - if (! hash_search(h, (byte *)fun->m_qname.str, fun->m_qname.length)) + if (!hash_search(&lex->sroutines, (byte *)key->str, key->length)) { - LEX_STRING *ls= (LEX_STRING *)sql_alloc(sizeof(LEX_STRING)); - ls->str= sql_strmake(fun->m_qname.str, fun->m_qname.length); - ls->length= fun->m_qname.length; - - my_hash_insert(h, (byte *)ls); + Sroutine_hash_entry *rn= + (Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry) + + key->length); + if (!rn) // OOM. Error will be reported using fatal_error(). + return FALSE; + rn->key.length= key->length; + rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry); + memcpy(rn->key.str, key->str, key->length); + my_hash_insert(&lex->sroutines, (byte *)rn); + lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next); + return TRUE; } + return FALSE; } /* - Merge contents of two hashes containing LEX_STRING's + Add routine to the set of stored routines used by statement. SYNOPSIS - sp_merge_hash() + sp_add_used_routine() + lex - LEX representing statement + arena - arena in which memory for new element of the set + will be allocated + rt - routine name + rt_type - routine type (one of TYPE_ENUM_PROCEDURE/...) + + NOTES + Will also add element to end of 'LEX::sroutines_list' list. + + To be friendly towards prepared statements one should pass + persistent arena as second argument. +*/ + +void sp_add_used_routine(LEX *lex, Query_arena *arena, + sp_name *rt, char rt_type) +{ + rt->set_routine_type(rt_type); + (void)add_used_routine(lex, arena, &rt->m_sroutines_key); +} + + +/* + Merge contents of two hashes representing sets of routines used + by statements or by other routines. + + SYNOPSIS + sp_update_sp_used_routines() dst - hash to which elements should be added src - hash from which elements merged - RETURN VALUE - TRUE - if we have added some new elements to destination hash. - FALSE - there were no new elements in src. + NOTE + This procedure won't create new Sroutine_hash_entry objects, + instead it will simply add elements from source to destination + hash. Thus time of life of elements in destination hash becomes + dependant on time of life of elements from source hash. It also + won't touch lists linking elements in source and destination + hashes. */ -bool -sp_merge_hash(HASH *dst, HASH *src) +void sp_update_sp_used_routines(HASH *dst, HASH *src) { - bool res= FALSE; for (uint i=0 ; i < src->records ; i++) { - LEX_STRING *ls= (LEX_STRING *)hash_element(src, i); - - if (! hash_search(dst, (byte *)ls->str, ls->length)) - { - my_hash_insert(dst, (byte *)ls); - res= TRUE; - } + Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i); + if (!hash_search(dst, (byte *)rt->key.str, rt->key.length)) + my_hash_insert(dst, (byte *)rt); } - return res; } /* - Cache all routines implicitly or explicitly used by query - (or whatever object is represented by LEX). + Add contents of hash representing set of routines to the set of + routines used by statement. SYNOPSIS - sp_cache_routines() + sp_update_stmt_used_routines() thd - thread context - lex - LEX representing query + lex - LEX representing statement + src - hash representing set from which routines will be added + + NOTE + It will also add elements to end of 'LEX::sroutines_list' list. +*/ + +static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src) +{ + for (uint i=0 ; i < src->records ; i++) + { + Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i); + (void)add_used_routine(lex, thd->current_arena, &rt->key); + } +} + + +/* + Cache sub-set of routines used by statement, add tables used by these + routines to statement table list. Do the same for all routines used + by these routines. + + SYNOPSIS + sp_cache_routines_and_add_tables_aux() + thd - thread context + lex - LEX representing statement + start - first routine from the list of routines to be cached + (this list defines mentioned sub-set). NOTE If some function is missing this won't be reported here. Instead this fact will be discovered during query execution. - TODO - Currently if after passing through routine hashes we discover - that we have added something to them, we do one more pass to - process all routines which were missed on previous pass because - of these additions. We can avoid this if along with hashes - we use lists holding routine names and iterate other these - lists instead of hashes (since addition to the end of list - does not reorder elements in it). + RETURN VALUE + TRUE - some tables were added + FALSE - no tables were added. */ -void -sp_cache_routines(THD *thd, LEX *lex) +static bool +sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, + Sroutine_hash_entry *start) { - bool routines_added= TRUE; + bool result= FALSE; - DBUG_ENTER("sp_cache_routines"); + DBUG_ENTER("sp_cache_routines_and_add_tables_aux"); - while (routines_added) + for (Sroutine_hash_entry *rt= start; rt; rt= rt->next) { - routines_added= FALSE; + sp_name name(rt->key.str, rt->key.length); + int type= rt->key.str[0]; + sp_head *sp; - for (int type= TYPE_ENUM_FUNCTION; type < TYPE_ENUM_TRIGGER; type++) + if (!(sp= sp_cache_lookup((type == TYPE_ENUM_FUNCTION ? + &thd->sp_func_cache : &thd->sp_proc_cache), + &name))) { - HASH *h= (type == TYPE_ENUM_FUNCTION ? &lex->spfuns : &lex->spprocs); - - for (uint i=0 ; i < h->records ; i++) + LEX *oldlex= thd->lex; + LEX *newlex= new st_lex; + thd->lex= newlex; + /* Pass hint pointer to mysql.proc table */ + newlex->proc_table= oldlex->proc_table; + newlex->current_select= NULL; + name.m_name.str= strchr(name.m_qname.str, '.'); + name.m_db.length= name.m_name.str - name.m_qname.str; + name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str, + name.m_db.length); + name.m_name.str+= 1; + name.m_name.length= name.m_qname.length - name.m_db.length - 1; + + if (db_find_routine(thd, type, &name, &sp) == SP_OK) { - LEX_STRING *ls= (LEX_STRING *)hash_element(h, i); - sp_name name(*ls); - sp_head *sp; - - name.m_qname= *ls; - if (!(sp= sp_cache_lookup((type == TYPE_ENUM_FUNCTION ? - &thd->sp_func_cache : &thd->sp_proc_cache), - &name))) - { - LEX *oldlex= thd->lex; - LEX *newlex= new st_lex; - - thd->lex= newlex; - /* Pass hint pointer to mysql.proc table */ - newlex->proc_table= oldlex->proc_table; - newlex->current_select= NULL; - name.m_name.str= strchr(name.m_qname.str, '.'); - name.m_db.length= name.m_name.str - name.m_qname.str; - name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str, - name.m_db.length); - name.m_name.str+= 1; - name.m_name.length= name.m_qname.length - name.m_db.length - 1; - - if (db_find_routine(thd, type, &name, &sp) == SP_OK) - { - if (type == TYPE_ENUM_FUNCTION) - sp_cache_insert(&thd->sp_func_cache, sp); - else - sp_cache_insert(&thd->sp_proc_cache, sp); - } - delete newlex; - thd->lex= oldlex; - } + if (type == TYPE_ENUM_FUNCTION) + sp_cache_insert(&thd->sp_func_cache, sp); + else + sp_cache_insert(&thd->sp_proc_cache, sp); + } + delete newlex; + thd->lex= oldlex; + } + if (sp) + { + sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines); + result|= sp->add_used_tables_to_table_list(thd, &lex->query_tables_last); + } + } + DBUG_RETURN(result); +} + + +/* + Cache all routines from the set of used by statement, add tables used + by those routines to statement table list. Do the same for all routines + used by those routines. + + SYNOPSIS + sp_cache_routines_and_add_tables() + thd - thread context + lex - LEX representing statement + + RETURN VALUE + TRUE - some tables were added + FALSE - no tables were added. +*/ + +bool +sp_cache_routines_and_add_tables(THD *thd, LEX *lex) +{ - if (sp) + return sp_cache_routines_and_add_tables_aux(thd, lex, + (Sroutine_hash_entry *)lex->sroutines_list.first); +} + + +/* + Add all routines used by view to the set of routines used by statement. + Add tables used by those routines to statement table list. Do the same + for all routines used by these routines. + + SYNOPSIS + sp_cache_routines_and_add_tables_for_view() + thd - thread context + lex - LEX representing statement + aux_lex - LEX representing view +*/ + +void +sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex) +{ + Sroutine_hash_entry **last_cached_routine_ptr= + (Sroutine_hash_entry **)lex->sroutines_list.next; + sp_update_stmt_used_routines(thd, lex, &aux_lex->sroutines); + (void)sp_cache_routines_and_add_tables_aux(thd, lex, + *last_cached_routine_ptr); +} + + +/* + Add triggers for table to the set of routines used by statement. + Add tables used by them to statement table list. Do the same for + all implicitly used routines. + + SYNOPSIS + sp_cache_routines_and_add_tables_for_triggers() + thd - thread context + lex - LEX respresenting statement + triggers - triggers of the table +*/ + +void +sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, + Table_triggers_list *triggers) +{ + if (add_used_routine(lex, thd->current_arena, &triggers->sroutines_key)) + { + Sroutine_hash_entry **last_cached_routine_ptr= + (Sroutine_hash_entry **)lex->sroutines_list.next; + for (int i= 0; i < 3; i++) + for (int j= 0; j < 2; j++) + if (triggers->bodies[i][j]) { - routines_added|= sp_merge_hash(&lex->spfuns, &sp->m_spfuns); - routines_added|= sp_merge_hash(&lex->spprocs, &sp->m_spprocs); + (void)triggers->bodies[i][j]->add_used_tables_to_table_list(thd, + &lex->query_tables_last); + sp_update_stmt_used_routines(thd, lex, + &triggers->bodies[i][j]->m_sroutines); } - } - } + + (void)sp_cache_routines_and_add_tables_aux(thd, lex, + *last_cached_routine_ptr); } - DBUG_VOID_RETURN; } + /* * Generates the CREATE... string from the table information. * Returns TRUE on success, FALSE on (alloc) failure. @@ -79,15 +79,19 @@ sp_function_exists(THD *thd, sp_name *name); /* - * For precaching of functions and procedures - */ -void -sp_add_to_hash(HASH *h, sp_name *fun); -bool -sp_merge_hash(HASH *dst, HASH *src); -void -sp_cache_routines(THD *thd, LEX *lex); - + Procedures for pre-caching of stored routines and building table list + for prelocking. +*/ +void sp_add_used_routine(LEX *lex, Query_arena *arena, + sp_name *rt, char rt_type); +void sp_update_sp_used_routines(HASH *dst, HASH *src); +bool sp_cache_routines_and_add_tables(THD *thd, LEX *lex); +void sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, + LEX *aux_lex); +void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, + Table_triggers_list *triggers); + +extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first); // // Utilities... diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 29cee6da4d3..272456d8c8e 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -117,7 +117,7 @@ sp_prepare_func_item(THD* thd, Item **it_addr) DBUG_ENTER("sp_prepare_func_item"); it_addr= it->this_item_addr(thd, it_addr); - if (!it->fixed && (*it_addr)->fix_fields(thd, 0, it_addr)) + if (!it->fixed && (*it_addr)->fix_fields(thd, it_addr)) { DBUG_PRINT("info", ("fix_fields() failed")); DBUG_RETURN(NULL); @@ -242,8 +242,11 @@ sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type, void sp_name::init_qname(THD *thd) { - m_qname.length= m_db.length+m_name.length+1; - m_qname.str= thd->alloc(m_qname.length+1); + m_sroutines_key.length= m_db.length + m_name.length + 2; + if (!(m_sroutines_key.str= thd->alloc(m_sroutines_key.length + 1))) + return; + m_qname.length= m_sroutines_key.length - 1; + m_qname.str= m_sroutines_key.str + 1; sprintf(m_qname.str, "%*s.%*s", m_db.length, (m_db.length ? m_db.str : ""), m_name.length, m_name.str); @@ -312,19 +315,17 @@ sp_head::operator delete(void *ptr, size_t size) sp_head::sp_head() :Query_arena(&main_mem_root, INITIALIZED_FOR_SP), m_returns_cs(NULL), m_has_return(FALSE), - m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(FALSE) + m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(FALSE), + m_is_invoked(FALSE) { extern byte * sp_table_key(const byte *ptr, uint *plen, my_bool first); - extern byte - *sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first); DBUG_ENTER("sp_head::sp_head"); m_backpatch.empty(); m_lex.empty(); hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); - hash_init(&m_spfuns, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0); - hash_init(&m_spprocs, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0); + hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0); DBUG_VOID_RETURN; } @@ -509,7 +510,7 @@ sp_head::destroy() delete i; delete_dynamic(&m_instr); m_pcont->destroy(); - free_items(free_list); + free_items(); /* If we have non-empty LEX stack then we just came out of parser with @@ -527,8 +528,7 @@ sp_head::destroy() } hash_free(&m_sptabs); - hash_free(&m_spfuns); - hash_free(&m_spprocs); + hash_free(&m_sroutines); DBUG_VOID_RETURN; } @@ -587,6 +587,28 @@ sp_head::execute(THD *thd) DBUG_RETURN(-1); } + if (m_is_invoked) + { + /* + We have to disable recursion for stored routines since in + many cases LEX structure and many Item's can't be used in + reentrant way now. + + TODO: We can circumvent this problem by using separate + sp_head instances for each recursive invocation. + + NOTE: Theoretically arguments of procedure can be evaluated + before its invocation so there should be no problem with + recursion. But since we perform cleanup for CALL statement + as for any other statement only after its execution, its LEX + structure is not reusable for recursive calls. Thus we have + to prohibit recursion for stored procedures too. + */ + my_error(ER_SP_NO_RECURSION, MYF(0)); + DBUG_RETURN(-1); + } + m_is_invoked= TRUE; + dbchanged= FALSE; if (m_db.length && (ret= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0, &dbchanged))) @@ -596,7 +618,6 @@ sp_head::execute(THD *thd) ctx->clear_handler(); thd->query_error= 0; old_arena= thd->current_arena; - thd->current_arena= this; /* We have to save/restore this info when we are changing call level to @@ -636,23 +657,24 @@ sp_head::execute(THD *thd) break; DBUG_PRINT("execute", ("Instruction %u", ip)); thd->set_time(); // Make current_time() et al work - { - /* - We have to substitute free_list of executing statement to - current_arena to store there all new items created during execution - (for example '*' expanding, or items made during permanent subquery - transformation) - Note: Every statement have to have all its items listed in free_list - for correct cleaning them up - */ - Item *save_free_list= thd->current_arena->free_list; - thd->current_arena->free_list= i->free_list; - ret= i->execute(thd, &ip); - i->free_list= thd->current_arena->free_list; - thd->current_arena->free_list= save_free_list; - } + /* + We have to set thd->current_arena before executing the instruction + to store in the instruction free_list all new items, created + during the first execution (for example expanding of '*' or the + items made during other permanent subquery transformations). + */ + thd->current_arena= i; + ret= i->execute(thd, &ip); + /* + If this SP instruction have sent eof, it has caused no_send_error to be + set. Clear it back to allow the next instruction to send error. (multi- + statement execution code clears no_send_error between statements too) + */ + thd->net.no_send_error= 0; if (i->free_list) cleanup_items(i->free_list); + i->state= Query_arena::EXECUTED; + // Check if an exception has occurred and a handler has been found // Note: We havo to check even if ret==0, since warnings (and some // errors don't return a non-zero value. @@ -694,7 +716,6 @@ sp_head::execute(THD *thd) DBUG_ASSERT(!thd->derived_tables); thd->derived_tables= old_derived_tables; - cleanup_items(thd->current_arena->free_list); thd->current_arena= old_arena; state= EXECUTED; @@ -711,6 +732,7 @@ sp_head::execute(THD *thd) if (! thd->killed) ret= sp_change_db(thd, olddb, 0); } + m_is_invoked= FALSE; DBUG_RETURN(ret); } @@ -728,8 +750,8 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) sp_rcontext *nctx = NULL; uint i; int ret; - MEM_ROOT *old_mem_root, call_mem_root; - Item *old_free_list, *call_free_list; + MEM_ROOT call_mem_root; + Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena; if (argcount != params) { @@ -741,14 +763,11 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) } init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); - old_mem_root= thd->mem_root; - thd->mem_root= &call_mem_root; - old_free_list= thd->free_list; // Keep the old list - thd->free_list= NULL; // Start a new one + // QQ Should have some error checking here? (types, etc...) nctx= new sp_rcontext(csize, hmax, cmax); - nctx->callers_mem_root= old_mem_root; + nctx->callers_mem_root= thd->mem_root; for (i= 0 ; i < argcount ; i++) { sp_pvar_t *pvar = m_pcont->find_pvar(i); @@ -774,15 +793,16 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) } } thd->spcont= nctx; + thd->set_n_backup_item_arena(&call_arena, &backup_arena); + /* mem_root was moved to backup_arena */ + DBUG_ASSERT(nctx->callers_mem_root == backup_arena.mem_root); ret= execute(thd); // Partially restore context now. // We still need the call mem root and free list for processing // of the result. - call_free_list= thd->free_list; - thd->free_list= old_free_list; - thd->mem_root= old_mem_root; + thd->restore_backup_item_arena(&call_arena, &backup_arena); if (m_type == TYPE_ENUM_FUNCTION && ret == 0) { @@ -802,8 +822,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) thd->spcont= octx; // Now get rid of the rest of the callee context - cleanup_items(call_free_list); - free_items(call_free_list); + call_arena.free_items(); free_root(&call_mem_root, MYF(0)); DBUG_RETURN(ret); @@ -835,8 +854,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) sp_rcontext *octx = thd->spcont; sp_rcontext *nctx = NULL; my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx - MEM_ROOT *old_mem_root, call_mem_root; - Item *old_free_list, *call_free_list; + MEM_ROOT call_mem_root; + Query_arena call_arena(&call_mem_root, INITIALIZED_FOR_SP), backup_arena; if (args->elements != params) { @@ -846,10 +865,6 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) } init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); - old_mem_root= thd->mem_root; - thd->mem_root= &call_mem_root; - old_free_list= thd->free_list; // Keep the old list - thd->free_list= NULL; // Start a new one if (csize > 0 || hmax > 0 || cmax > 0) { @@ -914,14 +929,11 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) } if (! ret) + { + thd->set_n_backup_item_arena(&call_arena, &backup_arena); ret= execute(thd); - - // Partially restore context now. - // We still need the call mem root and free list for processing - // of out parameters. - call_free_list= thd->free_list; - thd->free_list= old_free_list; - thd->mem_root= old_mem_root; + thd->restore_backup_item_arena(&call_arena, &backup_arena); + } if (!ret && csize > 0) { @@ -979,7 +991,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) we do not check suv->fixed, because it can't be fixed after creation */ - suv->fix_fields(thd, NULL, &item); + suv->fix_fields(thd, &item); suv->fix_length_and_dec(); suv->check(); suv->update(); @@ -996,8 +1008,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) thd->spcont= octx; // Now get rid of the rest of the callee context - cleanup_items(call_free_list); - free_items(call_free_list); + call_arena.free_items(); thd->lex->unit.cleanup(); free_root(&call_mem_root, MYF(0)); @@ -1052,11 +1063,10 @@ sp_head::restore_lex(THD *thd) oldlex->trg_table_fields.push_back(&sublex->trg_table_fields); /* - Add routines which are used by statement to respective sets for - this routine + Add routines which are used by statement to respective set for + this routine. */ - sp_merge_hash(&m_spfuns, &sublex->spfuns); - sp_merge_hash(&m_spprocs, &sublex->spprocs); + sp_update_sp_used_routines(&m_sroutines, &sublex->sroutines); /* Merge tables used by this statement (but not by its functions or procedures) to multiset of tables used by this routine. @@ -1291,6 +1301,13 @@ void sp_head::add_instr(sp_instr *instr) { instr->free_list= m_thd->free_list; m_thd->free_list= 0; + /* + Memory root of every instruction is designated for permanent + transformations (optimizations) made on the parsed tree during + the first execution. It points to the memory root of the + entire stored procedure, as their life span is equal. + */ + instr->mem_root= &main_mem_root; insert_dynamic(&m_instr, (gptr)&instr); } @@ -1485,13 +1502,6 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, they want to store some value in local variable, pass return value and etc... So their life time should be longer than one instruction. - Probably we can call destructors for most of them then we are leaving - routine. But this won't help much as they are allocated in main query - MEM_ROOT anyway. So they all go to global thd->free_list. - - May be we can use some other MEM_ROOT for this purprose ??? - - What else should we do for cleanup ? cleanup_items() is called in sp_head::execute() */ return res; @@ -1593,16 +1603,22 @@ sp_instr_set::print(String *str) int sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) { - int res= 0; - DBUG_ENTER("sp_instr_set_trigger_field::execute"); - /* QQ: Still unsure what should we return in case of error 1 or -1 ? */ - if (!value->fixed && value->fix_fields(thd, 0, &value) || - trigger_field->fix_fields(thd, 0, 0) || - (value->save_in_field(trigger_field->field, 0) < 0)) + DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); +} + + +int +sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp) +{ + int res= 0; + Item *it= sp_prepare_func_item(thd, &value); + if (!it || + !trigger_field->fixed && trigger_field->fix_fields(thd, 0) || + (it->save_in_field(trigger_field->field, 0) < 0)) res= -1; - *nextp= m_ip + 1; - DBUG_RETURN(res); + *nextp = m_ip+1; + return res; } void @@ -1953,7 +1969,7 @@ int sp_instr_cpush::execute(THD *thd, uint *nextp) { DBUG_ENTER("sp_instr_cpush::execute"); - thd->spcont->push_cursor(&m_lex_keeper); + thd->spcont->push_cursor(&m_lex_keeper, this); *nextp= m_ip+1; DBUG_RETURN(0); } @@ -2012,12 +2028,24 @@ sp_instr_copen::execute(THD *thd, uint *nextp) } else { + Query_arena *old_arena= thd->current_arena; + + /* + Get the Query_arena from the cpush instruction, which contains + the free_list of the query, so new items (if any) are stored in + the right free_list, and we can cleanup after each open. + */ + thd->current_arena= c->get_instr(); res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this); + /* Cleanup the query's items */ + if (thd->current_arena->free_list) + cleanup_items(thd->current_arena->free_list); + thd->current_arena= old_arena; /* Work around the fact that errors in selects are not returned properly (but instead converted into a warning), so if a condition handler caught, we have lost the result code. - */ + */ if (!res) { uint dummy1, dummy2; @@ -2414,72 +2442,3 @@ sp_add_to_query_tables(THD *thd, LEX *lex, return table; } - -/* - Auxilary function for adding tables used by routines used in query - to table lists. - - SYNOPSIS - sp_add_sp_tables_to_table_list_aux() - thd - thread context - lex - LEX to which table list tables will be added - func_hash - routines for which tables should be added - func_cache- SP cache in which this routines should be looked up - - NOTE - See sp_add_sp_tables_to_table_list() for more info. - - RETURN VALUE - TRUE - some tables were added - FALSE - no tables were added. -*/ - -static bool -sp_add_sp_tables_to_table_list_aux(THD *thd, LEX *lex, HASH *func_hash, - sp_cache **func_cache) -{ - uint i; - bool result= FALSE; - - for (i= 0 ; i < func_hash->records ; i++) - { - sp_head *sp; - LEX_STRING *ls= (LEX_STRING *)hash_element(func_hash, i); - sp_name name(*ls); - - name.m_qname= *ls; - if ((sp= sp_cache_lookup(func_cache, &name))) - result|= sp->add_used_tables_to_table_list(thd, &lex->query_tables_last); - } - - return result; -} - - -/* - Add tables used by routines used in query to table list. - - SYNOPSIS - sp_add_sp_tables_to_table_list() - thd - thread context - lex - LEX to which table list tables will be added - func_lex - LEX for which functions we get tables - (useful for adding tables used by view routines) - - NOTE - Elements of list will be allocated in PS memroot, so this - list will be persistent between PS execetutions. - - RETURN VALUE - TRUE - some tables were added - FALSE - no tables were added. -*/ - -bool -sp_add_sp_tables_to_table_list(THD *thd, LEX *lex, LEX *func_lex) -{ - return (sp_add_sp_tables_to_table_list_aux(thd, lex, &func_lex->spfuns, - &thd->sp_func_cache) | - sp_add_sp_tables_to_table_list_aux(thd, lex, &func_lex->spprocs, - &thd->sp_proc_cache)); -} diff --git a/sql/sp_head.h b/sql/sp_head.h index 2c75a320f30..32dc4449174 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -48,24 +48,50 @@ public: LEX_STRING m_db; LEX_STRING m_name; LEX_STRING m_qname; + /* + Key representing routine in the set of stored routines used by statement. + Consists of 1-byte routine type and m_qname (which usually refences to + same buffer). Note that one must complete initialization of the key by + calling set_routine_type(). + */ + LEX_STRING m_sroutines_key; sp_name(LEX_STRING name) : m_name(name) { - m_db.str= m_qname.str= 0; - m_db.length= m_qname.length= 0; + m_db.str= m_qname.str= m_sroutines_key.str= 0; + m_db.length= m_qname.length= m_sroutines_key.length= 0; } sp_name(LEX_STRING db, LEX_STRING name) : m_db(db), m_name(name) { - m_qname.str= 0; - m_qname.length= 0; + m_qname.str= m_sroutines_key.str= 0; + m_qname.length= m_sroutines_key.length= 0; + } + + /* + Creates temporary sp_name object from key, used mainly + for SP-cache lookups. + */ + sp_name(char *key, uint key_len) + { + m_sroutines_key.str= key; + m_sroutines_key.length= key_len; + m_name.str= m_qname.str= key + 1; + m_name.length= m_qname.length= key_len - 1; + m_db.str= 0; + m_db.length= 0; } // Init. the qualified name from the db and name. void init_qname(THD *thd); // thd for memroot allocation + void set_routine_type(char type) + { + m_sroutines_key.str[0]= type; + } + ~sp_name() {} }; @@ -107,13 +133,13 @@ public: longlong m_created; longlong m_modified; /* - Sets containing names of SP and SF used by this routine. - - TODO Probably we should combine these two hashes in one. It will - decrease memory overhead ans simplify algorithms using them. The - same applies to similar hashes in LEX. + Set containing names of stored routines used by this routine. + Note that unlike elements of similar set for statement elements of this + set are not linked in one list. Because of this we are able save memory + by using for this set same objects that are used in 'sroutines' sets + for statements of which this stored routine consists. */ - HASH m_spfuns, m_spprocs; + HASH m_sroutines; // Pointers set during parsing uchar *m_param_begin, *m_param_end, *m_body_begin; @@ -259,6 +285,9 @@ private: */ HASH m_sptabs; + /* Used for tracking of routine invocations and preventing recursion. */ + bool m_is_invoked; + int execute(THD *thd); @@ -274,7 +303,7 @@ private: // "Instructions"... // -class sp_instr : public Sql_alloc +class sp_instr :public Query_arena, public Sql_alloc { sp_instr(const sp_instr &); /* Prevent use of these */ void operator=(sp_instr &); @@ -282,17 +311,16 @@ class sp_instr : public Sql_alloc public: uint marked; - Item *free_list; // My Items uint m_ip; // My index sp_pcontext *m_ctx; // My parse context // Should give each a name or type code for debugging purposes? sp_instr(uint ip, sp_pcontext *ctx) - :Sql_alloc(), marked(0), free_list(0), m_ip(ip), m_ctx(ctx) + :Query_arena(0, INITIALIZED_FOR_SP), marked(0), m_ip(ip), m_ctx(ctx) {} virtual ~sp_instr() - { free_items(free_list); } + { free_items(); } // Execute this instrution. '*nextp' will be set to the index of the next // instruction to execute. (For most instruction this will be the @@ -472,10 +500,11 @@ class sp_instr_set_trigger_field : public sp_instr public: sp_instr_set_trigger_field(uint ip, sp_pcontext *ctx, - Item_trigger_field *trg_fld, Item *val) + Item_trigger_field *trg_fld, + Item *val, LEX *lex) : sp_instr(ip, ctx), trigger_field(trg_fld), - value(val) + value(val), m_lex_keeper(lex, TRUE) {} virtual ~sp_instr_set_trigger_field() @@ -483,11 +512,14 @@ public: virtual int execute(THD *thd, uint *nextp); + virtual int exec_core(THD *thd, uint *nextp); + virtual void print(String *str); private: Item_trigger_field *trigger_field; Item *value; + sp_lex_keeper m_lex_keeper; }; // class sp_instr_trigger_field : public sp_instr @@ -952,7 +984,5 @@ TABLE_LIST * sp_add_to_query_tables(THD *thd, LEX *lex, const char *db, const char *name, thr_lock_type locktype); -bool -sp_add_sp_tables_to_table_list(THD *thd, LEX *lex, LEX *func_lex); #endif /* _SP_HEAD_H_ */ diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index aacb9254753..d0817e43790 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -148,9 +148,9 @@ sp_rcontext::restore_variables(uint fp) } void -sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper) +sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i) { - m_cstack[m_ccount++]= new sp_cursor(lex_keeper); + m_cstack[m_ccount++]= new sp_cursor(lex_keeper, i); } void @@ -169,8 +169,9 @@ sp_rcontext::pop_cursors(uint count) * */ -sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper) - :m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL) +sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i) + :m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL), + m_i(i) { /* currsor can't be stored in QC, so we should prevent opening QC for diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index b188805435f..856beb13f6d 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -26,6 +26,7 @@ struct sp_cond_type; class sp_cursor; struct sp_pvar; class sp_lex_keeper; +class sp_instr_cpush; #define SP_HANDLER_NONE 0 #define SP_HANDLER_EXIT 1 @@ -161,7 +162,7 @@ class sp_rcontext : public Sql_alloc restore_variables(uint fp); void - push_cursor(sp_lex_keeper *lex_keeper); + push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i); void pop_cursors(uint count); @@ -203,7 +204,7 @@ class sp_cursor : public Sql_alloc { public: - sp_cursor(sp_lex_keeper *lex_keeper); + sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i); virtual ~sp_cursor() { @@ -229,6 +230,12 @@ public: int fetch(THD *, List<struct sp_pvar> *vars); + inline sp_instr_cpush * + get_instr() + { + return m_i; + } + private: MEM_ROOT m_mem_root; // My own mem_root @@ -238,6 +245,7 @@ private: my_bool m_nseof; // Original no_send_eof Protocol *m_oprot; // Original protcol MYSQL_ROWS *m_current_row; + sp_instr_cpush *m_i; // My push instruction void destroy(); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5e2df88f91e..315103aa8b1 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2034,7 +2034,8 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) { uint key_prefix_len; KEY_PART_INFO *key_part= col_privs->key_info->key_part; - col_privs->field[0]->store(host.hostname,(uint) strlen(host.hostname), + col_privs->field[0]->store(host.hostname, + host.hostname ? (uint) strlen(host.hostname) : 0, system_charset_info); col_privs->field[1]->store(db,(uint) strlen(db), system_charset_info); col_privs->field[2]->store(user,(uint) strlen(user), system_charset_info); @@ -2475,7 +2476,6 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, int old_row_exists= 1; int error=0; ulong store_proc_rights; - byte *key; DBUG_ENTER("replace_routine_table"); if (!initialized) @@ -3216,7 +3216,6 @@ my_bool grant_init(THD *org_thd) do { GRANT_NAME *mem_check; - longlong proc_type; HASH *hash; if (!(mem_check=new GRANT_NAME(p_table))) { diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 87280c4e9ba..5e62e7ce6e3 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -107,8 +107,15 @@ (((A) & DB_CHUNK2) >> 6) | \ (((A) & DB_CHUNK3) >> 9) | \ (((A) & DB_CHUNK4) >> 2)) -#define fix_rights_for_table(A) (((A) & 63) | (((A) & ~63) << 4)) -#define get_rights_for_table(A) (((A) & 63) | (((A) & ~63) >> 4)) +#define TBL_CHUNK0 DB_CHUNK0 +#define TBL_CHUNK1 DB_CHUNK1 +#define TBL_CHUNK2 (CREATE_VIEW_ACL | SHOW_VIEW_ACL) +#define fix_rights_for_table(A) (((A) & TBL_CHUNK0) | \ + (((A) << 4) & TBL_CHUNK1) | \ + (((A) << 11) & TBL_CHUNK2)) +#define get_rights_for_table(A) (((A) & TBL_CHUNK0) | \ + (((A) & TBL_CHUNK1) >> 4) | \ + (((A) & TBL_CHUNK2) >> 11)) #define fix_rights_for_column(A) (((A) & 7) | (((A) & ~7) << 8)) #define get_rights_for_column(A) (((A) & 7) | ((A) >> 8)) #define fix_rights_for_procedure(A) ((((A) << 18) & EXECUTE_ACL) | \ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b112ca971c3..5f1031bcf83 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1611,8 +1611,18 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, */ if (discover_retry_count++ != 0) goto err; - if (ha_create_table_from_engine(thd, db, name, TRUE) != 0) + if (ha_create_table_from_engine(thd, db, name) > 0) + { + /* Give right error message */ + thd->clear_error(); + DBUG_PRINT("error", ("Dicovery of %s/%s failed", db, name)); + my_printf_error(ER_UNKNOWN_ERROR, + "Failed to open '%-.64s', error while " + "unpacking from engine", + MYF(0), name); + goto err; + } mysql_reset_errors(thd, 1); // Clear warnings thd->clear_error(); // Clear error message @@ -1792,16 +1802,13 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter) may be still zero for prelocked statement... */ if (!thd->prelocked_mode && !thd->lex->requires_prelocking() && - (thd->lex->spfuns.records || thd->lex->spprocs.records)) + thd->lex->sroutines.records) { - TABLE_LIST **save_query_tables_last; - - sp_cache_routines(thd, thd->lex); - save_query_tables_last= thd->lex->query_tables_last; + TABLE_LIST **save_query_tables_last= thd->lex->query_tables_last; DBUG_ASSERT(thd->lex->query_tables == *start); - if (sp_add_sp_tables_to_table_list(thd, thd->lex, thd->lex) || + if (sp_cache_routines_and_add_tables(thd, thd->lex) || *start) { query_tables_last_own= save_query_tables_last; @@ -1837,19 +1844,16 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter) and add tables used by them to table list. */ if (!thd->prelocked_mode && !thd->lex->requires_prelocking() && - (tables->view->spfuns.records || tables->view->spprocs.records)) + tables->view->sroutines.records) { - // FIXME We should catch recursion for both views and funcs here - sp_cache_routines(thd, tables->view); - /* We have at least one table in TL here */ if (!query_tables_last_own) query_tables_last_own= thd->lex->query_tables_last; - sp_add_sp_tables_to_table_list(thd, thd->lex, tables->view); + sp_cache_routines_and_add_tables_for_view(thd, thd->lex, + tables->view); } /* Cleanup hashes because destructo for this LEX is never called */ - hash_free(&tables->view->spfuns); - hash_free(&tables->view->spprocs); + hash_free(&tables->view->sroutines); continue; } @@ -1904,9 +1908,6 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter) prelocking list. If we lock table for reading we won't update it so there is no need to process its triggers since they never will be activated. - - FIXME Now we are simply turning on prelocking. Proper integration - and testing is to be done later. */ if (!thd->prelocked_mode && !thd->lex->requires_prelocking() && tables->table->triggers && @@ -1914,6 +1915,8 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter) { if (!query_tables_last_own) query_tables_last_own= thd->lex->query_tables_last; + sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex, + tables->table->triggers); } free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC)); } @@ -2397,9 +2400,11 @@ Field *view_ref_found= (Field*) 0x2; name name of field item_name name of item if it will be created (VIEW) length length of name - ref expression substituted in VIEW should be + ref [in/out] expression substituted in VIEW should be passed using this reference (return view_ref_found) + (*ref != NULL) only if *ref contains + the item that we need to replace. check_grants_table do check columns grants for table? check_grants_view do check columns grants for view? allow_rowid do allow finding of "_rowid" field? @@ -2429,20 +2434,13 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, table_list->alias, name, item_name, (ulong) ref)); if (table_list->field_translation) { - uint num; - if (table_list->schema_table_reformed) - { - num= thd->lex->current_select->item_list.elements; - } - else - { - DBUG_ASSERT(ref != 0 && table_list->view != 0); - num= table_list->view->select_lex.item_list.elements; - } - Field_translator *trans= table_list->field_translation; - for (uint i= 0; i < num; i ++) + Field_iterator_view field_it; + field_it.set(table_list); + DBUG_ASSERT(table_list->schema_table_reformed || + (ref != 0 && table_list->view != 0)); + for (; !field_it.end_of_fields(); field_it.next()) { - if (!my_strcasecmp(system_charset_info, trans[i].name, name)) + if (!my_strcasecmp(system_charset_info, field_it.name(), name)) { if (table_list->schema_table_reformed) { @@ -2452,7 +2450,7 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, So we can return ->field. It is used only for 'show & where' commands. */ - DBUG_RETURN(((Item_field*) (trans[i].item))->field); + DBUG_RETURN(((Item_field*) (field_it.item()))->field); } #ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_grants_view && @@ -2462,26 +2460,23 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, name, length)) DBUG_RETURN(WRONG_GRANT); #endif - if (thd->lex->current_select->no_wrap_view_item) - { - if (register_tree_change) - thd->change_item_tree(ref, trans[i].item); - else - *ref= trans[i].item; - } - else + Item *item= field_it.create_item(thd); + if (!item) { - Item_ref *item_ref= new Item_ref(&trans[i].item, - table_list->view_name.str, - item_name); - /* as far as Item_ref have defined reference it do not need tables */ - if (register_tree_change && item_ref) - thd->change_item_tree(ref, item_ref); - else if (item_ref) - *ref= item_ref; - if (!(*ref)->fixed) - (*ref)->fix_fields(thd, 0, ref); + DBUG_RETURN(0); } + /* + *ref != NULL means that *ref contains the item that we need to + replace. If the item was aliased by the user, set the alias to + the replacing item. + */ + if (*ref && !(*ref)->is_autogenerated_name) + item->set_name((*ref)->name, (*ref)->name_length, + system_charset_info); + if (register_tree_change) + thd->change_item_tree(ref, item); + else + *ref= item; DBUG_RETURN((Field*) view_ref_found); } } @@ -2591,19 +2586,21 @@ Field *find_field_in_real_table(THD *thd, TABLE *table, SYNOPSIS find_field_in_tables() - thd Pointer to current thread structure - item Field item that should be found - tables Tables to be searched for item - ref If 'item' is resolved to a view field, ref is set to - point to the found view field - report_error Degree of error reporting: - - IGNORE_ERRORS then do not report any error - - IGNORE_EXCEPT_NON_UNIQUE report only non-unique - fields, suppress all other errors - - REPORT_EXCEPT_NON_UNIQUE report all other errors - except when non-unique fields were found - - REPORT_ALL_ERRORS - check_privileges need to check privileges + thd Pointer to current thread structure + item Field item that should be found + tables Tables to be searched for item + ref If 'item' is resolved to a view field, ref is set to + point to the found view field + report_error Degree of error reporting: + - IGNORE_ERRORS then do not report any error + - IGNORE_EXCEPT_NON_UNIQUE report only non-unique + fields, suppress all other errors + - REPORT_EXCEPT_NON_UNIQUE report all other errors + except when non-unique fields were found + - REPORT_ALL_ERRORS + check_privileges need to check privileges + register_tree_change TRUE if ref is not stack variable and we + need register changes in item tree RETURN VALUES 0 If error: the found field is not unique, or there are @@ -2619,7 +2616,7 @@ Field *find_field_in_real_table(THD *thd, TABLE *table, Field * find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, Item **ref, find_item_error_report_type report_error, - bool check_privileges) + bool check_privileges, bool register_tree_change) { Field *found=0; const char *db=item->db_name; @@ -2627,6 +2624,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, const char *name=item->field_name; uint length=(uint) strlen(name); char name_buff[NAME_LEN+1]; + bool allow_rowid; if (item->cached_table) { @@ -2661,7 +2659,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, (test(table->grant.want_privilege) && check_privileges), 1, &(item->cached_field_index), - TRUE); + register_tree_change); } if (found) { @@ -2694,13 +2692,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, db= name_buff; } - bool search_global= item->item_flags & MY_ITEM_PREFER_1ST_TABLE; if (table_name && table_name[0]) { /* Qualified field */ - bool found_table=0; - uint table_idx= 0; - for (; tables; tables= search_global?tables->next_global:tables->next_local, - table_idx++) + bool found_table= 0; + for (; tables; tables= tables->next_local) { /* TODO; Ensure that db and tables->db always points to something ! */ if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) && @@ -2717,7 +2712,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, (test(tables->grant.want_privilege) && check_privileges), 1, &(item->cached_field_index), - TRUE); + register_tree_change); if (find) { item->cached_table= tables; @@ -2736,8 +2731,6 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) 0; } found=find; - if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE) - break; } } } @@ -2762,11 +2755,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) not_found_field; return (Field*) 0; } - bool allow_rowid= tables && !tables->next_local; // Only one table - uint table_idx= 0; - for (; tables ; tables= search_global?tables->next_global:tables->next_local, - table_idx++) + allow_rowid= tables && !tables->next_local; // Only one table + for (; tables ; tables= tables->next_local) { + Field *field; if (!tables->table && !tables->ancestor) { if (report_error == REPORT_ALL_ERRORS || @@ -2775,17 +2767,17 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) not_found_field; } - Field *field= find_field_in_table(thd, tables, name, item->name, - length, ref, - (tables->table && - test(tables->table->grant. - want_privilege) && - check_privileges), - (test(tables->grant.want_privilege) && - check_privileges), - allow_rowid, - &(item->cached_field_index), - TRUE); + field= find_field_in_table(thd, tables, name, item->name, + length, ref, + (tables->table && + test(tables->table->grant. + want_privilege) && + check_privileges), + (test(tables->grant.want_privilege) && + check_privileges), + allow_rowid, + &(item->cached_field_index), + register_tree_change); if (field) { if (field == WRONG_GRANT) @@ -2801,8 +2793,6 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) 0; } found= field; - if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE) - break; } } if (found) @@ -3058,7 +3048,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, */ it.replace(new Item_int("Not_used", (longlong) 1, 21)); } - else if (insert_fields(thd,tables,((Item_field*) item)->db_name, + else if (insert_fields(thd, ((Item_field*) item)->context, + ((Item_field*) item)->db_name, ((Item_field*) item)->table_name, &it, any_privileges)) { @@ -3094,7 +3085,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, ** Check that all given fields exists and fill struct with current data ****************************************************************************/ -bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, +bool setup_fields(THD *thd, Item **ref_pointer_array, List<Item> &fields, ulong set_query_id, List<Item> *sum_func_list, bool allow_sum_func) { @@ -3123,7 +3114,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, Item **ref= ref_pointer_array; while ((item= it++)) { - if (!item->fixed && item->fix_fields(thd, tables, it.ref()) || + if (!item->fixed && item->fix_fields(thd, it.ref()) || (item= *(it.ref()))->check_cols(1)) { DBUG_RETURN(TRUE); /* purecov: inspected */ @@ -3173,6 +3164,7 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables) SYNOPSIS setup_tables() thd Thread handler + context name resolution contest to setup table list there tables Table list conds Condition of current SELECT (can be changed by VIEW) leaves List of join table leaves list @@ -3192,11 +3184,15 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables) TRUE error */ -bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, +bool setup_tables(THD *thd, Name_resolution_context *context, + TABLE_LIST *tables, Item **conds, TABLE_LIST **leaves, bool select_insert) { uint tablenr= 0; DBUG_ENTER("setup_tables"); + + context->table_list= tables; + /* this is used for INSERT ... SELECT. For select we setup tables except first (and its underlying tables) @@ -3251,10 +3247,21 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, table_list; table_list= table_list->next_local) { - if (table_list->ancestor && - table_list->setup_ancestor(thd, conds, - table_list->effective_with_check)) - DBUG_RETURN(1); + if (table_list->ancestor) + { + DBUG_ASSERT(table_list->view); + Query_arena *arena= thd->current_arena, backup; + bool res; + if (arena->is_conventional()) + arena= 0; // For easier test + else + thd->set_n_backup_item_arena(arena, &backup); + res= table_list->setup_ancestor(thd); + if (arena) + thd->restore_backup_item_arena(arena, &backup); + if (res) + DBUG_RETURN(1); + } } DBUG_RETURN(0); } @@ -3306,7 +3313,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, SYNOPSIS insert_fields() thd Thread handler - tables List of tables + context Context for name resolution db_name Database name in case of 'database_name.table_name.*' table_name Table name in case of 'table_name.*' it Pointer to '*' @@ -3320,7 +3327,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, */ bool -insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, +insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, List_iterator<Item> *it, bool any_privileges) { @@ -3344,7 +3351,9 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } found= 0; - for (; tables; tables= tables->next_local) + for (TABLE_LIST *tables= context->table_list; + tables; + tables= tables->next_local) { Field_iterator *iterator; TABLE_LIST *natural_join_table; @@ -3353,7 +3362,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, TABLE_LIST *last; TABLE_LIST *embedding; TABLE *table= tables->table; - bool alias_used= 0; if (!table_name || (!my_strcasecmp(table_alias_charset, table_name, tables->alias) && @@ -3387,16 +3395,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } } #endif - if (table) - thd->used_tables|= table->map; - else - { - view_iter.set(tables); - for (; !view_iter.end_of_fields(); view_iter.next()) - { - thd->used_tables|= view_iter.item(thd)->used_tables(); - } - } natural_join_table= 0; last= embedded= tables; @@ -3427,8 +3425,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, { iterator= &view_iter; view= 1; - alias_used= my_strcasecmp(table_alias_charset, - tables->table_name, tables->alias); } else { @@ -3437,6 +3433,10 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } iterator->set(tables); + /* for view used tables will be collected in following loop */ + if (table) + thd->used_tables|= table->map; + for (; !iterator->end_of_fields(); iterator->next()) { Item *not_used_item; @@ -3449,16 +3449,10 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, strlen(field_name), ¬_used_item, 0, 0, 0, ¬_used_field_index, TRUE)) { - Item *item= iterator->item(thd); - if (view && !thd->lex->current_select->no_wrap_view_item) - { - /* - as far as we have view, then item point to view_iter, so we - can use it directly for this view specific operation - */ - item= new Item_ref(view_iter.item_ptr(), tables->view_name.str, - field_name); - } + Item *item= iterator->create_item(thd); + if (!item) + goto err; + thd->used_tables|= item->used_tables(); if (!found++) (void) it->replace(item); // Replace '*' else @@ -3513,6 +3507,12 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, field->query_id=thd->query_id; table->used_keys.intersect(field->part_of_key); } + else + { + Item *item= ((Field_iterator_view *) iterator)->item(); + item->walk(&Item::reset_query_id_processor, + (byte *)(&thd->query_id)); + } } /* All fields are used in case if usual tables (in case of view used @@ -3532,9 +3532,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0)); else my_error(ER_BAD_TABLE_ERROR, MYF(0), table_name); -#ifndef NO_EMBEDDED_ACCESS_CHECKS err: -#endif DBUG_RETURN(1); } @@ -3545,16 +3543,25 @@ err: SYNOPSIS setup_conds() thd thread handler - tables list of tables for name resolving leaves list of leaves of join table tree */ -int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) +int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, + COND **conds) { SELECT_LEX *select_lex= thd->lex->current_select; Query_arena *arena= thd->current_arena, backup; - bool save_wrapper= thd->lex->current_select->no_wrap_view_item; TABLE_LIST *table= NULL; // For HP compilers + /* + it_is_update set to TRUE when tables of primary SELECT_LEX (SELECT_LEX + which belong to LEX, i.e. most up SELECT) will be updated by + INSERT/UPDATE/LOAD + NOTE: using this condition helps to prevent call of prepare_check_option() + from subquery of VIEW, because tables of subquery belongs to VIEW + (see condition before prepare_check_option() call) + */ + bool it_is_update= (select_lex == &thd->lex->select_lex) && + thd->lex->which_check_option_applicable(); DBUG_ENTER("setup_conds"); if (select_lex->conds_processed_with_permanent_arena || @@ -3563,12 +3570,17 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->set_query_id=1; - thd->lex->current_select->no_wrap_view_item= 0; + for (table= tables; table; table= table->next_local) + { + if (table->prepare_where(thd, conds, FALSE)) + goto err_no_arena; + } + select_lex->cond_count= 0; if (*conds) { thd->where="where clause"; - if (!(*conds)->fixed && (*conds)->fix_fields(thd, tables, conds) || + if (!(*conds)->fixed && (*conds)->fix_fields(thd, conds) || (*conds)->check_cols(1)) goto err_no_arena; } @@ -3586,11 +3598,12 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) /* Make a join an a expression */ thd->where="on clause"; if (!embedded->on_expr->fixed && - embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr) || + embedded->on_expr->fix_fields(thd, &embedded->on_expr) || embedded->on_expr->check_cols(1)) goto err_no_arena; select_lex->cond_count++; } + if (embedded->natural_join) { /* Make a join of all fields wich have the same name */ @@ -3670,7 +3683,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) { if (t2_field != view_ref_found) { - if (!(item_t2= new Item_field(thd, t2_field))) + if (!(item_t2= new Item_field(thd, &select_lex->context, + t2_field))) goto err; /* Mark field used for table cache */ t2_field->query_id= thd->query_id; @@ -3684,7 +3698,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) t1->file->ha_set_bit_in_read_set(t1_field->fieldnr); t1->used_keys.intersect(t1_field->part_of_key); } - Item_func_eq *tmp= new Item_func_eq(iterator->item(thd), + Item_func_eq *tmp= new Item_func_eq(iterator->create_item(thd), item_t2); if (!tmp) goto err; @@ -3700,7 +3714,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) { COND *on_expr= cond_and; if (!on_expr->fixed) - on_expr->fix_fields(thd, 0, &on_expr); + on_expr->fix_fields(thd, &on_expr); if (!embedded->outer_join) // Not left join { *conds= and_conds(*conds, cond_and); @@ -3709,7 +3723,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->restore_backup_item_arena(arena, &backup); if (*conds && !(*conds)->fixed) { - if ((*conds)->fix_fields(thd, tables, conds)) + if ((*conds)->fix_fields(thd, conds)) goto err_no_arena; } } @@ -3721,8 +3735,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->restore_backup_item_arena(arena, &backup); if (embedded->on_expr && !embedded->on_expr->fixed) { - if (embedded->on_expr->fix_fields(thd, tables, - &embedded->on_expr)) + if (embedded->on_expr->fix_fields(thd, &embedded->on_expr)) goto err_no_arena; } } @@ -3734,6 +3747,20 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) } while (embedding && embedding->nested_join->join_list.head() == embedded); + + /* process CHECK OPTION */ + if (it_is_update) + { + TABLE_LIST *view= table->belong_to_view; + if (!view) + view= table; + if (view->effective_with_check) + { + if (view->prepare_check_option(thd)) + goto err_no_arena; + thd->change_item_tree(&table->check_option, view->check_option); + } + } } if (!thd->current_arena->is_conventional()) @@ -3747,14 +3774,12 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) select_lex->where= *conds; select_lex->conds_processed_with_permanent_arena= 1; } - thd->lex->current_select->no_wrap_view_item= save_wrapper; DBUG_RETURN(test(thd->net.report_error)); err: if (arena) thd->restore_backup_item_arena(arena, &backup); err_no_arena: - thd->lex->current_select->no_wrap_view_item= save_wrapper; DBUG_RETURN(1); } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 6cd67adf16d..cbee80a8695 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -278,7 +278,6 @@ TODO list: - Move MRG_MYISAM table type processing to handlers, something like: tables_used->table->file->register_used_filenames(callback, first_argument); - - Make derived tables cachable. - QC improvement suggested by Monty: - Add a counter in open_table() for how many MERGE (ISAM or MyISAM) tables are cached in the table cache. @@ -2135,6 +2134,13 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used, tables_used; tables_used= tables_used->next_global, n++, block_table++) { + if (tables_used->derived) + { + DBUG_PRINT("qcache", ("derived table skipped")); + n--; + block_table--; + continue; + } block_table->n= n; if (tables_used->view) { @@ -2778,6 +2784,12 @@ static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used, tables_used->table->s->table_name, tables_used->table->s->table_cache_key, tables_used->table->s->db_type)); + if (tables_used->derived) + { + table_count--; + DBUG_PRINT("qcache", ("derived table skipped")); + continue; + } *tables_type|= tables_used->table->file->table_cache_type(); /* diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8abd7cbbe7d..bf6f41d00ed 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -171,9 +171,6 @@ THD::THD() spcont(NULL) { current_arena= this; -#ifndef DBUG_OFF - backup_arena= 0; -#endif host= user= priv_user= db= ip= 0; catalog= (char*)"std"; // the only catalog we have for now host_or_ip= "connecting host"; @@ -285,6 +282,8 @@ void THD::init(void) #endif pthread_mutex_unlock(&LOCK_global_system_variables); server_status= SERVER_STATUS_AUTOCOMMIT; + if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) + server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES; options= thd_startup_options; open_options=ha_open_options; update_lock_default= (variables.low_priority_updates ? @@ -528,7 +527,7 @@ void THD::cleanup_after_query() next_insert_id= 0; } /* Free Items that were created during this execution */ - free_items(free_list); + free_items(); /* In the rest of code we assume that free_list never points to garbage: Keep this predicate true. @@ -787,7 +786,10 @@ void THD::nocheck_register_item_tree_change(Item **place, Item *old_value, void *change_mem= alloc_root(runtime_memroot, sizeof(*change)); if (change_mem == 0) { - fatal_error(); + /* + OOM, thd->fatal_error() is called by the error handler of the + memroot. Just return. + */ return; } change= new (change_mem) Item_change_record; @@ -1454,17 +1456,16 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) (void)local_vars.push_back(new Item_splocal(mv->s, mv->offset)); else { - Item_func_set_user_var *xx = new Item_func_set_user_var(mv->s, item); + Item_func_set_user_var *var= new Item_func_set_user_var(mv->s, item); /* Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) Item_func_set_user_var can't be fixed after creation, so we do not - check xx->fixed + check var->fixed */ - xx->fix_fields(thd, (TABLE_LIST*) thd->lex->select_lex.table_list.first, - 0); - xx->fix_length_and_dec(); - vars.push_back(xx); + var->fix_fields(thd, 0); + var->fix_length_and_dec(); + vars.push_back(var); } } return 0; @@ -1485,6 +1486,21 @@ Query_arena::Type Query_arena::type() const } +void Query_arena::free_items() +{ + Item *next; + DBUG_ENTER("Query_arena::free_items"); + /* This works because items are allocated with sql_alloc() */ + for (; free_list; free_list= next) + { + next= free_list->next; + free_list->delete_self(); + } + /* Postcondition: free_list is 0 */ + DBUG_VOID_RETURN; +} + + /* Statement functions */ @@ -1526,15 +1542,19 @@ void Statement::set_statement(Statement *stmt) void Statement::set_n_backup_statement(Statement *stmt, Statement *backup) { + DBUG_ENTER("Statement::set_n_backup_statement"); backup->set_statement(this); set_statement(stmt); + DBUG_VOID_RETURN; } void Statement::restore_backup_statement(Statement *stmt, Statement *backup) { + DBUG_ENTER("Statement::restore_backup_statement"); stmt->set_statement(this); set_statement(backup); + DBUG_VOID_RETURN; } @@ -1556,11 +1576,12 @@ void THD::end_statement() void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup) { DBUG_ENTER("Query_arena::set_n_backup_item_arena"); - DBUG_ASSERT(backup_arena == 0); + DBUG_ASSERT(backup->is_backup_arena == FALSE); + backup->set_item_arena(this); set_item_arena(set); #ifndef DBUG_OFF - backup_arena= 1; + backup->is_backup_arena= TRUE; #endif DBUG_VOID_RETURN; } @@ -1569,10 +1590,11 @@ void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup) void Query_arena::restore_backup_item_arena(Query_arena *set, Query_arena *backup) { DBUG_ENTER("Query_arena::restore_backup_item_arena"); + DBUG_ASSERT(backup->is_backup_arena); set->set_item_arena(this); set_item_arena(backup); #ifndef DBUG_OFF - backup_arena= 0; + backup->is_backup_arena= FALSE; #endif DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index fbc5e5f85bf..66f91545f97 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -654,6 +654,14 @@ typedef struct system_status_var void free_tmp_table(THD *thd, TABLE *entry); +/* The following macro is to make init of Query_arena simpler */ +#ifndef DBUG_OFF +#define INIT_ARENA_DBUG_INFO is_backup_arena= 0 +#else +#define INIT_ARENA_DBUG_INFO +#endif + + class Query_arena { public: @@ -664,7 +672,7 @@ public: Item *free_list; MEM_ROOT *mem_root; // Pointer to current memroot #ifndef DBUG_OFF - bool backup_arena; + bool is_backup_arena; /* True if this arena is used for backup. */ #endif enum enum_state { @@ -682,12 +690,13 @@ public: Query_arena(MEM_ROOT *mem_root_arg, enum enum_state state_arg) : free_list(0), mem_root(mem_root_arg), state(state_arg) - {} + { INIT_ARENA_DBUG_INFO; } /* This constructor is used only when Query_arena is created as backup storage for another instance of Query_arena. */ - Query_arena() {}; + Query_arena() { INIT_ARENA_DBUG_INFO; } + virtual Type type() const; virtual ~Query_arena() {}; @@ -727,6 +736,8 @@ public: void set_n_backup_item_arena(Query_arena *set, Query_arena *backup); void restore_backup_item_arena(Query_arena *set, Query_arena *backup); void set_item_arena(Query_arena *set); + + void free_items(); }; @@ -1428,10 +1439,10 @@ public: }; #define tmp_disable_binlog(A) \ - ulong save_options= (A)->options; \ - (A)->options&= ~OPTION_BIN_LOG; + {ulong tmp_disable_binlog__save_options= (A)->options; \ + (A)->options&= ~OPTION_BIN_LOG -#define reenable_binlog(A) (A)->options= save_options; +#define reenable_binlog(A) (A)->options= tmp_disable_binlog__save_options;} /* Flags for the THD::system_thread (bitmap) variable */ #define SYSTEM_THREAD_DELAYED_INSERT 1 diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index e6f980859ab..2967e2a8a20 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -308,7 +308,9 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) SELECT_LEX *select_lex= &thd->lex->select_lex; DBUG_ENTER("mysql_prepare_delete"); - if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, FALSE) || + if (setup_tables(thd, &thd->lex->select_lex.context, + table_list, conds, &select_lex->leaf_tables, + FALSE) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || setup_ftfuncs(select_lex)) DBUG_RETURN(TRUE); @@ -364,7 +366,8 @@ bool mysql_multi_delete_prepare(THD *thd) lex->query_tables also point on local list of DELETE SELECT_LEX */ - if (setup_tables(thd, lex->query_tables, &lex->select_lex.where, + if (setup_tables(thd, &thd->lex->select_lex.context, + lex->query_tables, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE)) DBUG_RETURN(TRUE); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index e1d701936cf..fc9d15e94c4 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -114,6 +114,10 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) bool is_union= first_select->next_select() && first_select->next_select()->linkage == UNION_TYPE; + /* prevent name resolving out of derived table */ + for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select()) + sl->context.outer_context= 0; + if (!(derived_result= new select_union(0))) DBUG_RETURN(1); // out of memory diff --git a/sql/sql_do.cc b/sql/sql_do.cc index e37f3e86dda..08388dee516 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -24,7 +24,7 @@ bool mysql_do(THD *thd, List<Item> &values) List_iterator<Item> li(values); Item *value; DBUG_ENTER("mysql_do"); - if (setup_fields(thd, 0, 0, values, 0, 0, 0)) + if (setup_fields(thd, 0, values, 0, 0, 0)) DBUG_RETURN(TRUE); while ((value = li++)) value->val_int(); diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 8a12339ccee..2e262569386 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -146,6 +146,8 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, { DBUG_RETURN(NULL); } + query_cache_abort(&thd->net); + if (thd->warn_list.elements < thd->variables.max_error_count) { diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index e905f93b860..e109600bcd0 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -353,7 +353,9 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, LINT_INIT(key); LINT_INIT(key_len); - list.push_front(new Item_field(NULL,NULL,"*")); + thd->lex->select_lex.context.resolve_in_table_list_only(tables); + list.push_front(new Item_field(&thd->lex->select_lex.context, + NULL, NULL, "*")); List_iterator<Item> it(list); it++; @@ -410,7 +412,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, tables->table=table; if (cond && ((!cond->fixed && - cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1))) + cond->fix_fields(thd, &cond)) || cond->check_cols(1))) goto err0; if (keyname) @@ -422,7 +424,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } } - if (insert_fields(thd, tables, tables->db, tables->alias, &it, 0)) + if (insert_fields(thd, &thd->lex->select_lex.context, + tables->db, tables->alias, &it, 0)) goto err0; protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); @@ -505,7 +508,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, { // 'item' can be changed by fix_fields() call if ((!item->fixed && - item->fix_fields(thd, tables, it_ke.ref())) || + item->fix_fields(thd, it_ke.ref())) || (item= *it_ke.ref())->check_cols(1)) goto err; if (item->used_tables() & ~RAND_TABLE_BIT) diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 0cf8d1e93a7..6780beec258 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -81,14 +81,18 @@ enum enum_used_fields static bool init_fields(THD *thd, TABLE_LIST *tables, struct st_find_field *find_fields, uint count) { + Name_resolution_context *context= &thd->lex->select_lex.context; DBUG_ENTER("init_fields"); + context->resolve_in_table_list_only(tables); for (; count-- ; find_fields++) { /* We have to use 'new' here as field will be re_linked on free */ - Item_field *field= new Item_field("mysql", find_fields->table_name, + Item_field *field= new Item_field(context, + "mysql", find_fields->table_name, find_fields->field_name); if (!(find_fields->field= find_field_in_tables(thd, field, tables, - 0, REPORT_ALL_ERRORS, 1))) + 0, REPORT_ALL_ERRORS, 1, + TRUE))) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -544,7 +548,6 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol, prepare_simple_select() thd Thread handler cond WHERE part of select - tables list of tables, used in WHERE table goal table error code of error (out) @@ -553,11 +556,11 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol, # created SQL_SELECT */ -SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE_LIST *tables, +SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE *table, int *error) { if (!cond->fixed) - cond->fix_fields(thd, tables, &cond); // can never fail + cond->fix_fields(thd, &cond); // can never fail /* Assume that no indexes cover all required fields */ table->used_keys.clear_all(); @@ -599,7 +602,7 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen, new Item_string("\\",1,&my_charset_latin1)); if (thd->is_fatal_error) return 0; // OOM - return prepare_simple_select(thd,cond,tables,table,error); + return prepare_simple_select(thd, cond, table, error); } @@ -651,7 +654,8 @@ bool mysqld_help(THD *thd, const char *mask) tables do not contain VIEWs => we can pass 0 as conds */ - setup_tables(thd, tables, 0, &leaves, FALSE); + setup_tables(thd, &thd->lex->select_lex.context, + tables, 0, &leaves, FALSE); memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields)); if (init_fields(thd, tables, used_fields, array_elements(used_fields))) goto error; @@ -718,15 +722,15 @@ bool mysqld_help(THD *thd, const char *mask) Item *cond_cat_by_cat= new Item_func_equal(new Item_field(cat_cat_id), new Item_int((int32)category_id)); - if (!(select= prepare_simple_select(thd,cond_topic_by_cat, - tables,tables[0].table,&error))) + if (!(select= prepare_simple_select(thd, cond_topic_by_cat, + tables[0].table, &error))) goto error; get_all_items_for_category(thd,tables[0].table, used_fields[help_topic_name].field, select,&topics_list); delete select; - if (!(select= prepare_simple_select(thd,cond_cat_by_cat,tables, - tables[1].table,&error))) + if (!(select= prepare_simple_select(thd, cond_cat_by_cat, + tables[1].table, &error))) goto error; get_all_items_for_category(thd,tables[1].table, used_fields[help_category_name].field, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b1bb7c7e14b..2c1d481e104 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -31,7 +31,7 @@ static void end_delayed_insert(THD *thd); extern "C" pthread_handler_decl(handle_delayed_insert,arg); static void unlink_blobs(register TABLE *table); #endif -static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id); +static bool check_view_insertability(THD *thd, TABLE_LIST *view); /* Define to force use of my_malloc() if the allocated memory block is big */ @@ -111,7 +111,11 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } else { // Part field list - TABLE_LIST *save_next; + Name_resolution_context *context= &thd->lex->select_lex.context; + TABLE_LIST *save_next= table_list->next_local, + *save_context= context->table_list; + bool save_resolve_in_select_list= + thd->lex->select_lex.context.resolve_in_select_list; int res; if (fields.elements != values.elements) { @@ -120,16 +124,19 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } thd->dupp_field=0; - thd->lex->select_lex.no_wrap_view_item= 1; - save_next= table_list->next_local; // fields only from first table + thd->lex->select_lex.no_wrap_view_item= TRUE; + /* fields only from first table */ table_list->next_local= 0; + context->resolve_in_table_list_only(table_list); /* Indicate fields in list is to be updated by setting set_query_id parameter to 2. This sets the bit in the write_set for each field. */ - res= setup_fields(thd, 0, table_list, fields, 2, 0, 0); + res= setup_fields(thd, 0, fields, 2, 0, 0); table_list->next_local= save_next; - thd->lex->select_lex.no_wrap_view_item= 0; + thd->lex->select_lex.no_wrap_view_item= FALSE; + context->table_list= save_context; + context->resolve_in_select_list= save_resolve_in_select_list; if (res) return -1; if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE) @@ -168,7 +175,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, if (check_key_in_view(thd, table_list) || (table_list->view && - check_view_insertability(table_list, thd->query_id))) + check_view_insertability(thd, table_list))) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); return -1; @@ -201,7 +208,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, List<Item> &update_fields) { TABLE *table= insert_table_list->table; - ulong timestamp_query_id; + query_id_t timestamp_query_id; LINT_INIT(timestamp_query_id); /* @@ -219,7 +226,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, of all used fields to the threads query_id. It will also set all fields into the write set of this table. */ - if (setup_fields(thd, 0, insert_table_list, update_fields, 2, 0, 0)) + if (setup_fields(thd, 0, update_fields, 2, 0, 0)) return -1; if (table->timestamp_field) @@ -260,6 +267,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ulonglong id; COPY_INFO info; TABLE *table= 0; + TABLE_LIST *next_local; List_iterator_fast<List_item> its(values_list); List_item *values; #ifndef EMBEDDED_LIBRARY @@ -340,7 +348,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, /* mysql_prepare_insert set table_list->table if it was not set */ table= table_list->table; - // is table which we are changing used somewhere in other parts of query + next_local= table_list->next_local; + table_list->next_local= 0; + thd->lex->select_lex.context.resolve_in_table_list_only(table_list); value_count= values->elements; while ((values= its++)) { @@ -350,10 +360,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter); goto abort; } - if (setup_fields(thd, 0, table_list, *values, 0, 0, 0)) + if (setup_fields(thd, 0, *values, 0, 0, 0)) goto abort; } its.rewind (); + table_list->next_local= next_local; /* Fill in the given fields and dump it to the table file */ @@ -400,12 +411,16 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, MODE_STRICT_ALL_TABLES))); if ((fields.elements || !value_count) && - check_that_all_fields_are_given_values(thd, table)) + check_that_all_fields_are_given_values(thd, table, table_list)) { /* thd->net.report_error is now set, which will abort the next loop */ error= 1; } + if (table_list->prepare_where(thd, 0, TRUE) || + table_list->prepare_check_option(thd)) + error= 1; + while ((values= its++)) { if (fields.elements || !value_count) @@ -609,6 +624,7 @@ abort: SYNOPSIS check_view_insertability() + thd - thread handler view - reference on VIEW IMPLEMENTATION @@ -625,7 +641,7 @@ abort: TRUE - can't be used for insert */ -static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) +static bool check_view_insertability(THD * thd, TABLE_LIST *view) { uint num= view->view->select_lex.item_list.elements; TABLE *table= view->table; @@ -633,15 +649,25 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) *trans_end= trans_start + num; Field_translator *trans; Field **field_ptr= table->field; - query_id_t other_query_id= query_id - 1; + uint used_fields_buff_size= (table->s->fields + 7) / 8; + uchar *used_fields_buff= (uchar*)thd->alloc(used_fields_buff_size); + MY_BITMAP used_fields; DBUG_ENTER("check_key_in_view"); + if (!used_fields_buff) + DBUG_RETURN(TRUE); // EOM + DBUG_ASSERT(view->table != 0 && view->field_translation != 0); + bitmap_init(&used_fields, used_fields_buff, used_fields_buff_size * 8, 0); + bitmap_clear_all(&used_fields); + view->contain_auto_increment= 0; /* check simplicity and prepare unique test of view */ for (trans= trans_start; trans != trans_end; trans++) { + if (!trans->item->fixed && trans->item->fix_fields(thd, &trans->item)) + return TRUE; Item_field *field; /* simple SELECT list entry (field without expression) */ if (!(field= trans->item->filed_for_view_update())) @@ -649,7 +675,6 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) if (field->field->unireg_check == Field::NEXT_NUMBER) view->contain_auto_increment= 1; /* prepare unique test */ - field->field->query_id= other_query_id; /* remove collation (or other transparent for update function) if we have it @@ -661,29 +686,12 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) { /* Thanks to test above, we know that all columns are of type Item_field */ Item_field *field= (Item_field *)trans->item; - if (field->field->query_id == query_id) + /* check fields belong to table in which we are inserting */ + if (field->field->table == table && + bitmap_fast_test_and_set(&used_fields, field->field->field_index)) DBUG_RETURN(TRUE); - field->field->query_id= query_id; } - /* VIEW contain all fields without default value */ - for (; *field_ptr; field_ptr++) - { - Field *field= *field_ptr; - /* field have not default value */ - if ((field->type() == FIELD_TYPE_BLOB) && - (table->timestamp_field != field || - field->unireg_check == Field::TIMESTAMP_UN_FIELD)) - { - for (trans= trans_start; ; trans++) - { - if (trans == trans_end) - DBUG_RETURN(TRUE); // Field was not part of view - if (((Item_field *)trans->item)->field == *field_ptr) - break; // ok - } - } - } DBUG_RETURN(FALSE); } @@ -711,7 +719,8 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, bool insert_into_view= (table_list->view != 0); DBUG_ENTER("mysql_prepare_insert_check_table"); - if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables, + if (setup_tables(thd, &thd->lex->select_lex.context, + table_list, where, &thd->lex->select_lex.leaf_tables, select_insert)) DBUG_RETURN(TRUE); @@ -724,7 +733,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(TRUE); } - DBUG_RETURN(insert_view_fields(&fields, table_list)); + DBUG_RETURN(insert_view_fields(thd, &fields, table_list)); } DBUG_RETURN(FALSE); @@ -738,31 +747,63 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, mysql_prepare_insert() thd Thread handler table_list Global/local table list - table Table to insert into (can be NULL if table should be taken from - table_list->table) + table Table to insert into (can be NULL if table should + be taken from table_list->table) where Where clause (for insert ... select) select_insert TRUE if INSERT ... SELECT statement + TODO (in far future) + In cases of: + INSERT INTO t1 SELECT a, sum(a) as sum1 from t2 GROUP BY a + ON DUPLICATE KEY ... + we should be able to refer to sum1 in the ON DUPLICATE KEY part + + WARNING + You MUST set table->insert_values to 0 after calling this function + before releasing the table object. + RETURN VALUE FALSE OK TRUE error */ -bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, - List<Item> &fields, List_item *values, +bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, + TABLE *table, List<Item> &fields, List_item *values, List<Item> &update_fields, List<Item> &update_values, enum_duplicates duplic, COND **where, bool select_insert) { + SELECT_LEX *select_lex= &thd->lex->select_lex; + TABLE_LIST *save_table_list; + TABLE_LIST *save_next_local; bool insert_into_view= (table_list->view != 0); - /* TODO: use this condition for 'WITH CHECK OPTION' */ - bool res; - TABLE_LIST *next_local; + bool save_resolve_in_select_list; + bool res= 0; DBUG_ENTER("mysql_prepare_insert"); DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d", (ulong)table_list, (ulong)table, (int)insert_into_view)); + /* + For subqueries in VALUES() we should not see the table in which we are + inserting (for INSERT ... SELECT this is done by changing table_list, + because INSERT ... SELECT share SELECT_LEX it with SELECT. + */ + if (!select_insert) + { + for (SELECT_LEX_UNIT *un= select_lex->first_inner_unit(); + un; + un= un->next_unit()) + { + for (SELECT_LEX *sl= un->first_select(); + sl; + sl= sl->next_select()) + { + sl->context.outer_context= 0; + } + } + } + if (duplic == DUP_UPDATE) { /* it should be allocated before Item::fix_fields() */ @@ -774,31 +815,54 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, select_insert)) DBUG_RETURN(TRUE); - next_local= table_list->next_local; + save_table_list= select_lex->context.table_list; + save_resolve_in_select_list= select_lex->context.resolve_in_select_list; + save_next_local= table_list->next_local; + table_list->next_local= 0; + select_lex->context.resolve_in_table_list_only(table_list); if ((values && check_insert_fields(thd, table_list, fields, *values, !insert_into_view)) || - (values && setup_fields(thd, 0, table_list, *values, 0, 0, 0)) || - (duplic == DUP_UPDATE && - ((thd->lex->select_lex.no_wrap_view_item= 1, - (res= check_update_fields(thd, table_list, update_fields)), - thd->lex->select_lex.no_wrap_view_item= 0, - res) || - setup_fields(thd, 0, table_list, update_values, 1, 0, 0)))) - DBUG_RETURN(TRUE); - table_list->next_local= next_local; + (values && setup_fields(thd, 0, *values, 0, 0, 0))) + res= TRUE; + else if (duplic == DUP_UPDATE) + { + select_lex->no_wrap_view_item= TRUE; + res= check_update_fields(thd, table_list, update_fields); + select_lex->no_wrap_view_item= FALSE; + if (select_lex->group_list.elements == 0) + { + /* + When we are not using GROUP BY we can refer to other tables in the + ON DUPLICATE KEY part + */ + table_list->next_local= save_next_local; + } + if (!res) + res= setup_fields(thd, 0, update_values, 1, 0, 0); + } + table_list->next_local= save_next_local; + select_lex->context.table_list= save_table_list; + select_lex->context.resolve_in_select_list= save_resolve_in_select_list; + if (res) + DBUG_RETURN(res); if (!table) table= table_list->table; - if (!select_insert && unique_table(table_list, table_list->next_global)) + if (!select_insert) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); - DBUG_RETURN(TRUE); + Item *fake_conds= 0; + if (unique_table(table_list, table_list->next_global)) + { + my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); + DBUG_RETURN(TRUE); + } + select_lex->fix_prepare_information(thd, &fake_conds); + select_lex->first_execution= 0; } if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) table->file->ha_retrieve_all_pk(); - thd->lex->select_lex.first_execution= 0; DBUG_RETURN(FALSE); } @@ -1051,7 +1115,8 @@ before_trg_err: Check that all fields with arn't null_fields are used ******************************************************************************/ -int check_that_all_fields_are_given_values(THD *thd, TABLE *entry) +int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, + TABLE_LIST *table_list) { int err= 0; for (Field **field=entry->field ; *field ; field++) @@ -1060,10 +1125,29 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry) ((*field)->flags & NO_DEFAULT_VALUE_FLAG) && ((*field)->real_type() != FIELD_TYPE_ENUM)) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_NO_DEFAULT_FOR_FIELD, - ER(ER_NO_DEFAULT_FOR_FIELD), - (*field)->field_name); + bool view= FALSE; + if (table_list) + { + table_list= (table_list->belong_to_view ? + table_list->belong_to_view : + table_list); + view= (bool)(table_list->view); + } + if (view) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_VIEW_FIELD, + ER(ER_NO_DEFAULT_FOR_VIEW_FIELD), + table_list->view_db.str, + table_list->view_name.str); + } + else + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_FIELD, + ER(ER_NO_DEFAULT_FOR_FIELD), + (*field)->field_name); + } err= 1; } } @@ -1945,35 +2029,37 @@ bool delayed_insert::handle_inserts(void) bool mysql_insert_select_prepare(THD *thd) { LEX *lex= thd->lex; + SELECT_LEX *select_lex= &lex->select_lex; TABLE_LIST *first_select_leaf_table; DBUG_ENTER("mysql_insert_select_prepare"); + /* SELECT_LEX do not belong to INSERT statement, so we can't add WHERE clause if table is VIEW */ - lex->query_tables->no_where_clause= 1; + if (mysql_prepare_insert(thd, lex->query_tables, lex->query_tables->table, lex->field_list, 0, lex->update_list, lex->value_list, lex->duplicates, - &lex->select_lex.where, TRUE)) + &select_lex->where, TRUE)) DBUG_RETURN(TRUE); /* exclude first table from leaf tables list, because it belong to INSERT */ - DBUG_ASSERT(lex->select_lex.leaf_tables != 0); - lex->leaf_tables_insert= lex->select_lex.leaf_tables; + DBUG_ASSERT(select_lex->leaf_tables != 0); + lex->leaf_tables_insert= select_lex->leaf_tables; /* skip all leaf tables belonged to view where we are insert */ - for (first_select_leaf_table= lex->select_lex.leaf_tables->next_leaf; + for (first_select_leaf_table= select_lex->leaf_tables->next_leaf; first_select_leaf_table && first_select_leaf_table->belong_to_view && first_select_leaf_table->belong_to_view == lex->leaf_tables_insert->belong_to_view; first_select_leaf_table= first_select_leaf_table->next_leaf) {} - lex->select_lex.leaf_tables= first_select_leaf_table; + select_lex->leaf_tables= first_select_leaf_table; DBUG_RETURN(FALSE); } @@ -2001,8 +2087,8 @@ select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par, int select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) { - int res; LEX *lex= thd->lex; + int res; SELECT_LEX *lex_current_select_save= lex->current_select; DBUG_ENTER("select_insert::prepare"); @@ -2056,8 +2142,11 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); - DBUG_RETURN(fields->elements && - check_that_all_fields_are_given_values(thd, table)); + res= ((fields->elements && + check_that_all_fields_are_given_values(thd, table, table_list)) || + table_list->prepare_where(thd, 0, TRUE) || + table_list->prepare_check_option(thd)); + DBUG_RETURN(res); } @@ -2303,7 +2392,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); - DBUG_RETURN(check_that_all_fields_are_given_values(thd, table)); + DBUG_RETURN(check_that_all_fields_are_given_values(thd, table, + table_list)); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 08f0c3badf7..4d3de481c8b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -172,10 +172,9 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->proc_list.first= 0; lex->query_tables_own_last= 0; - if (lex->spfuns.records) - my_hash_reset(&lex->spfuns); - if (lex->spprocs.records) - my_hash_reset(&lex->spprocs); + if (lex->sroutines.records) + my_hash_reset(&lex->sroutines); + lex->sroutines_list.empty(); DBUG_VOID_RETURN; } @@ -1104,7 +1103,8 @@ void st_select_lex::init_query() having= where= prep_where= 0; olap= UNSPECIFIED_OLAP_TYPE; having_fix_field= 0; - resolve_mode= NOMATTER_MODE; + context.select_lex= this; + context.init(); cond_count= with_wild= 0; conds_processed_with_permanent_arena= 0; ref_pointer_array= 0; @@ -1571,6 +1571,28 @@ void st_select_lex::print_limit(THD *thd, String *str) /* + Initialize LEX object. + + SYNOPSIS + st_lex::st_lex() + + NOTE + LEX object initialized with this constructor can be used as part of + THD object for which one can safely call open_tables(), lock_tables() + and close_thread_tables() functions. But it is not yet ready for + statement parsing. On should use lex_start() function to prepare LEX + for this. +*/ + +st_lex::st_lex() + :result(0), sql_command(SQLCOM_END), query_tables_own_last(0) +{ + hash_init(&sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0); + sroutines_list.empty(); +} + + +/* Check whether the merging algorithm can be used on this VIEW SYNOPSIS @@ -1703,8 +1725,7 @@ bool st_lex::can_not_use_merged() bool st_lex::only_view_structure() { - switch(sql_command) - { + switch (sql_command) { case SQLCOM_SHOW_CREATE: case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_FIELDS: @@ -1744,6 +1765,31 @@ bool st_lex::need_correct_ident() } } +/* + Get effective type of CHECK OPTION for given view + + SYNOPSIS + get_effective_with_check() + view given view + + NOTE + It have not sense to set CHECK OPTION for SELECT satement or subqueries, + so we do not. + + RETURN + VIEW_CHECK_NONE no need CHECK OPTION + VIEW_CHECK_LOCAL CHECK OPTION LOCAL + VIEW_CHECK_CASCADED CHECK OPTION CASCADED +*/ + +uint8 st_lex::get_effective_with_check(st_table_list *view) +{ + if (view->select_lex->master_unit() == &unit && + which_check_option_applicable()) + return (uint8)view->with_check; + return VIEW_CHECK_NONE; +} + /* initialize limit counters @@ -1755,12 +1801,13 @@ bool st_lex::need_correct_ident() void st_select_lex_unit::set_limit(SELECT_LEX *sl) { - ulonglong select_limit_val; + ha_rows select_limit_val; DBUG_ASSERT(! thd->current_arena->is_stmt_prepare()); - select_limit_val= sl->select_limit ? sl->select_limit->val_uint() : - HA_POS_ERROR; - offset_limit_cnt= sl->offset_limit ? sl->offset_limit->val_uint() : ULL(0); + select_limit_val= (ha_rows)(sl->select_limit ? sl->select_limit->val_uint() : + HA_POS_ERROR); + offset_limit_cnt= (ha_rows)(sl->offset_limit ? sl->offset_limit->val_uint() : + ULL(0)); select_limit_cnt= select_limit_val + offset_limit_cnt; if (select_limit_cnt < select_limit_val) select_limit_cnt= HA_POS_ERROR; // no limit @@ -1804,7 +1851,8 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local) */ if ((*link_to_local= test(select_lex.table_list.first))) { - select_lex.table_list.first= (byte*) first->next_local; + select_lex.table_list.first= (byte*) (select_lex.context.table_list= + first->next_local); select_lex.table_list.elements--; //safety first->next_local= 0; /* @@ -1909,13 +1957,51 @@ void st_lex::link_first_table_back(TABLE_LIST *first, if (link_to_local) { first->next_local= (TABLE_LIST*) select_lex.table_list.first; - select_lex.table_list.first= (byte*) first; + select_lex.table_list.first= + (byte*) (select_lex.context.table_list= first); select_lex.table_list.elements++; //safety } } } + +/* + cleanup lex for case when we open table by table for processing + + SYNOPSIS + st_lex::cleanup_after_one_table_open() +*/ + +void st_lex::cleanup_after_one_table_open() +{ + /* + thd->lex->derived_tables & additional units may be set if we open + a view. It is necessary to clear thd->lex->derived_tables flag + to prevent processing of derived tables during next open_and_lock_tables + if next table is a real table and cleanup & remove underlying units + NOTE: all units will be connected to thd->lex->select_lex, because we + have not UNION on most upper level. + */ + if (all_selects_list != &select_lex) + { + derived_tables= 0; + /* cleunup underlying units (units of VIEW) */ + for (SELECT_LEX_UNIT *un= select_lex.first_inner_unit(); + un; + un= un->next_unit()) + un->cleanup(); + /* reduce all selects list to default state */ + all_selects_list= &select_lex; + /* remove underlying units (units of VIEW) subtree */ + select_lex.cut_subtree(); + } + time_zone_tables_used= 0; + if (sroutines.records) + my_hash_reset(&sroutines); +} + + /* fix some structures at the end of preparation @@ -1930,7 +2016,21 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds) if (!thd->current_arena->is_conventional() && first_execution) { first_execution= 0; - prep_where= where; + if (*conds) + { + prep_where= *conds; + *conds= where= prep_where->copy_andor_structure(thd); + } + for (TABLE_LIST *tbl= (TABLE_LIST *)table_list.first; + tbl; + tbl= tbl->next_local) + { + if (tbl->on_expr) + { + tbl->prep_on_expr= tbl->on_expr; + tbl->on_expr= tbl->on_expr->copy_andor_structure(thd); + } + } } } @@ -1945,3 +2045,4 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds) st_select_lex_unit::change_result are in sql_union.cc */ + diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 86539dd8c5e..d0dc98206b7 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -304,7 +304,7 @@ protected: *link_next, **link_prev; /* list of whole SELECT_LEX */ public: - uint32 options; + ulong options; /* result of this query can't be cached, bit field, can be : UNCACHEABLE_DEPENDENT @@ -371,7 +371,6 @@ typedef class st_select_lex_node SELECT_LEX_NODE; SELECT_LEX_UNIT - unit of selects (UNION, INTERSECT, ...) group SELECT_LEXs */ -struct st_lex; class THD; class select_result; class JOIN; @@ -470,6 +469,7 @@ typedef class st_select_lex_unit SELECT_LEX_UNIT; class st_select_lex: public st_select_lex_node { public: + Name_resolution_context context; char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */ Item *where, *having; /* WHERE & HAVING clauses */ Item *prep_where; /* saved WHERE clause for prepared statement processing */ @@ -549,27 +549,6 @@ public: /* exclude this select from check of unique_table() */ bool exclude_from_table_unique_test; - /* - SELECT for SELECT command st_select_lex. Used to privent scaning - item_list of non-SELECT st_select_lex (no sense find to finding - reference in it (all should be in tables, it is dangerouse due - to order of fix_fields calling for non-SELECTs commands (item list - can be not fix_fieldsd)). This value will be assigned for - primary select (sql_yac.yy) and for any subquery and - UNION SELECT (sql_parse.cc mysql_new_select()) - - - INSERT for primary st_select_lex structure of simple INSERT/REPLACE - (used for name resolution, see Item_fiels & Item_ref fix_fields, - FALSE for INSERT/REPLACE ... SELECT, because it's - st_select_lex->table_list will be preprocessed (first table removed) - before passing to handle_select) - - NOMATTER for other - */ - enum {NOMATTER_MODE, SELECT_MODE, INSERT_MODE} resolve_mode; - - void init_query(); void init_select(); st_select_lex_unit* master_unit(); @@ -627,7 +606,13 @@ public: order_list.first= 0; order_list.next= (byte**) &order_list.first; } - + /* + This method created for reiniting LEX in mysql_admin_table() and can be + used only if you are going remove all SELECT_LEX & units except belonger + to LEX (LEX::unit & LEX::select, for other purposes there are + SELECT_LEX_UNIT::exclude_level & SELECT_LEX_UNIT::exclude_tree + */ + void cut_subtree() { slave= 0; } bool test_limit(); friend void lex_start(THD *thd, uchar *buf, uint length); @@ -642,6 +627,11 @@ public: static void print_order(String *str, ORDER *order); void print_limit(THD *thd, String *str); void fix_prepare_information(THD *thd, Item **conds); + /* + Destroy the used execution plan (JOIN) of this subtree (this + SELECT_LEX and all nested SELECT_LEXes and SELECT_LEX_UNITs). + */ + bool cleanup(); }; typedef class st_select_lex SELECT_LEX; @@ -817,8 +807,14 @@ typedef struct st_lex bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */ bool all_privileges; sp_pcontext *spcont; - HASH spfuns; /* Called functions */ - HASH spprocs; /* Called procedures */ + /* Set of stored routines called by statement. */ + HASH sroutines; + /* + List linking elements of 'sroutines' set. Allows you to add new elements + to this set as you iterate through the list of existing elements. + */ + SQL_LIST sroutines_list; + st_sp_chistics sp_chistics; bool only_view; /* used for SHOW CREATE TABLE/VIEW */ /* @@ -851,17 +847,11 @@ typedef struct st_lex */ uchar *fname_start, *fname_end; - st_lex() :result(0), sql_command(SQLCOM_END), query_tables_own_last(0) - { - extern byte *sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first); - hash_init(&spfuns, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0); - hash_init(&spprocs, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0); - } + st_lex(); virtual ~st_lex() { - hash_free(&spfuns); - hash_free(&spprocs); + hash_free(&sroutines); } inline void uncacheable(uint8 cause) @@ -898,7 +888,30 @@ typedef struct st_lex bool can_not_use_merged(); bool only_view_structure(); bool need_correct_ident(); + uint8 get_effective_with_check(st_table_list *view); + /* + Is this update command where 'WHITH CHECK OPTION' clause is important + + SYNOPSIS + st_lex::which_check_option_applicable() + RETURN + TRUE have to take 'WHITH CHECK OPTION' clause into account + FALSE 'WHITH CHECK OPTION' clause do not need + */ + inline bool which_check_option_applicable() + { + switch (sql_command) { + case SQLCOM_UPDATE: + case SQLCOM_UPDATE_MULTI: + case SQLCOM_INSERT: + case SQLCOM_INSERT_SELECT: + case SQLCOM_LOAD: + return TRUE; + default: + return FALSE; + } + } inline bool requires_prelocking() { return test(query_tables_own_last); @@ -912,7 +925,7 @@ typedef struct st_lex { return ( query_tables_own_last ? *query_tables_own_last : 0); } - + void cleanup_after_one_table_open(); } LEX; struct st_lex_local: public st_lex diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 72fa7880268..0090f956521 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -149,7 +149,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } if (open_and_lock_tables(thd, table_list)) DBUG_RETURN(TRUE); - if (setup_tables(thd, table_list, &unused_conds, + if (setup_tables(thd, &thd->lex->select_lex.context, + table_list, &unused_conds, &thd->lex->select_lex.leaf_tables, FALSE)) DBUG_RETURN(-1); if (!table_list->table || // do not suport join view @@ -159,6 +160,11 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "LOAD"); DBUG_RETURN(TRUE); } + if (table_list->prepare_where(thd, 0, TRUE) || + table_list->prepare_check_option(thd)) + { + DBUG_RETURN(TRUE); + } /* Let us emit an error if we are loading data to table which is used in subselect in SET clause like we do it for INSERT. @@ -190,8 +196,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, Let us also prepare SET clause, altough it is probably empty in this case. */ - if (setup_fields(thd, 0, table_list, set_fields, 1, 0, 0) || - setup_fields(thd, 0, table_list, set_values, 1, 0, 0)) + if (setup_fields(thd, 0, set_fields, 1, 0, 0) || + setup_fields(thd, 0, set_values, 1, 0, 0)) DBUG_RETURN(TRUE); } else @@ -204,9 +210,9 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, LOAD DATA */ table->file->ha_set_all_bits_in_write_set(); - if (setup_fields(thd, 0, table_list, fields_vars, 2, 0, 0) || - setup_fields(thd, 0, table_list, set_fields, 2, 0, 0) || - check_that_all_fields_are_given_values(thd, table)) + if (setup_fields(thd, 0, fields_vars, 2, 0, 0) || + setup_fields(thd, 0, set_fields, 2, 0, 0) || + check_that_all_fields_are_given_values(thd, table, table_list)) DBUG_RETURN(TRUE); /* Check whenever TIMESTAMP field with auto-set feature specified @@ -220,7 +226,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, check_that_all_fields_are_given_values() and setting use_timestamp since it may update query_id for some fields. */ - if (setup_fields(thd, 0, table_list, set_values, 1, 0, 0)) + if (setup_fields(thd, 0, set_values, 1, 0, 0)) DBUG_RETURN(TRUE); } diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc index 831b15cf7ef..71e8fe4149f 100644 --- a/sql/sql_olap.cc +++ b/sql/sql_olap.cc @@ -77,7 +77,8 @@ static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List<Item> new { not_found= 0; ((Item_field*)new_item)->db_name=iif->db_name; - Item_field *new_one=new Item_field(iif->db_name, iif->table_name, iif->field_name); + Item_field *new_one=new Item_field(&select_lex->context, + iif->db_name, iif->table_name, iif->field_name); privlist.push_back(new_one); if (add_to_list(new_select->group_list,new_one,1)) return 1; @@ -152,12 +153,11 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) List<Item> all_fields(select_lex->item_list); - if (setup_tables(lex->thd, (TABLE_LIST *)select_lex->table_list.first + if (setup_tables(lex->thd, &select_lex->context, + (TABLE_LIST *)select_lex->table_list.first &select_lex->where, &select_lex->leaf_tables, FALSE) || - setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, - select_lex->item_list, 1, &all_fields,1) || - setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, - item_list_copy, 1, &all_fields, 1)) + setup_fields(lex->thd, 0, select_lex->item_list, 1, &all_fields,1) || + setup_fields(lex->thd, 0, item_list_copy, 1, &all_fields, 1)) return -1; if (select_lex->olap == CUBE_TYPE) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 788d12cb898..33db36ff255 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2293,6 +2293,10 @@ mysql_execute_command(THD *thd) lex->first_lists_tables_same(); /* should be assigned after making first tables same */ all_tables= lex->query_tables; + /* set context for commands which do not use setup_tables */ + select_lex-> + context.resolve_in_table_list_only((TABLE_LIST*)select_lex-> + table_list.first); /* Reset warning count for each query that uses tables @@ -2302,8 +2306,7 @@ mysql_execute_command(THD *thd) Don't reset warnings when executing a stored routine. */ if ((all_tables || &lex->select_lex != lex->all_selects_list || - lex->spfuns.records || lex->spprocs.records) && - !thd->spcont) + lex->sroutines.records) && !thd->spcont) mysql_reset_errors(thd, 0); #ifdef HAVE_REPLICATION @@ -2355,10 +2358,6 @@ mysql_execute_command(THD *thd) } #endif /* !HAVE_REPLICATION */ - - - - /* When option readonly is set deny operations which change tables. Except for the replication thread and the 'super' users. @@ -2576,7 +2575,7 @@ mysql_execute_command(THD *thd) goto error; /* PURGE MASTER LOGS BEFORE 'data' */ it= (Item *)lex->value_list.head(); - if ((!it->fixed &&it->fix_fields(lex->thd, 0, &it)) || + if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE"); @@ -2885,9 +2884,7 @@ mysql_execute_command(THD *thd) CREATE from SELECT give its SELECT_LEX for SELECT, and item_list belong to SELECT */ - select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; res= handle_select(thd, lex, result, 0); - select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE; delete result; } /* reset for PS */ @@ -3226,6 +3223,8 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if ((res= insert_precheck(thd, all_tables))) break; + /* Skip first table, which is the table we are inserting in */ + select_lex->context.table_list= first_table->next_local; res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values, lex->update_list, lex->value_list, lex->duplicates, lex->ignore); @@ -3236,6 +3235,7 @@ end_with_restore_list: case SQLCOM_REPLACE_SELECT: case SQLCOM_INSERT_SELECT: { + select_result *result; DBUG_ASSERT(first_table == all_tables && first_table != 0); if ((res= insert_precheck(thd, all_tables))) break; @@ -3247,27 +3247,24 @@ end_with_restore_list: /* Don't unlock tables until command is written to binary log */ select_lex->options|= SELECT_NO_UNLOCK; - select_result *result; unit->set_limit(select_lex); - if (!(res= open_and_lock_tables(thd, all_tables))) { /* Skip first table, which is the table we are inserting in */ select_lex->table_list.first= (byte*)first_table->next_local; res= mysql_insert_select_prepare(thd); + lex->select_lex.context.table_list= first_table->next_local; if (!res && (result= new select_insert(first_table, first_table->table, &lex->field_list, - &lex->update_list, &lex->value_list, + &lex->update_list, + &lex->value_list, lex->duplicates, lex->ignore))) { - /* - insert/replace from SELECT give its SELECT_LEX for SELECT, - and item_list belong to SELECT - */ - select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; + /* Skip first table, which is the table we are inserting in */ + select_lex->context.table_list= first_table->next_local; + res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE); - select_lex->resolve_mode= SELECT_LEX::INSERT_MODE; delete result; } /* revert changes for SP */ @@ -3276,7 +3273,6 @@ end_with_restore_list: if (first_table->view && !first_table->contain_auto_increment) thd->last_insert_id= 0; // do not show last insert ID if VIEW have not it - break; } case SQLCOM_TRUNCATE: @@ -3868,7 +3864,7 @@ end_with_restore_list: { Item *it= (Item *)lex->value_list.head(); - if ((!it->fixed && it->fix_fields(lex->thd, 0, &it)) || it->check_cols(1)) + if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) { my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), MYF(0)); @@ -5235,16 +5231,27 @@ mysql_new_select(LEX *lex, bool move_down) unit->link_prev= 0; unit->return_to= lex->current_select; select_lex->include_down(unit); - /* TODO: assign resolve_mode for fake subquery after merging with new tree */ + /* + By default we assume that it is usual subselect and we have outer name + resolution context, if no we will assign it to 0 later + */ + select_lex->context.outer_context= &select_lex->outer_select()->context; } else { + Name_resolution_context *outer_context; if (lex->current_select->order_list.first && !lex->current_select->braces) { my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY"); DBUG_RETURN(1); } select_lex->include_neighbour(lex->current_select); + /* + we are not sure that we have one level of SELECTs above, so we take + outer_context address from first select of unit + */ + outer_context= + select_lex->master_unit()->first_select()->context.outer_context; SELECT_LEX_UNIT *unit= select_lex->master_unit(); SELECT_LEX *fake= unit->fake_select_lex; if (!fake) @@ -5261,13 +5268,23 @@ mysql_new_select(LEX *lex, bool move_down) fake->make_empty_select(); fake->linkage= GLOBAL_OPTIONS_TYPE; fake->select_limit= 0; + + fake->context.outer_context= outer_context; + /* allow item list resolving in fake select for ORDER BY */ + fake->context.resolve_in_select_list= TRUE; + fake->context.select_lex= fake; } + select_lex->context.outer_context= outer_context; } select_lex->master_unit()->global_parameters= select_lex; select_lex->include_global((st_select_lex_node**)&lex->all_selects_list); lex->current_select= select_lex; - select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; + /* + in subquery is SELECT query and we allow resolution of names in SELECT + list + */ + select_lex->context.resolve_in_select_list= TRUE; DBUG_RETURN(0); } @@ -5498,6 +5515,21 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, DBUG_RETURN(1); } + if (type == FIELD_TYPE_TIMESTAMP && length) + { + /* Display widths are no longer supported for TIMSTAMP as of MySQL 4.1. + In other words, for declarations such as TIMESTAMP(2), TIMESTAMP(4), + and so on, the display width is ignored. + */ + char buf[32]; + my_snprintf(buf, sizeof(buf), + "TIMESTAMP(%s)", length, system_charset_info); + push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_DEPRECATED_SYNTAX, + ER(ER_WARN_DEPRECATED_SYNTAX), + buf, "TIMESTAMP"); + } + if (!(new_field= new_create_field(thd, field_name, type, length, decimals, type_modifier, default_value, on_update_value, comment, change, interval_list, cs, uint_geom_type))) @@ -5535,8 +5567,14 @@ new_create_field(THD *thd, char *field_name, enum_field_types type, new_field->flags= type_modifier; new_field->unireg_check= (type_modifier & AUTO_INCREMENT_FLAG ? Field::NEXT_NUMBER : Field::NONE); - new_field->decimals= decimals ? (uint) set_zone(atoi(decimals),0, - NOT_FIXED_DEC-1) : 0; + new_field->decimals= decimals ? (uint)atoi(decimals) : 0; + if (new_field->decimals >= NOT_FIXED_DEC) + { + my_error(ER_TOO_BIG_SCALE, MYF(0), new_field->decimals, field_name, + NOT_FIXED_DEC-1); + DBUG_RETURN(NULL); + } + new_field->sql_type=type; new_field->length=0; new_field->change=change; @@ -5557,11 +5595,6 @@ new_create_field(THD *thd, char *field_name, enum_field_types type, length=0; /* purecov: inspected */ sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1; - if (new_field->length && new_field->decimals && - new_field->length < new_field->decimals+1 && - new_field->decimals != NOT_FIXED_DEC) - new_field->length=new_field->decimals+1; /* purecov: inspected */ - switch (type) { case FIELD_TYPE_TINY: if (!length) new_field->length=MAX_TINYINT_WIDTH+sign_len; @@ -5587,22 +5620,24 @@ new_create_field(THD *thd, char *field_name, enum_field_types type, break; case FIELD_TYPE_NEWDECIMAL: if (!length) + new_field->length= 10; + if (new_field->length > DECIMAL_MAX_PRECISION) { - if (!(new_field->length= new_field->decimals)) - new_field->length= 10; // Default length for DECIMAL + my_error(ER_TOO_BIG_PRECISION, MYF(0), new_field->length, field_name, + DECIMAL_MAX_PRECISION); + DBUG_RETURN(NULL); } - new_field->pack_length= - my_decimal_get_binary_size(new_field->length, new_field->decimals); - if (new_field->length <= DECIMAL_MAX_PRECISION && - new_field->length >= new_field->decimals) + if (new_field->length < new_field->decimals) { - new_field->length= - my_decimal_precision_to_length(new_field->length, new_field->decimals, - type_modifier & UNSIGNED_FLAG); - break; + my_error(ER_SCALE_BIGGER_THAN_PRECISION, MYF(0), field_name); + DBUG_RETURN(NULL); } - my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name); - DBUG_RETURN(NULL); + new_field->length= + my_decimal_precision_to_length(new_field->length, new_field->decimals, + type_modifier & UNSIGNED_FLAG); + new_field->pack_length= + my_decimal_get_binary_size(new_field->length, new_field->decimals); + break; case MYSQL_TYPE_VARCHAR: /* Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table @@ -6371,9 +6406,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, */ /* - Writing this command to the binlog may result in infinite loops when doing - mysqlbinlog|mysql, and anyway it does not really make sense to log it - automatically (would cause more trouble to users than it would help them) + Writing this command to the binlog may result in infinite loops + when doing mysqlbinlog|mysql, and anyway it does not really make + sense to log it automatically (would cause more trouble to users + than it would help them) */ tmp_write_to_binlog= 0; mysql_log.new_file(1); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index eeea493d868..53f706bd0f6 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -917,12 +917,12 @@ static bool mysql_test_insert(Prepared_statement *stmt, goto error; /* - open temporary memory pool for temporary data allocated by derived - tables & preparation procedure - Note that this is done without locks (should not be needed as we will not - access any data here) - If we would use locks, then we have to ensure we are not using - TL_WRITE_DELAYED as having two such locks can cause table corruption. + open temporary memory pool for temporary data allocated by derived + tables & preparation procedure + Note that this is done without locks (should not be needed as we will not + access any data here) + If we would use locks, then we have to ensure we are not using + TL_WRITE_DELAYED as having two such locks can cause table corruption. */ if (open_normal_and_derived_tables(thd, table_list)) goto error; @@ -939,9 +939,9 @@ static bool mysql_test_insert(Prepared_statement *stmt, table_list->table->insert_values=(byte *)1; } - if (mysql_prepare_insert(thd, table_list, table_list->table, fields, - values, update_fields, update_values, duplic, - &unused_conds, FALSE)) + if (mysql_prepare_insert(thd, table_list, table_list->table, + fields, values, update_fields, update_values, + duplic, &unused_conds, FALSE)) goto error; value_count= values->elements; @@ -963,7 +963,7 @@ static bool mysql_test_insert(Prepared_statement *stmt, my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter); goto error; } - if (setup_fields(thd, 0, table_list, *values, 0, 0, 0)) + if (setup_fields(thd, 0, *values, 0, 0, 0)) goto error; } } @@ -1039,9 +1039,9 @@ static int mysql_test_update(Prepared_statement *stmt, table_list->grant.want_privilege= want_privilege; table_list->table->grant.want_privilege= want_privilege; #endif - thd->lex->select_lex.no_wrap_view_item= 1; - res= setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0); - thd->lex->select_lex.no_wrap_view_item= 0; + thd->lex->select_lex.no_wrap_view_item= TRUE; + res= setup_fields(thd, 0, select->item_list, 1, 0, 0); + thd->lex->select_lex.no_wrap_view_item= FALSE; if (res) goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1050,7 +1050,7 @@ static int mysql_test_update(Prepared_statement *stmt, table_list->table->grant.want_privilege= (SELECT_ACL & ~table_list->table->grant.privilege); #endif - if (setup_fields(thd, 0, table_list, stmt->lex->value_list, 0, 0, 0)) + if (setup_fields(thd, 0, stmt->lex->value_list, 0, 0, 0)) goto error; /* TODO: here we should send types of placeholders to the client. */ DBUG_RETURN(0); @@ -1119,6 +1119,8 @@ static bool mysql_test_select(Prepared_statement *stmt, SELECT_LEX_UNIT *unit= &lex->unit; DBUG_ENTER("mysql_test_select"); + lex->select_lex.context.resolve_in_select_list= TRUE; + #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL; if (tables) @@ -1207,7 +1209,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt, if (open_and_lock_tables(thd, tables)) DBUG_RETURN(TRUE); - DBUG_RETURN(setup_fields(thd, 0, 0, *values, 0, 0, 0)); + DBUG_RETURN(setup_fields(thd, 0, *values, 0, 0, 0)); } @@ -1277,6 +1279,8 @@ static bool select_like_stmt_test(Prepared_statement *stmt, THD *thd= stmt->thd; LEX *lex= stmt->lex; + lex->select_lex.context.resolve_in_select_list= TRUE; + if (specific_prepare && (*specific_prepare)(thd)) DBUG_RETURN(TRUE); @@ -1354,9 +1358,8 @@ static bool mysql_test_create_table(Prepared_statement *stmt) if (select_lex->item_list.elements) { - select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; + select_lex->context.resolve_in_select_list= TRUE; res= select_like_stmt_test_with_open_n_lock(stmt, tables, 0, 0); - select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE; } /* put tables back for PS rexecuting */ @@ -1446,16 +1449,21 @@ error: static bool mysql_insert_select_prepare_tester(THD *thd) { + TABLE_LIST *first; + bool res; SELECT_LEX *first_select= &thd->lex->select_lex; /* Skip first table, which is the table we are inserting in */ - first_select->table_list.first= (byte*)((TABLE_LIST*)first_select-> - table_list.first)->next_local; + first_select->table_list.first= (byte*)(first= + ((TABLE_LIST*)first_select-> + table_list.first)->next_local); + res= mysql_insert_select_prepare(thd); /* insert/replace from SELECT give its SELECT_LEX for SELECT, and item_list belong to SELECT */ - first_select->resolve_mode= SELECT_LEX::SELECT_MODE; - return mysql_insert_select_prepare(thd); + thd->lex->select_lex.context.resolve_in_select_list= TRUE; + thd->lex->select_lex.context.table_list= first; + return res; } @@ -1493,12 +1501,12 @@ static int mysql_test_insert_select(Prepared_statement *stmt, first_local_table= (TABLE_LIST *)lex->select_lex.table_list.first; DBUG_ASSERT(first_local_table != 0); - res= select_like_stmt_test_with_open_n_lock(stmt, tables, - &mysql_insert_select_prepare_tester, - OPTION_SETUP_TABLES_DONE); + res= + select_like_stmt_test_with_open_n_lock(stmt, tables, + &mysql_insert_select_prepare_tester, + OPTION_SETUP_TABLES_DONE); /* revert changes made by mysql_insert_select_prepare_tester */ lex->select_lex.table_list.first= (byte*) first_local_table; - lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; return res; } @@ -1538,6 +1546,10 @@ static bool check_prepared_statement(Prepared_statement *stmt, lex->first_lists_tables_same(); tables= lex->query_tables; + /* set context for commands which do not use setup_tables */ + lex->select_lex.context.resolve_in_table_list_only(select_lex-> + get_table_list()); + switch (sql_command) { case SQLCOM_REPLACE: case SQLCOM_INSERT: @@ -1813,18 +1825,9 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, void init_stmt_after_parse(THD *thd, LEX *lex) { SELECT_LEX *sl= lex->all_selects_list; - /* - Save WHERE clause pointers, because they may be changed during query - optimisation. - */ - for (; sl; sl= sl->next_select_in_list()) - { - sl->prep_where= sl->where; - sl->uncacheable&= ~UNCACHEABLE_PREPARE; - } - for (TABLE_LIST *table= lex->query_tables; table; table= table->next_global) - table->prep_on_expr= table->on_expr; + for (; sl; sl= sl->next_select_in_list()) + sl->uncacheable&= ~UNCACHEABLE_PREPARE; } @@ -2203,13 +2206,15 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) ulong num_rows= uint4korr(packet+4); Prepared_statement *stmt; Statement stmt_backup; + Cursor *cursor; DBUG_ENTER("mysql_stmt_fetch"); statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch"))) DBUG_VOID_RETURN; - if (!stmt->cursor || !stmt->cursor->is_open()) + cursor= stmt->cursor; + if (!cursor || !cursor->is_open()) { my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id); DBUG_VOID_RETURN; @@ -2222,22 +2227,27 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) my_pthread_setprio(pthread_self(), QUERY_PRIOR); thd->protocol= &thd->protocol_prep; // Switch to binary protocol - stmt->cursor->fetch(num_rows); + cursor->fetch(num_rows); thd->protocol= &thd->protocol_simple; // Use normal protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); - thd->restore_backup_statement(stmt, &stmt_backup); - thd->current_arena= thd; - - if (!stmt->cursor->is_open()) + if (!cursor->is_open()) { /* We're done with the fetch: reset PS for next execution */ cleanup_stmt_and_thd_after_use(stmt, thd); reset_stmt_params(stmt); + /* + Must be the last, as some momory is still needed for + the previous calls. + */ + free_root(cursor->mem_root, MYF(0)); } + thd->restore_backup_statement(stmt, &stmt_backup); + thd->current_arena= thd; + DBUG_VOID_RETURN; } @@ -2264,14 +2274,21 @@ void mysql_stmt_reset(THD *thd, char *packet) /* There is always space for 4 bytes in buffer */ ulong stmt_id= uint4korr(packet); Prepared_statement *stmt; + Cursor *cursor; DBUG_ENTER("mysql_stmt_reset"); statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset"))) DBUG_VOID_RETURN; - if (stmt->cursor && stmt->cursor->is_open()) - stmt->cursor->close(); + cursor= stmt->cursor; + if (cursor && cursor->is_open()) + { + thd->change_list= cursor->change_list; + cursor->close(FALSE); + cleanup_stmt_and_thd_after_use(stmt, thd); + free_root(cursor->mem_root, MYF(0)); + } stmt->state= Query_arena::PREPARED; @@ -2429,7 +2446,9 @@ Prepared_statement::~Prepared_statement() { if (cursor) cursor->Cursor::~Cursor(); - free_items(free_list); + free_items(); + if (cursor) + free_root(cursor->mem_root, MYF(0)); delete lex->result; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bea68bf4da5..b4afab24d4c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -28,8 +28,6 @@ #include <hash.h> #include <ft_global.h> -typedef uint32 cache_rec_length_type; - const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref", "MAYBE_REF","ALL","range","index","fulltext", "ref_or_null","unique_subquery","index_subquery", @@ -87,10 +85,9 @@ static void update_depend_map(JOIN *join, ORDER *order); static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond, bool change_list, bool *simple_order); static int return_zero_rows(JOIN *join, select_result *res,TABLE_LIST *tables, - List<Item> &fields, bool send_row, - uint select_options, const char *info, - Item *having, Procedure *proc, - SELECT_LEX_UNIT *unit); + List<Item> &fields, bool send_row, + uint select_options, const char *info, + Item *having); static COND *build_equal_items(THD *thd, COND *cond, COND_EQUAL *inherited, List<TABLE_LIST> *join_list, @@ -183,10 +180,10 @@ static void reset_cache_read(JOIN_CACHE *cache); static void reset_cache_write(JOIN_CACHE *cache); static void read_cached_record(JOIN_TAB *tab); static bool cmp_buffer_with_ref(JOIN_TAB *tab); -static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &all_fields,ORDER *new_order); -static ORDER *create_distinct_group(THD *thd, ORDER *order, - List<Item> &fields, +static bool setup_new_fields(THD *thd, List<Item> &fields, + List<Item> &all_fields, ORDER *new_order); +static ORDER *create_distinct_group(THD *thd, Item **ref_pointer_array, + ORDER *order, List<Item> &fields, bool *all_order_by_fields_used); static bool test_if_subpart(ORDER *a,ORDER *b); static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables); @@ -284,6 +281,7 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array, save_allow_sum_func= thd->allow_sum_func; thd->allow_sum_func= 0; res= setup_conds(thd, tables, leaves, conds); + thd->allow_sum_func= save_allow_sum_func; res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields, order); @@ -340,11 +338,12 @@ JOIN::prepare(Item ***rref_pointer_array, /* Check that all tables, fields, conds and order are ok */ if ((!(select_options & OPTION_SETUP_TABLES_DONE) && - setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, + setup_tables(thd, &select_lex->context, + tables_list, &conds, &select_lex->leaf_tables, FALSE)) || setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || select_lex->setup_ref_array(thd, og_num) || - setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1, + setup_fields(thd, (*rref_pointer_array), fields_list, 1, &all_fields, 1) || setup_without_group(thd, (*rref_pointer_array), tables_list, select_lex->leaf_tables, fields_list, @@ -360,7 +359,7 @@ JOIN::prepare(Item ***rref_pointer_array, thd->allow_sum_func=1; select_lex->having_fix_field= 1; bool having_fix_rc= (!having->fixed && - (having->fix_fields(thd, tables_list, &having) || + (having->fix_fields(thd, &having) || having->check_cols(1))); select_lex->having_fix_field= 0; if (having_fix_rc || thd->net.report_error) @@ -433,7 +432,7 @@ JOIN::prepare(Item ***rref_pointer_array, goto err; /* purecov: inspected */ if (procedure) { - if (setup_new_fields(thd, tables_list, fields_list, all_fields, + if (setup_new_fields(thd, fields_list, all_fields, procedure->param_fields)) goto err; /* purecov: inspected */ if (procedure->group) @@ -567,7 +566,7 @@ JOIN::optimize() Item_cond_and can't be fixed after creation, so we do not check conds->fixed */ - conds->fix_fields(thd, tables_list, &conds); + conds->fix_fields(thd, &conds); conds->change_ref_to_fields(thd, tables_list); conds->top_level_item(); having= 0; @@ -780,7 +779,8 @@ JOIN::optimize() bool all_order_fields_used; if (order) skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1); - if ((group_list=create_distinct_group(thd, order, fields_list, + if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array, + order, fields_list, &all_order_fields_used))) { bool skip_group= (skip_sort_order && @@ -1114,7 +1114,6 @@ int JOIN::reinit() { DBUG_ENTER("JOIN::reinit"); - first_record= 0; if (exec_tmp_table1) @@ -1223,8 +1222,7 @@ JOIN::exec() send_row_on_empty_set(), select_options, zero_result_cause, - having, procedure, - unit); + having); DBUG_VOID_RETURN; } @@ -1433,7 +1431,7 @@ JOIN::exec() DBUG_VOID_RETURN; } end_read_record(&curr_join->join_tab->read_record); - curr_join->const_tables= curr_join->tables; // Mark free for join_free() + curr_join->const_tables= curr_join->tables; // Mark free for cleanup() curr_join->join_tab[0].table= 0; // Table is freed // No sum funcs anymore @@ -1663,9 +1661,9 @@ JOIN::exec() */ int -JOIN::cleanup() +JOIN::destroy() { - DBUG_ENTER("JOIN::cleanup"); + DBUG_ENTER("JOIN::destroy"); select_lex->join= 0; if (tmp_join) @@ -1680,12 +1678,11 @@ JOIN::cleanup() } tmp_join->tmp_join= 0; tmp_table_param.copy_field=0; - DBUG_RETURN(tmp_join->cleanup()); + DBUG_RETURN(tmp_join->destroy()); } cond_equal= 0; - lock=0; // It's faster to unlock later - join_free(1); + cleanup(1); if (exec_tmp_table1) free_tmp_table(thd, exec_tmp_table1); if (exec_tmp_table2) @@ -1693,12 +1690,6 @@ JOIN::cleanup() delete select; delete_dynamic(&keyuse); delete procedure; - for (SELECT_LEX_UNIT *lex_unit= select_lex->first_inner_unit(); - lex_unit != 0; - lex_unit= lex_unit->next_unit()) - { - error|= lex_unit->cleanup(); - } DBUG_RETURN(error); } @@ -1742,6 +1733,7 @@ Cursor::init_from_thd(THD *thd) lock= thd->lock; query_id= thd->query_id; free_list= thd->free_list; + change_list= thd->change_list; reset_thd(thd); /* XXX: thd->locked_tables is not changed. @@ -1758,6 +1750,7 @@ Cursor::reset_thd(THD *thd) thd->open_tables= 0; thd->lock= 0; thd->free_list= 0; + thd->change_list.empty(); } @@ -1831,6 +1824,7 @@ Cursor::fetch(ulong num_rows) thd->open_tables= open_tables; thd->lock= lock; thd->query_id= query_id; + thd->change_list= change_list; /* save references to memory, allocated during fetch */ thd->set_n_backup_item_arena(this, &backup_arena); @@ -1847,10 +1841,8 @@ Cursor::fetch(ulong num_rows) #ifdef USING_TRANSACTIONS ha_release_temporary_latches(thd); #endif - + /* Grab free_list here to correctly free it in close */ thd->restore_backup_item_arena(this, &backup_arena); - DBUG_ASSERT(thd->free_list == 0); - reset_thd(thd); if (error == NESTED_LOOP_CURSOR_LIMIT) { @@ -1858,10 +1850,12 @@ Cursor::fetch(ulong num_rows) thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; ::send_eof(thd); thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; + change_list= thd->change_list; + reset_thd(thd); } else { - close(); + close(TRUE); if (error == NESTED_LOOP_OK) { thd->server_status|= SERVER_STATUS_LAST_ROW_SENT; @@ -1876,22 +1870,23 @@ Cursor::fetch(ulong num_rows) void -Cursor::close() +Cursor::close(bool is_active) { THD *thd= join->thd; DBUG_ENTER("Cursor::close"); - join->join_free(0); + /* + In case of UNIONs JOIN is freed inside of unit->cleanup(), + otherwise in select_lex->cleanup(). + */ if (unit) - { - /* In case of UNIONs JOIN is freed inside unit->cleanup() */ - unit->cleanup(); - } + (void) unit->cleanup(); + else + (void) join->select_lex->cleanup(); + + if (is_active) + close_thread_tables(thd); else - { - join->cleanup(); - delete join; - } { /* XXX: Another hack: closing tables used in the cursor */ DBUG_ASSERT(lock || open_tables || derived_tables); @@ -1910,13 +1905,8 @@ Cursor::close() } join= 0; unit= 0; - free_items(free_list); - free_list= 0; - /* - Must be last, as some memory might be allocated for free purposes, - like in free_tmp_table() (TODO: fix this issue) - */ - free_root(mem_root, MYF(0)); + free_items(); + change_list.empty(); DBUG_VOID_RETURN; } @@ -1924,7 +1914,7 @@ Cursor::close() Cursor::~Cursor() { if (is_open()) - close(); + close(FALSE); } /*********************************************************************/ @@ -1986,6 +1976,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array, bool free_join= 1; DBUG_ENTER("mysql_select"); + select_lex->context.resolve_in_select_list= TRUE; JOIN *join; if (select_lex->join != 0) { @@ -2068,8 +2059,7 @@ err: if (free_join) { thd->proc_info="end"; - err= join->cleanup(); - delete join; + err= select_lex->cleanup(); DBUG_RETURN(err || thd->net.report_error); } DBUG_RETURN(join->error); @@ -5902,29 +5892,68 @@ void JOIN_TAB::cleanup() } +void JOIN::join_free(bool full) +{ + SELECT_LEX_UNIT *unit; + SELECT_LEX *sl; + DBUG_ENTER("JOIN::join_free"); + + /* + Optimization: if not EXPLAIN and we are done with the JOIN, + free all tables. + */ + full= full || (!select_lex->uncacheable && !thd->lex->describe); + + cleanup(full); + + for (unit= select_lex->first_inner_unit(); unit; unit= unit->next_unit()) + for (sl= unit->first_select_in_union(); sl; sl= sl->next_select()) + { + JOIN *join= sl->join; + if (join) + join->join_free(full); + } + + /* + We are not using tables anymore + Unlock all tables. We may be in an INSERT .... SELECT statement. + */ + if (full && lock && thd->lock && !(select_options & SELECT_NO_UNLOCK) && + !select_lex->subquery_in_having && + (select_lex == (thd->lex->unit.fake_select_lex ? + thd->lex->unit.fake_select_lex : &thd->lex->select_lex))) + { + /* + TODO: unlock tables even if the join isn't top level select in the + tree. + */ + mysql_unlock_read_tables(thd, lock); // Don't free join->lock + lock= 0; + } + + DBUG_VOID_RETURN; +} + + /* Free resources of given join SYNOPSIS - JOIN::join_free() + JOIN::cleanup() fill - true if we should free all resources, call with full==1 should be last, before it this function can be called with full==0 NOTE: with subquery this function definitely will be called several times, but even for simple query it can be called several times. */ -void -JOIN::join_free(bool full) -{ - JOIN_TAB *tab,*end; - DBUG_ENTER("JOIN::join_free"); - full= full || (!select_lex->uncacheable && - !thd->lex->subqueries && - !thd->lex->describe); // do not cleanup too early on EXPLAIN +void JOIN::cleanup(bool full) +{ + DBUG_ENTER("JOIN::cleanup"); if (table) { + JOIN_TAB *tab,*end; /* Only a sorted table may be cached. This sorted table is always the first non const table in join->table @@ -5935,16 +5964,6 @@ JOIN::join_free(bool full) filesort_free_buffers(table[const_tables]); } - for (SELECT_LEX_UNIT *unit= select_lex->first_inner_unit(); unit; - unit= unit->next_unit()) - { - JOIN *join; - for (SELECT_LEX *sl= unit->first_select_in_union(); sl; - sl= sl->next_select()) - if ((join= sl->join)) - join->join_free(full); - } - if (full) { for (tab= join_tab, end= tab+tables; tab != end; tab++) @@ -5961,25 +5980,14 @@ JOIN::join_free(bool full) } } } - /* We are not using tables anymore Unlock all tables. We may be in an INSERT .... SELECT statement. */ - if (full && lock && thd->lock && !(select_options & SELECT_NO_UNLOCK) && - !select_lex->subquery_in_having) - { - // TODO: unlock tables even if the join isn't top level select in the tree - if (select_lex == (thd->lex->unit.fake_select_lex ? - thd->lex->unit.fake_select_lex : &thd->lex->select_lex)) - { - mysql_unlock_read_tables(thd, lock); // Don't free join->lock - lock=0; - } - } - if (full) { + if (tmp_join) + tmp_table_param.copy_field= 0; group_fields.delete_elements(); /* We can't call delete_elements() on copy_funcs as this will cause @@ -6214,8 +6222,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, static int return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, List<Item> &fields, bool send_row, uint select_options, - const char *info, Item *having, Procedure *procedure, - SELECT_LEX_UNIT *unit) + const char *info, Item *having) { DBUG_ENTER("return_zero_rows"); @@ -7438,7 +7445,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) conds->top_level_item(); /* conds is always a new item as both cond and on_expr existed */ DBUG_ASSERT(!conds->fixed); - conds->fix_fields(join->thd, 0, &conds); + conds->fix_fields(join->thd, &conds); } else conds= table->on_expr; @@ -7659,7 +7666,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) cond->fixed, also it do not need tables so we use 0 as second argument. */ - cond->fix_fields(thd, 0, &cond); + cond->fix_fields(thd, &cond); } thd->insert_id(0); // Clear for next request } @@ -7678,7 +7685,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) cond->fixed, also it do not need tables so we use 0 as second argument. */ - cond->fix_fields(thd, 0, &cond); + cond->fix_fields(thd, &cond); } } } @@ -7950,7 +7957,9 @@ Field *create_tmp_field_for_schema(THD *thd, Item *item, TABLE *table) Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Item ***copy_func, Field **from_field, - bool group, bool modify_item, uint convert_blob_length) + bool group, bool modify_item, + bool table_cant_handle_bit_fields, + uint convert_blob_length) { switch (type) { case Item::SUM_FUNC_ITEM: @@ -7965,15 +7974,20 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::DEFAULT_VALUE_ITEM: { Item_field *field= (Item_field*) item; + if (table_cant_handle_bit_fields && field->field->type() == FIELD_TYPE_BIT) + return create_tmp_field_from_item(thd, item, table, copy_func, + modify_item, convert_blob_length); return create_tmp_field_from_field(thd, (*from_field= field->field), item->name, table, modify_item ? (Item_field*) item : NULL, convert_blob_length); } case Item::REF_ITEM: - if ( item->real_item()->type() == Item::FIELD_ITEM) + { + Item *tmp_item; + if ((tmp_item= item->real_item())->type() == Item::FIELD_ITEM) { - Item_field *field= (Item_field*) *((Item_ref*)item)->ref; + Item_field *field= (Item_field*) tmp_item; Field *new_field= create_tmp_field_from_field(thd, (*from_field= field->field), item->name, table, @@ -7983,6 +7997,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, item->set_result_field(new_field); return new_field; } + } case Item::FUNC_ITEM: case Item::COND_ITEM: case Item::FIELD_AVG_ITEM: @@ -8186,6 +8201,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, Field *new_field= create_tmp_field(thd, table, arg, arg->type(), ©_func, tmp_from_field, group != 0,not_all_columns, + group || distinct, param->convert_blob_length); if (!new_field) goto err; // Should be OOM @@ -8196,6 +8212,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, *blob_field++= (uint) (reg_field - table->field); blob_count++; } + new_field->field_index= (uint) (reg_field - table->field); *(reg_field++)= new_field; if (new_field->real_type() == MYSQL_TYPE_STRING || new_field->real_type() == MYSQL_TYPE_VARCHAR) @@ -8234,7 +8251,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, create_tmp_field_for_schema(thd, item, table) : create_tmp_field(thd, table, item, type, ©_func, tmp_from_field, group != 0, - not_all_columns || group !=0, + not_all_columns || group != 0, 0, param->convert_blob_length); if (!new_field) @@ -8263,6 +8280,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, } new_field->query_id= thd->query_id; new_field->fieldnr= ++fieldnr; + new_field->field_index= (uint) (reg_field - table->field); *(reg_field++) =new_field; } if (!--hidden_field_count) @@ -8377,6 +8395,13 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, } else field->move_field((char*) pos,(uchar*) 0,0); + if (field->type() == FIELD_TYPE_BIT) + { + /* We have to reserve place for extra bits among null bits */ + ((Field_bit*) field)->set_bit_ptr(null_flags + null_count / 8, + null_count & 7); + null_count+= (field->field_length & 7); + } field->reset(); if (from_field[i]) { /* Not a table Item */ @@ -11168,8 +11193,7 @@ static bool fix_having(JOIN *join, Item **having) else // This should never happen if (!(table->select->cond= new Item_cond_and(table->select->cond, sort_table_cond)) || - table->select->cond->fix_fields(join->thd, join->tables_list, - &table->select->cond)) + table->select->cond->fix_fields(join->thd, &table->select->cond)) return 1; table->select_cond=table->select->cond; table->select_cond->top_level_item(); @@ -11619,7 +11643,7 @@ used_blob_length(CACHE_FIELD **ptr) static bool store_record_in_cache(JOIN_CACHE *cache) { - cache_rec_length_type length; + uint length; uchar *pos; CACHE_FIELD *copy,*end_field; bool last_record; @@ -11664,9 +11688,9 @@ store_record_in_cache(JOIN_CACHE *cache) end > str && end[-1] == ' ' ; end--) ; length=(uint) (end-str); - memcpy(pos+sizeof(length), str, length); - memcpy_fixed(pos, &length, sizeof(length)); - pos+= length+sizeof(length); + memcpy(pos+2, str, length); + int2store(pos, length); + pos+= length+2; } else { @@ -11700,7 +11724,7 @@ static void read_cached_record(JOIN_TAB *tab) { uchar *pos; - cache_rec_length_type length; + uint length; bool last_record; CACHE_FIELD *copy,*end_field; @@ -11729,10 +11753,10 @@ read_cached_record(JOIN_TAB *tab) { if (copy->strip) { - memcpy_fixed(&length, pos, sizeof(length)); - memcpy(copy->str, pos+sizeof(length), length); + length= uint2korr(pos); + memcpy(copy->str, pos+2, length); memset(copy->str+length, ' ', copy->length-length); - pos+= sizeof(length)+length; + pos+= 2 + length; } else { @@ -11769,10 +11793,10 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref) thd->count_cuted_fields= CHECK_FIELD_IGNORE; for (store_key **copy=ref->key_copy ; *copy ; copy++) { - if ((*copy)->copy()) + if ((*copy)->copy() & 1) { thd->count_cuted_fields= save_count_cuted_fields; - return 1; // Something went wrong + return 1; // Something went wrong } } thd->count_cuted_fields= save_count_cuted_fields; @@ -11789,14 +11813,13 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref) SYNOPSIS find_order_in_list() - thd [in] Pointer to current thread structure - ref_pointer_array [in/out] All select, group and order by fields - tables [in] List of tables to search in (usually FROM clause) - order [in] Column reference to be resolved - fields [in] List of fields to search in (usually SELECT list) - all_fields [in/out] All select, group and order by fields - is_group_field [in] True if order is a GROUP field, false if - ORDER by field + thd Pointer to current thread structure + ref_pointer_array All select, group and order by fields + tables List of tables to search in (usually FROM clause) + order Column reference to be resolved + fields List of fields to search in (usually SELECT list) + all_fields All select, group and order by fields + is_group_field True if order is a GROUP field, false if ORDER by field DESCRIPTION Given a column reference (represented by 'order') from a GROUP BY or ORDER @@ -11813,6 +11836,8 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref) RETURN FALSE if OK TRUE if error occurred + + ref_pointer_array and all_fields are updated */ static bool @@ -11858,26 +11883,25 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, original field name, we should additionaly check if we have conflict for this name (in case if we would perform lookup in all tables). */ - if (unaliased && !order_item->fixed && order_item->fix_fields(thd, tables, - order->item)) + if (unaliased && !order_item->fixed && + order_item->fix_fields(thd, order->item)) return TRUE; /* Lookup the current GROUP field in the FROM clause. */ order_item_type= order_item->type(); + from_field= (Field*) not_found_field; if (is_group_field && order_item_type == Item::FIELD_ITEM || order_item_type == Item::REF_ITEM) { from_field= find_field_in_tables(thd, (Item_ident*) order_item, tables, - &view_ref, IGNORE_ERRORS, TRUE); - if(!from_field) - from_field= (Field*) not_found_field; + &view_ref, IGNORE_ERRORS, TRUE, + FALSE); + if (!from_field) + from_field= (Field*) not_found_field; } - else - from_field= (Field*) not_found_field; if (from_field == not_found_field || - from_field && (from_field != view_ref_found ? /* it is field of base table => check that fields are same */ ((*select_item)->type() == Item::FIELD_ITEM && @@ -11890,43 +11914,46 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, view_ref->type() == Item::REF_ITEM && ((Item_ref *) (*select_item))->ref == ((Item_ref *) view_ref)->ref))) + { /* - If there is no such field in the FROM clause, or it is the same field as - the one found in the SELECT clause, then use the Item created for the - SELECT field. As a result if there was a derived field that 'shadowed' - a table field with the same name, the table field will be chosen over - the derived field. + If there is no such field in the FROM clause, or it is the same field + as the one found in the SELECT clause, then use the Item created for + the SELECT field. As a result if there was a derived field that + 'shadowed' a table field with the same name, the table field will be + chosen over the derived field. */ - { order->item= ref_pointer_array + counter; order->in_field_list=1; return FALSE; } else + { /* - There is a field with the same name in the FROM clause. This is the field - that will be chosen. In this case we issue a warning so the user knows - that the field from the FROM clause overshadows the column reference from - the SELECT list. + There is a field with the same name in the FROM clause. This + is the field that will be chosen. In this case we issue a + warning so the user knows that the field from the FROM clause + overshadows the column reference from the SELECT list. */ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR), from_field->field_name, current_thd->where); + } } order->in_field_list=0; /* - The call to order_item->fix_fields() means that here we resolve 'order_item' - to a column from a table in the list 'tables', or to a column in some outer - query. Exactly because of the second case we come to this point even if - (select_item == not_found_item), inspite of that fix_fields() calls - find_item_in_list() one more time. + The call to order_item->fix_fields() means that here we resolve + 'order_item' to a column from a table in the list 'tables', or to + a column in some outer query. Exactly because of the second case + we come to this point even if (select_item == not_found_item), + inspite of that fix_fields() calls find_item_in_list() one more + time. We check order_item->fixed because Item_func_group_concat can put arguments for which fix_fields already was called. */ if (!order_item->fixed && - (order_item->fix_fields(thd, tables, order->item) || + (order_item->fix_fields(thd, order->item) || (order_item= *order->item)->check_cols(1) || thd->is_fatal_error)) return TRUE; /* Wrong field. */ @@ -12038,7 +12065,7 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, */ static bool -setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, +setup_new_fields(THD *thd, List<Item> &fields, List<Item> &all_fields, ORDER *new_field) { Item **item; @@ -12055,7 +12082,7 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, else { thd->where="procedure list"; - if ((*new_field->item)->fix_fields(thd, tables, new_field->item)) + if ((*new_field->item)->fix_fields(thd, new_field->item)) DBUG_RETURN(1); /* purecov: inspected */ all_fields.push_front(*new_field->item); new_field->item=all_fields.head_ref(); @@ -12071,12 +12098,14 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, */ static ORDER * -create_distinct_group(THD *thd, ORDER *order_list, List<Item> &fields, +create_distinct_group(THD *thd, Item **ref_pointer_array, + ORDER *order_list, List<Item> &fields, bool *all_order_by_fields_used) { List_iterator<Item> li(fields); Item *item; ORDER *order,*group,**prev; + uint index= 0; *all_order_by_fields_used= 1; while ((item=li++)) @@ -12108,11 +12137,17 @@ create_distinct_group(THD *thd, ORDER *order_list, List<Item> &fields, ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER)); if (!ord) return 0; - ord->item=li.ref(); + /* + We have here only field_list (not all_field_list), so we can use + simple indexing of ref_pointer_array (order in the array and in the + list are same) + */ + ord->item= ref_pointer_array + index; ord->asc=1; *prev=ord; prev= &ord->next; } + index++; } *prev=0; return group; @@ -12135,7 +12170,7 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields, param->quick_group=1; while ((field=li++)) { - Item::Type type=field->type(); + Item::Type type=field->real_item()->type(); if (type == Item::FIELD_ITEM) param->field_count++; else if (type == Item::SUM_FUNC_ITEM) @@ -12149,7 +12184,7 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields, for (uint i=0 ; i < sum_item->arg_count ; i++) { - if (sum_item->args[0]->type() == Item::FIELD_ITEM) + if (sum_item->args[0]->real_item()->type() == Item::FIELD_ITEM) param->field_count++; else param->func_count++; @@ -12396,9 +12431,10 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, param->copy_funcs.empty(); for (i= 0; (pos= li++); i++) { - if (pos->type() == Item::FIELD_ITEM) + if (pos->real_item()->type() == Item::FIELD_ITEM) { Item_field *item; + pos= pos->real_item(); if (!(item= new Item_field(thd, ((Item_field*) pos)))) goto err; pos= item; @@ -12853,7 +12889,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) DBUG_RETURN(TRUE); if (!cond->fixed) - cond->fix_fields(thd,(TABLE_LIST *) 0, (Item**)&cond); + cond->fix_fields(thd, (Item**)&cond); if (join_tab->select) { error=(int) cond->add(join_tab->select->cond); @@ -12895,8 +12931,8 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) thd reference to the context expr expression to make replacement group_list list of references to group by items - changed out: returns 1 if item contains a replaced field item - + changed out: returns 1 if item contains a replaced field item + DESCRIPTION The function replaces occurrences of group by fields in expr by ref objects for these fields unless they are under aggregate @@ -12925,6 +12961,7 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, { if (expr->arg_count) { + Name_resolution_context *context= &thd->lex->current_select->context; Item **arg,**arg_end; for (arg= expr->arguments(), arg_end= expr->arguments()+expr->arg_count; @@ -12938,8 +12975,9 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, { if (item->eq(*group_tmp->item,0)) { - Item *new_item; - if(!(new_item= new Item_ref(group_tmp->item, 0, item->name))) + Item *new_item; + if(!(new_item= new Item_ref(context, group_tmp->item, 0, + item->name))) return 1; // fatal_error is set thd->change_item_tree(arg, new_item); *changed= TRUE; diff --git a/sql/sql_select.h b/sql/sql_select.h index e5266944251..ac3e8898cc6 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -325,7 +325,7 @@ class JOIN :public Sql_alloc int optimize(); int reinit(); void exec(); - int cleanup(); + int destroy(); void restore_tmp(); bool alloc_func_list(); bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields, @@ -349,7 +349,15 @@ class JOIN :public Sql_alloc int rollup_send_data(uint idx); int rollup_write_data(uint idx, TABLE *table); bool test_in_subselect(Item **where); + /* + Release memory and, if possible, the open tables held by this execution + plan (and nested plans). It's used to release some tables before + the end of execution in order to increase concurrency and reduce + memory consumption. + */ void join_free(bool full); + /* Cleanup this JOIN, possibly for reuse */ + void cleanup(bool full); void clear(); bool save_join_tab(); bool send_row_on_empty_set() @@ -382,6 +390,7 @@ class Cursor: public Sql_alloc, public Query_arena /* List of items created during execution */ query_id_t query_id; public: + Item_change_list change_list; select_send result; /* Temporary implementation as now we replace THD state by value */ @@ -394,7 +403,8 @@ public: void fetch(ulong num_rows); void reset() { join= 0; } bool is_open() const { return join != 0; } - void close(); + + void close(bool is_active); void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; } Cursor(THD *thd); @@ -448,6 +458,7 @@ class store_key :public Sql_alloc char *null_ptr; char err; public: + enum store_key_result { STORE_KEY_OK, STORE_KEY_FATAL, STORE_KEY_CONV }; store_key(THD *thd, Field *field_arg, char *ptr, char *null, uint length) :null_ptr(null),err(0) { @@ -463,7 +474,7 @@ class store_key :public Sql_alloc ptr, (uchar*) null, 1); } virtual ~store_key() {} /* Not actually needed */ - virtual bool copy()=0; + virtual enum store_key_result copy()=0; virtual const char *name() const=0; }; @@ -484,10 +495,10 @@ class store_key_field: public store_key copy_field.set(to_field,from_field,0); } } - bool copy() + enum store_key_result copy() { copy_field.do_copy(©_field); - return err != 0; + return err != 0 ? STORE_KEY_FATAL : STORE_KEY_OK; } const char *name() const { return field_name; } }; @@ -504,9 +515,11 @@ public: null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ? &err : NullS, length), item(item_arg) {} - bool copy() + enum store_key_result copy() { - return item->save_in_field_no_warnings(to_field, 1) || err != 0; + int res= item->save_in_field(to_field, 1); + return (err != 0 || res > 2 ? STORE_KEY_FATAL : (store_key_result) res); + } const char *name() const { return "func"; } }; @@ -524,15 +537,19 @@ public: &err : NullS, length, item_arg), inited(0) { } - bool copy() + enum store_key_result copy() { + int res; if (!inited) { inited=1; - if (item->save_in_field(to_field, 1)) - err= 1; + if ((res= item->save_in_field(to_field, 1))) + { + if (!err) + err= res; + } } - return err != 0; + return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err); } const char *name() const { return "const"; } }; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 12025c82da6..8343f9ec582 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -347,6 +347,9 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->table_name)); + /* We want to preserve the tree for views. */ + thd->lex->view_prepare_mode= TRUE; + /* Only one table for now, but VIEW can involve several tables */ if (open_normal_and_derived_tables(thd, table_list)) { @@ -1068,7 +1071,13 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) buff->append('.'); append_identifier(thd, buff, table->view_name.str, table->view_name.length); buff->append(" AS ", 4); - buff->append(table->query.str, table->query.length); + + /* + We can't just use table->query, because our SQL_MODE may trigger + a different syntax, like when ANSI_QUOTES is defined. + */ + table->view->unit.print(buff); + if (table->with_check != VIEW_CHECK_NONE) { if (table->with_check == VIEW_CHECK_LOCAL) @@ -3240,11 +3249,13 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) { ST_FIELD_INFO *field_info= schema_table->fields_info; + Name_resolution_context *context= &thd->lex->select_lex.context; for ( ; field_info->field_name; field_info++) { if (field_info->old_name) { - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (field) { field->set_name(field_info->old_name, @@ -3264,12 +3275,14 @@ int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) char tmp[128]; LEX *lex= thd->lex; SELECT_LEX *sel= lex->current_select; + Name_resolution_context *context= &sel->context; if (!sel->item_list.elements) { ST_FIELD_INFO *field_info= &schema_table->fields_info[1]; String buffer(tmp,sizeof(tmp), system_charset_info); - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (!field || add_item_to_list(thd, field)) return 1; buffer.length(0); @@ -3291,6 +3304,7 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) char tmp[128]; String buffer(tmp,sizeof(tmp), thd->charset()); LEX *lex= thd->lex; + Name_resolution_context *context= &lex->select_lex.context; ST_FIELD_INFO *field_info= &schema_table->fields_info[2]; buffer.length(0); @@ -3302,7 +3316,8 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) buffer.append(lex->wild->ptr()); buffer.append(")"); } - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (add_item_to_list(thd, field)) return 1; field->set_name(buffer.ptr(), buffer.length(), system_charset_info); @@ -3310,7 +3325,7 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) { field->set_name(buffer.ptr(), buffer.length(), system_charset_info); field_info= &schema_table->fields_info[3]; - field= new Item_field(NullS, NullS, field_info->field_name); + field= new Item_field(context, NullS, NullS, field_info->field_name); if (add_item_to_list(thd, field)) return 1; field->set_name(field_info->old_name, strlen(field_info->old_name), @@ -3325,6 +3340,8 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {3, 14, 13, 6, 15, 5, 16, 17, 18, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; + Name_resolution_context *context= &thd->lex->select_lex.context; + for (; *field_num >= 0; field_num++) { field_info= &schema_table->fields_info[*field_num]; @@ -3332,7 +3349,8 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) *field_num == 17 || *field_num == 18)) continue; - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (field) { field->set_name(field_info->old_name, @@ -3351,10 +3369,13 @@ int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {0, 2, 1, 3, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; + Name_resolution_context *context= &thd->lex->select_lex.context; + for (; *field_num >= 0; field_num++) { field_info= &schema_table->fields_info[*field_num]; - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (field) { field->set_name(field_info->old_name, @@ -3373,10 +3394,13 @@ int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {2, 3, 4, 19, 16, 15, 14, 18, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; + Name_resolution_context *context= &thd->lex->select_lex.context; + for (; *field_num >= 0; field_num++) { field_info= &schema_table->fields_info[*field_num]; - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (field) { field->set_name(field_info->old_name, @@ -3442,12 +3466,11 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) if (table_list->field_translation) { - Field_translator *end= table_list->field_translation + - sel->item_list.elements; + Field_translator *end= table_list->field_translation_end; for (transl= table_list->field_translation; transl < end; transl++) { if (!transl->item->fixed && - transl->item->fix_fields(thd, table_list, &transl->item)) + transl->item->fix_fields(thd, &transl->item)) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -3464,11 +3487,12 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) { char *name= item->name; transl[i].item= item; - if (!item->fixed && item->fix_fields(thd, table_list, &transl[i].item)) + if (!item->fixed && item->fix_fields(thd, &transl[i].item)) DBUG_RETURN(1); transl[i++].name= name; } table_list->field_translation= transl; + table_list->field_translation_end= transl + sel->item_list.elements; } DBUG_RETURN(0); @@ -3495,7 +3519,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, ST_SCHEMA_TABLE *schema_table= get_schema_table(schema_table_idx); LEX_STRING db, table; DBUG_ENTER("mysql_schema_select"); - /* + /* We have to make non const db_name & table_name because of lower_case_table_names */ @@ -3503,7 +3527,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, information_schema_name.length, 0); make_lex_string(thd, &table, schema_table->table_name, strlen(schema_table->table_name), 0); - if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */ + if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */ !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0), 0, 0, TL_READ, (List<String> *) 0, (List<String> *) 0)) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e34718ec05a..22eb2489451 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -256,16 +256,17 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, build_table_path(path, sizeof(path), db, alias, reg_ext); } if (drop_temporary || - (access(path,F_OK) && - ha_create_table_from_engine(thd,db,alias,TRUE)) || + (access(path,F_OK) && + ha_create_table_from_engine(thd,db,alias)) || (!drop_view && mysql_frm_type(path) != FRMTYPE_TABLE)) { + // Table was not found on disk and table can't be created from engine if (if_exists) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), table->table_name); else - error= 1; + error= 1; } else { @@ -1549,14 +1550,12 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, /* Check if table exists */ if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { - char tmp_table_name[tmp_file_prefix_length+22+22+22+3]; - my_snprintf(tmp_table_name, sizeof(tmp_table_name), "%s%lx_%lx_%x", - tmp_file_prefix, current_pid, thd->thread_id, - thd->tmp_table++); + my_snprintf(path, sizeof(path), "%s%s%lx_%lx_%x%s", + mysql_tmpdir, tmp_file_prefix, current_pid, thd->thread_id, + thd->tmp_table++, reg_ext); if (lower_case_table_names) - my_casedn_str(files_charset_info, tmp_table_name); + my_casedn_str(files_charset_info, path); create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE; - build_table_path(path, sizeof(path), db, tmp_table_name, reg_ext); } else build_table_path(path, sizeof(path), db, alias, reg_ext); @@ -1604,15 +1603,14 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, { bool create_if_not_exists = create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS; - if (!ha_create_table_from_engine(thd, db, table_name, - create_if_not_exists)) + if (ha_table_exists_in_engine(thd, db, table_name)) { - DBUG_PRINT("info", ("Table already existed in handler")); + DBUG_PRINT("info", ("Table with same name already existed in handler")); if (create_if_not_exists) { - create_info->table_existed= 1; // Mark that table existed - error= FALSE; + create_info->table_existed= 1; // Mark that table existed + error= FALSE; } else my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); @@ -1734,7 +1732,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, field=item->tmp_table_field(&tmp_table); else field=create_tmp_field(thd, &tmp_table, item, item->type(), - (Item ***) 0, &tmp_field,0,0,0); + (Item ***) 0, &tmp_field, 0, 0, 0, 0); if (!field || !(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ? ((Item_field *)item)->field : @@ -2104,6 +2102,7 @@ end: } + /* RETURN VALUES FALSE Message sent to net (admin operation went ok) @@ -2123,10 +2122,12 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT *), int (view_operator_func)(THD *, TABLE_LIST*)) { - TABLE_LIST *table, *next_global_table; + TABLE_LIST *table, *save_next_global, *save_next_local; + SELECT_LEX *select= &thd->lex->select_lex; List<Item> field_list; Item *item; Protocol *protocol= thd->protocol; + LEX *lex= thd->lex; int result_code; DBUG_ENTER("mysql_admin_table"); @@ -2153,12 +2154,25 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, thd->open_options|= extra_open_options; table->lock_type= lock_type; /* open only one table from local list of command */ - next_global_table= table->next_global; + save_next_global= table->next_global; table->next_global= 0; + save_next_local= table->next_local; + table->next_local= 0; + select->table_list.first= (byte*)table; + /* + Time zone tables and SP tables can be add to lex->query_tables list, + so it have to be prepared. + TODO: Investigate if we can put extra tables into argument instead of + using lex->query_tables + */ + lex->query_tables= table; + lex->query_tables_last= &table->next_global; + lex->query_tables_own_last= 0;; thd->no_warnings_for_error= no_warnings_for_error; open_and_lock_tables(thd, table); thd->no_warnings_for_error= 0; - table->next_global= next_global_table; + table->next_global= save_next_global; + table->next_local= save_next_local; /* if view are unsupported */ if (table->view && view_operator_func == NULL) { @@ -2206,7 +2220,13 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, err_msg= (const char *)buf; } protocol->store(err_msg, system_charset_info); + lex->cleanup_after_one_table_open(); thd->clear_error(); + /* + View opening can be interrupted in the middle of process so some + tables can be left opening + */ + close_thread_tables(thd); if (protocol->write()) goto err; continue; @@ -2275,6 +2295,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, send_result: + lex->cleanup_after_one_table_open(); thd->clear_error(); // these errors shouldn't get client protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); @@ -2402,13 +2423,6 @@ send_result_message: } close_thread_tables(thd); table->table=0; // For query cache - /* - thd->lex->derived_tables may be set to non zero value if we open - a view. It is necessary to clear thd->lex->derived_tables flag - to prevent processing of derived tables during next open_and_lock_tables - if next table is a real table. - */ - thd->lex->derived_tables= 0; if (protocol->write()) goto err; } @@ -3400,7 +3414,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, */ if (!Field::type_can_have_key_part(cfield->field->type()) || !Field::type_can_have_key_part(cfield->sql_type) || - cfield->field->field_length == key_part_length || + (cfield->field->field_length == key_part_length && + !f_is_blob(key_part->key_type)) || (cfield->length && (cfield->length < key_part_length / key_part->field->charset()->mbmaxlen))) key_part_length= 0; // Use whole field diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 95524a6dfbf..f058c306d42 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1,3 +1,20 @@ +/* Copyright (C) 2004-2005 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 "mysql_priv.h" #include "sp_head.h" #include "sql_trigger.h" @@ -201,7 +218,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) { trg_field->setup_field(thd, table); if (!trg_field->fixed && - trg_field->fix_fields(thd, (TABLE_LIST *)0, (Item **)0)) + trg_field->fix_fields(thd, (Item **)0)) return 1; } @@ -418,6 +435,18 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, table->triggers= triggers; /* + Construct key that will represent triggers for this table in the set + of routines used by statement. + */ + triggers->sroutines_key.length= 1+strlen(db)+1+strlen(table_name)+1; + if (!(triggers->sroutines_key.str= + alloc_root(&table->mem_root, triggers->sroutines_key.length))) + DBUG_RETURN(1); + triggers->sroutines_key.str[0]= TYPE_ENUM_TRIGGER; + strmov(strmov(strmov(triggers->sroutines_key.str+1, db), "."), + table_name); + + /* TODO: This could be avoided if there is no triggers for UPDATE and DELETE. */ diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 0547283d0c5..044219d5ac9 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -1,3 +1,20 @@ +/* Copyright (C) 2004-2005 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 */ + + /* This class holds all information about triggers of table. @@ -28,6 +45,14 @@ class Table_triggers_list: public Sql_alloc used in CREATE/DROP TRIGGER for looking up trigger by name. */ List<LEX_STRING> names_list; + /* + Key representing triggers for this table in set of all stored + routines used by statement. + TODO: We won't need this member once triggers namespace will be + database-wide instead of table-wide because then we will be able + to use key based on sp_name as for other stored routines. + */ + LEX_STRING sroutines_key; public: /* @@ -112,6 +137,8 @@ public: } friend class Item_trigger_field; + friend void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, + Table_triggers_list *triggers); private: bool prepare_record1_accessors(TABLE *table); diff --git a/sql/sql_udf.h b/sql/sql_udf.h index 4df3fe0949d..d588572a762 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -65,8 +65,8 @@ class udf_handler :public Sql_alloc Item_result result_type () const { return u_d ? u_d->returns : STRING_RESULT;} bool get_arguments(); - bool fix_fields(THD *thd,struct st_table_list *tlist,Item_result_field *item, - uint arg_count,Item **args); + bool fix_fields(THD *thd, Item_result_field *item, + uint arg_count, Item **args); void cleanup(); double val(my_bool *null_value) { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index f59d7fffe85..f2b637dc5f4 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -124,6 +124,13 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd) fake_select_lex->table_list.link_in_list((byte *)&result_table_list, (byte **) &result_table_list.next_local); + for (ORDER *order= (ORDER *)global_parameters->order_list.first; + order; + order=order->next) + { + (*order->item)->walk(&Item::change_context_processor, + (byte *) &fake_select_lex->context); + } } @@ -187,6 +194,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, else tmp_result= sel_result; + sl->context.resolve_in_select_list= TRUE; + for (;sl; sl= sl->next_select()) { bool can_skip_order_by; @@ -448,7 +457,9 @@ bool st_select_lex_unit::exec() table->no_keyread=1; } res= sl->join->error; - offset_limit_cnt= sl->offset_limit ? sl->offset_limit->val_uint() : 0; + offset_limit_cnt= (ha_rows)(sl->offset_limit ? + sl->offset_limit->val_uint() : + 0); if (!res) { examined_rows+= thd->examined_row_count; @@ -553,7 +564,6 @@ bool st_select_lex_unit::exec() bool st_select_lex_unit::cleanup() { int error= 0; - JOIN *join; DBUG_ENTER("st_select_lex_unit::cleanup"); if (cleaned) @@ -572,29 +582,17 @@ bool st_select_lex_unit::cleanup() } for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select()) + error|= sl->cleanup(); + + if (fake_select_lex) { - if ((join= sl->join)) - { - error|= sl->join->cleanup(); - delete join; - } - else + JOIN *join; + if ((join= fake_select_lex->join)) { - // it can be DO/SET with subqueries - for (SELECT_LEX_UNIT *lex_unit= sl->first_inner_unit(); - lex_unit != 0; - lex_unit= lex_unit->next_unit()) - { - error|= lex_unit->cleanup(); - } + join->tables_list= 0; + join->tables= 0; } - } - if (fake_select_lex && (join= fake_select_lex->join)) - { - join->tables_list= 0; - join->tables= 0; - error|= join->cleanup(); - delete join; + error|= fake_select_lex->cleanup(); } DBUG_RETURN(error); @@ -650,3 +648,25 @@ bool st_select_lex_unit::change_result(select_subselect *result, res= fake_select_lex->join->change_result(result); return (res); } + + +bool st_select_lex::cleanup() +{ + bool error= FALSE; + DBUG_ENTER("st_select_lex::cleanup()"); + + if (join) + { + DBUG_ASSERT((st_select_lex*)join->select_lex == this); + error= join->destroy(); + delete join; + join= 0; + } + for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ; + lex_unit= lex_unit->next_unit()) + { + error= (bool) ((uint) error | (uint) lex_unit->cleanup()); + } + DBUG_RETURN(error); +} + diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 1c81b1b5a92..c5d8e0d98e2 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -67,6 +67,8 @@ static bool check_fields(THD *thd, List<Item> &items) List_iterator<Item> it(items); Item *item; Item_field *field; + Name_resolution_context *context= &thd->lex->select_lex.context; + while ((item= it++)) { if (!(field= item->filed_for_view_update())) @@ -185,18 +187,12 @@ int mysql_update(THD *thd, #ifndef NO_EMBEDDED_ACCESS_CHECKS table_list->grant.want_privilege= table->grant.want_privilege= want_privilege; #endif - { - bool res; - select_lex->no_wrap_view_item= 1; - /* - Indicate that the set of fields is to be updated by passing 2 for - set_query_id. - */ - res= setup_fields(thd, 0, table_list, fields, 2, 0, 0); - select_lex->no_wrap_view_item= 0; - if (res) - DBUG_RETURN(1); /* purecov: inspected */ - } + /* + Indicate that the set of fields is to be updated by passing 2 for + set_query_id. + */ + if (setup_fields_with_no_wrap(thd, 0, fields, 2, 0, 0)) + DBUG_RETURN(1); /* purecov: inspected */ if (table_list->view && check_fields(thd, fields)) { DBUG_RETURN(1); @@ -223,7 +219,7 @@ int mysql_update(THD *thd, table_list->grant.want_privilege= table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); #endif - if (setup_fields(thd, 0, table_list, values, 1, 0, 0)) + if (setup_fields(thd, 0, values, 1, 0, 0)) { free_underlaid_joins(thd, select_lex); DBUG_RETURN(1); /* purecov: inspected */ @@ -657,7 +653,9 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, tables.table= table; tables.alias= table_list->alias; - if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, FALSE) || + if (setup_tables(thd, &select_lex->context, + table_list, conds, &select_lex->leaf_tables, + FALSE) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || select_lex->setup_ref_array(thd, order_num) || setup_order(thd, select_lex->ref_pointer_array, @@ -717,7 +715,6 @@ bool mysql_multi_update_prepare(THD *thd) TABLE_LIST *tl, *leaves; List<Item> *fields= &lex->select_lex.item_list; table_map tables_for_update; - int res; bool update_view= 0; /* if this multi-update was converted from usual update, here is table @@ -742,15 +739,12 @@ bool mysql_multi_update_prepare(THD *thd) call in setup_tables()). */ - if (setup_tables(thd, table_list, &lex->select_lex.where, + if (setup_tables(thd, &lex->select_lex.context, + table_list, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE)) DBUG_RETURN(TRUE); - leaves= lex->select_lex.leaf_tables; - if ((lex->select_lex.no_wrap_view_item= 1, - res= setup_fields(thd, 0, table_list, *fields, 2, 0, 0), - lex->select_lex.no_wrap_view_item= 0, - res)) + if (setup_fields_with_no_wrap(thd, 0, *fields, 2, 0, 0)) DBUG_RETURN(TRUE); for (tl= table_list; tl ; tl= tl->next_local) @@ -772,6 +766,7 @@ bool mysql_multi_update_prepare(THD *thd) /* Setup timestamp handling and locking mode */ + leaves= lex->select_lex.leaf_tables; for (tl= leaves; tl; tl= tl->next_leaf) { TABLE *table= tl->table; @@ -862,12 +857,10 @@ bool mysql_multi_update_prepare(THD *thd) for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global) tbl->cleanup_items(); - if (setup_tables(thd, table_list, &lex->select_lex.where, + if (setup_tables(thd, &lex->select_lex.context, + table_list, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE) || - (lex->select_lex.no_wrap_view_item= 1, - res= setup_fields(thd, 0, table_list, *fields, 2, 0, 0), - lex->select_lex.no_wrap_view_item= 0, - res)) + setup_fields_with_no_wrap(thd, 0, *fields, 2, 0, 0)) DBUG_RETURN(TRUE); } @@ -997,7 +990,7 @@ int multi_update::prepare(List<Item> ¬_used_values, reference tables */ - if (setup_fields(thd, 0, all_tables, *values, 1, 0, 0)) + if (setup_fields(thd, 0, *values, 1, 0, 0)) DBUG_RETURN(1); /* diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 0b351407c13..d74b96de2cd 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -20,6 +20,7 @@ #include "parse_file.h" #include "sp.h" #include "sp_head.h" +#include "sp_cache.h" #define MD5_BUFF_LENGTH 33 @@ -58,13 +59,13 @@ static void make_unique_view_field_name(Item *target, char *name= (target->orig_name ? target->orig_name : target->name); - uint name_len; - uint attempt= 0; + uint name_len, attempt; char buff[NAME_LEN+1]; - for (;; attempt++) + List_iterator_fast<Item> itc(item_list); + + for (attempt= 0;; attempt++) { Item *check; - List_iterator_fast<Item> itc(item_list); bool ok= TRUE; if (attempt) @@ -84,6 +85,7 @@ static void make_unique_view_field_name(Item *target, } while (check != last_element); if (ok) break; + itc.rewind(); } target->orig_name= target->name; @@ -140,6 +142,9 @@ bool mysql_create_view(THD *thd, goto err; } + if (mode != VIEW_CREATE_NEW) + sp_cache_invalidate(); + #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Privilege check for view creation: @@ -305,13 +310,14 @@ bool mysql_create_view(THD *thd, { Item *item; List_iterator_fast<Item> it(select_lex->item_list); + List_iterator_fast<Item> itc(select_lex->item_list); while ((item= it++)) { Item *check; - List_iterator_fast<Item> itc(select_lex->item_list); /* treat underlying fields like set by user names */ if (item->real_item()->type() == Item::FIELD_ITEM) item->is_autogenerated_name= FALSE; + itc.rewind(); while ((check= itc++) && check != item) { if (my_strcasecmp(system_charset_info, item->name, check->name) == 0) @@ -822,16 +828,30 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) old_lex->can_use_merged()) && !old_lex->can_not_use_merged()) { + List_iterator_fast<TABLE_LIST> ti(view_select->top_join_list); /* lex should contain at least one table */ DBUG_ASSERT(view_tables != 0); table->effective_algorithm= VIEW_ALGORITHM_MERGE; DBUG_PRINT("info", ("algorithm: MERGE")); table->updatable= (table->updatable_view != 0); - table->effective_with_check= (uint8)table->with_check; - - table->ancestor= view_tables; - + table->effective_with_check= + old_lex->get_effective_with_check(table); + + /* prepare view context */ + lex->select_lex.context.resolve_in_table_list_only(table->ancestor= + view_tables); + lex->select_lex.context.outer_context= 0; + lex->select_lex.context.select_lex= table->select_lex; + /* do not check privileges & hide errors for view underlyings */ + for (SELECT_LEX *sl= lex->all_selects_list; + sl; + sl= sl->next_select_in_list()) + { + sl->context.check_privileges= FALSE; + sl->context.error_processor= &view_error_processor; + sl->context.error_processor_data= (void *)table; + } /* Tables of the main select of the view should be marked as belonging to the same select as original view (again we can use LEX::select_lex @@ -852,13 +872,11 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) nested_join->join_list= view_select->top_join_list; /* re-nest tables of VIEW */ + ti.rewind(); + while ((tbl= ti++)) { - List_iterator_fast<TABLE_LIST> ti(nested_join->join_list); - while ((tbl= ti++)) - { - tbl->join_list= &nested_join->join_list; - tbl->embedding= table; - } + tbl->join_list= &nested_join->join_list; + tbl->embedding= table; } } @@ -866,13 +884,12 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) table->where= view_select->where; /* Add subqueries units to SELECT into which we merging current view. - unit(->next)* chain starts with subqueries that are used by this view and continues with subqueries that are used by other views. We must not add any subquery twice (otherwise we'll form a loop), - to do this we remember in end_unit the first subquery that has + to do this we remember in end_unit the first subquery that has been already added. - + NOTE: we do not support UNION here, so we take only one select */ SELECT_LEX_NODE *end_unit= table->select_lex->slave; @@ -1058,9 +1075,9 @@ frm_type_enum mysql_frm_type(char *path) bool check_key_in_view(THD *thd, TABLE_LIST *view) { TABLE *table; - Field_translator *trans; + Field_translator *trans, *end_of_trans; KEY *key_info, *key_info_end; - uint i, elements_in_view; + uint i; DBUG_ENTER("check_key_in_view"); /* @@ -1077,9 +1094,24 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) trans= view->field_translation; key_info_end= (key_info= table->key_info)+ table->s->keys; - elements_in_view= view->view->select_lex.item_list.elements; + end_of_trans= view->field_translation_end; DBUG_ASSERT(table != 0 && view->field_translation != 0); + { + /* + We should be sure that all fields are ready to get keys from them, but + this operation should not have influence on Field::query_id, to avoid + marking as used fields which are not used + */ + bool save_set_query_id= thd->set_query_id; + thd->set_query_id= 0; + for (Field_translator *fld= trans; fld < end_of_trans; fld++) + { + if (!fld->item->fixed && fld->item->fix_fields(thd, &fld->item)) + return TRUE; + } + thd->set_query_id= save_set_query_id; + } /* Loop over all keys to see if a unique-not-null key is used */ for (;key_info != key_info_end ; key_info++) { @@ -1091,15 +1123,15 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) /* check that all key parts are used */ for (;;) { - uint k; - for (k= 0; k < elements_in_view; k++) + Field_translator *k; + for (k= trans; k < end_of_trans; k++) { Item_field *field; - if ((field= trans[k].item->filed_for_view_update()) && + if ((field= k->item->filed_for_view_update()) && field->field == key_part->field) break; } - if (k == elements_in_view) + if (k == end_of_trans) break; // Key is not possible if (++key_part == key_part_end) DBUG_RETURN(FALSE); // Found usable key @@ -1111,19 +1143,20 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) /* check all fields presence */ { Field **field_ptr; + Field_translator *fld; for (field_ptr= table->field; *field_ptr; field_ptr++) { - for (i= 0; i < elements_in_view; i++) + for (fld= trans; fld < end_of_trans; fld++) { Item_field *field; - if ((field= trans[i].item->filed_for_view_update()) && + if ((field= fld->item->filed_for_view_update()) && field->field == *field_ptr) break; } - if (i == elements_in_view) // If field didn't exists + if (fld == end_of_trans) // If field didn't exists { /* - Keys or all fields of underlying tables are not foud => we have + Keys or all fields of underlying tables are not found => we have to check variable updatable_views_with_limit to decide should we issue an error or just a warning */ @@ -1148,6 +1181,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) SYNOPSIS insert_view_fields() + thd thread handler list list for insertion view view for processing @@ -1156,19 +1190,20 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) TRUE error (is not sent to cliet) */ -bool insert_view_fields(List<Item> *list, TABLE_LIST *view) +bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view) { - uint elements_in_view= view->view->select_lex.item_list.elements; + Field_translator *trans_end; Field_translator *trans; DBUG_ENTER("insert_view_fields"); if (!(trans= view->field_translation)) DBUG_RETURN(FALSE); + trans_end= view->field_translation_end; - for (uint i= 0; i < elements_in_view; i++) + for (Field_translator *entry= trans; entry < trans_end; entry++) { Item_field *fld; - if ((fld= trans[i].item->filed_for_view_update())) + if ((fld= entry->item->filed_for_view_update())) list->push_back(fld); else { diff --git a/sql/sql_view.h b/sql/sql_view.h index 4e6aaf7f477..3246dbae383 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -25,7 +25,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode); bool check_key_in_view(THD *thd, TABLE_LIST * view); -bool insert_view_fields(List<Item> *list, TABLE_LIST *view); +bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view); frm_type_enum mysql_frm_type(char *path); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index edca9cf3c5f..46e267fe165 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -676,7 +676,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); 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 key_cache_name - sp_opt_label BIN_NUM + sp_opt_label BIN_NUM label_ident %type <lex_str_ptr> opt_table_alias @@ -764,7 +764,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <udf_type> udf_func_type -%type <symbol> FUNC_ARG0 FUNC_ARG1 FUNC_ARG2 FUNC_ARG3 keyword +%type <symbol> FUNC_ARG0 FUNC_ARG1 FUNC_ARG2 FUNC_ARG3 keyword keyword_sp %type <lex_user> user grant_user @@ -1259,7 +1259,6 @@ create: THD *thd= YYTHD; LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_VIEW; - lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE; /* first table in list is target VIEW name */ if (!lex->select_lex.add_table_to_list(thd, $5, NULL, 0)) YYABORT; @@ -1532,7 +1531,7 @@ call: lex->sql_command= SQLCOM_CALL; lex->spname= $2; lex->value_list.empty(); - sp_add_to_hash(&lex->spprocs, $2); + sp_add_used_routine(lex, YYTHD, $2, TYPE_ENUM_PROCEDURE); } '(' sp_cparam_list ')' {} ; @@ -2054,7 +2053,7 @@ sp_proc_stmt: lex->sphead->backpatch(lex->spcont->pop_label()); } - | LEAVE_SYM IDENT + | LEAVE_SYM label_ident { LEX *lex= Lex; sp_head *sp = lex->sphead; @@ -2084,7 +2083,7 @@ sp_proc_stmt: sp->add_instr(i); } } - | ITERATE_SYM IDENT + | ITERATE_SYM label_ident { LEX *lex= Lex; sp_head *sp= lex->sphead; @@ -2114,6 +2113,7 @@ sp_proc_stmt: } | LABEL_SYM IDENT { +#ifdef SP_GOTO LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; @@ -2131,9 +2131,14 @@ sp_proc_stmt: lab->ctx= ctx; sp->backpatch(lab); } +#else + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; +#endif } | GOTO_SYM IDENT { +#ifdef SP_GOTO LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; @@ -2186,6 +2191,10 @@ sp_proc_stmt: i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */ sp->add_instr(i); } +#else + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; +#endif } | OPEN_SYM ident { @@ -2391,7 +2400,7 @@ sp_whens: ; sp_labeled_control: - IDENT ':' + label_ident ':' { LEX *lex= Lex; sp_pcontext *ctx= lex->spcont; @@ -2430,7 +2439,7 @@ sp_labeled_control: sp_opt_label: /* Empty */ { $$= null_lex_str; } - | IDENT { $$= $1; } + | label_ident { $$= $1; } ; sp_unlabeled_control: @@ -3383,7 +3392,6 @@ alter: LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_VIEW; lex->create_view_mode= VIEW_ALTER; - lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE; /* first table in list is target VIEW name */ lex->select_lex.add_table_to_list(thd, $4, NULL, 0); } @@ -3941,7 +3949,6 @@ select: { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; - lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE; } ; @@ -4095,7 +4102,10 @@ select_item_list: | '*' { THD *thd= YYTHD; - if (add_item_to_list(thd, new Item_field(NULL, NULL, "*"))) + if (add_item_to_list(thd, + new Item_field(&thd->lex->current_select-> + context, + NULL, NULL, "*"))) YYABORT; (thd->lex->current_select->with_wild)++; }; @@ -4393,10 +4403,10 @@ simple_expr: my_error(ER_WRONG_COLUMN_NAME, MYF(0), name->str); YYABORT; } - $$= new Item_default_value($3); + $$= new Item_default_value(&Select->context, $3); } | VALUES '(' simple_ident ')' - { $$= new Item_insert_value($3); } + { $$= new Item_insert_value(&Select->context, $3); } | FUNC_ARG0 '(' ')' { if (!$1.symbol->create_func) @@ -4685,17 +4695,18 @@ simple_expr: sp_name *name= new sp_name($1, $3); name->init_qname(YYTHD); - sp_add_to_hash(&lex->spfuns, name); + sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION); if ($5) - $$= new Item_func_sp(name, *$5); + $$= new Item_func_sp(&lex->current_select->context, name, *$5); else - $$= new Item_func_sp(name); + $$= new Item_func_sp(&lex->current_select->context, name); lex->safe_to_cache_query=0; } | IDENT_sys '(' udf_expr_list ')' { #ifdef HAVE_DLOPEN udf_func *udf; + SELECT_LEX *sel= Select; if (using_udf_functions && (udf=find_udf($1.str, $1.length))) { @@ -4774,11 +4785,11 @@ simple_expr: LEX *lex= Lex; sp_name *name= sp_name_current_db_new(YYTHD, $1); - sp_add_to_hash(&lex->spfuns, name); + sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION); if ($3) - $$= new Item_func_sp(name, *$3); + $$= new Item_func_sp(&lex->current_select->context, name, *$3); else - $$= new Item_func_sp(name); + $$= new Item_func_sp(&lex->current_select->context, name); lex->safe_to_cache_query=0; } } @@ -4980,8 +4991,10 @@ sum_expr: opt_gconcat_separator ')' { - Select->in_sum_expr--; - $$=new Item_func_group_concat($3,$5,Select->gorder_list,$7); + SELECT_LEX *sel= Select; + sel->in_sum_expr--; + $$=new Item_func_group_concat(&sel->context, $3, $5, + sel->gorder_list, $7); $5->empty(); }; @@ -5400,16 +5413,30 @@ using_list: ident { SELECT_LEX *sel= Select; - if (!($$= new Item_func_eq(new Item_field(sel->db1, sel->table1, + if (!($$= new Item_func_eq(new Item_field(&sel->context, + sel->db1, sel->table1, $1.str), - new Item_field(sel->db2, sel->table2, + new Item_field(&sel->context, + sel->db2, sel->table2, $1.str)))) YYABORT; } | using_list ',' ident { SELECT_LEX *sel= Select; - if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(sel->db1,sel->table1,$3.str), new Item_field(sel->db2,sel->table2,$3.str)), $1))) + if (!($$= + new Item_cond_and(new + Item_func_eq(new + Item_field(&sel->context, + sel->db1, + sel->table1, + $3.str), + new + Item_field(&sel->context, + sel->db2, + sel->table2, + $3.str)), + $1))) YYABORT; }; @@ -5647,7 +5674,7 @@ delete_limit_clause: ulong_num: NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } - | HEX_NUM { int error; $$= (ulong) strtol($1.str, (char**) 0, 16); } + | HEX_NUM { $$= (ulong) strtol($1.str, (char**) 0, 16); } | LONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } | ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } | DECIMAL_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } @@ -5675,7 +5702,10 @@ procedure_clause: lex->proc_list.elements=0; lex->proc_list.first=0; lex->proc_list.next= (byte**) &lex->proc_list.first; - if (add_proc_to_list(lex->thd, new Item_field(NULL,NULL,$2.str))) + if (add_proc_to_list(lex->thd, new Item_field(&lex-> + current_select-> + context, + NULL,NULL,$2.str))) YYABORT; Lex->uncacheable(UNCACHEABLE_SIDEEFFECT); } @@ -5922,7 +5952,6 @@ insert: mysql_init_select(lex); /* for subselects */ lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; - lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; } insert_lock_option opt_ignore insert2 { @@ -5940,7 +5969,6 @@ replace: lex->sql_command = SQLCOM_REPLACE; lex->duplicates= DUP_REPLACE; mysql_init_select(lex); - lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; } replace_lock_option insert2 { @@ -6058,7 +6086,7 @@ values: expr_or_default: expr { $$= $1;} - | DEFAULT {$$= new Item_default_value(); } + | DEFAULT {$$= new Item_default_value(&Select->context); } ; opt_insert_update: @@ -6120,24 +6148,9 @@ insert_update_elem: simple_ident_nospvar equal expr_or_default { LEX *lex= Lex; - uint8 tmp= MY_ITEM_PREFER_1ST_TABLE; if (lex->update_list.push_back($1) || lex->value_list.push_back($3)) YYABORT; - /* - INSERT INTO a1(a) SELECT b1.a FROM b1 ON DUPLICATE KEY - UPDATE a= a + b1.b - - Set MY_ITEM_PREFER_1ST_TABLE flag to $1 and $3 items - to prevent find_field_in_tables() doing further item searching - if it finds item occurence in first table in insert_table_list. - This allows to avoid ambiguity in resolving 'a' field in - example above. - */ - $1->walk(&Item::set_flags_processor, - (byte *) &tmp); - $3->walk(&Item::set_flags_processor, - (byte *) &tmp); }; opt_low_priority: @@ -7027,15 +7040,17 @@ insert_ident: table_wild: ident '.' '*' { - $$ = new Item_field(NullS,$1.str,"*"); - Lex->current_select->with_wild++; + SELECT_LEX *sel= Select; + $$ = new Item_field(&sel->context, NullS, $1.str, "*"); + sel->with_wild++; } | ident '.' ident '.' '*' { - $$ = new Item_field((YYTHD->client_capabilities & + SELECT_LEX *sel= Select; + $$ = new Item_field(&sel->context, (YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str,"*"); - Lex->current_select->with_wild++; + sel->with_wild++; } ; @@ -7060,8 +7075,8 @@ simple_ident: SELECT_LEX *sel=Select; $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,NullS,$1.str) : - (Item*) new Item_ref(NullS,NullS,$1.str); + (Item*) new Item_field(&sel->context, NullS, NullS, $1.str) : + (Item*) new Item_ref(&sel->context, NullS, NullS, $1.str); } } | simple_ident_q { $$= $1; } @@ -7073,8 +7088,8 @@ simple_ident_nospvar: SELECT_LEX *sel=Select; $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,NullS,$1.str) : - (Item*) new Item_ref(NullS,NullS,$1.str); + (Item*) new Item_field(&sel->context, NullS, NullS, $1.str) : + (Item*) new Item_ref(&sel->context, NullS, NullS, $1.str); } | simple_ident_q { $$= $1; } ; @@ -7111,7 +7126,8 @@ simple_ident_q: YYABORT; } - if (!(trg_fld= new Item_trigger_field(new_row ? + if (!(trg_fld= new Item_trigger_field(&lex->current_select->context, + new_row ? Item_trigger_field::NEW_ROW: Item_trigger_field::OLD_ROW, $3.str))) @@ -7136,8 +7152,8 @@ simple_ident_q: } $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,$1.str,$3.str) : - (Item*) new Item_ref(NullS,$1.str,$3.str); + (Item*) new Item_field(&sel->context, NullS, $1.str, $3.str) : + (Item*) new Item_ref(&sel->context, NullS, $1.str, $3.str); } } | '.' ident '.' ident @@ -7152,8 +7168,8 @@ simple_ident_q: } $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,$2.str,$4.str) : - (Item*) new Item_ref(NullS, $2.str, $4.str); + (Item*) new Item_field(&sel->context, NullS, $2.str, $4.str) : + (Item*) new Item_ref(&sel->context, NullS, $2.str, $4.str); } | ident '.' ident '.' ident { @@ -7167,10 +7183,12 @@ simple_ident_q: } $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field((YYTHD->client_capabilities & + (Item*) new Item_field(&sel->context, + (YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str, $5.str) : - (Item*) new Item_ref((YYTHD->client_capabilities & + (Item*) new Item_ref(&sel->context, + (YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str, $5.str); }; @@ -7277,6 +7295,16 @@ ident: } ; +label_ident: + IDENT_sys { $$=$1; } + | keyword_sp + { + THD *thd= YYTHD; + $$.str= thd->strmake($1.str, $1.length); + $$.length= $1.length; + } + ; + ident_or_text: ident { $$=$1;} | TEXT_STRING_sys { $$=$1;} @@ -7318,9 +7346,53 @@ user: } }; -/* Keyword that we allow for identifiers */ - +/* Keyword that we allow for identifiers (except SP labels) */ keyword: + keyword_sp {} + | ASCII_SYM {} + | BACKUP_SYM {} + | BEGIN_SYM {} + | BYTE_SYM {} + | CACHE_SYM {} + | CHARSET {} + | CHECKSUM_SYM {} + | CLOSE_SYM {} + | COMMENT_SYM {} + | COMMIT_SYM {} + | CONTAINS_SYM {} + | DEALLOCATE_SYM {} + | DO_SYM {} + | END {} + | EXECUTE_SYM {} + | FLUSH_SYM {} + | HANDLER_SYM {} + | HELP_SYM {} + | LANGUAGE_SYM {} + | NO_SYM {} + | OPEN_SYM {} + | PREPARE_SYM {} + | REPAIR {} + | RESET_SYM {} + | RESTORE_SYM {} + | ROLLBACK_SYM {} + | SAVEPOINT_SYM {} + | SECURITY_SYM {} + | SIGNED_SYM {} + | SLAVE {} + | START_SYM {} + | STOP_SYM {} + | TRUNCATE_SYM {} + | UNICODE_SYM {} + | XA_SYM {} + ; + +/* + * Keywords that we allow for labels in SPs. + * Anything that's the beginning of a statement or characteristics + * must be in keyword above, otherwise we get (harmful) shift/reduce + * conflicts. + */ +keyword_sp: ACTION {} | ADDDATE_SYM {} | AFTER_SYM {} @@ -7328,61 +7400,46 @@ keyword: | AGGREGATE_SYM {} | ALGORITHM_SYM {} | ANY_SYM {} - | ASCII_SYM {} | AUTO_INC {} | AVG_ROW_LENGTH {} | AVG_SYM {} - | BACKUP_SYM {} - | BEGIN_SYM {} | BERKELEY_DB_SYM {} | BINLOG_SYM {} | BIT_SYM {} | BOOL_SYM {} | BOOLEAN_SYM {} - | BYTE_SYM {} | BTREE_SYM {} - | CACHE_SYM {} | CASCADED {} | CHAIN_SYM {} | CHANGED {} - | CHARSET {} - | CHECKSUM_SYM {} | CIPHER_SYM {} | CLIENT_SYM {} - | CLOSE_SYM {} | COLLATION_SYM {} | COLUMNS {} - | COMMENT_SYM {} | COMMITTED_SYM {} - | COMMIT_SYM {} | COMPACT_SYM {} | COMPRESSED_SYM {} | CONCURRENT {} | CONSISTENT_SYM {} - | CONTAINS_SYM {} | CUBE_SYM {} | DATA_SYM {} | DATETIME {} | DATE_SYM {} | DAY_SYM {} - | DEALLOCATE_SYM {} | DEFINER_SYM {} | DELAY_KEY_WRITE_SYM {} | DES_KEY_FILE {} | DIRECTORY_SYM {} | DISCARD {} - | DO_SYM {} | DUMPFILE {} | DUPLICATE_SYM {} | DYNAMIC_SYM {} - | END {} | ENUM {} | ENGINE_SYM {} | ENGINES_SYM {} | ERRORS {} | ESCAPE_SYM {} | EVENTS_SYM {} - | EXECUTE_SYM {} | EXPANSION_SYM {} | EXTENDED_SYM {} | FAST_SYM {} @@ -7393,16 +7450,13 @@ keyword: | FILE_SYM {} | FIRST_SYM {} | FIXED_SYM {} - | FLUSH_SYM {} | FRAC_SECOND_SYM {} | GEOMETRY_SYM {} | GEOMETRYCOLLECTION {} | GET_FORMAT {} | GRANTS {} | GLOBAL_SYM {} - | HANDLER_SYM {} | HASH_SYM {} - | HELP_SYM {} | HOSTS_SYM {} | HOUR_SYM {} | IDENTIFIED_SYM {} @@ -7414,8 +7468,6 @@ keyword: | INNOBASE_SYM {} | INSERT_METHOD {} | RELAY_THREAD {} - | LABEL_SYM {} - | LANGUAGE_SYM {} | LAST_SYM {} | LEAVES {} | LEVEL_SYM {} @@ -7463,21 +7515,18 @@ keyword: | NDBCLUSTER_SYM {} | NEXT_SYM {} | NEW_SYM {} - | NO_SYM {} | NONE_SYM {} | NVARCHAR_SYM {} | OFFSET_SYM {} | OLD_PASSWORD {} | ONE_SHOT_SYM {} | ONE_SYM {} - | OPEN_SYM {} | PACK_KEYS_SYM {} | PARTIAL {} | PASSWORD {} | PHASE_SYM {} | POINT_SYM {} | POLYGON {} - | PREPARE_SYM {} | PREV_SYM {} | PRIVILEGES {} | PROCESS {} @@ -7495,41 +7544,31 @@ keyword: | RELAY_LOG_FILE_SYM {} | RELAY_LOG_POS_SYM {} | RELOAD {} - | REPAIR {} | REPEATABLE_SYM {} | REPLICATION {} - | RESET_SYM {} | RESOURCES {} - | RESTORE_SYM {} | RESUME_SYM {} | RETURNS_SYM {} - | ROLLBACK_SYM {} | ROLLUP_SYM {} | ROUTINE_SYM {} | ROWS_SYM {} | ROW_FORMAT_SYM {} | ROW_SYM {} | RTREE_SYM {} - | SAVEPOINT_SYM {} | SECOND_SYM {} - | SECURITY_SYM {} | SERIAL_SYM {} | SERIALIZABLE_SYM {} | SESSION_SYM {} - | SIGNED_SYM {} | SIMPLE_SYM {} | SHARE_SYM {} | SHUTDOWN {} - | SLAVE {} | SNAPSHOT_SYM {} | SOUNDS_SYM {} | SQL_CACHE_SYM {} | SQL_BUFFER_RESULT {} | SQL_NO_CACHE_SYM {} | SQL_THREAD {} - | START_SYM {} | STATUS_SYM {} - | STOP_SYM {} | STORAGE_SYM {} | STRING_SYM {} | SUBDATE_SYM {} @@ -7542,7 +7581,6 @@ keyword: | TEMPTABLE_SYM {} | TEXT_SYM {} | TRANSACTION_SYM {} - | TRUNCATE_SYM {} | TIMESTAMP {} | TIMESTAMP_ADD {} | TIMESTAMP_DIFF {} @@ -7553,7 +7591,6 @@ keyword: | FUNCTION_SYM {} | UNCOMMITTED_SYM {} | UNDEFINED_SYM {} - | UNICODE_SYM {} | UNKNOWN_SYM {} | UNTIL_SYM {} | USER {} @@ -7565,7 +7602,6 @@ keyword: | WEEK_SYM {} | WORK_SYM {} | X509_SYM {} - | XA_SYM {} | YEAR_SYM {} ; @@ -7706,12 +7742,6 @@ sys_option_value: yyerror(ER(ER_SYNTAX_ERROR)); YYABORT; } - if (lex->query_tables) - { - my_message(ER_SP_SUBSELECT_NYI, ER(ER_SP_SUBSELECT_NYI), - MYF(0)); - YYABORT; - } if ($4) it= $4; else @@ -7720,11 +7750,14 @@ sys_option_value: it= new Item_null(); } - if (!(trg_fld= new Item_trigger_field(Item_trigger_field::NEW_ROW, + if (!(trg_fld= new Item_trigger_field(&lex->current_select-> + context, + Item_trigger_field::NEW_ROW, $2.base_name.str)) || - !(i= new sp_instr_set_trigger_field( - lex->sphead->instructions(), lex->spcont, - trg_fld, it))) + !(i= new sp_instr_set_trigger_field(lex->sphead-> + instructions(), + lex->spcont, trg_fld, + it, lex))) YYABORT; /* diff --git a/sql/table.cc b/sql/table.cc index 4ddaeeea248..bbf34ae2c25 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -595,6 +595,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, } reg_field->fieldnr= i+1; //Set field number + reg_field->field_index= i; reg_field->comment=comment; if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag)) { @@ -746,8 +747,9 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, error. */ keyinfo->key_length-= (key_part->length - field->key_length()); - key_part->store_length-= (key_part->length - field->key_length()); - key_part->length= field->key_length(); + key_part->store_length-= (uint16)(key_part->length - + field->key_length()); + key_part->length= (uint16)field->key_length(); sql_print_error("Found wrong key definition in %s; Please do \"ALTER TABLE '%s' FORCE \" to fix it!", name, share->table_name); push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_CRASHED_ON_USAGE, @@ -1716,8 +1718,6 @@ void st_table_list::set_ancestor() } if (tbl->multitable_view) multitable_view= TRUE; - if (tbl->table) - tbl->table->grant= grant; } while ((tbl= tbl->next_local)); if (!multitable_view) @@ -1730,68 +1730,18 @@ void st_table_list::set_ancestor() /* - Save old want_privilege and clear want_privilege - - SYNOPSIS - save_and_clear_want_privilege() -*/ - -void st_table_list::save_and_clear_want_privilege() -{ - for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) - { - if (tbl->table) - { - privilege_backup= tbl->table->grant.want_privilege; - tbl->table->grant.want_privilege= 0; - } - else - { - tbl->save_and_clear_want_privilege(); - } - } -} - - -/* - restore want_privilege saved by save_and_clear_want_privilege - - SYNOPSIS - restore_want_privilege() -*/ - -void st_table_list::restore_want_privilege() -{ - for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) - { - if (tbl->table) - tbl->table->grant.want_privilege= privilege_backup; - else - { - tbl->restore_want_privilege(); - } - } -} - - -/* setup fields of placeholder of merged VIEW SYNOPSIS st_table_list::setup_ancestor() thd - thread handler - conds - condition of this JOIN - check_opt_type - WHITH CHECK OPTION type (VIEW_CHECK_NONE, - VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED) + NOTES ancestor is list of tables and views used by view (underlying tables/views) DESCRIPTION It is: - - preparing translation table for view columns (fix_fields() for every - call and creation for first call) - - preparing WHERE, ON and CHECK OPTION condition (fix_fields() for every - call and merging for first call). + - preparing translation table for view columns If there are underlying view(s) procedure first will be called for them. RETURN @@ -1799,163 +1749,114 @@ void st_table_list::restore_want_privilege() TRUE - error */ -bool st_table_list::setup_ancestor(THD *thd, Item **conds, - uint8 check_opt_type) +bool st_table_list::setup_ancestor(THD *thd) { - Field_translator *transl; - SELECT_LEX *select= &view->select_lex; - SELECT_LEX *current_select_save= thd->lex->current_select; - byte *main_table_list_save= select_lex->table_list.first; - Item *item; - TABLE_LIST *tbl; - List_iterator_fast<Item> it(select->item_list); - uint i= 0; - enum sub_select_type linkage_save= - select_lex->master_unit()->first_select()->linkage; - bool save_set_query_id= thd->set_query_id; - bool save_wrapper= select_lex->no_wrap_view_item; - bool save_allow_sum_func= thd->allow_sum_func; - bool res= FALSE; DBUG_ENTER("st_table_list::setup_ancestor"); - - if (check_stack_overrun(thd, STACK_MIN_SIZE, (char *)&res)) - return TRUE; - - for (tbl= ancestor; tbl; tbl= tbl->next_local) + if (!field_translation) { - if (tbl->ancestor && - tbl->setup_ancestor(thd, conds, - (check_opt_type == VIEW_CHECK_CASCADED ? - VIEW_CHECK_CASCADED : - VIEW_CHECK_NONE))) + Field_translator *transl; + SELECT_LEX *select= &view->select_lex; + Item *item; + TABLE_LIST *tbl; + List_iterator_fast<Item> it(select->item_list); + uint field_count= 0; + + if (check_stack_overrun(thd, STACK_MIN_SIZE, (char *)&field_count)) + { DBUG_RETURN(TRUE); - } + } - /* - We have to ensure that inside the view we are not referring to any - table outside of the view. We do it by changing the pointers used - by fix_fields to look up tables so that only tables and views in - view are seen. We also set linkage to DERIVED_TABLE_TYPE as a barrier - so that we stop resolving fields as this level. - */ - thd->lex->current_select= select_lex; - select_lex->table_list.first= (byte *)ancestor; - select_lex->master_unit()->first_select()->linkage= DERIVED_TABLE_TYPE; + for (tbl= ancestor; tbl; tbl= tbl->next_local) + { + if (tbl->ancestor && + tbl->setup_ancestor(thd)) + { + DBUG_RETURN(TRUE); + } + } - if (field_translation) - { - DBUG_PRINT("info", ("there are already translation table")); - - select_lex->no_wrap_view_item= 1; - - thd->set_query_id= 1; - /* this view was prepared already on previous PS/SP execution */ - Field_translator *end= field_translation + select->item_list.elements; - /* real rights will be checked in VIEW field */ - save_and_clear_want_privilege(); - /* aggregate function are allowed */ - thd->allow_sum_func= 1; - for (transl= field_translation; transl < end; transl++) + /* Create view fields translation table */ + + if (!(transl= + (Field_translator*)(thd->current_arena-> + alloc(select->item_list.elements * + sizeof(Field_translator))))) { - if (!transl->item->fixed && - transl->item->fix_fields(thd, ancestor, &transl->item)) - goto err; + DBUG_RETURN(TRUE); } - for (tbl= ancestor; tbl; tbl= tbl->next_local) + + while ((item= it++)) { - if (tbl->on_expr && !tbl->on_expr->fixed && - tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr)) - goto err; + transl[field_count].name= item->name; + transl[field_count++].item= item; } - if (where && !where->fixed && where->fix_fields(thd, ancestor, &where)) - goto err; - if (check_option && !check_option->fixed && - check_option->fix_fields(thd, ancestor, &check_option)) - goto err; - restore_want_privilege(); + field_translation= transl; + field_translation_end= transl + field_count; + /* TODO: use hash for big number of fields */ - /* WHERE/ON resolved => we can rename fields */ - for (transl= field_translation; transl < end; transl++) + /* full text function moving to current select */ + if (view->select_lex.ftfunc_list->elements) { - transl->item->rename((char *)transl->name); + Item_func_match *ifm; + SELECT_LEX *current_select= thd->lex->current_select; + List_iterator_fast<Item_func_match> + li(*(view->select_lex.ftfunc_list)); + while ((ifm= li++)) + current_select->ftfunc_list->push_front(ifm); } - goto ok; } + DBUG_RETURN(FALSE); +} - /* Create view fields translation table */ - if (!(transl= - (Field_translator*)(thd->current_arena-> - alloc(select->item_list.elements * - sizeof(Field_translator))))) - { - res= TRUE; - goto ok; // Restore thd - } +/* + Prepare where expression of view - select_lex->no_wrap_view_item= 1; + SYNOPSIS + st_table_list::prep_where() + thd - thread handler + conds - condition of this JOIN + no_where_clause - do not build WHERE or ON outer qwery do not need it + (it is INSERT), we do not need conds if this flag is set - /* - Resolve all view items against ancestor table. + NOTE: have to be called befor CHECK OPTION preparation, because it makes + fix_fields for view WHERE clause - TODO: do it only for real used fields "on demand" to mark really - used fields correctly. - */ - thd->set_query_id= 1; - /* real rights will be checked in VIEW field */ - save_and_clear_want_privilege(); - /* aggregate function are allowed */ - thd->allow_sum_func= 1; - while ((item= it++)) - { - /* save original name of view column */ - char *name= item->name; - transl[i].item= item; - if (!item->fixed && item->fix_fields(thd, ancestor, &transl[i].item)) - goto err; - /* set new item get in fix fields and original column name */ - transl[i++].name= name; - } - field_translation= transl; - /* TODO: sort this list? Use hash for big number of fields */ + RETURN + FALSE - OK + TRUE - error +*/ - for (tbl= ancestor; tbl; tbl= tbl->next_local) +bool st_table_list::prep_where(THD *thd, Item **conds, + bool no_where_clause) +{ + DBUG_ENTER("st_table_list::prep_where"); + + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) { - if (tbl->on_expr && !tbl->on_expr->fixed && - tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr)) - goto err; + if (tbl->view && tbl->prep_where(thd, conds, no_where_clause)) + { + DBUG_RETURN(TRUE); + } } - if (where || - (check_opt_type == VIEW_CHECK_CASCADED && - ancestor->check_option)) - { - Query_arena *arena= thd->current_arena, backup; - TABLE_LIST *tbl= this; - if (arena->is_conventional()) - arena= 0; // For easier test - - if (where && !where->fixed && where->fix_fields(thd, ancestor, &where)) - goto err; - - if (arena) - thd->set_n_backup_item_arena(arena, &backup); - if (check_opt_type) + if (where) + { + if (!where->fixed && where->fix_fields(thd, &where)) { - if (where) - check_option= where->copy_andor_structure(thd); - if (check_opt_type == VIEW_CHECK_CASCADED) - { - check_option= and_conds(check_option, ancestor->check_option); - } + DBUG_RETURN(TRUE); } /* check that it is not VIEW in which we insert with INSERT SELECT (in this case we can't add view WHERE condition to main SELECT_LEX) */ - if (where && !no_where_clause) + if (!no_where_clause && !where_processed) { + TABLE_LIST *tbl= this; + Query_arena *arena= thd->current_arena, backup; + arena= thd->change_arena_if_needed(&backup); // For easier test + /* Go up to join tree and try to find left join */ for (; tbl; tbl= tbl->embedding) { @@ -1972,72 +1873,107 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds, } } if (tbl == 0) - { - if (outer_join) - { - /* - Store WHERE condition to ON expression for outer join, because - we can't use WHERE to correctly execute left joins on VIEWs and - this expression will not be moved to WHERE condition (i.e. will - be clean correctly for PS/SP) - */ - on_expr= and_conds(on_expr, where); - } - else - { - /* - It is conds of JOIN, but it will be stored in - st_select_lex::prep_where for next reexecution - */ - *conds= and_conds(*conds, where); - } - } + *conds= and_conds(*conds, where); + if (arena) + thd->restore_backup_item_arena(arena, &backup); + where_processed= TRUE; } - - if (arena) - thd->restore_backup_item_arena(arena, &backup); } - restore_want_privilege(); - /* - fix_fields do not need tables, because new are only AND operation and we - just need recollect statistics - */ - if (check_option && !check_option->fixed && - check_option->fix_fields(thd, 0, &check_option)) - goto err; + DBUG_RETURN(FALSE); +} + + +/* + Prepare check option expression of table + + SYNOPSIS + st_table_list::prep_check_option() + thd - thread handler + check_opt_type - WITH CHECK OPTION type (VIEW_CHECK_NONE, + VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED) + we use this parameter instead of direct check of + effective_with_check to change type of underlying + views to VIEW_CHECK_CASCADED if outer view have + such option and prevent processing of underlying + view check options if outer view have just + VIEW_CHECK_LOCAL option. + + NOTE + This method build check options for every call + (usual execution or every SP/PS call) + This method have to be called after WHERE preparation + (st_table_list::prep_where) - /* WHERE/ON resolved => we can rename fields */ + RETURN + FALSE - OK + TRUE - error +*/ + +bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type) +{ + DBUG_ENTER("st_table_list::prep_check_option"); + + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) { - Field_translator *end= field_translation + select->item_list.elements; - for (transl= field_translation; transl < end; transl++) + /* see comment of check_opt_type parameter */ + if (tbl->view && + tbl->prep_check_option(thd, + ((check_opt_type == VIEW_CHECK_CASCADED) ? + VIEW_CHECK_CASCADED : + VIEW_CHECK_NONE))) { - transl->item->rename((char *)transl->name); + DBUG_RETURN(TRUE); } } - /* full text function moving to current select */ - if (view->select_lex.ftfunc_list->elements) + if (check_opt_type) { - Query_arena *arena= thd->current_arena, backup; - if (arena->is_conventional()) - arena= 0; // For easier test - else - thd->set_n_backup_item_arena(arena, &backup); - - Item_func_match *ifm; - List_iterator_fast<Item_func_match> - li(*(view->select_lex.ftfunc_list)); - while ((ifm= li++)) - current_select_save->ftfunc_list->push_front(ifm); - if (arena) - thd->restore_backup_item_arena(arena, &backup); + Item *item= 0; + if (where) + { + DBUG_ASSERT(where->fixed); + item= where->copy_andor_structure(thd); + } + if (check_opt_type == VIEW_CHECK_CASCADED) + { + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) + { + if (tbl->check_option) + item= and_conds(item, tbl->check_option); + } + } + if (item) + thd->change_item_tree(&check_option, item); + } + + if (check_option) + { + const char *save_where= thd->where; + thd->where= "check option"; + if (!check_option->fixed && + check_option->fix_fields(thd, &check_option) || + check_option->check_cols(1)) + { + DBUG_RETURN(TRUE); + } + thd->where= save_where; } + DBUG_RETURN(FALSE); +} + - goto ok; +/* + Hide errors which show view underlying table information + + SYNOPSIS + st_table_list::hide_view_error() + thd thread handler -err: - res= TRUE; +*/ + +void st_table_list::hide_view_error(THD *thd) +{ /* Hide "Unknown column" or "Unknown function" error */ if (thd->net.last_errno == ER_BAD_FIELD_ERROR || thd->net.last_errno == ER_SP_DOES_NOT_EXIST) @@ -2045,15 +1981,12 @@ err: thd->clear_error(); my_error(ER_VIEW_INVALID, MYF(0), view_db.str, view_name.str); } - -ok: - select_lex->no_wrap_view_item= save_wrapper; - thd->lex->current_select= current_select_save; - select_lex->table_list.first= main_table_list_save; - select_lex->master_unit()->first_select()->linkage= linkage_save; - thd->set_query_id= save_set_query_id; - thd->allow_sum_func= save_allow_sum_func; - DBUG_RETURN(res); + else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD) + { + thd->clear_error(); + // TODO: make correct error message + my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0), view_db.str, view_name.str); + } } @@ -2097,9 +2030,9 @@ void st_table_list::cleanup_items() if (!field_translation) return; - Field_translator *end= (field_translation + - view->select_lex.item_list.elements); - for (Field_translator *transl= field_translation; transl < end; transl++) + for (Field_translator *transl= field_translation; + transl < field_translation_end; + transl++) transl->item->walk(&Item::cleanup_processor, 0); } @@ -2212,8 +2145,9 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root) void Field_iterator_view::set(TABLE_LIST *table) { + view= table; ptr= table->field_translation; - array_end= ptr + table->view->select_lex.item_list.elements; + array_end= table->field_translation_end; } @@ -2223,9 +2157,9 @@ const char *Field_iterator_table::name() } -Item *Field_iterator_table::item(THD *thd) +Item *Field_iterator_table::create_item(THD *thd) { - return new Item_field(thd, *ptr); + return new Item_field(thd, &thd->lex->current_select->context, *ptr); } @@ -2235,6 +2169,51 @@ const char *Field_iterator_view::name() } +Item *Field_iterator_view::create_item(THD *thd) +{ + return create_view_field(thd, view, &ptr->item, ptr->name); +} + +Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, + const char *name) +{ + bool save_wrapper= thd->lex->select_lex.no_wrap_view_item; + Item *field= *field_ref; + DBUG_ENTER("create_view_field"); + + if (view->schema_table_reformed) + { + /* + In case of SHOW command (schema_table_reformed set) all items are + fixed + */ + DBUG_ASSERT(field && field->fixed); + DBUG_RETURN(field); + } + + DBUG_ASSERT(field); + thd->lex->current_select->no_wrap_view_item= TRUE; + if (!field->fixed) + { + if (field->fix_fields(thd, field_ref)) + { + thd->lex->current_select->no_wrap_view_item= save_wrapper; + DBUG_RETURN(0); + } + field= *field_ref; + } + thd->lex->current_select->no_wrap_view_item= save_wrapper; + if (thd->lex->current_select->no_wrap_view_item) + { + DBUG_RETURN(field); + } + Item *item= new Item_direct_view_ref(&view->view->select_lex.context, + field_ref, view->view_name.str, + name); + DBUG_RETURN(item); +} + + /***************************************************************************** ** Instansiate templates *****************************************************************************/ diff --git a/sql/table.h b/sql/table.h index 8bc4e01852f..d0c998c4c10 100644 --- a/sql/table.h +++ b/sql/table.h @@ -314,9 +314,9 @@ typedef struct st_schema_table #define JOIN_TYPE_LEFT 1 #define JOIN_TYPE_RIGHT 2 -#define VIEW_ALGORITHM_UNDEFINED 0 -#define VIEW_ALGORITHM_TMPTABLE 1 -#define VIEW_ALGORITHM_MERGE 2 +#define VIEW_ALGORITHM_UNDEFINED 0 +#define VIEW_ALGORITHM_TMPTABLE 1 +#define VIEW_ALGORITHM_MERGE 2 /* view WITH CHECK OPTION parameter options */ #define VIEW_CHECK_NONE 0 @@ -329,9 +329,13 @@ typedef struct st_schema_table #define VIEW_CHECK_SKIP 2 struct st_lex; +struct st_table_list; class select_union; class TMP_TABLE_PARAM; +Item *create_view_field(THD *thd, st_table_list *view, Item **field_ref, + const char *name); + struct Field_translator { Item *item; @@ -384,6 +388,8 @@ typedef struct st_table_list st_select_lex *select_lex; st_lex *view; /* link on VIEW lex for merging */ Field_translator *field_translation; /* array of VIEW fields */ + /* pointer to element after last one in translation table above */ + Field_translator *field_translation_end; /* list of ancestor(s) of this table (underlying table(s)/view(s) */ st_table_list *ancestor; /* most upper view this table belongs to */ @@ -408,8 +414,7 @@ typedef struct st_table_list algorithm) */ uint8 effective_with_check; - uint effective_algorithm; /* which algorithm was really used */ - uint privilege_backup; /* place for saving privileges */ + uint8 effective_algorithm; /* which algorithm was really used */ GRANT_INFO grant; /* data need by some engines in query cache*/ ulonglong engine_data; @@ -424,7 +429,6 @@ typedef struct st_table_list bool updating; /* for replicate-do/ignore table */ bool force_index; /* prefer index over table scan */ bool ignore_leaves; /* preload only non-leaf nodes */ - bool no_where_clause; /* do not attach WHERE to SELECT */ table_map dep_tables; /* tables the table depends on */ table_map on_expr_dep_tables; /* tables on expression depends on */ struct st_nested_join *nested_join; /* if the element is a nested join */ @@ -437,6 +441,8 @@ typedef struct st_table_list /* TRUE if this merged view contain auto_increment field */ bool contain_auto_increment; bool multitable_view; /* TRUE iff this is multitable view */ + /* view where processed */ + bool where_processed; /* FRMTYPE_ERROR if any type is acceptable */ enum frm_type_enum required_type; char timestamp_buffer[20]; /* buffer for timestamp (19+1) */ @@ -449,16 +455,32 @@ typedef struct st_table_list void calc_md5(char *buffer); void set_ancestor(); int view_check_option(THD *thd, bool ignore_failure); - bool setup_ancestor(THD *thd, Item **conds, uint8 check_option); + bool setup_ancestor(THD *thd); void cleanup_items(); bool placeholder() {return derived || view; } void print(THD *thd, String *str); - void save_and_clear_want_privilege(); - void restore_want_privilege(); bool check_single_table(st_table_list **table, table_map map, st_table_list *view); bool set_insert_values(MEM_ROOT *mem_root); + void hide_view_error(THD *thd); st_table_list *find_underlying_table(TABLE *table); + inline bool prepare_check_option(THD *thd) + { + bool res= FALSE; + if (effective_with_check) + res= prep_check_option(thd, effective_with_check); + return res; + } + inline bool prepare_where(THD *thd, Item **conds, + bool no_where_clause) + { + if (effective_algorithm == VIEW_ALGORITHM_MERGE) + return prep_where(thd, conds, no_where_clause); + return FALSE; + } +private: + bool prep_check_option(THD *thd, uint8 check_opt_type); + bool prep_where(THD *thd, Item **conds, bool no_where_clause); } TABLE_LIST; class Item; @@ -471,7 +493,7 @@ public: virtual void next()= 0; virtual bool end_of_fields()= 0; /* Return 1 at end of list */ virtual const char *name()= 0; - virtual Item *item(THD *)= 0; + virtual Item *create_item(THD *)= 0; virtual Field *field()= 0; }; @@ -486,7 +508,7 @@ public: void next() { ptr++; } bool end_of_fields() { return *ptr == 0; } const char *name(); - Item *item(THD *thd); + Item *create_item(THD *thd); Field *field() { return *ptr; } }; @@ -494,15 +516,18 @@ public: class Field_iterator_view: public Field_iterator { Field_translator *ptr, *array_end; + TABLE_LIST *view; public: Field_iterator_view() :ptr(0), array_end(0) {} void set(TABLE_LIST *table); void next() { ptr++; } bool end_of_fields() { return ptr == array_end; } const char *name(); - Item *item(THD *thd) { return ptr->item; } + Item *create_item(THD *thd); Item **item_ptr() {return &ptr->item; } Field *field() { return 0; } + + inline Item *item() { return ptr->item; } }; diff --git a/storage/heap/Makefile.am b/storage/heap/Makefile.am index f9f0ba775ff..2890dc6ee23 100644 --- a/storage/heap/Makefile.am +++ b/storage/heap/Makefile.am @@ -14,7 +14,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -INCLUDES = -I$(top_srcdir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include LDADD = libheap.a $(top_srcdir)/mysys/libmysys.a \ $(top_srcdir)/dbug/libdbug.a \ $(top_srcdir)/strings/libmystrings.a diff --git a/storage/heap/hp_hash.c b/storage/heap/hp_hash.c index 9e4636ebdc0..d643f776731 100644 --- a/storage/heap/hp_hash.c +++ b/storage/heap/hp_hash.c @@ -552,9 +552,9 @@ int hp_rec_key_cmp(HP_KEYDEF *keydef, const byte *rec1, const byte *rec2, if (cs->mbmaxlen > 1) { uint char_length= seg->length / cs->mbmaxlen; - char_length1= my_charpos(cs, pos1, pos1 + char_length1, char_length); + char_length1= my_charpos(cs, pos1, pos1 + char_length1, char_length1); set_if_smaller(char_length1, seg->length); - char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length); + char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length2); set_if_smaller(char_length2, seg->length); } diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index 2d84586216a..c27fb73ff8d 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -143,7 +143,7 @@ btr_root_get( root_page_no = dict_tree_get_page(tree); root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr); - ut_a(!!page_is_comp(root) == + ut_a((ibool)!!page_is_comp(root) == UT_LIST_GET_FIRST(tree->tree_indexes)->table->comp); return(root); @@ -2014,7 +2014,7 @@ btr_compress( page = btr_cur_get_page(cursor); tree = btr_cur_get_tree(cursor); comp = page_is_comp(page); - ut_a(!!comp == cursor->index->table->comp); + ut_a((ibool)!!comp == cursor->index->table->comp); ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), MTR_MEMO_X_LOCK)); @@ -2508,7 +2508,7 @@ btr_index_rec_validate( return(TRUE); } - if (UNIV_UNLIKELY(!!page_is_comp(page) != index->table->comp)) { + if (UNIV_UNLIKELY((ibool)!!page_is_comp(page) != index->table->comp)) { btr_index_rec_validate_report(page, rec, index); fprintf(stderr, "InnoDB: compact flag=%lu, should be %lu\n", (ulong) !!page_is_comp(page), diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 4ae27f007d6..f81cce5b8e9 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -316,7 +316,9 @@ btr_cur_search_to_nth_level( if (btr_search_latch.writer == RW_LOCK_NOT_LOCKED && latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ && !estimate +#ifdef PAGE_CUR_LE_OR_EXTENDS && mode != PAGE_CUR_LE_OR_EXTENDS +#endif /* PAGE_CUR_LE_OR_EXTENDS */ && srv_use_adaptive_hash_indexes && btr_search_guess_on_hash(index, info, tuple, mode, latch_mode, cursor, @@ -390,9 +392,12 @@ btr_cur_search_to_nth_level( page_mode = PAGE_CUR_LE; break; default: - ut_ad(mode == PAGE_CUR_L - || mode == PAGE_CUR_LE +#ifdef PAGE_CUR_LE_OR_EXTENDS + ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE || mode == PAGE_CUR_LE_OR_EXTENDS); +#else /* PAGE_CUR_LE_OR_EXTENDS */ + ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE); +#endif /* PAGE_CUR_LE_OR_EXTENDS */ page_mode = mode; break; } @@ -507,7 +512,7 @@ retry_page_get: /* x-latch the page */ page = btr_page_get(space, page_no, RW_X_LATCH, mtr); - ut_a(!!page_is_comp(page) + ut_a((ibool)!!page_is_comp(page) == index->table->comp); } @@ -1385,7 +1390,7 @@ btr_cur_parse_update_in_place( goto func_exit; } - ut_a(!!page_is_comp(page) == index->table->comp); + ut_a((ibool)!!page_is_comp(page) == index->table->comp); rec = page + rec_offset; /* We do not need to reserve btr_search_latch, as the page is only diff --git a/storage/innobase/configure.in b/storage/innobase/configure.in index baf11272ab9..c56bd8274c4 100644 --- a/storage/innobase/configure.in +++ b/storage/innobase/configure.in @@ -117,6 +117,13 @@ case "$target" in CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; esac +# must go in pair with AR as set by MYSQL_CHECK_AR +if test -z "$ARFLAGS" +then + ARFLAGS="cru" +fi +AC_SUBST(ARFLAGS) + AC_OUTPUT(Makefile os/Makefile ut/Makefile btr/Makefile dnl buf/Makefile data/Makefile dnl dict/Makefile dyn/Makefile dnl diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c index 299b55f3d2b..20f522c1a60 100644 --- a/storage/innobase/fil/fil0fil.c +++ b/storage/innobase/fil/fil0fil.c @@ -3410,9 +3410,9 @@ fil_extend_space_to_desired_size( fil_space_t* space; byte* buf2; byte* buf; + ulint buf_size; ulint start_page_no; ulint file_start_page_no; - ulint n_pages; ulint offset_high; ulint offset_low; ibool success = TRUE; @@ -3437,22 +3437,20 @@ fil_extend_space_to_desired_size( fil_node_prepare_for_io(node, system, space); - /* 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); - 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; + /* Extend at most 64 pages at a time */ + buf_size = ut_min(64, size_after_extend - start_page_no) + * UNIV_PAGE_SIZE; + buf2 = mem_alloc(buf_size + UNIV_PAGE_SIZE); + buf = ut_align(buf2, UNIV_PAGE_SIZE); - if (n_pages > (1024 * 1024) / UNIV_PAGE_SIZE) { - n_pages = (1024 * 1024) / UNIV_PAGE_SIZE; - } + memset(buf, 0, buf_size); + + while (start_page_no < size_after_extend) { + ulint n_pages = ut_min(buf_size / UNIV_PAGE_SIZE, + size_after_extend - start_page_no); offset_high = (start_page_no - file_start_page_no) / (4096 * ((1024 * 1024) / UNIV_PAGE_SIZE)); @@ -4034,7 +4032,7 @@ fil_aio_wait( if (os_aio_use_native_aio) { srv_set_io_thread_op_info(segment, "native aio handle"); #ifdef WIN_ASYNC_IO - ret = os_aio_windows_handle(segment, 0, (void**) &fil_node, + ret = os_aio_windows_handle(segment, 0, &fil_node, &message, &type); #elif defined(POSIX_ASYNC_IO) ret = os_aio_posix_handle(segment, &fil_node, &message); diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 712d43f916c..d7fa48b6e66 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -2810,7 +2810,7 @@ ibuf_insert_to_index_page( ut_ad(ibuf_inside()); ut_ad(dtuple_check_typed(entry)); - if (UNIV_UNLIKELY(index->table->comp != !!page_is_comp(page))) { + if (UNIV_UNLIKELY(index->table->comp != (ibool)!!page_is_comp(page))) { fputs( "InnoDB: Trying to insert a record from the insert buffer to an index page\n" "InnoDB: but the 'compact' flag does not match!\n", stderr); diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index e75281dd93c..362e3552411 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -373,7 +373,7 @@ os_file_get_size_as_iblonglong( /* out: size in bytes, -1 if error */ os_file_t file); /* in: handle to a file */ /*************************************************************************** -Sets a file size. This function can be used to extend or truncate a file. */ +Write the specified number of zeros to a newly created file. */ ibool os_file_set_size( diff --git a/storage/innobase/include/page0cur.h b/storage/innobase/include/page0cur.h index e89e740e775..b03302b0e77 100644 --- a/storage/innobase/include/page0cur.h +++ b/storage/innobase/include/page0cur.h @@ -26,11 +26,13 @@ Created 10/4/1994 Heikki Tuuri #define PAGE_CUR_GE 2 #define PAGE_CUR_L 3 #define PAGE_CUR_LE 4 -#define PAGE_CUR_LE_OR_EXTENDS 5 /* This is a search mode used in +/*#define PAGE_CUR_LE_OR_EXTENDS 5*/ /* This is a search mode used in "column LIKE 'abc%' ORDER BY column DESC"; we have to find strings which are <= 'abc' or which extend it */ -#define PAGE_CUR_DBG 6 +#ifdef UNIV_SEARCH_DEBUG +# define PAGE_CUR_DBG 6 /* As PAGE_CUR_LE, but skips search shortcut */ +#endif /* UNIV_SEARCH_DEBUG */ #ifdef PAGE_CUR_ADAPT # ifdef UNIV_SEARCH_PERF_STAT diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 4bb9fa63cd1..4e6ff73b0f8 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -243,17 +243,27 @@ row_update_for_mysql( the MySQL format */ row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL handle */ - /************************************************************************* -Does an unlock of a row for MySQL. */ +This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before +calling this function we must use trx_reset_new_rec_lock_info() and +trx_register_new_rec_lock() to store the information which new record locks +really were set. This function removes a newly set lock under prebuilt->pcur, +and also under prebuilt->clust_pcur. Currently, this is only used and tested +in the case of an UPDATE or a DELETE statement, where the row lock is of the +LOCK_X type. +Thus, this implements a 'mini-rollback' that releases the latest record +locks we set. */ int row_unlock_for_mysql( /*=================*/ /* out: error code or DB_SUCCESS */ - row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL + row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL handle */ - + ibool has_latches_on_recs);/* TRUE if called so that we have + the latches on the records under pcur + and clust_pcur, and we do not need to + reposition the cursors. */ /************************************************************************* Creates an query graph node of 'update' type to be used in the MySQL interface. */ diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 6e4241965c1..116ae7b6438 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -182,6 +182,7 @@ extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs, #define kernel_mutex (*kernel_mutex_temp) #define SRV_MAX_N_IO_THREADS 100 +#define SRV_CONCURRENCY_THRESHOLD 20 /* Array of English strings describing the current state of an i/o handler thread */ diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 8df50d6703d..146730d46f8 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -16,10 +16,39 @@ Created 3/26/1996 Heikki Tuuri #include "que0types.h" #include "mem0mem.h" #include "read0types.h" +#include "dict0types.h" #include "trx0xa.h" extern ulint trx_n_mysql_transactions; +/***************************************************************** +Resets the new record lock info in a transaction struct. */ +UNIV_INLINE +void +trx_reset_new_rec_lock_info( +/*========================*/ + trx_t* trx); /* in: transaction struct */ +/***************************************************************** +Registers that we have set a new record lock on an index. We only have space +to store 2 indexes! If this is called to store more than 2 indexes after +trx_reset_new_rec_lock_info(), then this function does nothing. */ +UNIV_INLINE +void +trx_register_new_rec_lock( +/*======================*/ + trx_t* trx, /* in: transaction struct */ + dict_index_t* index); /* in: trx sets a new record lock on this + index */ +/***************************************************************** +Checks if trx has set a new record lock on an index. */ +UNIV_INLINE +ibool +trx_new_rec_locks_contain( +/*======================*/ + /* out: TRUE if trx has set a new record lock + on index */ + trx_t* trx, /* in: transaction struct */ + dict_index_t* index); /* in: index */ /************************************************************************ Releases the search latch if trx has reserved it. */ @@ -495,8 +524,18 @@ struct trx_struct{ lock_t* auto_inc_lock; /* possible auto-inc lock reserved by the transaction; note that it is also in the lock list trx_locks */ - ibool trx_create_lock;/* this is TRUE if we have created a - new lock for a record accessed */ + dict_index_t* new_rec_locks[2];/* these are normally NULL; if + srv_locks_unsafe_for_binlog is TRUE, + in a cursor search, if we set a new + record lock on an index, this is set + to point to the index; this is + used in releasing the locks under the + cursors if we are performing an UPDATE + and we determine after retrieving + the row that it does not need to be + locked; thus, these can be used to + implement a 'mini-rollback' that + releases the latest record locks */ UT_LIST_NODE_T(trx_t) trx_list; /* list of transactions */ UT_LIST_NODE_T(trx_t) diff --git a/storage/innobase/include/trx0trx.ic b/storage/innobase/include/trx0trx.ic index 78e5acda148..54cf2ff331f 100644 --- a/storage/innobase/include/trx0trx.ic +++ b/storage/innobase/include/trx0trx.ic @@ -39,4 +39,60 @@ trx_start_if_not_started_low( } } +/***************************************************************** +Resets the new record lock info in a transaction struct. */ +UNIV_INLINE +void +trx_reset_new_rec_lock_info( +/*========================*/ + trx_t* trx) /* in: transaction struct */ +{ + trx->new_rec_locks[0] = NULL; + trx->new_rec_locks[1] = NULL; +} + +/***************************************************************** +Registers that we have set a new record lock on an index. We only have space +to store 2 indexes! If this is called to store more than 2 indexes after +trx_reset_new_rec_lock_info(), then this function does nothing. */ +UNIV_INLINE +void +trx_register_new_rec_lock( +/*======================*/ + trx_t* trx, /* in: transaction struct */ + dict_index_t* index) /* in: trx sets a new record lock on this + index */ +{ + if (trx->new_rec_locks[0] == NULL) { + trx->new_rec_locks[0] = index; + + return; + } + + if (trx->new_rec_locks[0] == index) { + return; + } + + if (trx->new_rec_locks[1] != NULL) { + + return; + } + + trx->new_rec_locks[1] = index; +} + +/***************************************************************** +Checks if trx has set a new record lock on an index. */ +UNIV_INLINE +ibool +trx_new_rec_locks_contain( +/*======================*/ + /* out: TRUE if trx has set a new record lock + on index */ + trx_t* trx, /* in: transaction struct */ + dict_index_t* index) /* in: index */ +{ + return(trx->new_rec_locks[0] == index + || trx->new_rec_locks[1] == index); +} diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c index 48db7ced0cb..280c4871ee9 100644 --- a/storage/innobase/lock/lock0lock.c +++ b/storage/innobase/lock/lock0lock.c @@ -956,7 +956,7 @@ lock_rec_has_to_wait( cause waits */ if ((lock_is_on_supremum || (type_mode & LOCK_GAP)) - && !(type_mode & LOCK_INSERT_INTENTION)) { + && !(type_mode & LOCK_INSERT_INTENTION)) { /* Gap type locks without LOCK_INSERT_INTENTION flag do not need to wait for anything. This is because @@ -1765,10 +1765,7 @@ lock_rec_create( lock_rec_set_nth_bit(lock, heap_no); HASH_INSERT(lock_t, hash, lock_sys->rec_hash, - lock_rec_fold(space, page_no), lock); - /* Note that we have create a new lock */ - trx->trx_create_lock = TRUE; - + lock_rec_fold(space, page_no), lock); if (type_mode & LOCK_WAIT) { lock_set_lock_and_trx_wait(lock, trx); @@ -1945,15 +1942,6 @@ lock_rec_add_to_queue( if (similar_lock && !somebody_waits && !(type_mode & LOCK_WAIT)) { - /* If the nth bit of a record lock is already set then we - do not set a new lock bit, otherwice we set */ - - if (lock_rec_get_nth_bit(similar_lock, heap_no)) { - trx->trx_create_lock = FALSE; - } else { - trx->trx_create_lock = TRUE; - } - lock_rec_set_nth_bit(similar_lock, heap_no); return(similar_lock); @@ -2005,11 +1993,14 @@ lock_rec_lock_fast( lock = lock_rec_get_first_on_page(rec); trx = thr_get_trx(thr); - trx->trx_create_lock = FALSE; if (lock == NULL) { if (!impl) { lock_rec_create(mode, rec, index, trx); + + if (srv_locks_unsafe_for_binlog) { + trx_register_new_rec_lock(trx, index); + } } return(TRUE); @@ -2021,23 +2012,22 @@ lock_rec_lock_fast( } if (lock->trx != trx - || lock->type_mode != (mode | LOCK_REC) - || lock_rec_get_n_bits(lock) <= heap_no) { + || lock->type_mode != (mode | LOCK_REC) + || lock_rec_get_n_bits(lock) <= heap_no) { + return(FALSE); } if (!impl) { + /* If the nth bit of the record lock is already set then we + do not set a new lock bit, otherwise we do set */ - /* If the nth bit of a record lock is already set then we - do not set a new lock bit, otherwice we set */ - - if (lock_rec_get_nth_bit(lock, heap_no)) { - trx->trx_create_lock = FALSE; - } else { - trx->trx_create_lock = TRUE; + if (!lock_rec_get_nth_bit(lock, heap_no)) { + lock_rec_set_nth_bit(lock, heap_no); + if (srv_locks_unsafe_for_binlog) { + trx_register_new_rec_lock(trx, index); + } } - - lock_rec_set_nth_bit(lock, heap_no); } return(TRUE); @@ -2093,12 +2083,19 @@ lock_rec_lock_slow( enough already granted on the record, we have to wait. */ err = lock_rec_enqueue_waiting(mode, rec, index, thr); + + if (srv_locks_unsafe_for_binlog) { + trx_register_new_rec_lock(trx, index); + } } else { if (!impl) { /* Set the requested lock on the record */ lock_rec_add_to_queue(LOCK_REC | mode, rec, index, trx); + if (srv_locks_unsafe_for_binlog) { + trx_register_new_rec_lock(trx, index); + } } err = DB_SUCCESS; @@ -2436,8 +2433,15 @@ lock_rec_inherit_to_gap( lock = lock_rec_get_first(rec); + /* If srv_locks_unsafe_for_binlog is TRUE, we do not want locks set + by an UPDATE or a DELETE to be inherited as gap type locks. But we + DO want S-locks set by a consistency constraint to be inherited also + then. */ + while (lock != NULL) { - if (!lock_rec_get_insert_intention(lock)) { + if (!lock_rec_get_insert_intention(lock) + && !(srv_locks_unsafe_for_binlog + && lock_get_mode(lock) == LOCK_X)) { lock_rec_add_to_queue(LOCK_REC | lock_get_mode(lock) | LOCK_GAP, @@ -3069,7 +3073,7 @@ lock_update_insert( lock_rec_inherit_to_gap_if_gap_lock(rec, page_rec_get_next(rec)); lock_mutex_exit_kernel(); -} +} /***************************************************************** Updates the lock table when a record is removed. */ diff --git a/storage/innobase/log/log0recv.c b/storage/innobase/log/log0recv.c index 8d9780bfbda..42e854398ba 100644 --- a/storage/innobase/log/log0recv.c +++ b/storage/innobase/log/log0recv.c @@ -768,7 +768,8 @@ recv_parse_or_apply_log_rec_body( case MLOG_REC_INSERT: case MLOG_COMP_REC_INSERT: if (NULL != (ptr = mlog_parse_index(ptr, end_ptr, type == MLOG_COMP_REC_INSERT, &index))) { - ut_a(!page||!!page_is_comp(page)==index->table->comp); + ut_a(!page + || (ibool)!!page_is_comp(page)==index->table->comp); ptr = page_cur_parse_insert_rec(FALSE, ptr, end_ptr, index, page, mtr); } @@ -776,7 +777,8 @@ recv_parse_or_apply_log_rec_body( case MLOG_REC_CLUST_DELETE_MARK: case MLOG_COMP_REC_CLUST_DELETE_MARK: if (NULL != (ptr = mlog_parse_index(ptr, end_ptr, type == MLOG_COMP_REC_CLUST_DELETE_MARK, &index))) { - ut_a(!page||!!page_is_comp(page)==index->table->comp); + ut_a(!page + || (ibool)!!page_is_comp(page)==index->table->comp); ptr = btr_cur_parse_del_mark_set_clust_rec(ptr, end_ptr, index, page); } @@ -796,7 +798,8 @@ recv_parse_or_apply_log_rec_body( case MLOG_REC_UPDATE_IN_PLACE: case MLOG_COMP_REC_UPDATE_IN_PLACE: if (NULL != (ptr = mlog_parse_index(ptr, end_ptr, type == MLOG_COMP_REC_UPDATE_IN_PLACE, &index))) { - ut_a(!page||!!page_is_comp(page)==index->table->comp); + ut_a(!page + || (ibool)!!page_is_comp(page)==index->table->comp); ptr = btr_cur_parse_update_in_place(ptr, end_ptr, page, index); } @@ -806,7 +809,8 @@ recv_parse_or_apply_log_rec_body( if (NULL != (ptr = mlog_parse_index(ptr, end_ptr, type == MLOG_COMP_LIST_END_DELETE || type == MLOG_COMP_LIST_START_DELETE, &index))) { - ut_a(!page||!!page_is_comp(page)==index->table->comp); + ut_a(!page + || (ibool)!!page_is_comp(page)==index->table->comp); ptr = page_parse_delete_rec_list(type, ptr, end_ptr, index, page, mtr); } @@ -814,7 +818,8 @@ recv_parse_or_apply_log_rec_body( case MLOG_LIST_END_COPY_CREATED: case MLOG_COMP_LIST_END_COPY_CREATED: if (NULL != (ptr = mlog_parse_index(ptr, end_ptr, type == MLOG_COMP_LIST_END_COPY_CREATED, &index))) { - ut_a(!page||!!page_is_comp(page)==index->table->comp); + ut_a(!page + || (ibool)!!page_is_comp(page)==index->table->comp); ptr = page_parse_copy_rec_list_to_created_page(ptr, end_ptr, index, page, mtr); } @@ -822,7 +827,8 @@ recv_parse_or_apply_log_rec_body( case MLOG_PAGE_REORGANIZE: case MLOG_COMP_PAGE_REORGANIZE: if (NULL != (ptr = mlog_parse_index(ptr, end_ptr, type == MLOG_COMP_PAGE_REORGANIZE, &index))) { - ut_a(!page||!!page_is_comp(page)==index->table->comp); + ut_a(!page + || (ibool)!!page_is_comp(page)==index->table->comp); ptr = btr_parse_page_reorganize(ptr, end_ptr, index, page, mtr); } @@ -855,7 +861,8 @@ recv_parse_or_apply_log_rec_body( case MLOG_REC_DELETE: case MLOG_COMP_REC_DELETE: if (NULL != (ptr = mlog_parse_index(ptr, end_ptr, type == MLOG_COMP_REC_DELETE, &index))) { - ut_a(!page||!!page_is_comp(page)==index->table->comp); + ut_a(!page + || (ibool)!!page_is_comp(page)==index->table->comp); ptr = page_cur_parse_delete_rec(ptr, end_ptr, index, page, mtr); } diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c index c68f5738798..48dc808e36c 100644 --- a/storage/innobase/os/os0file.c +++ b/storage/innobase/os/os0file.c @@ -1653,7 +1653,7 @@ os_file_get_size_as_iblonglong( } /*************************************************************************** -Sets a file size. This function can be used to extend or truncate a file. */ +Write the specified number of zeros to a newly created file. */ ibool os_file_set_size( @@ -1666,44 +1666,46 @@ os_file_set_size( size */ ulint size_high)/* in: most significant 32 bits of size */ { - ib_longlong offset; - ib_longlong low; - ulint n_bytes; + ib_longlong current_size; + ib_longlong desired_size; ibool ret; byte* buf; byte* buf2; + ulint buf_size; ut_a(size == (size & 0xFFFFFFFF)); - /* We use a very big 8 MB buffer in writing because Linux may be - extremely slow in fsync on 1 MB writes */ + current_size = 0; + desired_size = (ib_longlong)size + (((ib_longlong)size_high) << 32); - buf2 = ut_malloc(UNIV_PAGE_SIZE * 513); + /* Write up to 1 megabyte at a time. */ + buf_size = ut_min(64, (ulint) (desired_size / UNIV_PAGE_SIZE)) + * UNIV_PAGE_SIZE; + buf2 = ut_malloc(buf_size + UNIV_PAGE_SIZE); /* Align the buffer for possible raw i/o */ buf = ut_align(buf2, UNIV_PAGE_SIZE); /* Write buffer full of zeros */ - memset(buf, 0, UNIV_PAGE_SIZE * 512); + memset(buf, 0, buf_size); - offset = 0; - low = (ib_longlong)size + (((ib_longlong)size_high) << 32); - - if (low >= (ib_longlong)(100 * 1024 * 1024)) { + if (desired_size >= (ib_longlong)(100 * 1024 * 1024)) { fprintf(stderr, "InnoDB: Progress in MB:"); } - while (offset < low) { - if (low - offset < UNIV_PAGE_SIZE * 512) { - n_bytes = (ulint)(low - offset); - } else { - n_bytes = UNIV_PAGE_SIZE * 512; - } - + while (current_size < desired_size) { + ulint n_bytes; + + if (desired_size - current_size < (ib_longlong) buf_size) { + n_bytes = (ulint) (desired_size - current_size); + } else { + n_bytes = buf_size; + } + ret = os_file_write(name, file, buf, - (ulint)(offset & 0xFFFFFFFF), - (ulint)(offset >> 32), + (ulint)(current_size & 0xFFFFFFFF), + (ulint)(current_size >> 32), n_bytes); if (!ret) { ut_free(buf2); @@ -1711,18 +1713,18 @@ os_file_set_size( } /* Print about progress for each 100 MB written */ - if ((ib_longlong) (offset + n_bytes) / (ib_longlong)(100 * 1024 * 1024) - != offset / (ib_longlong)(100 * 1024 * 1024)) { + if ((current_size + n_bytes) / (ib_longlong)(100 * 1024 * 1024) + != current_size / (ib_longlong)(100 * 1024 * 1024)) { fprintf(stderr, " %lu00", - (ulong) ((offset + n_bytes) + (ulong) ((current_size + n_bytes) / (ib_longlong)(100 * 1024 * 1024))); } - offset += n_bytes; + current_size += n_bytes; } - if (low >= (ib_longlong)(100 * 1024 * 1024)) { + if (desired_size >= (ib_longlong)(100 * 1024 * 1024)) { fprintf(stderr, "\n"); } @@ -3296,7 +3298,7 @@ os_aio( ibool retval; BOOL ret = TRUE; DWORD len = (DWORD) n; - void* dummy_mess1; + struct fil_node_struct * dummy_mess1; void* dummy_mess2; ulint dummy_type; #endif diff --git a/storage/innobase/page/page0cur.c b/storage/innobase/page/page0cur.c index df6d898d4ac..d0b89e81787 100644 --- a/storage/innobase/page/page0cur.c +++ b/storage/innobase/page/page0cur.c @@ -47,7 +47,6 @@ page_cur_try_search_shortcut( not yet completely matched */ page_cur_t* cursor) /* out: page cursor */ { - int cmp; rec_t* rec; rec_t* next_rec; ulint low_match; @@ -79,9 +78,8 @@ page_cur_try_search_shortcut( up_match = low_match; up_bytes = low_bytes; - cmp = page_cmp_dtuple_rec_with_match(tuple, rec, offsets, &low_match, - &low_bytes); - if (cmp == -1) { + if (page_cmp_dtuple_rec_with_match(tuple, rec, offsets, + &low_match, &low_bytes) < 0) { goto exit_func; } @@ -89,9 +87,8 @@ page_cur_try_search_shortcut( offsets = rec_get_offsets(next_rec, index, offsets, dtuple_get_n_fields(tuple), &heap); - cmp = page_cmp_dtuple_rec_with_match(tuple, next_rec, offsets, - &up_match, &up_bytes); - if (cmp != -1) { + if (page_cmp_dtuple_rec_with_match(tuple, next_rec, offsets, + &up_match, &up_bytes) >= 0) { goto exit_func; } @@ -115,7 +112,7 @@ page_cur_try_search_shortcut( ut_a(*ilow_matched_fields == low_match); ut_a(*ilow_matched_bytes == low_bytes); #endif - if (next_rec != page_get_supremum_rec(page)) { + if (!page_rec_is_supremum(next_rec)) { *iup_matched_fields = up_match; *iup_matched_bytes = up_bytes; @@ -137,6 +134,7 @@ exit_func: #endif +#ifdef PAGE_CUR_LE_OR_EXTENDS /******************************************************************** Checks if the nth field in a record is a character type field which extends the nth field in tuple, i.e., the field is longer or equal in length and has @@ -185,6 +183,7 @@ page_cur_rec_field_extends( return(FALSE); } +#endif /* PAGE_CUR_LE_OR_EXTENDS */ /******************************************************************** Searches the right position for a page cursor. */ @@ -239,10 +238,17 @@ page_cur_search_with_match( && ilow_matched_fields && ilow_matched_bytes && cursor); ut_ad(dtuple_validate(tuple)); ut_ad(dtuple_check_typed(tuple)); +#ifdef UNIV_DEBUG +# ifdef PAGE_CUR_DBG + if (mode != PAGE_CUR_DBG) +# endif /* PAGE_CUR_DBG */ +# ifdef PAGE_CUR_LE_OR_EXTENDS + if (mode != PAGE_CUR_LE_OR_EXTENDS) +# endif /* PAGE_CUR_LE_OR_EXTENDS */ ut_ad((mode == PAGE_CUR_L) || (mode == PAGE_CUR_LE) - || (mode == PAGE_CUR_G) || (mode == PAGE_CUR_GE) - || (mode == PAGE_CUR_LE_OR_EXTENDS) || (mode == PAGE_CUR_DBG)); - + || (mode == PAGE_CUR_G) || (mode == PAGE_CUR_GE)); +#endif /* UNIV_DEBUG */ + page_check_dir(page); #ifdef PAGE_CUR_ADAPT @@ -261,16 +267,18 @@ page_cur_search_with_match( return; } } -/*#ifdef UNIV_SEARCH_DEBUG */ +# ifdef PAGE_CUR_DBG if (mode == PAGE_CUR_DBG) { mode = PAGE_CUR_LE; } -/*#endif */ +# endif #endif /* The following flag does not work for non-latin1 char sets because cmp_full_field does not tell how many bytes matched */ +#ifdef PAGE_CUR_LE_OR_EXTENDS ut_a(mode != PAGE_CUR_LE_OR_EXTENDS); +#endif /* PAGE_CUR_LE_OR_EXTENDS */ /* If mode PAGE_CUR_G is specified, we are trying to position the cursor to answer a query of the form "tuple < X", where tuple is @@ -308,33 +316,36 @@ page_cur_search_with_match( cmp = cmp_dtuple_rec_with_match(tuple, mid_rec, offsets, &cur_matched_fields, &cur_matched_bytes); - if (cmp == 1) { + if (UNIV_LIKELY(cmp > 0)) { +low_slot_match: low = mid; low_matched_fields = cur_matched_fields; low_matched_bytes = cur_matched_bytes; - } else if (cmp == -1) { + } else if (UNIV_LIKELY(cmp /* == -1 */)) { +#ifdef PAGE_CUR_LE_OR_EXTENDS if (mode == PAGE_CUR_LE_OR_EXTENDS && page_cur_rec_field_extends(tuple, mid_rec, offsets, cur_matched_fields)) { - low = mid; - low_matched_fields = cur_matched_fields; - low_matched_bytes = cur_matched_bytes; - } else { - up = mid; - up_matched_fields = cur_matched_fields; - up_matched_bytes = cur_matched_bytes; - } - } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE - || mode == PAGE_CUR_LE_OR_EXTENDS) { - low = mid; - low_matched_fields = cur_matched_fields; - low_matched_bytes = cur_matched_bytes; - } else { + goto low_slot_match; + } +#endif /* PAGE_CUR_LE_OR_EXTENDS */ +up_slot_match: up = mid; up_matched_fields = cur_matched_fields; up_matched_bytes = cur_matched_bytes; + + } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE +#ifdef PAGE_CUR_LE_OR_EXTENDS + || mode == PAGE_CUR_LE_OR_EXTENDS +#endif /* PAGE_CUR_LE_OR_EXTENDS */ + ) { + + goto low_slot_match; + } else { + + goto up_slot_match; } } @@ -360,32 +371,35 @@ page_cur_search_with_match( cmp = cmp_dtuple_rec_with_match(tuple, mid_rec, offsets, &cur_matched_fields, &cur_matched_bytes); - if (cmp == 1) { + if (UNIV_LIKELY(cmp > 0)) { +low_rec_match: low_rec = mid_rec; low_matched_fields = cur_matched_fields; low_matched_bytes = cur_matched_bytes; - } else if (cmp == -1) { + } else if (UNIV_LIKELY(cmp /* == -1 */)) { +#ifdef PAGE_CUR_LE_OR_EXTENDS if (mode == PAGE_CUR_LE_OR_EXTENDS && page_cur_rec_field_extends(tuple, mid_rec, offsets, cur_matched_fields)) { - low_rec = mid_rec; - low_matched_fields = cur_matched_fields; - low_matched_bytes = cur_matched_bytes; - } else { - up_rec = mid_rec; - up_matched_fields = cur_matched_fields; - up_matched_bytes = cur_matched_bytes; + + goto low_rec_match; } - } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE - || mode == PAGE_CUR_LE_OR_EXTENDS) { - low_rec = mid_rec; - low_matched_fields = cur_matched_fields; - low_matched_bytes = cur_matched_bytes; - } else { +#endif /* PAGE_CUR_LE_OR_EXTENDS */ +up_rec_match: up_rec = mid_rec; up_matched_fields = cur_matched_fields; up_matched_bytes = cur_matched_bytes; + } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE +#ifdef PAGE_CUR_LE_OR_EXTENDS + || mode == PAGE_CUR_LE_OR_EXTENDS +#endif /* PAGE_CUR_LE_OR_EXTENDS */ + ) { + + goto low_rec_match; + } else { + + goto up_rec_match; } } diff --git a/storage/innobase/page/page0page.c b/storage/innobase/page/page0page.c index 1fe7f1d9356..7e09cdf073e 100644 --- a/storage/innobase/page/page0page.c +++ b/storage/innobase/page/page0page.c @@ -483,7 +483,7 @@ page_copy_rec_list_end_no_locks( page_cur_move_to_next(&cur1); } - ut_a(!!page_is_comp(new_page) == index->table->comp); + ut_a((ibool)!!page_is_comp(new_page) == index->table->comp); ut_a(page_is_comp(new_page) == page_is_comp(page)); ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == (ulint) (page_is_comp(new_page) @@ -1347,7 +1347,7 @@ page_print_list( ulint* offsets = offsets_; *offsets_ = (sizeof offsets_) / sizeof *offsets_; - ut_a(!!page_is_comp(page) == index->table->comp); + ut_a((ibool)!!page_is_comp(page) == index->table->comp); fprintf(stderr, "--------------------------------\n" @@ -1741,7 +1741,7 @@ page_validate( ulint* offsets = NULL; ulint* old_offsets = NULL; - if (!!comp != index->table->comp) { + if ((ibool)!!comp != index->table->comp) { fputs("InnoDB: 'compact format' flag mismatch\n", stderr); goto func_exit2; } diff --git a/storage/innobase/rem/rem0rec.c b/storage/innobase/rem/rem0rec.c index 580a7bfe509..fbc33aea669 100644 --- a/storage/innobase/rem/rem0rec.c +++ b/storage/innobase/rem/rem0rec.c @@ -601,30 +601,38 @@ rec_set_nth_field_extern_bit_new( /* read the lengths of fields 0..n */ for (i = 0; i < n_fields; i++) { - ibool is_null; - ulint len; field = dict_index_get_nth_field(index, i); type = dict_col_get_type(dict_field_get_col(field)); - is_null = !(dtype_get_prtype(type) & DATA_NOT_NULL); - if (is_null) { - /* nullable field => read the null flag */ - is_null = !!(*nulls & null_mask); + if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) { + if (UNIV_UNLIKELY(!(byte) null_mask)) { + nulls--; + null_mask = 1; + } + + if (*nulls & null_mask) { + null_mask <<= 1; + /* NULL fields cannot be external. */ + ut_ad(i != ith); + continue; + } + null_mask <<= 1; - if (null_mask == 0x100) - nulls--, null_mask = 1; } - if (is_null || field->fixed_len) { - /* No length (or extern bit) is stored for - fields that are NULL or fixed-length. */ + if (field->fixed_len) { + /* fixed-length fields cannot be external + (Fixed-length fields longer than + DICT_MAX_COL_PREFIX_LEN will be treated as + variable-length ones in dict_index_add_col().) */ ut_ad(i != ith); continue; } - len = *lens--; + lens--; if (dtype_get_len(type) > 255 || dtype_get_mtype(type) == DATA_BLOB) { + ulint len = lens[1]; if (len & 0x80) { /* 1exxxxxx: 2-byte length */ if (i == ith) { - if (!val == !(len & 0x20)) { + if (!val == !(len & 0x40)) { return; /* no change */ } /* toggle the extern bit */ @@ -823,6 +831,7 @@ rec_convert_dtuple_to_rec_new( byte* lens; ulint len; ulint i; + ulint n_node_ptr_field; ulint fixed_len; ulint null_mask = 1; const ulint n_fields = dtuple_get_n_fields(dtuple); @@ -831,16 +840,26 @@ rec_convert_dtuple_to_rec_new( ut_ad(index->table->comp); ut_ad(n_fields > 0); - switch (status) { + + /* Try to ensure that the memset() between the for() loops + completes fast. The address is not exact, but UNIV_PREFETCH + should never generate a memory fault. */ + UNIV_PREFETCH_RW(rec - REC_N_NEW_EXTRA_BYTES - n_fields); + UNIV_PREFETCH_RW(rec); + + switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) { case REC_STATUS_ORDINARY: ut_ad(n_fields <= dict_index_get_n_fields(index)); + n_node_ptr_field = ULINT_UNDEFINED; break; case REC_STATUS_NODE_PTR: ut_ad(n_fields == dict_index_get_n_unique_in_tree(index) + 1); + n_node_ptr_field = n_fields - 1; break; case REC_STATUS_INFIMUM: case REC_STATUS_SUPREMUM: ut_ad(n_fields == 1); + n_node_ptr_field = ULINT_UNDEFINED; goto init; default: ut_a(0); @@ -852,15 +871,18 @@ rec_convert_dtuple_to_rec_new( rec += (index->n_nullable + 7) / 8; for (i = 0; i < n_fields; i++) { + if (UNIV_UNLIKELY(i == n_node_ptr_field)) { +#ifdef UNIV_DEBUG + field = dtuple_get_nth_field(dtuple, i); + type = dfield_get_type(field); + ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL); + ut_ad(dfield_get_len(field) == 4); +#endif /* UNIV_DEBUG */ + goto init; + } field = dtuple_get_nth_field(dtuple, i); type = dfield_get_type(field); len = dfield_get_len(field); - if (status == REC_STATUS_NODE_PTR && i == n_fields - 1) { - fixed_len = 4; - ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL); - ut_ad(len == 4); - continue; - } fixed_len = dict_index_get_nth_field(index, i)->fixed_len; if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) { @@ -902,27 +924,33 @@ init: type = dfield_get_type(field); len = dfield_get_len(field); - if (status == REC_STATUS_NODE_PTR && i == n_fields - 1) { - fixed_len = 4; + if (UNIV_UNLIKELY(i == n_node_ptr_field)) { ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL); ut_ad(len == 4); - goto copy; + memcpy(end, dfield_get_data(field), len); + break; } fixed_len = dict_index_get_nth_field(index, i)->fixed_len; if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) { /* nullable field */ ut_ad(index->n_nullable > 0); + + if (UNIV_UNLIKELY(!(byte) null_mask)) { + nulls--; + null_mask = 1; + } + ut_ad(*nulls < null_mask); + /* set the null flag if necessary */ if (len == UNIV_SQL_NULL) { *nulls |= null_mask; + null_mask <<= 1; + continue; } + null_mask <<= 1; - if (null_mask == 0x100) - nulls--, null_mask = 1; - if (len == UNIV_SQL_NULL) - continue; } /* only nullable fields can be null */ ut_ad(len != UNIV_SQL_NULL); @@ -942,7 +970,7 @@ init: *lens-- = (byte) len; } } - copy: + memcpy(end, dfield_get_data(field), len); end += len; } @@ -1105,7 +1133,6 @@ rec_copy_prefix_to_buf( dtype_t* type; ulint i; ulint prefix_len; - ibool is_null; ulint null_mask; ulint status; @@ -1146,20 +1173,22 @@ rec_copy_prefix_to_buf( for (i = 0; i < n_fields; i++) { field = dict_index_get_nth_field(index, i); type = dict_col_get_type(dict_field_get_col(field)); - is_null = !(dtype_get_prtype(type) & DATA_NOT_NULL); - if (is_null) { + if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) { /* nullable field => read the null flag */ - is_null = !!(*nulls & null_mask); - null_mask <<= 1; - if (null_mask == 0x100) { - --nulls; - UNIV_PREFETCH_R(nulls); + if (UNIV_UNLIKELY(!(byte) null_mask)) { + nulls--; null_mask = 1; } + + if (*nulls & null_mask) { + null_mask <<= 1; + continue; + } + + null_mask <<= 1; } - if (is_null) { - } else if (field->fixed_len) { + if (field->fixed_len) { prefix_len += field->fixed_len; } else { ulint len = *lens--; diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index eb50b83a4d5..2ac0824b331 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -1429,51 +1429,106 @@ run_again: } /************************************************************************* -Does an unlock of a row for MySQL. */ +This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before +calling this function we must use trx_reset_new_rec_lock_info() and +trx_register_new_rec_lock() to store the information which new record locks +really were set. This function removes a newly set lock under prebuilt->pcur, +and also under prebuilt->clust_pcur. Currently, this is only used and tested +in the case of an UPDATE or a DELETE statement, where the row lock is of the +LOCK_X type. +Thus, this implements a 'mini-rollback' that releases the latest record +locks we set. */ int row_unlock_for_mysql( /*=================*/ /* out: error code or DB_SUCCESS */ - row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL + row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL handle */ + ibool has_latches_on_recs)/* TRUE if called so that we have + the latches on the records under pcur + and clust_pcur, and we do not need to + reposition the cursors. */ { - rec_t* rec; - btr_pcur_t* cur = prebuilt->pcur; + dict_index_t* index; + btr_pcur_t* pcur = prebuilt->pcur; + btr_pcur_t* clust_pcur = prebuilt->clust_pcur; trx_t* trx = prebuilt->trx; + rec_t* rec; mtr_t mtr; ut_ad(prebuilt && trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); - + + if (!srv_locks_unsafe_for_binlog) { + + fprintf(stderr, +"InnoDB: Error: calling row_unlock_for_mysql though\n" +"InnoDB: srv_locks_unsafe_for_binlog is FALSE.\n"); + + return(DB_SUCCESS); + } + trx->op_info = "unlock_row"; - - if (srv_locks_unsafe_for_binlog) { - if (trx->trx_create_lock == TRUE) { - mtr_start(&mtr); + index = btr_pcur_get_btr_cur(pcur)->index; + + if (index != NULL && trx_new_rec_locks_contain(trx, index)) { + + mtr_start(&mtr); - /* Restore a cursor position and find a record */ - btr_pcur_restore_position(BTR_SEARCH_LEAF, cur, &mtr); - rec = btr_pcur_get_rec(cur); + /* Restore the cursor position and find the record */ + + if (!has_latches_on_recs) { + btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr); + } - if (rec) { + rec = btr_pcur_get_rec(pcur); - lock_rec_reset_and_release_wait(rec); - } else { - fputs("InnoDB: Error: " - "Record for the lock not found\n", - stderr); - mem_analyze_corruption((byte*) trx); - ut_error; - } + mutex_enter(&kernel_mutex); - trx->trx_create_lock = FALSE; - mtr_commit(&mtr); + lock_rec_reset_and_release_wait(rec); + + mutex_exit(&kernel_mutex); + + mtr_commit(&mtr); + + /* If the search was done through the clustered index, then + we have not used clust_pcur at all, and we must NOT try to + reset locks on clust_pcur. The values in clust_pcur may be + garbage! */ + + if (index->type & DICT_CLUSTERED) { + + goto func_exit; } - + } + + index = btr_pcur_get_btr_cur(clust_pcur)->index; + + if (index != NULL && trx_new_rec_locks_contain(trx, index)) { + + mtr_start(&mtr); + + /* Restore the cursor position and find the record */ + + if (!has_latches_on_recs) { + btr_pcur_restore_position(BTR_SEARCH_LEAF, clust_pcur, + &mtr); + } + + rec = btr_pcur_get_rec(clust_pcur); + + mutex_enter(&kernel_mutex); + + lock_rec_reset_and_release_wait(rec); + + mutex_exit(&kernel_mutex); + + mtr_commit(&mtr); } +func_exit: trx->op_info = ""; return(DB_SUCCESS); diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index c7a548fe448..15439bed7e7 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -2784,6 +2784,10 @@ sel_restore_position_for_mysql( process the record the cursor is now positioned on (i.e. we should not go to the next record yet) */ + ibool* same_user_rec, /* out: TRUE if we were able to restore + the cursor on a user record with the + same ordering prefix in in the + B-tree index */ ulint latch_mode, /* in: latch mode wished in restoration */ btr_pcur_t* pcur, /* in: cursor whose position @@ -2800,6 +2804,8 @@ sel_restore_position_for_mysql( success = btr_pcur_restore_position(latch_mode, pcur, mtr); + *same_user_rec = success; + if (relative_position == BTR_PCUR_ON) { if (success) { return(FALSE); @@ -3064,10 +3070,12 @@ row_search_for_mysql( ulint cnt = 0; #endif /* UNIV_SEARCH_DEBUG */ ulint next_offs; + ibool same_user_rec; mtr_t mtr; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; + *offsets_ = (sizeof offsets_) / sizeof *offsets_; ut_ad(index && pcur && search_tuple); @@ -3138,6 +3146,16 @@ row_search_for_mysql( trx->search_latch_timeout = BTR_SEA_TIMEOUT; } + /* Reset the new record lock info if we srv_locks_unsafe_for_binlog + is set. Then we are able to remove the record locks set here on an + individual row. */ + + if (srv_locks_unsafe_for_binlog + && prebuilt->select_lock_type != LOCK_NONE) { + + trx_reset_new_rec_lock_info(trx); + } + /*-------------------------------------------------------------*/ /* PHASE 1: Try to pop the row from the prefetch cache */ @@ -3396,8 +3414,9 @@ shortcut_fails_too_big_rec: clust_index = dict_table_get_first_index(index->table); if (UNIV_LIKELY(direction != 0)) { - if (!sel_restore_position_for_mysql(BTR_SEARCH_LEAF, pcur, - moves_up, &mtr)) { + if (!sel_restore_position_for_mysql(&same_user_rec, + BTR_SEARCH_LEAF, + pcur, moves_up, &mtr)) { goto next_rec; } @@ -3659,7 +3678,7 @@ rec_loop: goto normal_return; } } - + /* We are ready to look at a possible new index entry in the result set: the cursor is now placed on a user record */ @@ -3679,6 +3698,7 @@ rec_loop: || srv_locks_unsafe_for_binlog || (unique_search && !UNIV_UNLIKELY(rec_get_deleted_flag( rec, page_rec_is_comp(rec))))) { + goto no_gap_lock; } else { lock_type = LOCK_ORDINARY; @@ -3701,7 +3721,7 @@ rec_loop: && dtuple_get_n_fields_cmp(search_tuple) == dict_index_get_n_unique(index) && 0 == cmp_dtuple_rec(search_tuple, rec, offsets)) { - no_gap_lock: +no_gap_lock: lock_type = LOCK_REC_NOT_GAP; } @@ -3764,6 +3784,7 @@ rec_loop: /* Get the clustered index record if needed */ index_rec = rec; ut_ad(index != clust_index); + goto requires_clust_rec; } } @@ -3773,6 +3794,17 @@ rec_loop: /* The record is delete-marked: we can skip it if this is not a consistent read which might see an earlier version of a non-clustered index record */ + + if (srv_locks_unsafe_for_binlog + && prebuilt->select_lock_type != LOCK_NONE) { + + /* No need to keep a lock on a delete-marked record + if we do not want to use next-key locking. */ + + row_unlock_for_mysql(prebuilt, TRUE); + + trx_reset_new_rec_lock_info(trx); + } goto next_rec; } @@ -3783,7 +3815,8 @@ rec_loop: index_rec = rec; if (index != clust_index && prebuilt->need_to_access_clustered) { - requires_clust_rec: + +requires_clust_rec: /* Before and after this "if" block, "offsets" will be related to "rec", which may be in a secondary index "index" or the clustered index ("clust_index"). However, after this @@ -3816,6 +3849,18 @@ rec_loop: /* The record is delete marked: we can skip it */ + if (srv_locks_unsafe_for_binlog + && prebuilt->select_lock_type != LOCK_NONE) { + + /* No need to keep a lock on a delete-marked + record if we do not want to use next-key + locking. */ + + row_unlock_for_mysql(prebuilt, TRUE); + + trx_reset_new_rec_lock_info(trx); + } + goto next_rec; } @@ -3908,7 +3953,7 @@ got_row: next_rec: /*-------------------------------------------------------------*/ /* PHASE 5: Move the cursor to the next index record */ - + if (UNIV_UNLIKELY(mtr_has_extra_clust_latch)) { /* We must commit mtr if we are moving to the next non-clustered index record, because we could break the @@ -3921,8 +3966,9 @@ next_rec: mtr_has_extra_clust_latch = FALSE; mtr_start(&mtr); - if (sel_restore_position_for_mysql(BTR_SEARCH_LEAF, pcur, - moves_up, &mtr)) { + if (sel_restore_position_for_mysql(&same_user_rec, + BTR_SEARCH_LEAF, + pcur, moves_up, &mtr)) { #ifdef UNIV_SEARCH_DEBUG cnt++; #endif /* UNIV_SEARCH_DEBUG */ @@ -3973,11 +4019,34 @@ lock_wait_or_error: thr->lock_state = QUE_THR_LOCK_ROW; if (row_mysql_handle_errors(&err, trx, thr, NULL)) { + /* It was a lock wait, and it ended */ + thr->lock_state = QUE_THR_LOCK_NOLOCK; mtr_start(&mtr); - sel_restore_position_for_mysql(BTR_SEARCH_LEAF, pcur, - moves_up, &mtr); + sel_restore_position_for_mysql(&same_user_rec, + BTR_SEARCH_LEAF, pcur, + moves_up, &mtr); + if (srv_locks_unsafe_for_binlog && !same_user_rec) { + /* Since we were not able to restore the cursor + on the same user record, we cannot use + row_unlock_for_mysql() to unlock any records, and + we must thus reset the new rec lock info. Since + in lock0lock.c we have blocked the inheriting of gap + X-locks, we actually do not have any new record locks + set in this case. + + Note that if we were able to restore on the 'same' + user record, it is still possible that we were actually + waiting on a delete-marked record, and meanwhile + it was removed by purge and inserted again by some + other user. But that is no problem, because in + rec_loop we will again try to set a lock, and + new_rec_lock_info in trx will be right at the end. */ + + trx_reset_new_rec_lock_info(trx); + } + mode = pcur->search_mode; goto rec_loop; diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index cf2b8db5d32..514fb6bd577 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -818,7 +818,7 @@ row_upd_build_difference_binary( extern_bit = upd_ext_vec_contains(ext_vec, n_ext_vec, i); if (UNIV_UNLIKELY(extern_bit == - !rec_offs_nth_extern(offsets, i)) + (ibool)!rec_offs_nth_extern(offsets, i)) || !dfield_data_is_binary_equal(dfield, len, data)) { upd_field = upd_get_nth_field(update, n_diff); diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index f901425a5f9..837c5be2bb6 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -260,7 +260,7 @@ semaphore contention and convoy problems can occur withput this restriction. Value 10 should be good if there are less than 4 processors + 4 disks in the computer. Bigger computers need bigger values. */ -ulong srv_thread_concurrency = 8; +ulong srv_thread_concurrency = SRV_CONCURRENCY_THRESHOLD; os_fast_mutex_t srv_conc_mutex; /* this mutex protects srv_conc data structures */ @@ -983,12 +983,6 @@ srv_conc_enter_innodb( srv_conc_slot_t* slot = NULL; ulint i; - if (srv_thread_concurrency >= 500) { - /* Disable the concurrency check */ - - return; - } - /* If trx has 'free tickets' to enter the engine left, then use one such ticket */ @@ -1134,7 +1128,7 @@ srv_conc_force_enter_innodb( trx_t* trx) /* in: transaction object associated with the thread */ { - if (srv_thread_concurrency >= 500) { + if (srv_thread_concurrency >= SRV_CONCURRENCY_THRESHOLD) { return; } @@ -1160,7 +1154,7 @@ srv_conc_force_exit_innodb( { srv_conc_slot_t* slot = NULL; - if (srv_thread_concurrency >= 500) { + if (srv_thread_concurrency >= SRV_CONCURRENCY_THRESHOLD) { return; } @@ -1212,11 +1206,6 @@ srv_conc_exit_innodb( trx_t* trx) /* in: transaction object associated with the thread */ { - if (srv_thread_concurrency >= 500) { - - return; - } - if (trx->n_tickets_to_enter_innodb > 0) { /* We will pretend the thread is still inside InnoDB though it now leaves the InnoDB engine. In this way we save diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index 9e155ee1de0..10fbf3468c0 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -166,6 +166,8 @@ trx_create( memset(&trx->xid, 0, sizeof(trx->xid)); trx->xid.formatID = -1; + trx_reset_new_rec_lock_info(trx); + return(trx); } diff --git a/storage/innobase/trx/trx0undo.c b/storage/innobase/trx/trx0undo.c index c14e4a1f3ab..7441dd3f152 100644 --- a/storage/innobase/trx/trx0undo.c +++ b/storage/innobase/trx/trx0undo.c @@ -559,14 +559,14 @@ trx_undo_write_xid( const XID* xid, /* in: X/Open XA Transaction Identification */ mtr_t* mtr) /* in: mtr */ { - mlog_write_ulint(log_hdr + TRX_UNDO_XA_FORMAT, xid->formatID, - MLOG_4BYTES, mtr); + mlog_write_ulint(log_hdr + TRX_UNDO_XA_FORMAT, + (ulint)xid->formatID, MLOG_4BYTES, mtr); - mlog_write_ulint(log_hdr + TRX_UNDO_XA_TRID_LEN, xid->gtrid_length, - MLOG_4BYTES, mtr); + mlog_write_ulint(log_hdr + TRX_UNDO_XA_TRID_LEN, + (ulint)xid->gtrid_length, MLOG_4BYTES, mtr); - mlog_write_ulint(log_hdr + TRX_UNDO_XA_BQUAL_LEN, xid->bqual_length, - MLOG_4BYTES, mtr); + mlog_write_ulint(log_hdr + TRX_UNDO_XA_BQUAL_LEN, + (ulint)xid->bqual_length, MLOG_4BYTES, mtr); mlog_write_string(log_hdr + TRX_UNDO_XA_XID, (const byte*) xid->data, XIDDATASIZE, mtr); @@ -581,18 +581,14 @@ trx_undo_read_xid( trx_ulogf_t* log_hdr,/* in: undo log header */ XID* xid) /* out: X/Open XA Transaction Identification */ { - ulint i; - - xid->formatID = mach_read_from_4(log_hdr + TRX_UNDO_XA_FORMAT); + xid->formatID = (long)mach_read_from_4(log_hdr + TRX_UNDO_XA_FORMAT); - xid->gtrid_length = mach_read_from_4(log_hdr + TRX_UNDO_XA_TRID_LEN); - - xid->bqual_length = mach_read_from_4(log_hdr + TRX_UNDO_XA_BQUAL_LEN); + xid->gtrid_length = + (long)mach_read_from_4(log_hdr + TRX_UNDO_XA_TRID_LEN); + xid->bqual_length = + (long)mach_read_from_4(log_hdr + TRX_UNDO_XA_BQUAL_LEN); - for (i = 0; i < XIDDATASIZE; i++) { - xid->data[i] = (char)mach_read_from_1(log_hdr + - TRX_UNDO_XA_XID + i); - } + memcpy(xid->data, log_hdr + TRX_UNDO_XA_XID, XIDDATASIZE); } /******************************************************************* diff --git a/storage/myisam/Makefile.am b/storage/myisam/Makefile.am index c61647b25f7..e4327070997 100644 --- a/storage/myisam/Makefile.am +++ b/storage/myisam/Makefile.am @@ -17,7 +17,7 @@ EXTRA_DIST = mi_test_all.sh mi_test_all.res pkgdata_DATA = mi_test_all mi_test_all.res -INCLUDES = -I$(top_srcdir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include LDADD = @CLIENT_EXTRA_LDFLAGS@ libmyisam.a \ $(top_builddir)/mysys/libmysys.a \ $(top_builddir)/dbug/libdbug.a \ diff --git a/storage/myisam/mi_create.c b/storage/myisam/mi_create.c index 47332b02a72..33b344405ec 100644 --- a/storage/myisam/mi_create.c +++ b/storage/myisam/mi_create.c @@ -770,10 +770,13 @@ err: uint mi_get_pointer_length(ulonglong file_length, uint def) { + DBUG_ASSERT(def >= 2 && def <= 7); if (file_length) /* If not default */ { +#ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS if (file_length >= (longlong) 1 << 56) def=8; +#endif if (file_length >= (longlong) 1 << 48) def=7; if (file_length >= (longlong) 1 << 40) diff --git a/storage/myisam/mi_open.c b/storage/myisam/mi_open.c index 456b87b7799..74b97a65609 100644 --- a/storage/myisam/mi_open.c +++ b/storage/myisam/mi_open.c @@ -78,7 +78,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) int lock_error,kfile,open_mode,save_errno,have_rtree=0; uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys, key_parts,unique_key_parts,fulltext_keys,uniques; - char name_buff[FN_REFLEN], org_name [FN_REFLEN], index_name[FN_REFLEN], + char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN], data_name[FN_REFLEN]; char *disk_cache, *disk_pos, *end_pos; MI_INFO info,*m_info,*old_info; diff --git a/storage/myisam/mi_packrec.c b/storage/myisam/mi_packrec.c index 4b512dd89dd..c251e4dda4a 100644 --- a/storage/myisam/mi_packrec.c +++ b/storage/myisam/mi_packrec.c @@ -416,8 +416,19 @@ static uint find_longest_bitstream(uint16 *table, uint16 *end) } - /* Read record from datafile */ - /* Returns length of packed record, -1 if error */ +/* + Read record from datafile. + + SYNOPSIS + _mi_read_pack_record() + info A pointer to MI_INFO. + filepos File offset of the record. + buf RETURN The buffer to receive the record. + + RETURN + 0 on success + HA_ERR_WRONG_IN_RECORD or -1 on error +*/ int _mi_read_pack_record(MI_INFO *info, my_off_t filepos, byte *buf) { diff --git a/storage/myisam/mi_unique.c b/storage/myisam/mi_unique.c index f2d5f01be25..34f5f595f30 100644 --- a/storage/myisam/mi_unique.c +++ b/storage/myisam/mi_unique.c @@ -64,7 +64,12 @@ my_bool mi_check_unique(MI_INFO *info, MI_UNIQUEDEF *def, byte *record, } -/* Calculate a hash for a row */ +/* + Calculate a hash for a row + + TODO + Add support for bit fields +*/ ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const byte *record) { @@ -126,9 +131,17 @@ ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const byte *record) return crc; } - /* - Returns 0 if both rows have equal unique value - */ + +/* + compare unique key for two rows + + TODO + Add support for bit fields + + RETURN + 0 if both rows have equal unique value + # Rows are different +*/ int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b, my_bool null_are_equal) diff --git a/storage/myisam/myisampack.c b/storage/myisam/myisampack.c index 74bb541b220..daf2bbdf85c 100644 --- a/storage/myisam/myisampack.c +++ b/storage/myisam/myisampack.c @@ -33,10 +33,10 @@ #include <my_getopt.h> #include <assert.h> -#if INT_MAX > 32767 -#define BITS_SAVED 32 +#if SIZEOF_LONG_LONG > 4 +#define BITS_SAVED 64 #else -#define BITS_SAVED 16 +#define BITS_SAVED 32 #endif #define IS_OFFSET ((uint) 32768) /* Bit if offset or char in tree */ @@ -49,10 +49,10 @@ struct st_file_buffer { File file; - char *buffer,*pos,*end; + uchar *buffer,*pos,*end; my_off_t pos_in_file; int bits; - uint current_byte; + ulonglong bitbucket; }; struct st_huff_tree; @@ -69,13 +69,17 @@ typedef struct st_huff_counts { my_off_t end_space[8]; my_off_t pre_space[8]; my_off_t tot_end_space,tot_pre_space,zero_fields,empty_fields,bytes_packed; - TREE int_tree; - byte *tree_buff; - byte *tree_pos; + TREE int_tree; /* Tree for detecting distinct column values. */ + byte *tree_buff; /* Column values, 'field_length' each. */ + byte *tree_pos; /* Points to end of column values in 'tree_buff'. */ } HUFF_COUNTS; typedef struct st_huff_element HUFF_ELEMENT; +/* + WARNING: It is crucial for the optimizations in calc_packed_length() + that 'count' is the first element of 'HUFF_ELEMENT'. +*/ struct st_huff_element { my_off_t count; union un_element { @@ -98,7 +102,7 @@ typedef struct st_huff_tree { my_off_t bytes_packed; uint tree_pack_length; uint min_chr,max_chr,char_bits,offset_bits,max_offset,height; - ulong *code; + ulonglong *code; uchar *code_len; } HUFF_TREE; @@ -146,7 +150,7 @@ static uint join_same_trees(HUFF_COUNTS *huff_counts,uint trees); static int make_huff_decode_table(HUFF_TREE *huff_tree,uint trees); static void make_traverse_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element,uint size, - ulong code); + ulonglong code); static int write_header(PACK_MRG_INFO *isam_file, uint header_length,uint trees, my_off_t tot_elements,my_off_t filelength); static void write_field_info(HUFF_COUNTS *counts, uint fields,uint trees); @@ -161,7 +165,7 @@ static char *make_old_name(char *new_name,char *old_name); static void init_file_buffer(File file,pbool read_buffer); static int flush_buffer(ulong neaded_length); static void end_file_buffer(void); -static void write_bits(ulong value,uint bits); +static void write_bits(ulonglong value, uint bits); static void flush_bits(void); static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length, ha_checksum crc); @@ -170,13 +174,23 @@ static int save_state_mrg(File file,PACK_MRG_INFO *isam_file,my_off_t new_length static int mrg_close(PACK_MRG_INFO *mrg); static int mrg_rrnd(PACK_MRG_INFO *info,byte *buf); static void mrg_reset(PACK_MRG_INFO *mrg); +#if !defined(DBUG_OFF) +static void fakebigcodes(HUFF_COUNTS *huff_counts, HUFF_COUNTS *end_count); +static int fakecmp(my_off_t **count1, my_off_t **count2); +#endif static int error_on_write=0,test_only=0,verbose=0,silent=0, write_loop=0,force_pack=0, isamchk_neaded=0; static int tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL; static my_bool backup, opt_wait; -static uint tree_buff_length=8196-MALLOC_OVERHEAD; +/* + tree_buff_length is somewhat arbitrary. The bigger it is the better + the chance to win in terms of compression factor. On the other hand, + this table becomes part of the compressed file header. And its length + is coded with 16 bits in the header. Hence the limit is 2**16 - 1. +*/ +static uint tree_buff_length= 65536 - MALLOC_OVERHEAD; static char tmp_dir[FN_REFLEN]={0},*join_table; static my_off_t intervall_length; static ha_checksum glob_crc; @@ -225,7 +239,8 @@ int main(int argc, char **argv) } if (ok && isamchk_neaded && !silent) puts("Remember to run myisamchk -rq on compressed tables"); - VOID(fflush(stdout)); VOID(fflush(stderr)); + VOID(fflush(stdout)); + VOID(fflush(stderr)); free_defaults(default_argv); my_end(verbose ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR); exit(error ? 2 : 0); @@ -260,7 +275,7 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"test", 't', "Don't pack table, only test packing it.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"verbose", 'v', "Write info about progress and packing result.", + {"verbose", 'v', "Write info about progress and packing result. Use many -v for more verbosity!", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -273,7 +288,8 @@ static struct my_option my_long_options[] = static void print_version(void) { - printf("%s Ver 1.22 for %s on %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE); + VOID(printf("%s Ver 1.23 for %s on %s\n", + my_progname, SYSTEM_TYPE, MACHINE_TYPE)); NETWARE_SET_SCREEN_MODE(1); } @@ -290,7 +306,7 @@ static void usage(void) puts("afterwards to update the keys."); puts("You should give the .MYI file as the filename argument."); - printf("\nUsage: %s [OPTIONS] filename...\n", my_progname); + VOID(printf("\nUsage: %s [OPTIONS] filename...\n", my_progname)); my_print_help(my_long_options); print_defaults("my", load_default_groups); my_print_variables(my_long_options); @@ -314,7 +330,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), silent= 1; break; case 't': - test_only= verbose= 1; + test_only= 1; + /* Avoid to reset 'verbose' if it was already set > 1. */ + if (! verbose) + verbose= 1; break; case 'T': length= (uint) (strmov(tmp_dir, argument) - tmp_dir); @@ -325,7 +344,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), } break; case 'v': - verbose= 1; + verbose++; /* Allow for selecting the level of verbosity. */ silent= 0; break; case '#': @@ -380,7 +399,7 @@ static MI_INFO *open_isam_file(char *name,int mode) (opt_wait ? HA_OPEN_WAIT_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED)))) { - VOID(fprintf(stderr,"%s gave error %d on open\n",name,my_errno)); + VOID(fprintf(stderr, "%s gave error %d on open\n", name, my_errno)); DBUG_RETURN(0); } share=isam_file->s; @@ -388,7 +407,7 @@ static MI_INFO *open_isam_file(char *name,int mode) { if (!force_pack) { - VOID(fprintf(stderr,"%s is already compressed\n",name)); + VOID(fprintf(stderr, "%s is already compressed\n", name)); VOID(mi_close(isam_file)); DBUG_RETURN(0); } @@ -400,7 +419,7 @@ static MI_INFO *open_isam_file(char *name,int mode) (share->state.state.records <= 1 || share->state.state.data_file_length < 1024)) { - VOID(fprintf(stderr,"%s is too small to compress\n",name)); + VOID(fprintf(stderr, "%s is too small to compress\n", name)); VOID(mi_close(isam_file)); DBUG_RETURN(0); } @@ -446,8 +465,8 @@ static bool open_isam_files(PACK_MRG_INFO *mrg,char **names,uint count) return 0; diff_file: - fprintf(stderr,"%s: Tables '%s' and '%s' are not identical\n", - my_progname,names[j],names[j+1]); + VOID(fprintf(stderr, "%s: Tables '%s' and '%s' are not identical\n", + my_progname, names[j], names[j+1])); error: while (i--) mi_close(mrg->file[i]); @@ -518,16 +537,25 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table) mrg->records=0; for (i=0 ; i < mrg->count ; i++) mrg->records+=mrg->file[i]->s->state.state.records; + + DBUG_PRINT("info", ("Compressing %s: (%lu records)", + result_table ? new_name : org_name, + (ulong) mrg->records)); if (write_loop || verbose) { - printf("Compressing %s: (%lu records)\n", - result_table ? new_name : org_name,(ulong) mrg->records); + VOID(printf("Compressing %s: (%lu records)\n", + result_table ? new_name : org_name, (ulong) mrg->records)); } trees=fields=share->base.fields; huff_counts=init_huff_count(isam_file,mrg->records); QUICK_SAFEMALLOC; + + /* + Read the whole data file(s) for statistics. + */ + DBUG_PRINT("info", ("- Calculating statistics")); if (write_loop || verbose) - printf("- Calculating statistics\n"); + VOID(printf("- Calculating statistics\n")); if (get_statistic(mrg,huff_counts)) goto err; NORMAL_SAFEMALLOC; @@ -536,29 +564,74 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table) old_length+= (mrg->file[i]->s->state.state.data_file_length - mrg->file[i]->s->state.state.empty); + /* + Create a global priority queue in preparation for making + temporary Huffman trees. + */ if (init_queue(&queue,256,0,0,compare_huff_elements,0)) goto err; + + /* + Check each column if we should use pre-space-compress, end-space- + compress, empty-field-compress or zero-field-compress. + */ check_counts(huff_counts,fields,mrg->records); + + /* + Build a Huffman tree for each column. + */ huff_trees=make_huff_trees(huff_counts,trees); + + /* + If the packed lengths of combined columns is less then the sum of + the non-combined columns, then create common Huffman trees for them. + We do this only for byte compressed columns, not for distinct values + compressed columns. + */ if ((int) (used_trees=join_same_trees(huff_counts,trees)) < 0) goto err; + + /* + Assign codes to all byte or column values. + */ if (make_huff_decode_table(huff_trees,fields)) goto err; + /* Prepare a file buffer. */ init_file_buffer(new_file,0); + + /* + Reserve space in the target file for the fixed compressed file header. + */ file_buffer.pos_in_file=HEAD_LENGTH; if (! test_only) VOID(my_seek(new_file,file_buffer.pos_in_file,MY_SEEK_SET,MYF(0))); + /* + Write field infos: field type, pack type, length bits, tree number. + */ write_field_info(huff_counts,fields,used_trees); + + /* + Write decode trees. + */ if (!(tot_elements=write_huff_tree(huff_trees,trees))) goto err; + + /* + Calculate the total length of the compression info header. + This includes the fixed compressed file header, the column compression + type descriptions, and the decode trees. + */ header_length=(uint) file_buffer.pos_in_file+ (uint) (file_buffer.pos-file_buffer.buffer); - /* Compress file */ + /* + Compress the source file into the target file. + */ + DBUG_PRINT("info", ("- Compressing file")); if (write_loop || verbose) - printf("- Compressing file\n"); + VOID(printf("- Compressing file\n")); error=compress_isam_file(mrg,huff_counts); new_length=file_buffer.pos_in_file; if (!error && !test_only) @@ -568,16 +641,28 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table) error=my_write(file_buffer.file,buff,sizeof(buff), MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)) != 0; } + + /* + Write the fixed compressed file header. + */ if (!error) error=write_header(mrg,header_length,used_trees,tot_elements, new_length); + + /* Flush the file buffer. */ end_file_buffer(); + /* Display statistics. */ + DBUG_PRINT("info", ("Min record length: %6d Max length: %6d " + "Mean total length: %6ld\n", + mrg->min_pack_length, mrg->max_pack_length, + (ulong) (mrg->records ? (new_length/mrg->records) : 0))); if (verbose && mrg->records) - printf("Min record length: %6d Max length: %6d Mean total length: %6ld\n", - mrg->min_pack_length,mrg->max_pack_length, - (ulong) (new_length/mrg->records)); + VOID(printf("Min record length: %6d Max length: %6d " + "Mean total length: %6ld\n", mrg->min_pack_length, + mrg->max_pack_length, (ulong) (new_length/mrg->records))); + /* Close source and target file. */ if (!test_only) { error|=my_close(new_file,MYF(MY_WME)); @@ -588,6 +673,7 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table) } } + /* Cleanup. */ free_counts_and_tree_and_queue(huff_trees,trees,huff_counts,fields); if (! test_only && ! error) { @@ -629,15 +715,16 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table) error|=my_close(join_isam_file,MYF(MY_WME)); if (error) { - VOID(fprintf(stderr,"Aborting: %s is not compressed\n",org_name)); + VOID(fprintf(stderr, "Aborting: %s is not compressed\n", org_name)); VOID(my_delete(new_name,MYF(MY_WME))); DBUG_RETURN(-1); } if (write_loop || verbose) { if (old_length) - printf("%.4g%% \n", (((longlong) (old_length -new_length))*100.0/ - (longlong) old_length)); + VOID(printf("%.4g%% \n", + (((longlong) (old_length - new_length)) * 100.0 / + (longlong) old_length))); else puts("Empty file saved in compressed format"); } @@ -650,7 +737,7 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table) if (join_isam_file >= 0) VOID(my_close(join_isam_file,MYF(0))); mrg_close(mrg); - VOID(fprintf(stderr,"Aborted: %s is not compressed\n",org_name)); + VOID(fprintf(stderr, "Aborted: %s is not compressed\n", org_name)); DBUG_RETURN(-1); } @@ -677,6 +764,12 @@ static HUFF_COUNTS *init_huff_count(MI_INFO *info,my_off_t records) (type == FIELD_NORMAL || type == FIELD_SKIP_ZERO)) count[i].max_zero_fill= count[i].field_length; + /* + For every column initialize a tree, which is used to detect distinct + column values. 'int_tree' works together with 'tree_buff' and + 'tree_pos'. It's keys are implemented by pointers into 'tree_buff'. + This is accomplished by '-1' as the element size. + */ init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0, NULL, NULL); if (records && type != FIELD_BLOB && type != FIELD_VARCHAR) @@ -762,10 +855,13 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) ulong tot_blob_length=0; if (! error) { + /* glob_crc is a checksum over all bytes of all records. */ if (static_row_size) glob_crc+=mi_static_checksum(mrg->file[0],record); else glob_crc+=mi_checksum(mrg->file[0],record); + + /* Count the incidence of values separately for every column. */ for (pos=record,count=huff_counts ; count < end_count ; count++, @@ -773,15 +869,48 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) { next_pos=end_pos=(start_pos=pos)+count->field_length; - /* Put value in tree if there is room for it */ + /* + Put the whole column value in a tree if there is room for it. + 'int_tree' is used to quickly check for duplicate values. + 'tree_buff' collects as many distinct column values as + possible. If the field length is > 1, it is tree_buff_length, + else 2 bytes. Each value is 'field_length' bytes big. If there + are more distinct column values than fit into the buffer, we + give up with this tree. BLOBs and VARCHARs do not have a + tree_buff as it can only be used with fixed length columns. + For the special case of field length == 1, we handle only the + case that there is only one distinct value in the table(s). + Otherwise, we can have a maximum of 256 distinct values. This + is then handled by the normal Huffman tree build. + + Another limit for collecting distinct column values is the + number of values itself. Since we would need to build a + Huffman tree for the values, we are limited by the 'IS_OFFSET' + constant. This constant expresses a bit which is used to + determine if a tree element holds a final value or an offset + to a child element. Hence, all values and offsets need to be + smaller than 'IS_OFFSET'. A tree element is implemented with + two integer values, one for the left branch and one for the + right branch. For the extreme case that the first element + points to the last element, the number of integers in the tree + must be less or equal to IS_OFFSET. So the number of elements + must be less or equal to IS_OFFSET / 2. + + WARNING: At first, we insert a pointer into the record buffer + as the key for the tree. If we got a new distinct value, which + is really inserted into the tree, instead of being counted + only, we will copy the column value from the record buffer to + 'tree_buff' and adjust the key pointer of the tree accordingly. + */ if (count->tree_buff) { global_count=count; if (!(element=tree_insert(&count->int_tree,pos, 0, count->int_tree.custom_arg)) || (element->count == 1 && - count->tree_buff + tree_buff_length < - count->tree_pos + count->field_length) || + (count->tree_buff + tree_buff_length < + count->tree_pos + count->field_length)) || + (count->int_tree.elements_in_tree > IS_OFFSET / 2) || (count->field_length == 1 && count->int_tree.elements_in_tree > 1)) { @@ -791,10 +920,17 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) } else { + /* + If tree_insert() succeeds, it either creates a new element + or increments the counter of an existing element. + */ if (element->count == 1) - { /* New element */ + { + /* Copy the new column value into 'tree_buff'. */ memcpy(count->tree_pos,pos,(size_t) count->field_length); + /* Adjust the key pointer in the tree. */ tree_set_pointer(element,count->tree_pos); + /* Point behind the last column value so far. */ count->tree_pos+=count->field_length; } } @@ -804,15 +940,21 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) if (count->field_type == FIELD_NORMAL || count->field_type == FIELD_SKIP_ENDSPACE) { + /* Ignore trailing space. */ for ( ; end_pos > pos ; end_pos--) if (end_pos[-1] != ' ') break; + /* Empty fields are just counted. Go to the next record. */ if (end_pos == pos) { count->empty_fields++; count->max_zero_fill=0; continue; } + /* + Count the total of all trailing spaces and the number of + short trailing spaces. Remember the longest trailing space. + */ length= (uint) (next_pos-end_pos); count->tot_end_space+=length; if (length < 8) @@ -820,18 +962,25 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) if (count->max_end_space < length) count->max_end_space = length; } + if (count->field_type == FIELD_NORMAL || count->field_type == FIELD_SKIP_PRESPACE) { + /* Ignore leading space. */ for (pos=start_pos; pos < end_pos ; pos++) if (pos[0] != ' ') break; + /* Empty fields are just counted. Go to the next record. */ if (end_pos == pos) { count->empty_fields++; count->max_zero_fill=0; continue; } + /* + Count the total of all leading spaces and the number of + short leading spaces. Remember the longest leading space. + */ length= (uint) (pos-start_pos); count->tot_pre_space+=length; if (length < 8) @@ -839,6 +988,8 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) if (count->max_pre_space < length) count->max_pre_space = length; } + + /* Calculate pos, end_pos, and max_length for variable length fields. */ if (count->field_type == FIELD_BLOB) { uint field_length=count->field_length -mi_portable_sizeof_char_ptr; @@ -857,45 +1008,121 @@ static int get_statistic(PACK_MRG_INFO *mrg,HUFF_COUNTS *huff_counts) end_pos= pos+length; set_if_bigger(count->max_length,length); } + + /* Evaluate 'max_zero_fill' for short fields. */ if (count->field_length <= 8 && (count->field_type == FIELD_NORMAL || count->field_type == FIELD_SKIP_ZERO)) { uint i; + /* Zero fields are just counted. Go to the next record. */ if (!memcmp((byte*) start_pos,zero_string,count->field_length)) { count->zero_fields++; continue; } + /* + max_zero_fill starts with field_length. It is decreased every + time a shorter "zero trailer" is found. It is set to zero when + an empty field is found (see above). This suggests that the + variable should be called 'min_zero_fill'. + */ for (i =0 ; i < count->max_zero_fill && ! end_pos[-1 - (int) i] ; i++) ; if (i < count->max_zero_fill) count->max_zero_fill=i; } + + /* Ignore zero fields and check fields. */ if (count->field_type == FIELD_ZERO || count->field_type == FIELD_CHECK) continue; + + /* + Count the incidence of every byte value in the + significant field value. + */ for ( ; pos < end_pos ; pos++) count->counts[(uchar) *pos]++; + + /* Step to next field. */ } + if (tot_blob_length > max_blob_length) max_blob_length=tot_blob_length; record_count++; if (write_loop && record_count % WRITE_COUNT == 0) { - printf("%lu\r",(ulong) record_count); VOID(fflush(stdout)); + VOID(printf("%lu\r", (ulong) record_count)); + VOID(fflush(stdout)); } } else if (error != HA_ERR_RECORD_DELETED) { - fprintf(stderr,"Got error %d while reading rows",error); + VOID(fprintf(stderr, "Got error %d while reading rows", error)); break; } + + /* Step to next record. */ } if (write_loop) { - printf(" \r"); VOID(fflush(stdout)); + VOID(printf(" \r")); + VOID(fflush(stdout)); } + + /* + If --debug=d,fakebigcodes is set, fake the counts to get big Huffman + codes. + */ + DBUG_EXECUTE_IF("fakebigcodes", fakebigcodes(huff_counts, end_count);); + + DBUG_PRINT("info", ("Found the following number of incidents " + "of the byte codes:")); + if (verbose >= 2) + VOID(printf("Found the following number of incidents " + "of the byte codes:\n")); + for (count= huff_counts ; count < end_count; count++) + { + uint idx; + my_off_t total_count; + char llbuf[32]; + + DBUG_PRINT("info", ("column: %3u", count - huff_counts + 1)); + if (verbose >= 2) + VOID(printf("column: %3u\n", count - huff_counts + 1)); + if (count->tree_buff) + { + DBUG_PRINT("info", ("number of distinct values: %u", + (count->tree_pos - count->tree_buff) / + count->field_length)); + if (verbose >= 2) + VOID(printf("number of distinct values: %u\n", + (count->tree_pos - count->tree_buff) / + count->field_length)); + } + total_count= 0; + for (idx= 0; idx < 256; idx++) + { + if (count->counts[idx]) + { + total_count+= count->counts[idx]; + DBUG_PRINT("info", ("counts[0x%02x]: %12s", idx, + llstr((longlong) count->counts[idx], llbuf))); + if (verbose >= 2) + VOID(printf("counts[0x%02x]: %12s\n", idx, + llstr((longlong) count->counts[idx], llbuf))); + } + } + DBUG_PRINT("info", ("total: %12s", llstr((longlong) total_count, + llbuf))); + if ((verbose >= 2) && total_count) + { + VOID(printf("total: %12s\n", + llstr((longlong) total_count, llbuf))); + } + } + mrg->records=record_count; mrg->max_blob_length=max_blob_length; my_afree((gptr) record); @@ -944,9 +1171,14 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees, huff_counts->field_type=FIELD_NORMAL; huff_counts->pack_type=0; + /* Check for zero-filled records (in this column), or zero records. */ if (huff_counts->zero_fields || ! records) { my_off_t old_space_count; + /* + If there are only zero filled records (in this column), + or no records at all, we are done. + */ if (huff_counts->zero_fields == records) { huff_counts->field_type= FIELD_ZERO; @@ -954,14 +1186,22 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees, huff_counts->counts[0]=0; goto found_pack; } + /* Remeber the number of significant spaces. */ old_space_count=huff_counts->counts[' ']; - huff_counts->counts[' ']+=huff_counts->tot_end_space+ - huff_counts->tot_pre_space + - huff_counts->empty_fields * huff_counts->field_length; + /* Add all leading and trailing spaces. */ + huff_counts->counts[' ']+= (huff_counts->tot_end_space + + huff_counts->tot_pre_space + + huff_counts->empty_fields * + huff_counts->field_length); + /* Check, what the compressed length of this would be. */ old_length=calc_packed_length(huff_counts,0)+records/8; + /* Get the number of zero bytes. */ length=huff_counts->zero_fields*huff_counts->field_length; + /* Add it to the counts. */ huff_counts->counts[0]+=length; + /* Check, what the compressed length of this would be. */ new_length=calc_packed_length(huff_counts,0); + /* If the compression without the zeroes would be shorter, we are done. */ if (old_length < new_length && huff_counts->field_length > 1) { huff_counts->field_type=FIELD_SKIP_ZERO; @@ -969,9 +1209,16 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees, huff_counts->bytes_packed=old_length- records/8; goto found_pack; } + /* Remove the insignificant spaces, but keep the zeroes. */ huff_counts->counts[' ']=old_space_count; } + /* Check, what the compressed length of this column would be. */ huff_counts->bytes_packed=calc_packed_length(huff_counts,0); + + /* + If there are enough empty records (in this column), + treating them specially may pay off. + */ if (huff_counts->empty_fields) { if (huff_counts->field_length > 2 && @@ -1003,6 +1250,11 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees, } } } + + /* + If there are enough trailing spaces (in this column), + treating them specially may pay off. + */ if (huff_counts->tot_end_space) { huff_counts->counts[' ']+=huff_counts->tot_pre_space; @@ -1012,6 +1264,11 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees, goto found_pack; huff_counts->counts[' ']-=huff_counts->tot_pre_space; } + + /* + If there are enough leading spaces (in this column), + treating them specially may pay off. + */ if (huff_counts->tot_pre_space) { if (test_space_compress(huff_counts,records,huff_counts->max_pre_space, @@ -1041,6 +1298,8 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees, { HUFF_TREE tree; + DBUG_EXECUTE_IF("forceintervall", + huff_counts->bytes_packed= ~ (my_off_t) 0;); tree.element_buffer=0; if (!make_huff_tree(&tree,huff_counts) && tree.bytes_packed+tree.tree_pack_length < huff_counts->bytes_packed) @@ -1066,14 +1325,27 @@ static void check_counts(HUFF_COUNTS *huff_counts, uint trees, fill_zero_fields++; field_count[huff_counts->field_type]++; } + DBUG_PRINT("info", ("normal: %3d empty-space: %3d " + "empty-zero: %3d empty-fill: %3d", + field_count[FIELD_NORMAL],space_fields, + field_count[FIELD_SKIP_ZERO],fill_zero_fields)); + DBUG_PRINT("info", ("pre-space: %3d end-space: %3d " + "intervall-fields: %3d zero: %3d", + field_count[FIELD_SKIP_PRESPACE], + field_count[FIELD_SKIP_ENDSPACE], + field_count[FIELD_INTERVALL], + field_count[FIELD_ZERO])); if (verbose) - printf("\nnormal: %3d empty-space: %3d empty-zero: %3d empty-fill: %3d\npre-space: %3d end-space: %3d intervall-fields: %3d zero: %3d\n", - field_count[FIELD_NORMAL],space_fields, - field_count[FIELD_SKIP_ZERO],fill_zero_fields, - field_count[FIELD_SKIP_PRESPACE], - field_count[FIELD_SKIP_ENDSPACE], - field_count[FIELD_INTERVALL], - field_count[FIELD_ZERO]); + VOID(printf("\nnormal: %3d empty-space: %3d " + "empty-zero: %3d empty-fill: %3d\n" + "pre-space: %3d end-space: %3d " + "intervall-fields: %3d zero: %3d\n", + field_count[FIELD_NORMAL],space_fields, + field_count[FIELD_SKIP_ZERO],fill_zero_fields, + field_count[FIELD_SKIP_PRESPACE], + field_count[FIELD_SKIP_ENDSPACE], + field_count[FIELD_INTERVALL], + field_count[FIELD_ZERO])); DBUG_VOID_RETURN; } @@ -1170,8 +1442,24 @@ static HUFF_TREE* make_huff_trees(HUFF_COUNTS *huff_counts, uint trees) DBUG_RETURN(huff_tree); } - /* Update huff_tree according to huff_counts->counts or - huff_counts->tree_buff */ +/* + Build a Huffman tree. + + SYNOPSIS + make_huff_tree() + huff_tree The Huffman tree. + huff_counts The counts. + + DESCRIPTION + Build a Huffman tree according to huff_counts->counts or + huff_counts->tree_buff. tree_buff, if non-NULL contains up to + tree_buff_length of distinct column values. In that case, whole + values can be Huffman encoded instead of single bytes. + + RETURN + 0 OK + != 0 Error +*/ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts) { @@ -1182,12 +1470,14 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts) first=last=0; if (huff_counts->tree_buff) { + /* Calculate the number of distinct values in tree_buff. */ found= (uint) (huff_counts->tree_pos - huff_counts->tree_buff) / huff_counts->field_length; first=0; last=found-1; } else { + /* Count the number of byte codes found in the column. */ for (i=found=0 ; i < 256 ; i++) { if (huff_counts->counts[i]) @@ -1201,6 +1491,7 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts) found=2; } + /* When using 'tree_buff' we can have more that 256 values. */ if (queue.max_elements < found) { delete_queue(&queue); @@ -1208,6 +1499,7 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts) return -1; } + /* Allocate or reallocate an element buffer for the Huffman tree. */ if (!huff_tree->element_buffer) { if (!(huff_tree->element_buffer= @@ -1235,15 +1527,25 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts) if (huff_counts->tree_buff) { huff_tree->elements=0; - tree_walk(&huff_counts->int_tree, - (int (*)(void*, element_count,void*)) save_counts_in_queue, - (gptr) huff_tree, left_root_right); huff_tree->tree_pack_length=(1+15+16+5+5+ (huff_tree->char_bits+1)*found+ (huff_tree->offset_bits+1)* (found-2)+7)/8 + (uint) (huff_tree->counts->tree_pos- huff_tree->counts->tree_buff); + /* + Put a HUFF_ELEMENT into the queue for every distinct column value. + + tree_walk() calls save_counts_in_queue() for every element in + 'int_tree'. This takes elements from the target trees element + buffer and places references to them into the buffer of the + priority queue. We insert in column value order, but the order is + in fact irrelevant here. We will establish the correct order + later. + */ + tree_walk(&huff_counts->int_tree, + (int (*)(void*, element_count,void*)) save_counts_in_queue, + (gptr) huff_tree, left_root_right); } else { @@ -1252,7 +1554,15 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts) (huff_tree->char_bits+1)*found+ (huff_tree->offset_bits+1)* (found-2)+7)/8; + /* + Put a HUFF_ELEMENT into the queue for every byte code found in the column. + The elements are taken from the target trees element buffer. + Instead of using queue_insert(), we just place references to the + elements into the buffer of the priority queue. We insert in byte + value order, but the order is in fact irrelevant here. We will + establish the correct order later. + */ for (i=first, found=0 ; i <= last ; i++) { if (huff_counts->counts[i]) @@ -1264,8 +1574,13 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts) queue.root[found]=(byte*) new_huff_el; } } + /* + If there is only a single byte value in this field in all records, + add a second element with zero incidence. This is required to enter + the loop, which builds the Huffman tree. + */ while (found < 2) - { /* Our huff_trees request at least 2 elements */ + { new_huff_el=huff_tree->element_buffer+(found++); new_huff_el->count=0; new_huff_el->a.leaf.null=0; @@ -1276,21 +1591,53 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts) queue.root[found]=(byte*) new_huff_el; } } + + /* Make a queue from the queue buffer. */ queue.elements=found; + /* + Make a priority queue from the queue. Construct its index so that we + have a partially ordered tree. + */ for (i=found/2 ; i > 0 ; i--) _downheap(&queue,i); + + /* The Huffman algorithm. */ bytes_packed=0; bits_packed=0; for (i=1 ; i < found ; i++) { + /* + Pop the top element from the queue (the one with the least incidence). + Popping from a priority queue includes a re-ordering of the queue, + to get the next least incidence element to the top. + */ a=(HUFF_ELEMENT*) queue_remove(&queue,0); + /* + Copy the next least incidence element. The queue implementation + reserves root[0] for temporary purposes. root[1] is the top. + */ b=(HUFF_ELEMENT*) queue.root[1]; + /* Get a new element from the element buffer. */ new_huff_el=huff_tree->element_buffer+found+i; + /* The new element gets the sum of the two least incidence elements. */ new_huff_el->count=a->count+b->count; + /* + The Huffman algorithm assigns another bit to the code for a byte + every time that bytes incidence is combined (directly or indirectly) + to a new element as one of the two least incidence elements. + This means that one more bit per incidence of that byte is required + in the resulting file. So we add the new combined incidence as the + number of bits by which the result grows. + */ bits_packed+=(uint) (new_huff_el->count & 7); bytes_packed+=new_huff_el->count/8; - new_huff_el->a.nod.left=a; /* lesser in left */ + /* The new element points to its children, lesser in left. */ + new_huff_el->a.nod.left=a; new_huff_el->a.nod.right=b; + /* + Replace the copied top element by the new element and re-order the + queue. + */ queue.root[1]=(byte*) new_huff_el; queue_replaced(&queue); } @@ -1309,7 +1656,26 @@ static int compare_tree(void* cmp_arg __attribute__((unused)), return 0; } - /* Used by make_huff_tree to save intervall-counts in queue */ +/* + Organize distinct column values and their incidences into a priority queue. + + SYNOPSIS + save_counts_in_queue() + key The column value. + count The incidence of this value. + tree The Huffman tree to be built later. + + DESCRIPTION + We use the element buffer of the targeted tree. The distinct column + values are organized in a priority queue first. The Huffman + algorithm will later organize the elements into a Huffman tree. For + the time being, we just place references to the elements into the + queue buffer. The buffer will later be organized into a priority + queue. + + RETURN + 0 + */ static int save_counts_in_queue(byte *key, element_count count, HUFF_TREE *tree) @@ -1326,8 +1692,23 @@ static int save_counts_in_queue(byte *key, element_count count, } - /* Calculate length of file if given counts should be used */ - /* Its actually a faster version of make_huff_tree */ +/* + Calculate length of file if given counts should be used. + + SYNOPSIS + calc_packed_length() + huff_counts The counts for a column of the table(s). + add_tree_lenght If the decode tree length should be added. + + DESCRIPTION + We need to follow the Huffman algorithm until we know, how many bits + are required for each byte code. But we do not need the resulting + Huffman tree. Hence, we can leave out some steps which are essential + in make_huff_tree(). + + RETURN + Number of bytes required to compress this table column. +*/ static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts, uint add_tree_lenght) @@ -1337,6 +1718,23 @@ static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts, HUFF_ELEMENT element_buffer[256]; DBUG_ENTER("calc_packed_length"); + /* + WARNING: We use a small hack for efficiency: Instead of placing + references to HUFF_ELEMENTs into the queue, we just insert + references to the counts of the byte codes which appeared in this + table column. During the Huffman algorithm they are successively + replaced by references to HUFF_ELEMENTs. This works, because + HUFF_ELEMENTs have the incidence count at their beginning. + Regardless, wether the queue array contains references to counts of + type my_off_t or references to HUFF_ELEMENTs which have the count of + type my_off_t at their beginning, it always points to a count of the + same type. + + Instead of using queue_insert(), we just copy the references into + the buffer of the priority queue. We insert in byte value order, but + the order is in fact irrelevant here. We will establish the correct + order later. + */ first=last=0; for (i=found=0 ; i < 256 ; i++) { @@ -1345,31 +1743,73 @@ static my_off_t calc_packed_length(HUFF_COUNTS *huff_counts, if (! found++) first=i; last=i; + /* We start with root[1], which is the queues top element. */ queue.root[found]=(byte*) &huff_counts->counts[i]; } } if (!found) DBUG_RETURN(0); /* Empty tree */ + /* + If there is only a single byte value in this field in all records, + add a second element with zero incidence. This is required to enter + the loop, which follows the Huffman algorithm. + */ if (found < 2) queue.root[++found]=(byte*) &huff_counts->counts[last ? 0 : 1]; + /* Make a queue from the queue buffer. */ queue.elements=found; bytes_packed=0; bits_packed=0; + /* Add the length of the coding table, which would become part of the file. */ if (add_tree_lenght) bytes_packed=(8+9+5+5+(max_bit(last-first)+1)*found+ (max_bit(found-1)+1+1)*(found-2) +7)/8; + + /* + Make a priority queue from the queue. Construct its index so that we + have a partially ordered tree. + */ for (i=(found+1)/2 ; i > 0 ; i--) _downheap(&queue,i); + + /* The Huffman algorithm. */ for (i=0 ; i < found-1 ; i++) { - HUFF_ELEMENT *a,*b,*new_huff_el; - a=(HUFF_ELEMENT*) queue_remove(&queue,0); - b=(HUFF_ELEMENT*) queue.root[1]; - new_huff_el=element_buffer+i; - new_huff_el->count=a->count+b->count; + my_off_t *a; + my_off_t *b; + HUFF_ELEMENT *new_huff_el; + + /* + Pop the top element from the queue (the one with the least + incidence). Popping from a priority queue includes a re-ordering + of the queue, to get the next least incidence element to the top. + */ + a= (my_off_t*) queue_remove(&queue, 0); + /* + Copy the next least incidence element. The queue implementation + reserves root[0] for temporary purposes. root[1] is the top. + */ + b= (my_off_t*) queue.root[1]; + /* Create a new element in a local (automatic) buffer. */ + new_huff_el= element_buffer + i; + /* The new element gets the sum of the two least incidence elements. */ + new_huff_el->count= *a + *b; + /* + The Huffman algorithm assigns another bit to the code for a byte + every time that bytes incidence is combined (directly or indirectly) + to a new element as one of the two least incidence elements. + This means that one more bit per incidence of that byte is required + in the resulting file. So we add the new combined incidence as the + number of bits by which the result grows. + */ bits_packed+=(uint) (new_huff_el->count & 7); bytes_packed+=new_huff_el->count/8; + /* + Replace the copied top element by the new element and re-order the + queue. This successively replaces the references to counts by + references to HUFF_ELEMENTs. + */ queue.root[1]=(byte*) new_huff_el; queue_replaced(&queue); } @@ -1417,13 +1857,26 @@ static uint join_same_trees(HUFF_COUNTS *huff_counts, uint trees) } } } + DBUG_PRINT("info", ("Original trees: %d After join: %d", + trees, tree_number)); if (verbose) - printf("Original trees: %d After join: %d\n",trees,tree_number); + VOID(printf("Original trees: %d After join: %d\n", trees, tree_number)); return tree_number; /* Return trees left */ } - /* Fill in huff_tree decode tables */ +/* + Fill in huff_tree encode tables. + + SYNOPSIS + make_huff_decode_table() + huff_tree An array of HUFF_TREE which are to be encoded. + trees The number of HUFF_TREE in the array. + + RETURN + 0 success + != 0 error +*/ static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees) { @@ -1434,12 +1887,13 @@ static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees) { elements=huff_tree->counts->tree_buff ? huff_tree->elements : 256; if (!(huff_tree->code = - (ulong*) my_malloc(elements* - (sizeof(ulong)+sizeof(uchar)), - MYF(MY_WME | MY_ZEROFILL)))) + (ulonglong*) my_malloc(elements* + (sizeof(ulonglong) + sizeof(uchar)), + MYF(MY_WME | MY_ZEROFILL)))) return 1; huff_tree->code_len=(uchar*) (huff_tree->code+elements); - make_traverse_code_tree(huff_tree,huff_tree->root,32,0); + make_traverse_code_tree(huff_tree, huff_tree->root, + 8 * sizeof(ulonglong), LL(0)); } } return 0; @@ -1448,28 +1902,90 @@ static int make_huff_decode_table(HUFF_TREE *huff_tree, uint trees) static void make_traverse_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element, - uint size, ulong code) + uint size, ulonglong code) { uint chr; if (!element->a.leaf.null) { chr=element->a.leaf.element_nr; - huff_tree->code_len[chr]=(uchar) (32-size); - huff_tree->code[chr]= (code >> size); - if (huff_tree->height < 32-size) - huff_tree->height= 32-size; + huff_tree->code_len[chr]= (uchar) (8 * sizeof(ulonglong) - size); + huff_tree->code[chr]= (code >> size); + if (huff_tree->height < 8 * sizeof(ulonglong) - size) + huff_tree->height= 8 * sizeof(ulonglong) - size; } else { size--; make_traverse_code_tree(huff_tree,element->a.nod.left,size,code); - make_traverse_code_tree(huff_tree,element->a.nod.right,size, - code+((ulong) 1L << size)); + make_traverse_code_tree(huff_tree, element->a.nod.right, size, + code + (((ulonglong) 1) << size)); } return; } +/* + Convert a value into binary digits. + + SYNOPSIS + bindigits() + value The value. + length The number of low order bits to convert. + + NOTE + The result string is in static storage. It is reused on every call. + So you cannot use it twice in one expression. + + RETURN + A pointer to a static NUL-terminated string. + */ + +static char *bindigits(ulonglong value, uint bits) +{ + static char digits[72]; + char *ptr= digits; + uint idx= bits; + + DBUG_ASSERT(idx < sizeof(digits)); + while (idx) + *(ptr++)= '0' + ((value >> (--idx)) & 1); + *ptr= '\0'; + return digits; +} + + +/* + Convert a value into hexadecimal digits. + + SYNOPSIS + hexdigits() + value The value. + + NOTE + The result string is in static storage. It is reused on every call. + So you cannot use it twice in one expression. + + RETURN + A pointer to a static NUL-terminated string. + */ + +static char *hexdigits(ulonglong value) +{ + static char digits[20]; + char *ptr= digits; + uint idx= 2 * sizeof(value); /* Two hex digits per byte. */ + + DBUG_ASSERT(idx < sizeof(digits)); + while (idx) + { + if ((*(ptr++)= '0' + ((value >> (4 * (--idx))) & 0xf)) > '9') + *(ptr - 1)+= 'a' - '9' - 1; + } + *ptr= '\0'; + return digits; +} + + /* Write header to new packed data file */ static int write_header(PACK_MRG_INFO *mrg,uint head_length,uint trees, @@ -1503,15 +2019,64 @@ static void write_field_info(HUFF_COUNTS *counts, uint fields, uint trees) uint huff_tree_bits; huff_tree_bits=max_bit(trees ? trees-1 : 0); + DBUG_PRINT("info", ("")); + DBUG_PRINT("info", ("column types:")); + DBUG_PRINT("info", ("FIELD_NORMAL 0")); + DBUG_PRINT("info", ("FIELD_SKIP_ENDSPACE 1")); + DBUG_PRINT("info", ("FIELD_SKIP_PRESPACE 2")); + DBUG_PRINT("info", ("FIELD_SKIP_ZERO 3")); + DBUG_PRINT("info", ("FIELD_BLOB 4")); + DBUG_PRINT("info", ("FIELD_CONSTANT 5")); + DBUG_PRINT("info", ("FIELD_INTERVALL 6")); + DBUG_PRINT("info", ("FIELD_ZERO 7")); + DBUG_PRINT("info", ("FIELD_VARCHAR 8")); + DBUG_PRINT("info", ("FIELD_CHECK 9")); + DBUG_PRINT("info", ("")); + DBUG_PRINT("info", ("pack type as a set of flags:")); + DBUG_PRINT("info", ("PACK_TYPE_SELECTED 1")); + DBUG_PRINT("info", ("PACK_TYPE_SPACE_FIELDS 2")); + DBUG_PRINT("info", ("PACK_TYPE_ZERO_FILL 4")); + DBUG_PRINT("info", ("")); + if (verbose >= 2) + { + VOID(printf("\n")); + VOID(printf("column types:\n")); + VOID(printf("FIELD_NORMAL 0\n")); + VOID(printf("FIELD_SKIP_ENDSPACE 1\n")); + VOID(printf("FIELD_SKIP_PRESPACE 2\n")); + VOID(printf("FIELD_SKIP_ZERO 3\n")); + VOID(printf("FIELD_BLOB 4\n")); + VOID(printf("FIELD_CONSTANT 5\n")); + VOID(printf("FIELD_INTERVALL 6\n")); + VOID(printf("FIELD_ZERO 7\n")); + VOID(printf("FIELD_VARCHAR 8\n")); + VOID(printf("FIELD_CHECK 9\n")); + VOID(printf("\n")); + VOID(printf("pack type as a set of flags:\n")); + VOID(printf("PACK_TYPE_SELECTED 1\n")); + VOID(printf("PACK_TYPE_SPACE_FIELDS 2\n")); + VOID(printf("PACK_TYPE_ZERO_FILL 4\n")); + VOID(printf("\n")); + } for (i=0 ; i++ < fields ; counts++) { - write_bits((ulong) (int) counts->field_type,5); + write_bits((ulonglong) (int) counts->field_type, 5); write_bits(counts->pack_type,6); if (counts->pack_type & PACK_TYPE_ZERO_FILL) write_bits(counts->max_zero_fill,5); else write_bits(counts->length_bits,5); - write_bits((ulong) counts->tree->tree_number-1,huff_tree_bits); + write_bits((ulonglong) counts->tree->tree_number - 1, huff_tree_bits); + DBUG_PRINT("info", ("column: %3u type: %2u pack: %2u zero: %4u " + "lbits: %2u tree: %2u length: %4u", + i , counts->field_type, counts->pack_type, + counts->max_zero_fill, counts->length_bits, + counts->tree->tree_number, counts->field_length)); + if (verbose >= 2) + VOID(printf("column: %3u type: %2u pack: %2u zero: %4u lbits: %2u " + "tree: %2u length: %4u\n", i , counts->field_type, + counts->pack_type, counts->max_zero_fill, counts->length_bits, + counts->tree->tree_number, counts->field_length)); } flush_bits(); return; @@ -1524,45 +2089,72 @@ static void write_field_info(HUFF_COUNTS *counts, uint fields, uint trees) static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees) { uint i,int_length; + uint tree_no; + uint codes; + uint errors= 0; uint *packed_tree,*offset,length; my_off_t elements; + /* Find the highest number of elements in the trees. */ for (i=length=0 ; i < trees ; i++) if (huff_tree[i].tree_number > 0 && huff_tree[i].elements > length) length=huff_tree[i].elements; + /* + Allocate a buffer for packing a decode tree. Two numbers per element + (left child and right child). + */ if (!(packed_tree=(uint*) my_alloca(sizeof(uint)*length*2))) { my_error(EE_OUTOFMEMORY,MYF(ME_BELL),sizeof(uint)*length*2); return 0; } + DBUG_PRINT("info", ("")); + if (verbose >= 2) + VOID(printf("\n")); + tree_no= 0; intervall_length=0; for (elements=0; trees-- ; huff_tree++) { + /* Skip columns that have been joined with other columns. */ if (huff_tree->tree_number == 0) continue; /* Deleted tree */ + tree_no++; + DBUG_PRINT("info", ("")); + if (verbose >= 3) + VOID(printf("\n")); + /* Count the total number of elements (byte codes or column values). */ elements+=huff_tree->elements; huff_tree->max_offset=2; + /* Build a tree of offsets and codes for decoding in 'packed_tree'. */ if (huff_tree->elements <= 1) offset=packed_tree; else offset=make_offset_code_tree(huff_tree,huff_tree->root,packed_tree); + + /* This should be the same as 'length' above. */ huff_tree->offset_bits=max_bit(huff_tree->max_offset); + + /* + Since we check this during collecting the distinct column values, + this should never happen. + */ if (huff_tree->max_offset >= IS_OFFSET) { /* This should be impossible */ - VOID(fprintf(stderr,"Tree offset got too big: %d, aborted\n", - huff_tree->max_offset)); + VOID(fprintf(stderr, "Tree offset got too big: %d, aborted\n", + huff_tree->max_offset)); my_afree((gptr) packed_tree); return 0; } -#ifdef EXTRA_DBUG - printf("pos: %d elements: %d tree-elements: %d char_bits: %d\n", - (uint) (file_buffer.pos-file_buffer.buffer), - huff_tree->elements, (offset-packed_tree),huff_tree->char_bits); -#endif + DBUG_PRINT("info", ("pos: %lu elements: %u tree-elements: %lu " + "char_bits: %u\n", + (ulong) (file_buffer.pos - file_buffer.buffer), + huff_tree->elements, (ulong) (offset - packed_tree), + huff_tree->char_bits)); if (!huff_tree->counts->tree_buff) { + /* We do a byte compression on this column. Mark with bit 0. */ write_bits(0,1); write_bits(huff_tree->min_chr,8); write_bits(huff_tree->elements,9); @@ -1574,6 +2166,7 @@ static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees) { int_length=(uint) (huff_tree->counts->tree_pos - huff_tree->counts->tree_buff); + /* We have distinct column values for this column. Mark with bit 1. */ write_bits(1,1); write_bits(huff_tree->elements,15); write_bits(int_length,16); @@ -1581,10 +2174,29 @@ static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees) write_bits(huff_tree->offset_bits,5); intervall_length+=int_length; } + DBUG_PRINT("info", ("tree: %2u elements: %4u char_bits: %2u " + "offset_bits: %2u %s: %5u codelen: %2u", + tree_no, huff_tree->elements, huff_tree->char_bits, + huff_tree->offset_bits, huff_tree->counts->tree_buff ? + "bufflen" : "min_chr", huff_tree->counts->tree_buff ? + int_length : huff_tree->min_chr, huff_tree->height)); + if (verbose >= 2) + VOID(printf("tree: %2u elements: %4u char_bits: %2u offset_bits: %2u " + "%s: %5u codelen: %2u\n", tree_no, huff_tree->elements, + huff_tree->char_bits, huff_tree->offset_bits, + huff_tree->counts->tree_buff ? "bufflen" : "min_chr", + huff_tree->counts->tree_buff ? int_length : + huff_tree->min_chr, huff_tree->height)); + + /* Check that the code tree length matches the element count. */ length=(uint) (offset-packed_tree); if (length != huff_tree->elements*2-2) - printf("error: Huff-tree-length: %d != calc_length: %d\n", - length,huff_tree->elements*2-2); + { + VOID(fprintf(stderr, "error: Huff-tree-length: %d != calc_length: %d\n", + length, huff_tree->elements * 2 - 2)); + errors++; + break; + } for (i=0 ; i < length ; i++) { @@ -1593,16 +2205,122 @@ static my_off_t write_huff_tree(HUFF_TREE *huff_tree, uint trees) huff_tree->offset_bits+1); else write_bits(packed_tree[i]-huff_tree->min_chr,huff_tree->char_bits+1); + DBUG_PRINT("info", ("tree[0x%04x]: %s0x%04x", + i, (packed_tree[i] & IS_OFFSET) ? + " -> " : "", (packed_tree[i] & IS_OFFSET) ? + packed_tree[i] - IS_OFFSET + i : packed_tree[i])); + if (verbose >= 3) + VOID(printf("tree[0x%04x]: %s0x%04x\n", + i, (packed_tree[i] & IS_OFFSET) ? " -> " : "", + (packed_tree[i] & IS_OFFSET) ? + packed_tree[i] - IS_OFFSET + i : packed_tree[i])); } flush_bits(); + + /* + Display coding tables and check their correctness. + */ + codes= huff_tree->counts->tree_buff ? huff_tree->elements : 256; + for (i= 0; i < codes; i++) + { + ulonglong code; + uint bits; + uint len; + uint idx; + + if (! (len= huff_tree->code_len[i])) + continue; + DBUG_PRINT("info", ("code[0x%04x]: 0x%s bits: %2u bin: %s", i, + hexdigits(huff_tree->code[i]), huff_tree->code_len[i], + bindigits(huff_tree->code[i], + huff_tree->code_len[i]))); + if (verbose >= 3) + VOID(printf("code[0x%04x]: 0x%s bits: %2u bin: %s\n", i, + hexdigits(huff_tree->code[i]), huff_tree->code_len[i], + bindigits(huff_tree->code[i], huff_tree->code_len[i]))); + + /* Check that the encode table decodes correctly. */ + code= 0; + bits= 0; + idx= 0; + DBUG_EXECUTE_IF("forcechkerr1", len--;); + DBUG_EXECUTE_IF("forcechkerr2", bits= 8 * sizeof(code);); + DBUG_EXECUTE_IF("forcechkerr3", idx= length;); + for (;;) + { + if (! len) + { + VOID(fflush(stdout)); + VOID(fprintf(stderr, "error: code 0x%s with %u bits not found\n", + hexdigits(huff_tree->code[i]), huff_tree->code_len[i])); + errors++; + break; + } + code<<= 1; + code|= (huff_tree->code[i] >> (--len)) & 1; + bits++; + if (bits > 8 * sizeof(code)) + { + VOID(fflush(stdout)); + VOID(fprintf(stderr, "error: Huffman code too long: %u/%u\n", + bits, 8 * sizeof(code))); + errors++; + break; + } + idx+= code & 1; + if (idx >= length) + { + VOID(fflush(stdout)); + VOID(fprintf(stderr, "error: illegal tree offset: %u/%u\n", + idx, length)); + errors++; + break; + } + if (packed_tree[idx] & IS_OFFSET) + idx+= packed_tree[idx] & ~IS_OFFSET; + else + break; /* Hit a leaf. This contains the result value. */ + } + if (errors) + break; + + DBUG_EXECUTE_IF("forcechkerr4", packed_tree[idx]++;); + if (packed_tree[idx] != i) + { + VOID(fflush(stdout)); + VOID(fprintf(stderr, "error: decoded value 0x%04x should be: 0x%04x\n", + packed_tree[idx], i)); + errors++; + break; + } + } /*end for (codes)*/ + if (errors) + break; + + /* Write column values in case of distinct column value compression. */ if (huff_tree->counts->tree_buff) { for (i=0 ; i < int_length ; i++) - write_bits((uint) (uchar) huff_tree->counts->tree_buff[i],8); + { + write_bits((ulonglong) (uchar) huff_tree->counts->tree_buff[i], 8); + DBUG_PRINT("info", ("column_values[0x%04x]: 0x%02x", + i, (uchar) huff_tree->counts->tree_buff[i])); + if (verbose >= 3) + VOID(printf("column_values[0x%04x]: 0x%02x\n", + i, (uchar) huff_tree->counts->tree_buff[i])); + } } flush_bits(); } + DBUG_PRINT("info", ("")); + if (verbose >= 2) + VOID(printf("\n")); my_afree((gptr) packed_tree); + if (errors) + { + VOID(fprintf(stderr, "Error: Generated decode trees are corrupt. Stop.\n")); + return 0; + } return elements; } @@ -1613,23 +2331,43 @@ static uint *make_offset_code_tree(HUFF_TREE *huff_tree, HUFF_ELEMENT *element, uint *prev_offset; prev_offset= offset; + /* + 'a.leaf.null' takes the same place as 'a.nod.left'. If this is null, + then there is no left child and, hence no right child either. This + is a property of a binary tree. An element is either a node with two + childs, or a leaf without childs. + + The current element is always a node with two childs. Go left first. + */ if (!element->a.nod.left->a.leaf.null) { - offset[0] =(uint) element->a.nod.left->a.leaf.element_nr; + /* Store the byte code or the index of the column value. */ + prev_offset[0] =(uint) element->a.nod.left->a.leaf.element_nr; offset+=2; } else { + /* + Recursively traverse the tree to the left. Mark it as an offset to + another tree node (in contrast to a byte code or column value index). + */ prev_offset[0]= IS_OFFSET+2; offset=make_offset_code_tree(huff_tree,element->a.nod.left,offset+2); } + + /* Now, check the right child. */ if (!element->a.nod.right->a.leaf.null) { + /* Store the byte code or the index of the column value. */ prev_offset[1]=element->a.nod.right->a.leaf.element_nr; return offset; } else { + /* + Recursively traverse the tree to the right. Mark it as an offset to + another tree node (in contrast to a byte code or column value index). + */ uint temp=(uint) (offset-prev_offset-1); prev_offset[1]= IS_OFFSET+ temp; if (huff_tree->max_offset < temp) @@ -1656,6 +2394,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) uint i,max_calc_length,pack_ref_length,min_record_length,max_record_length, intervall,field_length,max_pack_length,pack_blob_length; my_off_t record_count; + char llbuf[32]; ulong length,pack_length; byte *record,*pos,*end_pos,*record_pos,*start_pos; HUFF_COUNTS *count,*end_count; @@ -1663,12 +2402,23 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) MI_INFO *isam_file=mrg->file[0]; DBUG_ENTER("compress_isam_file"); + /* Allocate a buffer for the records (excluding blobs). */ if (!(record=(byte*) my_alloca(isam_file->s->base.reclength))) return -1; + end_count=huff_counts+isam_file->s->base.fields; min_record_length= (uint) ~0; max_record_length=0; + /* + Calculate the maximum number of bits required to pack the records. + Remember to understand 'max_zero_fill' as 'min_zero_fill'. + The tree height determines the maximum number of bits per value. + Some fields skip leading or trailing spaces or zeroes. The skipped + number of bytes is encoded by 'length_bits' bits. + Empty blobs and varchar are encoded with a single 1 bit. Other blobs + and varchar get a leading 0 bit. + */ for (i=max_calc_length=0 ; i < isam_file->s->base.fields ; i++) { if (!(huff_counts[i].pack_type & PACK_TYPE_ZERO_FILL)) @@ -1687,14 +2437,16 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) (huff_counts[i].field_length - huff_counts[i].max_zero_fill)* huff_counts[i].tree->height+huff_counts[i].length_bits; } - max_calc_length/=8; + max_calc_length= (max_calc_length + 7) / 8; if (max_calc_length < 254) pack_ref_length=1; else if (max_calc_length <= 65535) pack_ref_length=3; else pack_ref_length=4; + record_count=0; + /* 'max_blob_length' is the max length of all blobs of a record. */ pack_blob_length=0; if (isam_file->s->base.blobs) { @@ -1707,6 +2459,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) } max_pack_length=pack_ref_length+pack_blob_length; + DBUG_PRINT("fields", ("===")); mrg_reset(mrg); while ((error=mrg_rrnd(mrg,record)) != HA_ERR_END_OF_FILE) { @@ -1722,15 +2475,29 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) end_pos=start_pos+(field_length=count->field_length); tree=count->tree; + DBUG_PRINT("fields", ("column: %3lu type: %2u pack: %2u zero: %4u " + "lbits: %2u tree: %2u length: %4u", + (ulong) (count - huff_counts + 1), + count->field_type, + count->pack_type, count->max_zero_fill, + count->length_bits, count->tree->tree_number, + count->field_length)); + + /* Check if the column contains spaces only. */ if (count->pack_type & PACK_TYPE_SPACE_FIELDS) { for (pos=start_pos ; *pos == ' ' && pos < end_pos; pos++) ; if (pos == end_pos) { + DBUG_PRINT("fields", + ("PACK_TYPE_SPACE_FIELDS spaces only, bits: 1")); + DBUG_PRINT("fields", ("---")); write_bits(1,1); start_pos=end_pos; continue; } + DBUG_PRINT("fields", + ("PACK_TYPE_SPACE_FIELDS not only spaces, bits: 1")); write_bits(0,1); } end_pos-=count->max_zero_fill; @@ -1740,65 +2507,129 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) case FIELD_SKIP_ZERO: if (!memcmp((byte*) start_pos,zero_string,field_length)) { + DBUG_PRINT("fields", ("FIELD_SKIP_ZERO zeroes only, bits: 1")); write_bits(1,1); start_pos=end_pos; break; } + DBUG_PRINT("fields", ("FIELD_SKIP_ZERO not only zeroes, bits: 1")); write_bits(0,1); /* Fall through */ case FIELD_NORMAL: + DBUG_PRINT("fields", ("FIELD_NORMAL %lu bytes", + (ulong) (end_pos - start_pos))); for ( ; start_pos < end_pos ; start_pos++) + { + DBUG_PRINT("fields", + ("value: 0x%02x code: 0x%s bits: %2u bin: %s", + (uchar) *start_pos, + hexdigits(tree->code[(uchar) *start_pos]), + (uint) tree->code_len[(uchar) *start_pos], + bindigits(tree->code[(uchar) *start_pos], + (uint) tree->code_len[(uchar) *start_pos]))); write_bits(tree->code[(uchar) *start_pos], (uint) tree->code_len[(uchar) *start_pos]); + } break; case FIELD_SKIP_ENDSPACE: for (pos=end_pos ; pos > start_pos && pos[-1] == ' ' ; pos--) ; - length=(uint) (end_pos-pos); + length= (ulong) (end_pos - pos); if (count->pack_type & PACK_TYPE_SELECTED) { if (length > count->min_space) { + DBUG_PRINT("fields", + ("FIELD_SKIP_ENDSPACE more than min_space, bits: 1")); + DBUG_PRINT("fields", + ("FIELD_SKIP_ENDSPACE skip %lu/%u bytes, bits: %2u", + length, field_length, count->length_bits)); write_bits(1,1); write_bits(length,count->length_bits); } else { + DBUG_PRINT("fields", + ("FIELD_SKIP_ENDSPACE not more than min_space, " + "bits: 1")); write_bits(0,1); pos=end_pos; } } else + { + DBUG_PRINT("fields", + ("FIELD_SKIP_ENDSPACE skip %lu/%u bytes, bits: %2u", + length, field_length, count->length_bits)); write_bits(length,count->length_bits); + } + /* Encode all significant bytes. */ + DBUG_PRINT("fields", ("FIELD_SKIP_ENDSPACE %lu bytes", + (ulong) (pos - start_pos))); for ( ; start_pos < pos ; start_pos++) + { + DBUG_PRINT("fields", + ("value: 0x%02x code: 0x%s bits: %2u bin: %s", + (uchar) *start_pos, + hexdigits(tree->code[(uchar) *start_pos]), + (uint) tree->code_len[(uchar) *start_pos], + bindigits(tree->code[(uchar) *start_pos], + (uint) tree->code_len[(uchar) *start_pos]))); write_bits(tree->code[(uchar) *start_pos], (uint) tree->code_len[(uchar) *start_pos]); + } start_pos=end_pos; break; case FIELD_SKIP_PRESPACE: for (pos=start_pos ; pos < end_pos && pos[0] == ' ' ; pos++) ; - length=(uint) (pos-start_pos); + length= (ulong) (pos - start_pos); if (count->pack_type & PACK_TYPE_SELECTED) { if (length > count->min_space) { + DBUG_PRINT("fields", + ("FIELD_SKIP_PRESPACE more than min_space, bits: 1")); + DBUG_PRINT("fields", + ("FIELD_SKIP_PRESPACE skip %lu/%u bytes, bits: %2u", + length, field_length, count->length_bits)); write_bits(1,1); write_bits(length,count->length_bits); } else { + DBUG_PRINT("fields", + ("FIELD_SKIP_PRESPACE not more than min_space, " + "bits: 1")); pos=start_pos; write_bits(0,1); } } else + { + DBUG_PRINT("fields", + ("FIELD_SKIP_PRESPACE skip %lu/%u bytes, bits: %2u", + length, field_length, count->length_bits)); write_bits(length,count->length_bits); + } + /* Encode all significant bytes. */ + DBUG_PRINT("fields", ("FIELD_SKIP_PRESPACE %lu bytes", + (ulong) (end_pos - start_pos))); for (start_pos=pos ; start_pos < end_pos ; start_pos++) + { + DBUG_PRINT("fields", + ("value: 0x%02x code: 0x%s bits: %2u bin: %s", + (uchar) *start_pos, + hexdigits(tree->code[(uchar) *start_pos]), + (uint) tree->code_len[(uchar) *start_pos], + bindigits(tree->code[(uchar) *start_pos], + (uint) tree->code_len[(uchar) *start_pos]))); write_bits(tree->code[(uchar) *start_pos], (uint) tree->code_len[(uchar) *start_pos]); + } break; case FIELD_CONSTANT: case FIELD_ZERO: case FIELD_CHECK: + DBUG_PRINT("fields", ("FIELD_CONSTANT/ZERO/CHECK")); start_pos=end_pos; break; case FIELD_INTERVALL: @@ -1806,6 +2637,10 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) pos=(byte*) tree_search(&count->int_tree, start_pos, count->int_tree.custom_arg); intervall=(uint) (pos - count->tree_buff)/field_length; + DBUG_PRINT("fields", ("FIELD_INTERVALL")); + DBUG_PRINT("fields", ("index: %4u code: 0x%s bits: %2u", + intervall, hexdigits(tree->code[intervall]), + (uint) tree->code_len[intervall])); write_bits(tree->code[intervall],(uint) tree->code_len[intervall]); start_pos=end_pos; break; @@ -1814,21 +2649,36 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) ulong blob_length=_mi_calc_blob_length(field_length- mi_portable_sizeof_char_ptr, start_pos); + /* Empty blobs are encoded with a single 1 bit. */ if (!blob_length) { - write_bits(1,1); /* Empty blob */ + DBUG_PRINT("fields", ("FIELD_BLOB empty, bits: 1")); + write_bits(1,1); } else { byte *blob,*blob_end; + DBUG_PRINT("fields", ("FIELD_BLOB not empty, bits: 1")); write_bits(0,1); + /* Write the blob length. */ + DBUG_PRINT("fields", ("FIELD_BLOB %lu bytes, bits: %2u", + blob_length, count->length_bits)); write_bits(blob_length,count->length_bits); memcpy_fixed(&blob,end_pos-mi_portable_sizeof_char_ptr, sizeof(char*)); blob_end=blob+blob_length; + /* Encode the blob bytes. */ for ( ; blob < blob_end ; blob++) + { + DBUG_PRINT("fields", + ("value: 0x%02x code: 0x%s bits: %2u bin: %s", + (uchar) *blob, hexdigits(tree->code[(uchar) *blob]), + (uint) tree->code_len[(uchar) *blob], + bindigits(tree->code[(uchar) *start_pos], + (uint)tree->code_len[(uchar) *start_pos]))); write_bits(tree->code[(uchar) *blob], (uint) tree->code_len[(uchar) *blob]); + } tot_blob_length+=blob_length; } start_pos= end_pos; @@ -1839,18 +2689,34 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) uint pack_length= HA_VARCHAR_PACKLENGTH(count->field_length-1); ulong col_length= (pack_length == 1 ? (uint) *(uchar*) start_pos : uint2korr(start_pos)); + /* Empty varchar are encoded with a single 1 bit. */ if (!col_length) { + DBUG_PRINT("fields", ("FIELD_VARCHAR empty, bits: 1")); write_bits(1,1); /* Empty varchar */ } else { byte *end=start_pos+pack_length+col_length; + DBUG_PRINT("fields", ("FIELD_VARCHAR not empty, bits: 1")); write_bits(0,1); + /* Write the varchar length. */ + DBUG_PRINT("fields", ("FIELD_VARCHAR %lu bytes, bits: %2u", + col_length, count->length_bits)); write_bits(col_length,count->length_bits); + /* Encode the varchar bytes. */ for (start_pos+=pack_length ; start_pos < end ; start_pos++) + { + DBUG_PRINT("fields", + ("value: 0x%02x code: 0x%s bits: %2u bin: %s", + (uchar) *start_pos, + hexdigits(tree->code[(uchar) *start_pos]), + (uint) tree->code_len[(uchar) *start_pos], + bindigits(tree->code[(uchar) *start_pos], + (uint)tree->code_len[(uchar) *start_pos]))); write_bits(tree->code[(uchar) *start_pos], (uint) tree->code_len[(uchar) *start_pos]); + } } start_pos= end_pos; break; @@ -1859,12 +2725,17 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) abort(); /* Impossible */ } start_pos+=count->max_zero_fill; + DBUG_PRINT("fields", ("---")); } flush_bits(); - length=(ulong) (file_buffer.pos-record_pos)-max_pack_length; + length=(ulong) ((byte*) file_buffer.pos - record_pos) - max_pack_length; pack_length=save_pack_length(record_pos,length); if (pack_blob_length) pack_length+=save_pack_length(record_pos+pack_length,tot_blob_length); + DBUG_PRINT("fields", ("record: %lu length: %lu blob-length: %lu " + "length-bytes: %lu", (ulong) record_count, length, + tot_blob_length, pack_length)); + DBUG_PRINT("fields", ("===")); /* Correct file buffer if the header was smaller */ if (pack_length != max_pack_length) @@ -1876,9 +2747,11 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) min_record_length=(uint) length; if (length > (ulong) max_record_length) max_record_length=(uint) length; - if (write_loop && ++record_count % WRITE_COUNT == 0) + record_count++; + if (write_loop && record_count % WRITE_COUNT == 0) { - printf("%lu\r",(ulong) record_count); VOID(fflush(stdout)); + VOID(printf("%lu\r", (ulong) record_count)); + VOID(fflush(stdout)); } } else if (error != HA_ERR_RECORD_DELETED) @@ -1888,8 +2761,11 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) error=0; else { - fprintf(stderr,"%s: Got error %d reading records\n",my_progname,error); + VOID(fprintf(stderr, "%s: Got error %d reading records\n", + my_progname, error)); } + if (verbose >= 2) + VOID(printf("wrote %s records.\n", llstr((longlong) record_count, llbuf))); my_afree((gptr) record); mrg->ref_length=max_pack_length; @@ -1929,7 +2805,7 @@ static void init_file_buffer(File file, pbool read_buffer) file_buffer.pos=file_buffer.buffer; file_buffer.bits=BITS_SAVED; } - file_buffer.current_byte=0; + file_buffer.bitbucket= 0; } @@ -1972,7 +2848,8 @@ static int flush_buffer(ulong neaded_length) tmp=my_realloc(file_buffer.buffer, neaded_length,MYF(MY_WME)); if (!tmp) return 1; - file_buffer.pos= tmp + (ulong) (file_buffer.pos - file_buffer.buffer); + file_buffer.pos= ((uchar*) tmp + + (ulong) (file_buffer.pos - file_buffer.buffer)); file_buffer.buffer=tmp; file_buffer.end=tmp+neaded_length-8; } @@ -1987,68 +2864,59 @@ static void end_file_buffer(void) /* output `bits` low bits of `value' */ -static void write_bits (register ulong value, register uint bits) +static void write_bits(register ulonglong value, register uint bits) { - if ((file_buffer.bits-=(int) bits) >= 0) + DBUG_ASSERT(((bits < 8 * sizeof(value)) && ! (value >> bits)) || + (bits == 8 * sizeof(value))); + + if ((file_buffer.bits-= (int) bits) >= 0) { - file_buffer.current_byte|=value << file_buffer.bits; + file_buffer.bitbucket|= value << file_buffer.bits; } else { - reg3 uint byte_buff; + reg3 ulonglong bit_buffer; bits= (uint) -file_buffer.bits; - DBUG_ASSERT(bits <= 8 * sizeof(value)); - byte_buff= (file_buffer.current_byte | - ((bits != 8 * sizeof(value)) ? (uint) (value >> bits) : 0)); -#if BITS_SAVED == 32 - *file_buffer.pos++= (byte) (byte_buff >> 24) ; - *file_buffer.pos++= (byte) (byte_buff >> 16) ; + bit_buffer= (file_buffer.bitbucket | + ((bits != 8 * sizeof(value)) ? (value >> bits) : 0)); +#if BITS_SAVED == 64 + *file_buffer.pos++= (uchar) (bit_buffer >> 56); + *file_buffer.pos++= (uchar) (bit_buffer >> 48); + *file_buffer.pos++= (uchar) (bit_buffer >> 40); + *file_buffer.pos++= (uchar) (bit_buffer >> 32); #endif - *file_buffer.pos++= (byte) (byte_buff >> 8) ; - *file_buffer.pos++= (byte) byte_buff; + *file_buffer.pos++= (uchar) (bit_buffer >> 24); + *file_buffer.pos++= (uchar) (bit_buffer >> 16); + *file_buffer.pos++= (uchar) (bit_buffer >> 8); + *file_buffer.pos++= (uchar) (bit_buffer); - DBUG_ASSERT(bits <= 8 * sizeof(ulong)); if (bits != 8 * sizeof(value)) - value&= (((ulong) 1) << bits) - 1; -#if BITS_SAVED == 16 - if (bits >= sizeof(uint)) - { - bits-=8; - *file_buffer.pos++= (uchar) (value >> bits); - value&= (1 << bits)-1; - if (bits >= sizeof(uint)) - { - bits-=8; - *file_buffer.pos++= (uchar) (value >> bits); - value&= (1 << bits)-1; - } - } -#endif + value&= (((ulonglong) 1) << bits) - 1; if (file_buffer.pos >= file_buffer.end) VOID(flush_buffer(~ (ulong) 0)); file_buffer.bits=(int) (BITS_SAVED - bits); - file_buffer.current_byte=(uint) (value << (BITS_SAVED - bits)); + file_buffer.bitbucket= value << (BITS_SAVED - bits); } return; } /* Flush bits in bit_buffer to buffer */ -static void flush_bits (void) +static void flush_bits(void) { - uint bits,byte_buff; + int bits; + ulonglong bit_buffer; - bits=(file_buffer.bits) & ~7; - byte_buff = file_buffer.current_byte >> bits; - bits=BITS_SAVED - bits; + bits= file_buffer.bits & ~7; + bit_buffer= file_buffer.bitbucket >> bits; + bits= BITS_SAVED - bits; while (bits > 0) { - bits-=8; - *file_buffer.pos++= (byte) (uchar) (byte_buff >> bits) ; + bits-= 8; + *file_buffer.pos++= (uchar) (bit_buffer >> bits); } - file_buffer.bits=BITS_SAVED; - file_buffer.current_byte=0; - return; + file_buffer.bits= BITS_SAVED; + file_buffer.bitbucket= 0; } @@ -2196,3 +3064,131 @@ static int mrg_close(PACK_MRG_INFO *mrg) my_free((gptr) mrg->file,MYF(0)); return error; } + + +#if !defined(DBUG_OFF) +/* + Fake the counts to get big Huffman codes. + + SYNOPSIS + fakebigcodes() + huff_counts A pointer to the counts array. + end_count A pointer past the counts array. + + DESCRIPTION + + Huffman coding works by removing the two least frequent values from + the list of values and add a new value with the sum of their + incidences in a loop until only one value is left. Every time a + value is reused for a new value, it gets one more bit for its + encoding. Hence, the least frequent values get the longest codes. + + To get a maximum code length for a value, two of the values must + have an incidence of 1. As their sum is 2, the next infrequent value + must have at least an incidence of 2, then 4, 8, 16 and so on. This + means that one needs 2**n bytes (values) for a code length of n + bits. However, using more distinct values forces the use of longer + codes, or reaching the code length with less total bytes (values). + + To get 64(32)-bit codes, I sort the counts by decreasing incidence. + I assign counts of 1 to the two most frequent values, a count of 2 + for the next one, then 4, 8, and so on until 2**64-1(2**30-1). All + the remaining values get 1. That way every possible byte has an + assigned code, though not all codes are used if not all byte values + are present in the column. + + This strategy would work with distinct column values too, but + requires that at least 64(32) values are present. To make things + easier here, I cancel all distinct column values and force byte + compression for all columns. + + RETURN + void +*/ + +static void fakebigcodes(HUFF_COUNTS *huff_counts, HUFF_COUNTS *end_count) +{ + HUFF_COUNTS *count; + my_off_t *cur_count_p; + my_off_t *end_count_p; + my_off_t **cur_sort_p; + my_off_t **end_sort_p; + my_off_t *sort_counts[256]; + my_off_t total; + DBUG_ENTER("fakebigcodes"); + + for (count= huff_counts; count < end_count; count++) + { + /* + Remove distinct column values. + */ + if (huff_counts->tree_buff) + { + my_free((gptr) huff_counts->tree_buff, MYF(0)); + delete_tree(&huff_counts->int_tree); + huff_counts->tree_buff= NULL; + DBUG_PRINT("fakebigcodes", ("freed distinct column values")); + } + + /* + Sort counts by decreasing incidence. + */ + cur_count_p= count->counts; + end_count_p= cur_count_p + 256; + cur_sort_p= sort_counts; + while (cur_count_p < end_count_p) + *(cur_sort_p++)= cur_count_p++; + (void) qsort(sort_counts, 256, sizeof(my_off_t*), (qsort_cmp) fakecmp); + + /* + Assign faked counts. + */ + cur_sort_p= sort_counts; +#if SIZEOF_LONG_LONG > 4 + end_sort_p= sort_counts + 8 * sizeof(ulonglong) - 1; +#else + end_sort_p= sort_counts + 8 * sizeof(ulonglong) - 2; +#endif + /* Most frequent value gets a faked count of 1. */ + **(cur_sort_p++)= 1; + total= 1; + while (cur_sort_p < end_sort_p) + { + **(cur_sort_p++)= total; + total<<= 1; + } + /* Set the last value. */ + **(cur_sort_p++)= --total; + /* + Set the remaining counts. + */ + end_sort_p= sort_counts + 256; + while (cur_sort_p < end_sort_p) + **(cur_sort_p++)= 1; + } + DBUG_VOID_RETURN; +} + + +/* + Compare two counts for reverse sorting. + + SYNOPSIS + fakecmp() + count1 One count. + count2 Another count. + + RETURN + 1 count1 < count2 + 0 count1 == count2 + -1 count1 > count2 +*/ + +static int fakecmp(my_off_t **count1, my_off_t **count2) +{ + return ((**count1 < **count2) ? 1 : + (**count1 > **count2) ? -1 : 0); +} +#endif + + diff --git a/storage/myisammrg/Makefile.am b/storage/myisammrg/Makefile.am index 6975fab6770..14e3295c1ae 100644 --- a/storage/myisammrg/Makefile.am +++ b/storage/myisammrg/Makefile.am @@ -14,7 +14,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -INCLUDES = -I$(top_srcdir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include pkglib_LIBRARIES = libmyisammrg.a noinst_HEADERS = myrg_def.h libmyisammrg_a_SOURCES = myrg_open.c myrg_extra.c myrg_info.c myrg_locking.c \ diff --git a/storage/ndb/include/mgmcommon/ConfigRetriever.hpp b/storage/ndb/include/mgmcommon/ConfigRetriever.hpp index 95d257dea23..c0b877af07d 100644 --- a/storage/ndb/include/mgmcommon/ConfigRetriever.hpp +++ b/storage/ndb/include/mgmcommon/ConfigRetriever.hpp @@ -32,6 +32,7 @@ public: ~ConfigRetriever(); int do_connect(int no_retries, int retry_delay_in_seconds, int verbose); + int disconnect(); /** * Get configuration for current node. diff --git a/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp b/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp index eca886c8586..0e9b2a83e2f 100644 --- a/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp +++ b/storage/ndb/src/common/mgmcommon/ConfigRetriever.cpp @@ -107,6 +107,12 @@ ConfigRetriever::do_connect(int no_retries, 0 : -1; } +int +ConfigRetriever::disconnect() +{ + return ndb_mgm_disconnect(m_handle); +} + //**************************************************************************** //**************************************************************************** //**************************************************************************** diff --git a/storage/ndb/src/mgmsrv/main.cpp b/storage/ndb/src/mgmsrv/main.cpp index 3335fdc827c..c7315c61ba1 100644 --- a/storage/ndb/src/mgmsrv/main.cpp +++ b/storage/ndb/src/mgmsrv/main.cpp @@ -353,7 +353,8 @@ int main(int argc, char** argv) g_eventLogger.info("Shutting down server..."); glob.socketServer->stopServer(); - glob.socketServer->stopSessions(); + glob.mgmObject->get_config_retriever()->disconnect(); + glob.socketServer->stopSessions(true); g_eventLogger.info("Shutdown complete"); return 0; error_end: diff --git a/strings/Makefile.am b/strings/Makefile.am index a98908ad54a..5e02c7c1a2b 100644 --- a/strings/Makefile.am +++ b/strings/Makefile.am @@ -16,7 +16,7 @@ # This file is public domain and comes with NO WARRANTY of any kind -INCLUDES = -I$(top_srcdir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include pkglib_LIBRARIES = libmystrings.a # Exact one of ASSEMBLER_X diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index 5844a6e688b..408e511d2e8 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -223,7 +223,7 @@ static int my_strnncoll_ucs2(CHARSET_INFO *cs, t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].sort : t_wc; if ( s_wc != t_wc ) { - return ((int) s_wc) - ((int) t_wc); + return s_wc > t_wc ? 1 : -1; } s+=s_res; @@ -284,7 +284,7 @@ static int my_strnncollsp_ucs2(CHARSET_INFO *cs __attribute__((unused)), int t_wc = uni_plane[t[0]] ? (int) uni_plane[t[0]][t[1]].sort : (((int) t[0]) << 8) + (int) t[1]; if ( s_wc != t_wc ) - return s_wc - t_wc; + return s_wc > t_wc ? 1 : -1; s+= 2; t+= 2; @@ -1364,7 +1364,7 @@ int my_strnncoll_ucs2_bin(CHARSET_INFO *cs, } if ( s_wc != t_wc ) { - return ((int) s_wc) - ((int) t_wc); + return s_wc > t_wc ? 1 : -1; } s+=s_res; diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 53197972dab..de08c080b3b 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -2204,7 +2204,7 @@ static int my_strnncoll_utf8(CHARSET_INFO *cs, t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].sort : t_wc; if ( s_wc != t_wc ) { - return ((int) s_wc) - ((int) t_wc); + return s_wc > t_wc ? 1 : -1; } s+=s_res; @@ -2277,7 +2277,7 @@ static int my_strnncollsp_utf8(CHARSET_INFO *cs, t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].sort : t_wc; if ( s_wc != t_wc ) { - return ((int) s_wc) - ((int) t_wc); + return s_wc > t_wc ? 1 : -1; } s+=s_res; @@ -2790,7 +2790,7 @@ static void test_mb(CHARSET_INFO *cs, uchar *s) { while(*s) { - if(my_ismbhead_utf8(cs,*s)) + if (my_ismbhead_utf8(cs,*s)) { int len=my_mbcharlen_utf8(cs,*s); while(len--) diff --git a/strings/ctype.c b/strings/ctype.c index ba6dbaeb887..91fa1413259 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -218,14 +218,6 @@ static int cs_value(MY_XML_PARSER *st,const char *attr, uint len) struct my_cs_file_section_st *s; int state= (int)((s=cs_file_sec(st->attr, (int) strlen(st->attr))) ? s->state : 0); -#ifndef DBUG_OFF - if(0){ - char str[1024]; - mstr(str,attr,len,sizeof(str)-1); - printf("VALUE %d %s='%s'\n",state,st->attr,str); - } -#endif - switch (state) { case _CS_ID: i->cs.number= strtol(attr,(char**)NULL,10); diff --git a/strings/decimal.c b/strings/decimal.c index 18f920badd3..1d75502f0da 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -739,11 +739,20 @@ int decimal_shift(decimal_t *dec, int shift) beg= ROUND_UP(beg + 1) - 1; end= ROUND_UP(end) - 1; DBUG_ASSERT(new_point >= 0); - new_point= ROUND_UP(new_point) - 1; - for(; new_point > end; new_point--) - dec->buf[new_point]= 0; - for(; new_point < beg; new_point++) - dec->buf[new_point]= 0; + + /* We don't want negative new_point below */ + if (new_point != 0) + new_point= ROUND_UP(new_point) - 1; + + if (new_point > end) + do + { + dec->buf[new_point]=0; + }while (--new_point > end); + else + for (; new_point < beg; new_point++) + dec->buf[new_point]= 0; + dec->intg= digits_int; dec->frac= digits_frac; return err; @@ -1434,6 +1443,7 @@ decimal_round(decimal_t *from, decimal_t *to, int scale, intg1=ROUND_UP(from->intg + (((intg0 + frac0)>0) && (from->buf[0] == DIG_MAX))); dec1 *buf0=from->buf, *buf1=to->buf, x, y, carry=0; + int first_dig; sanity(to); @@ -1492,17 +1502,18 @@ decimal_round(decimal_t *from, decimal_t *to, int scale, { int do_inc= FALSE; DBUG_ASSERT(frac0+intg0 >= 0); - switch (round_digit) - { + switch (round_digit) { case 0: { dec1 *p0= buf0 + (frac1-frac0); for (; p0 > buf0; p0--) + { if (*p0) { do_inc= TRUE; break; - }; + } + } break; } case 5: @@ -1511,9 +1522,10 @@ decimal_round(decimal_t *from, decimal_t *to, int scale, do_inc= (x>5) || ((x == 5) && (mode == HALF_UP || (frac0+intg0 > 0 && *buf0 & 1))); break; - }; - default:; - }; + } + default: + break; + } if (do_inc) { if (frac0+intg0>0) @@ -1567,14 +1579,6 @@ decimal_round(decimal_t *from, decimal_t *to, int scale, *buf1=1; to->intg++; } - /* Here we check 999.9 -> 1000 case when we need to increase intg */ - else - { - int first_dig= to->intg % DIG_PER_DEC1; - /* first_dig==0 should be handled above in the 'if' */ - if (first_dig && (*buf1 >= powers10[first_dig])) - to->intg++; - } } else { @@ -1595,6 +1599,12 @@ decimal_round(decimal_t *from, decimal_t *to, int scale, } } } + + /* Here we check 999.9 -> 1000 case when we need to increase intg */ + first_dig= to->intg % DIG_PER_DEC1; + if (first_dig && (*buf1 >= powers10[first_dig])) + to->intg++; + if (scale<0) scale=0; diff --git a/strings/xml.c b/strings/xml.c index 17f1b400957..02ca3932c39 100644 --- a/strings/xml.c +++ b/strings/xml.c @@ -96,13 +96,13 @@ static int my_xml_scan(MY_XML_PARSER *p,MY_XML_ATTR *a) a->end=p->cur; lex=a->beg[0]; } - else if ( (p->cur[0]=='"') || (p->cur[0]=='\'') ) + else if ( (p->cur[0] == '"') || (p->cur[0] == '\'') ) { p->cur++; for( ; ( p->cur < p->end ) && (p->cur[0] != a->beg[0]); p->cur++) {} a->end=p->cur; - if (a->beg[0]==p->cur[0])p->cur++; + if (a->beg[0] == p->cur[0])p->cur++; a->beg++; my_xml_norm_text(a); lex=MY_XML_STRING; @@ -169,8 +169,8 @@ static int my_xml_leave(MY_XML_PARSER *p, const char *str, uint slen) int rc; /* Find previous '.' or beginning */ - for( e=p->attrend; (e>p->attr) && (e[0]!='.') ; e--); - glen = (uint) ((e[0]=='.') ? (p->attrend-e-1) : p->attrend-e); + for( e=p->attrend; (e>p->attr) && (e[0] != '.') ; e--); + glen = (uint) ((e[0] == '.') ? (p->attrend-e-1) : p->attrend-e); if (str && (slen != glen)) { @@ -199,7 +199,7 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len) while ( p->cur < p->end ) { MY_XML_ATTR a; - if(p->cur[0]=='<') + if (p->cur[0] == '<') { int lex; int question=0; @@ -207,40 +207,40 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len) lex=my_xml_scan(p,&a); - if (MY_XML_COMMENT==lex) + if (MY_XML_COMMENT == lex) { continue; } lex=my_xml_scan(p,&a); - if (MY_XML_SLASH==lex) + if (MY_XML_SLASH == lex) { - if(MY_XML_IDENT!=(lex=my_xml_scan(p,&a))) + if (MY_XML_IDENT != (lex=my_xml_scan(p,&a))) { sprintf(p->errstr,"1: %s unexpected (ident wanted)",lex2str(lex)); return MY_XML_ERROR; } - if(MY_XML_OK!=my_xml_leave(p,a.beg,(uint) (a.end-a.beg))) + if (MY_XML_OK != my_xml_leave(p,a.beg,(uint) (a.end-a.beg))) return MY_XML_ERROR; lex=my_xml_scan(p,&a); goto gt; } - if (MY_XML_EXCLAM==lex) + if (MY_XML_EXCLAM == lex) { lex=my_xml_scan(p,&a); exclam=1; } - else if (MY_XML_QUESTION==lex) + else if (MY_XML_QUESTION == lex) { lex=my_xml_scan(p,&a); question=1; } - if (MY_XML_IDENT==lex) + if (MY_XML_IDENT == lex) { - if(MY_XML_OK!=my_xml_enter(p,a.beg,(uint) (a.end-a.beg))) + if (MY_XML_OK != my_xml_enter(p,a.beg,(uint) (a.end-a.beg))) return MY_XML_ERROR; } else @@ -250,17 +250,18 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len) return MY_XML_ERROR; } - while ((MY_XML_IDENT==(lex=my_xml_scan(p,&a))) || (MY_XML_STRING==lex)) + while ((MY_XML_IDENT == (lex=my_xml_scan(p,&a))) || + (MY_XML_STRING == lex)) { MY_XML_ATTR b; - if(MY_XML_EQ==(lex=my_xml_scan(p,&b))) + if (MY_XML_EQ == (lex=my_xml_scan(p,&b))) { lex=my_xml_scan(p,&b); - if ( (lex==MY_XML_IDENT) || (lex==MY_XML_STRING) ) + if ( (lex == MY_XML_IDENT) || (lex == MY_XML_STRING) ) { - if((MY_XML_OK!=my_xml_enter(p,a.beg,(uint) (a.end-a.beg))) || - (MY_XML_OK!=my_xml_value(p,b.beg,(uint) (b.end-b.beg))) || - (MY_XML_OK!=my_xml_leave(p,a.beg,(uint) (a.end-a.beg)))) + if ((MY_XML_OK != my_xml_enter(p,a.beg,(uint) (a.end-a.beg))) || + (MY_XML_OK != my_xml_value(p,b.beg,(uint) (b.end-b.beg))) || + (MY_XML_OK != my_xml_leave(p,a.beg,(uint) (a.end-a.beg)))) return MY_XML_ERROR; } else @@ -270,19 +271,19 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len) return MY_XML_ERROR; } } - else if ( (MY_XML_STRING==lex) || (MY_XML_IDENT==lex) ) + else if ((MY_XML_STRING == lex) || (MY_XML_IDENT == lex)) { - if((MY_XML_OK!=my_xml_enter(p,a.beg,(uint) (a.end-a.beg))) || - (MY_XML_OK!=my_xml_leave(p,a.beg,(uint) (a.end-a.beg)))) + if ((MY_XML_OK != my_xml_enter(p,a.beg,(uint) (a.end-a.beg))) || + (MY_XML_OK != my_xml_leave(p,a.beg,(uint) (a.end-a.beg)))) return MY_XML_ERROR; } else break; } - if (lex==MY_XML_SLASH) + if (lex == MY_XML_SLASH) { - if(MY_XML_OK!=my_xml_leave(p,NULL,0)) + if (MY_XML_OK != my_xml_leave(p,NULL,0)) return MY_XML_ERROR; lex=my_xml_scan(p,&a); } @@ -290,23 +291,23 @@ int my_xml_parse(MY_XML_PARSER *p,const char *str, uint len) gt: if (question) { - if (lex!=MY_XML_QUESTION) + if (lex != MY_XML_QUESTION) { sprintf(p->errstr,"6: %s unexpected ('?' wanted)",lex2str(lex)); return MY_XML_ERROR; } - if(MY_XML_OK!=my_xml_leave(p,NULL,0)) + if (MY_XML_OK != my_xml_leave(p,NULL,0)) return MY_XML_ERROR; lex=my_xml_scan(p,&a); } if (exclam) { - if(MY_XML_OK!=my_xml_leave(p,NULL,0)) + if (MY_XML_OK != my_xml_leave(p,NULL,0)) return MY_XML_ERROR; } - if (lex!=MY_XML_GT) + if (lex != MY_XML_GT) { sprintf(p->errstr,"5: %s unexpected ('>' wanted)",lex2str(lex)); return MY_XML_ERROR; @@ -315,11 +316,11 @@ gt: else { a.beg=p->cur; - for ( ; (p->cur < p->end) && (p->cur[0]!='<') ; p->cur++); + for ( ; (p->cur < p->end) && (p->cur[0] != '<') ; p->cur++); a.end=p->cur; my_xml_norm_text(&a); - if (a.beg!=a.end) + if (a.beg != a.end) { my_xml_value(p,a.beg,(uint) (a.end-a.beg)); } @@ -381,7 +382,7 @@ uint my_xml_error_pos(MY_XML_PARSER *p) const char *s; for ( s=p->beg ; s<p->cur; s++) { - if (s[0]=='\n') + if (s[0] == '\n') beg=s; } return (uint) (p->cur-beg); @@ -391,9 +392,9 @@ uint my_xml_error_lineno(MY_XML_PARSER *p) { uint res=0; const char *s; - for ( s=p->beg ; s<p->cur; s++) + for (s=p->beg ; s<p->cur; s++) { - if (s[0]=='\n') + if (s[0] == '\n') res++; } return res; diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 9df255a611a..0fa668b29ac 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -179,7 +179,7 @@ Summary: MySQL - server with extended functionality Group: Applications/Databases Provides: mysql-Max Obsoletes: mysql-Max -Requires: MySQL-server >= 4.0 +Requires: MySQL-server >= @MYSQL_BASE_VERSION@ %description Max Optional MySQL server binary that supports additional features like: diff --git a/tests/Makefile.am b/tests/Makefile.am index ee3e31aa040..ca7f04c91f9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -37,7 +37,8 @@ noinst_PROGRAMS = insert_test select_test thread_test # # C Test for 4.1 protocol # -INCLUDES = -I$(top_srcdir)/include $(openssl_includes) +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ + $(openssl_includes) LIBS = @CLIENT_LIBS@ LDADD = @CLIENT_EXTRA_LDFLAGS@ \ $(top_builddir)/libmysql/libmysqlclient.la diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 8debf7614a3..b237387ef35 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -13332,6 +13332,318 @@ static void test_bug9992() mysql_close(mysql1); } +/* Bug#10736: cursors and subqueries, memroot management */ + +static void test_bug10736() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + char a[21]; + int rc; + const char *stmt_text; + int i= 0; + ulong type; + + myheader("test_bug10736"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key," + "name VARCHAR(20) NOT NULL)"); + rc= mysql_query(mysql, "insert into t1 (id, name) values " + "(1, 'aaa'), (2, 'bbb'), (3, 'ccc')"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + type= (ulong) CURSOR_TYPE_READ_ONLY; + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); + check_execute(stmt, rc); + stmt_text= "select name from t1 where name=(select name from t1 where id=2)"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void*) a; + bind[0].buffer_length= sizeof(a); + mysql_stmt_bind_result(stmt, bind); + + for (i= 0; i < 3; i++) + { + int row_no= 0; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + if (!opt_silent) + printf("%d: %s\n", row_no, a); + ++row_no; + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + } + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + +/* Bug#10794: cursors, packets out of order */ + +static void test_bug10794() +{ + MYSQL_STMT *stmt, *stmt1; + MYSQL_BIND bind[2]; + char a[21]; + int id_val; + ulong a_len; + int rc; + const char *stmt_text; + int i= 0; + ulong type; + + myheader("test_bug10794"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key," + "name varchar(20) not null)"); + stmt= mysql_stmt_init(mysql); + stmt_text= "insert into t1 (id, name) values (?, ?)"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void*) &id_val; + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (void*) a; + bind[1].length= &a_len; + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + for (i= 0; i < 34; i++) + { + id_val= (i+1)*10; + sprintf(a, "a%d", i); + a_len= strlen(a); /* safety against broken sprintf */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + stmt_text= "select name from t1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + stmt1= mysql_stmt_init(mysql); + mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void*) a; + bind[0].buffer_length= sizeof(a); + bind[0].length= &a_len; + rc= mysql_stmt_bind_result(stmt, bind); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent) + printf("Fetched row from stmt: %s\n", a); + /* Don't optimize: an attribute of the original test case */ + mysql_stmt_free_result(stmt); + mysql_stmt_reset(stmt); + stmt_text= "select name from t1 where id=10"; + rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text)); + check_execute(stmt1, rc); + rc= mysql_stmt_bind_result(stmt1, bind); + check_execute(stmt1, rc); + rc= mysql_stmt_execute(stmt1); + while (1) + { + rc= mysql_stmt_fetch(stmt1); + if (rc == MYSQL_NO_DATA) + { + if (!opt_silent) + printf("End of data in stmt1\n"); + break; + } + check_execute(stmt1, rc); + if (!opt_silent) + printf("Fetched row from stmt1: %s\n", a); + } + mysql_stmt_close(stmt); + mysql_stmt_close(stmt1); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* Bug#11172: cursors, crash on a fetch from a datetime column */ + +static void test_bug11172() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind_in[1], bind_out[2]; + MYSQL_TIME hired; + int rc; + const char *stmt_text; + int i= 0, id; + ulong type; + + myheader("test_bug11172"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key," + "hired date not null)"); + rc= mysql_query(mysql, + "insert into t1 (id, hired) values (1, '1933-08-24'), " + "(2, '1965-01-01'), (3, '1949-08-17'), (4, '1945-07-07'), " + "(5, '1941-05-15'), (6, '1978-09-15'), (7, '1936-03-28')"); + myquery(rc); + stmt= mysql_stmt_init(mysql); + stmt_text= "SELECT id, hired FROM t1 WHERE hired=?"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + bzero(bind_in, sizeof(bind_in)); + bzero(bind_out, sizeof(bind_out)); + bzero(&hired, sizeof(hired)); + hired.year= 1965; + hired.month= 1; + hired.day= 1; + bind_in[0].buffer_type= MYSQL_TYPE_DATE; + bind_in[0].buffer= (void*) &hired; + bind_in[0].buffer_length= sizeof(hired); + bind_out[0].buffer_type= MYSQL_TYPE_LONG; + bind_out[0].buffer= (void*) &id; + bind_out[1]= bind_in[0]; + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_bind_param(stmt, bind_in); + check_execute(stmt, rc); + rc= mysql_stmt_bind_result(stmt, bind_out); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + if (!opt_silent) + printf("fetched data %d:%d-%d-%d\n", id, + hired.year, hired.month, hired.day); + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + mysql_stmt_free_result(stmt) || mysql_stmt_reset(stmt); + } + mysql_stmt_close(stmt); + mysql_rollback(mysql); + mysql_rollback(mysql); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* Bug#11656: cursors, crash on a fetch from a query with distinct. */ + +static void test_bug11656() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[2]; + int rc; + const char *stmt_text; + char buf[2][20]; + int i= 0; + ulong type; + + myheader("test_bug11656"); + + mysql_query(mysql, "drop table if exists t1"); + + rc= mysql_query(mysql, "create table t1 (" + "server varchar(40) not null, " + "test_kind varchar(1) not null, " + "test_id varchar(30) not null , " + "primary key (server,test_kind,test_id))"); + myquery(rc); + + stmt_text= "select distinct test_kind, test_id from t1 " + "where server in (?, ?)"; + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + bzero(bind, sizeof(bind)); + strcpy(buf[0], "pcint502_MY2"); + strcpy(buf[1], "*"); + for (i=0; i < 2; i++) + { + bind[i].buffer_type= MYSQL_TYPE_STRING; + bind[i].buffer= (gptr *)&buf[i]; + bind[i].buffer_length= strlen(buf[i]); + } + mysql_stmt_bind_param(stmt, bind); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* + Check that the server signals when NO_BACKSLASH_ESCAPES mode is in effect, + and mysql_real_escape_string() does the right thing as a result. +*/ + +static void test_bug10214() +{ + MYSQL_RES* res ; + int len; + char out[8]; + + myheader("test_bug10214"); + + DIE_UNLESS(!(mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)); + + len= mysql_real_escape_string(mysql, out, "a'b\\c", 5); + DIE_UNLESS(memcmp(out, "a\\'b\\\\c", len) == 0); + + mysql_query(mysql, "set sql_mode='NO_BACKSLASH_ESCAPES'"); + DIE_UNLESS(mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES); + + len= mysql_real_escape_string(mysql, out, "a'b\\c", 5); + DIE_UNLESS(memcmp(out, "a''b\\c", len) == 0); + + mysql_query(mysql, "set sql_mode=''"); +} + +static void test_client_character_set() +{ + MY_CHARSET_INFO cs; + const char *csname; + int rc; + + myheader("test_client_character_set"); + + csname = "utf8"; + rc = mysql_set_character_set(mysql, csname); + DIE_UNLESS(rc == 0); + + mysql_get_character_set_info(mysql, &cs); + DIE_UNLESS(!strcmp(cs.csname, "utf8")); + DIE_UNLESS(!strcmp(cs.name, "utf8_general_ci")); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -13555,6 +13867,7 @@ static struct my_tests_st my_tests[]= { { "test_cursors_with_union", test_cursors_with_union }, { "test_truncation", test_truncation }, { "test_truncation_option", test_truncation_option }, + { "test_client_character_set", test_client_character_set }, { "test_bug8330", test_bug8330 }, { "test_bug7990", test_bug7990 }, { "test_bug8378", test_bug8378 }, @@ -13567,6 +13880,11 @@ static struct my_tests_st my_tests[]= { { "test_bug10729", test_bug10729 }, { "test_bug11111", test_bug11111 }, { "test_bug9992", test_bug9992 }, + { "test_bug10736", test_bug10736 }, + { "test_bug10794", test_bug10794 }, + { "test_bug11172", test_bug11172 }, + { "test_bug11656", test_bug11656 }, + { "test_bug10214", test_bug10214 }, { 0, 0 } }; diff --git a/tools/Makefile.am b/tools/Makefile.am index 651ef2d22b3..0f726bd5fc3 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -20,11 +20,11 @@ if HAVE_YASSL else yassl_dummy_link_fix= endif -INCLUDES=-I$(top_srcdir)/include $(openssl_includes) \ - -I$(top_builddir)/include -LDADD= @CLIENT_EXTRA_LDFLAGS@ \ - $(top_builddir)/libmysql_r/libmysqlclient_r.la \ - @openssl_libs@ @ZLIB_LIBS@ +INCLUDES= -I$(top_builddir)/include -I$(top_srcdir)/include \ + $(openssl_includes) +LDADD= @CLIENT_EXTRA_LDFLAGS@ \ + $(top_builddir)/libmysql_r/libmysqlclient_r.la \ + @openssl_libs@ @ZLIB_LIBS@ bin_PROGRAMS= mysqltestmanager mysqltestmanager_SOURCES= mysqlmanager.c $(yassl_dummy_link_fix) mysqltestmanager_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) diff --git a/vio/Makefile.am b/vio/Makefile.am index cd4212089c4..0d4f052b30a 100644 --- a/vio/Makefile.am +++ b/vio/Makefile.am @@ -19,7 +19,8 @@ if HAVE_YASSL else yassl_dummy_link_fix= endif -INCLUDES= -I$(top_srcdir)/include $(openssl_includes) +INCLUDES= -I$(top_builddir)/include -I$(top_srcdir)/include \ + $(openssl_includes) LDADD= @CLIENT_EXTRA_LDFLAGS@ $(openssl_libs) pkglib_LIBRARIES= libvio.a noinst_PROGRAMS = test-ssl test-sslserver test-sslclient diff --git a/vio/viossl.c b/vio/viossl.c index 9a5eb1eb8df..7528e9071cf 100644 --- a/vio/viossl.c +++ b/vio/viossl.c @@ -316,7 +316,7 @@ int sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio, long timeout) vio_blocking(vio, net_blocking, &unused); DBUG_RETURN(1); } -#ifndef DBUF_OFF +#ifndef DBUG_OFF DBUG_PRINT("info",("SSL_get_cipher_name() = '%s'" ,SSL_get_cipher_name((SSL*) vio->ssl_arg))); client_cert = SSL_get_peer_certificate ((SSL*) vio->ssl_arg); |