diff options
333 files changed, 7199 insertions, 3865 deletions
diff --git a/.bzrignore b/.bzrignore index 18ad5e18be6..6746bb863b7 100644 --- a/.bzrignore +++ b/.bzrignore @@ -38,7 +38,11 @@ COPYING.LIB Docs/#manual.texi# Docs/INSTALL-BINARY Docs/include.texi +Docs/internals.html Docs/internals.info +Docs/internals.pdf +Docs/internals.txt +Docs/internals_toc.html Docs/manual.aux Docs/manual.cp Docs/manual.cps @@ -239,6 +243,7 @@ client/select_test client/ssl_test client/thimble client/thread_test +client_test cmd-line-utils/libedit/common.h comon.h config.cache @@ -287,6 +292,7 @@ innobase/conftest.subs innobase/ib_config.h innobase/ib_config.h.in innobase/stamp-h1 +insert_test isam/isamchk isam/isamlog isam/pack_isam @@ -513,6 +519,7 @@ scripts/mysqld_safe scripts/mysqldumpslow scripts/mysqlhotcopy scripts/safe_mysqld +select_test sql-bench/Results-linux/ATIS-mysql_bdb-Linux_2.2.14_my_SMP_i686 sql-bench/bench-count-distinct sql-bench/bench-init.pl @@ -578,6 +585,7 @@ strings/ctype_autoconf.c strings/ctype_extra_sources.c support-files/MacOSX/Description.plist support-files/MacOSX/Info.plist +support-files/MacOSX/ReadMe.txt support-files/MacOSX/StartupParameters.plist support-files/MacOSX/postinstall support-files/MacOSX/preinstall @@ -597,6 +605,7 @@ support-files/mysql.spec tags test_xml tests/client_test +thread_test tmp/* tools/my_vsnprintf.c tools/mysqlmanager @@ -607,7 +616,3 @@ vio/test-ssl vio/test-sslclient vio/test-sslserver vio/viotest-ssl -client_test -thread_test -select_test -insert_test diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 9a092b84a8f..4a19c490e5d 100644 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -52,7 +52,7 @@ debug_cflags="-DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS -DSAFEMA base_cxxflags="-felide-constructors -fno-exceptions -fno-rtti" -base_configs="--prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client" +base_configs="--prefix=/usr/local/mysql --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-readline" static_link="--with-mysqld-ldflags=-all-static --with-client-ldflags=-all-static" alpha_configs="" # Not used yet pentium_configs="" @@ -71,4 +71,6 @@ else make=make fi -CXX=gcc +if test -z $CXX ; then + CXX=gcc +fi diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index b6f9647ea49..0f0947a8305 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -51,6 +51,7 @@ miguel@hegel.br miguel@hegel.local miguel@light. miguel@light.local +mmatthew@markslaptop. monty@bitch.mysql.fi monty@butch. monty@donna.mysql.fi @@ -67,6 +68,7 @@ mwagner@cash.mwagner.org mwagner@evoq.mwagner.org mwagner@work.mysql.com mysql@home.(none) +mysqldev@build.mysql2.com nick@mysql.com nick@nick.leippe.com papa@gbichot.local @@ -75,6 +77,7 @@ paul@teton.kitebird.com pem@mysql.com peter@linux.local peter@mysql.com +peterg@mysql.com pgulutzan@linux.local ram@gw.udmsearch.izhnet.ru ram@mysql.r18.ru diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile index b499e3059b3..07657c0bdeb 100755 --- a/Build-tools/Do-compile +++ b/Build-tools/Do-compile @@ -276,7 +276,11 @@ if ($opt_stage <= 3) my $flags= ""; log_timestamp(); log_system("rm -fr mysql-3* mysql-4* $pwd/$host/*.tar.gz"); - log_system("nm -n sql/mysqld | gzip -9 -v 2>&1 > sql/mysqld.sym.gz | cat"); + # No need to add the debug symbols, if the binaries are not stripped (saves space) + unless ($opt_with_debug || $opt_no_strip) + { + log_system("nm -n sql/mysqld | gzip -9 -v 2>&1 > sql/mysqld.sym.gz | cat"); + } $flags.= "--no-strip" if ($opt_no_strip || $opt_with_debug); check_system("scripts/make_binary_distribution --tmp=$opt_tmp --suffix=$opt_suffix $flags",".tar.gz created"); diff --git a/Docs/Makefile.am b/Docs/Makefile.am index af771a5728d..00eb936c408 100644 --- a/Docs/Makefile.am +++ b/Docs/Makefile.am @@ -27,7 +27,7 @@ EXTRA_DIST = $(noinst_SCRIPTS) $(BUILT_SOURCES) mysqld_error.txt \ all: $(targets) txt_files txt_files: ../INSTALL-SOURCE ../COPYING ../COPYING.LIB \ - INSTALL-BINARY + INSTALL-BINARY ../support-files/MacOSX/ReadMe.txt CLEAN_FILES: $(BUILD_SOURCES) touch $(BUILD_SOURCES) @@ -254,5 +254,8 @@ INSTALL-BINARY: mysql.info $(GT) ../COPYING.LIB: mysql.info $(GT) perl -w $(GT) mysql.info "LGPL license" "Function Index" > $@ +../support-files/MacOSX/ReadMe.txt: mysql.info $(GT) + perl -w $(GT) mysql.info "Mac OS X installation" "Netware installation" > $@ + # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/Docs/internals.texi b/Docs/internals.texi index 9f9b08b96c3..ddaedbe5b9b 100644 --- a/Docs/internals.texi +++ b/Docs/internals.texi @@ -43,20 +43,19 @@ END-INFO-DIR-ENTRY @page @end titlepage -@node Top, caching, (dir), (dir) +@node Top, coding guidelines, (dir), (dir) @ifinfo This is a manual about @strong{MySQL} internals. @end ifinfo @menu +* coding guidelines:: Coding Guidelines * caching:: How MySQL Handles Caching -* join_buffer_size:: * flush tables:: How MySQL Handles @code{FLUSH TABLES} -* filesort:: How MySQL Does Sorting (@code{filesort}) -* selects:: How MySQL performs different selects -* transformations:: How MySQL transforms subqueries -* coding guidelines:: Coding Guidelines +* Algorithms:: +* selects:: How MySQL performs different selects +* transformations:: How MySQL transforms subqueries * mysys functions:: Functions In The @code{mysys} Library * DBUG:: DBUG Tags To Use * protocol:: MySQL Client/Server Protocol @@ -69,7 +68,166 @@ This is a manual about @strong{MySQL} internals. @end menu -@node caching, join_buffer_size, Top, Top +@node coding guidelines, caching, Top, Top +@chapter Coding Guidelines + +@itemize @bullet + +@item +We use @uref{http://www.bitkeeper.com/, BitKeeper} for source management. + +@item +You should use the @strong{MySQL} 4.1 or 5.0 source for all developments. + +@item +If you have any questions about the @strong{MySQL} source, you can post these +to @email{internals@@lists.mysql.com} and we will answer them. + +@item +Try to write code in a lot of black boxes that can be reused or use at +least a clean, easy to change interface. + +@item +Reuse code; There is already a lot of algorithms in MySQL for list handling, +queues, dynamic and hashed arrays, sorting, etc. that can be reused. + +@item +Use the @code{my_*} functions like @code{my_read()}/@code{my_write()}/ +@code{my_malloc()} that you can find in the @code{mysys} library instead +of the direct system calls; This will make your code easier to debug and +more portable. + +@item +Try to always write optimized code, so that you don't have to +go back and rewrite it a couple of months later. It's better to +spend 3 times as much time designing and writing an optimal function than +having to do it all over again later on. + +@item +Avoid CPU wasteful code, even where it does not matter, so that +you will not develop sloppy coding habits. + +@item +If you can write it in fewer lines, do it (as long as the code will not +be slower or much harder to read). + +@item +Don't use two commands on the same line. + +@item +Do not check the same pointer for @code{NULL} more than once. + +@item +Use long function and variable names in English. This makes your code +easier to read. + +@item +Use @code{my_var} as opposed to @code{myVar} or @code{MyVar} (@samp{_} +rather than dancing SHIFT to seperate words in identifiers). + +@item +Think assembly - make it easier for the compiler to optimize your code. + +@item +Comment your code when you do something that someone else may think +is not ``trivial''. + +@item +Use @code{libstring} functions (in the @file{strings} directory) +instead of standard @code{libc} string functions whenever possible. + +@item +Avoid using @code{malloc()} (its REAL slow); For memory allocations +that only need to live for the lifetime of one thread, one should use +@code{sql_alloc()} instead. + +@item +Before making big design decisions, please first post a summary of +what you want to do, why you want to do it, and how you plan to do +it. This way we can easily provide you with feedback and also +easily discuss it thoroughly if some other developer thinks there is better +way to do the same thing! + +@item +Class names start with a capital letter. + +@item +Structure types are @code{typedef}'ed to an all-caps identifier. + +@item +Any @code{#define}'s are in all-caps. + +@item +Matching @samp{@{} are in the same column. + +@item +Put the @samp{@{} after a @code{switch} on the same line, as this gives +better overall indentation for the switch statement: + +@example +switch (arg) @{ +@end example + +@item +In all other cases, @samp{@{} and @samp{@}} should be on their own line, except +if there is nothing inside @samp{@{} and @samp{@}}. + +@item +Have a space after @code{if} + +@item +Put a space after @samp{,} for function arguments + +@item +Functions return @samp{0} on success, and non-zero on error, so you can do: + +@example +if(a() || b() || c()) @{ error("something went wrong"); @} +@end example + +@item +Using @code{goto} is okay if not abused. + +@item +Avoid default variable initalizations, use @code{LINT_INIT()} if the +compiler complains after making sure that there is really no way +the variable can be used uninitialized. + +@item +Do not instantiate a class if you do not have to. + +@item +Use pointers rather than array indexing when operating on strings. + +@end itemize + +Suggested mode in emacs: + +@example +(load "cc-mode") +(setq c-mode-common-hook '(lambda () + (turn-on-font-lock) + (setq comment-column 48))) +(setq c-style-alist + (cons + '("MY" + (c-basic-offset . 2) + (c-comment-only-line-offset . 0) + (c-offsets-alist . ((statement-block-intro . +) + (knr-argdecl-intro . 0) + (substatement-open . 0) + (label . -) + (statement-cont . +) + (arglist-intro . c-lineup-arglist-intro-after-paren) + (arglist-close . c-lineup-arglist) + )) + ) + c-style-alist)) +(c-set-style "MY") +(setq c-default-style "MY") +@end example + +@node caching, flush tables, coding guidelines, Top @chapter How MySQL Handles Caching @strong{MySQL} has the following caches: @@ -111,8 +269,12 @@ the found rows are cached in a join cache. One @code{SELECT} query can use many join caches in the worst case. @end table -@node join_buffer_size, flush tables, caching, Top -@chapter How MySQL uses the join_buffer cache +@menu +* join_buffer_size:: +@end menu + +@node join_buffer_size, , caching, caching +@section How MySQL uses the join_buffer cache Basic information about @code{join_buffer_size}: @@ -183,7 +345,7 @@ same algorithm described above to handle it. (In other words, we store the same row combination several times into different buffers) @end itemize -@node flush tables, filesort, join_buffer_size, Top +@node flush tables, Algorithms, caching, Top @chapter How MySQL Handles @code{FLUSH TABLES} @itemize @bullet @@ -228,8 +390,19 @@ After this it will give other threads a chance to open the same tables. @end itemize -@node filesort, selects, flush tables, Top -@chapter How MySQL Does Sorting (@code{filesort}) +@node Algorithms, selects, flush tables, Top +@chapter Different algoritms used in MySQL + +MySQL uses a lot of different algorithms. This chapter tries to describe +some of these: + +@menu +* filesort:: +* bulk-insert:: +@end menu + +@node filesort, bulk-insert, Algorithms, Algorithms +@section How MySQL Does Sorting (@code{filesort}) @itemize @bullet @@ -268,10 +441,38 @@ and then we read the rows in the sorted order into a row buffer @end itemize -@node selects, transformations, flush tables, Top +@end itemize + +@node bulk-insert, , filesort, Algorithms +@section Bulk insert + +Logic behind bulk insert optimisation is simple. + +Instead of writing each key value to b-tree (that is to keycache, but +bulk insert code doesn't know about keycache) keys are stored in +balanced binary (red-black) tree, in memory. When this tree reaches its +memory limit it's writes all keys to disk (to keycache, that is). But +as key stream coming from the binary tree is already sorted inserting +goes much faster, all the necessary pages are already in cache, disk +access is minimized, etc. + +@node selects, transformations, Algorithms, Top @chapter How MySQL performs different selects -@node select steps,,, +@menu +* select steps:: +* select select_result:: +* select simple:: +* select structure:: +* select union:: +* select derived:: +* select subselect:: +* select select engine:: +* select union engine:: +* selectexplain:: +@end menu + +@node select steps, select select_result, selects, selects @section Steps of select executing Every select performed in such base steps: @@ -317,7 +518,7 @@ Every select performed in such base steps: @end itemize @end itemize -@node select select_result +@node select select_result, select simple, select steps, selects @section select_result CLASS Very important role in SELECT performing have select_result class and @@ -349,7 +550,7 @@ For example there are fillowing select_result classes: @strong{multi_update} used for multi-update @end itemize -@node select simple +@node select simple, select structure, select select_result, selects @section SIMPLE or PRIMARY SELECT. For performing single primary select SELECT used function mysql_select, @@ -369,7 +570,7 @@ which: In previous versions of mysql all SELECTs was performed with help of this function and mysql_select() was not divided on parts. -@node select structure +@node select structure, select union, select simple, selects @section Structure Of Complex Select There 2 structures which describe SELECTS: @@ -425,7 +626,7 @@ LEX::current_select points to SELECT_LEX_UNIT of this unit to store this parameter in this SELECT_LEX_UNIT (SELECT_LEX and SELECT_LEX_UNIT are inherited from st_select_lex_node). -@node select union +@node select union, select derived, select structure, selects @section Non-Subselect UNIONs Executing Non subselect unions performed with help of mysql_union(). for now it @@ -468,7 +669,7 @@ this SELECT_LEX with JOIN on this mysql_select() session. PROBLEM: this fake select need workaround in many places. -@node select derived +@node select derived, select subselect, select union, selects @section Derived Tables Executing Derived tables processing is first operation on any query. It performed @@ -507,7 +708,7 @@ mysql_derived(): second parameter of it (bool skip_derived) will be true. @end itemize -@node select subselect +@node select subselect, select select engine, select derived, selects @section Subselects In expression subselect represented by Item inherited from Item_subselect. @@ -546,7 +747,7 @@ Item_select will never call cleanup() procedure for JOIN. Every JOIN::cleanup will call cleanup() for inner JOINs. Most upper JOIN::cleanup will be called by mysql_select() or mysql_union(). -@node select select engine +@node select select engine, select union engine, select subselect, selects @section Single Select Engine subselect_single_select_engine: @@ -565,7 +766,7 @@ subselect_single_select_engine: JOIN::exec() depending of type of subquery. @end itemize -@node select union engine +@node select union engine, selectexplain, select select engine, selects @section Union Engine subselect_union_engine: @@ -585,7 +786,7 @@ subselect_union_engine: st_select_lex_unit::item is not 0. @end itemize -@node selectexplain +@node selectexplain, , select union engine, selects @section Explain Execution For EXPLAIN result showing for every SELECT will be called mysql_select @@ -611,20 +812,31 @@ mysql_explain_union for every inner UNION PROBLEM: how it will work with global query optimization? -@node transformations, coding guidelines, selects, Top +@node transformations, mysys functions, selects, Top @chapter How MySQL transforms subqueries Item_subselect virtual method select_transformer is used to rewrite subqueries. It is called from Item_subselect::init (which called in Item_subselect constructor) -@node transformation IN +@menu +* transformation IN:: +* transformations all any:: +* transformations singlerow:: +@end menu + +@node transformation IN, transformations all any, transformations, transformations @section Item_in_subselect::select_transformer Item_in_subselect::select_transformer is divided on two parts for scalar left part and row left part: -@node transformation scalar IN +@menu +* transformation scalar IN:: +* transformations row IN:: +@end menu + +@node transformation scalar IN, transformations row IN, transformation IN, transformation IN @subsection Scalar IN Subselect To rewrite scalar IN subselect used method @@ -777,7 +989,7 @@ If subselect have not HAVING, sum function or GROUP BY (case b) then: Single select without FROM will be reduced to just <left_expression> = <item> without using Item_in_optimizer. -@node transformations row IN +@node transformations row IN, , transformation scalar IN, transformation IN @subsection Row IN Subselect To rewrite row IN subselect used method @@ -809,7 +1021,7 @@ In this way will be transformed select without FROM, too. For other subselect it will be same but for WHERE clause. -@node transformations all any +@node transformations all any, transformations singlerow, transformation IN, transformations @section Item_allany_subselect Item_allany_subselect is inherited from Item_in_subselect. @@ -821,7 +1033,7 @@ ANY/SOME use same function that was listed after left expression. ALL use inverted function, and all subselect passed as argument to Item_func_not. -@node transformations singlerow +@node transformations singlerow, , transformations all any, transformations @section Item_singlerow_subselect Item_singlerow_subselect will be rewritten only if it have not FROM @@ -854,168 +1066,7 @@ expression is Item_fields or Item_ref then name of this new item will be same as name of this item (but not '(SELECT ...)'). It is done to prevent broke references on such items from more inner subselects. -@node coding guidelines, mysys functions, transformations, Top -@chapter Coding Guidelines - -@itemize @bullet - -@item -We are using @uref{http://www.bitkeeper.com/, BitKeeper} for source management. - -@item -You should use the @strong{MySQL} 4.0 source for all developments. - -@item -If you have any questions about the @strong{MySQL} source, you can post these -to @email{dev-public@@mysql.com} and we will answer them. Please -remember to not use this internal email list in public! - -@item -Try to write code in a lot of black boxes that can be reused or use at -least a clean, easy to change interface. - -@item -Reuse code; There is already a lot of algorithms in MySQL for list handling, -queues, dynamic and hashed arrays, sorting, etc. that can be reused. - -@item -Use the @code{my_*} functions like @code{my_read()}/@code{my_write()}/ -@code{my_malloc()} that you can find in the @code{mysys} library instead -of the direct system calls; This will make your code easier to debug and -more portable. - -@item -Try to always write optimized code, so that you don't have to -go back and rewrite it a couple of months later. It's better to -spend 3 times as much time designing and writing an optimal function than -having to do it all over again later on. - -@item -Avoid CPU wasteful code, even where it does not matter, so that -you will not develop sloppy coding habits. - -@item -If you can write it in fewer lines, do it (as long as the code will not -be slower or much harder to read). - -@item -Don't use two commands on the same line. - -@item -Do not check the same pointer for @code{NULL} more than once. - -@item -Use long function and variable names in English. This makes your code -easier to read. - -@item -Use @code{my_var} as opposed to @code{myVar} or @code{MyVar} (@samp{_} -rather than dancing SHIFT to seperate words in identifiers). - -@item -Think assembly - make it easier for the compiler to optimize your code. - -@item -Comment your code when you do something that someone else may think -is not ``trivial''. - -@item -Use @code{libstring} functions (in the @file{strings} directory) -instead of standard @code{libc} string functions whenever possible. - -@item -Avoid using @code{malloc()} (its REAL slow); For memory allocations -that only need to live for the lifetime of one thread, one should use -@code{sql_alloc()} instead. - -@item -Before making big design decisions, please first post a summary of -what you want to do, why you want to do it, and how you plan to do -it. This way we can easily provide you with feedback and also -easily discuss it thoroughly if some other developer thinks there is better -way to do the same thing! - -@item -Class names start with a capital letter. - -@item -Structure types are @code{typedef}'ed to an all-caps identifier. - -@item -Any @code{#define}'s are in all-caps. - -@item -Matching @samp{@{} are in the same column. - -@item -Put the @samp{@{} after a @code{switch} on the same line, as this gives -better overall indentation for the switch statement: - -@example -switch (arg) @{ -@end example - -@item -In all other cases, @samp{@{} and @samp{@}} should be on their own line, except -if there is nothing inside @samp{@{} and @samp{@}}. - -@item -Have a space after @code{if} - -@item -Put a space after @samp{,} for function arguments - -@item -Functions return @samp{0} on success, and non-zero on error, so you can do: - -@example -if(a() || b() || c()) @{ error("something went wrong"); @} -@end example - -@item -Using @code{goto} is okay if not abused. - -@item -Avoid default variable initalizations, use @code{LINT_INIT()} if the -compiler complains after making sure that there is really no way -the variable can be used uninitialized. - -@item -Do not instantiate a class if you do not have to. - -@item -Use pointers rather than array indexing when operating on strings. - -@end itemize - -Suggested mode in emacs: - -@example -(load "cc-mode") -(setq c-mode-common-hook '(lambda () - (turn-on-font-lock) - (setq comment-column 48))) -(setq c-style-alist - (cons - '("MY" - (c-basic-offset . 2) - (c-comment-only-line-offset . 0) - (c-offsets-alist . ((statement-block-intro . +) - (knr-argdecl-intro . 0) - (substatement-open . 0) - (label . -) - (statement-cont . +) - (arglist-intro . c-lineup-arglist-intro-after-paren) - (arglist-close . c-lineup-arglist) - )) - ) - c-style-alist)) -(c-set-style "MY") -(setq c-default-style "MY") -@end example - - -@node mysys functions, DBUG, coding guidelines, Top +@node mysys functions, DBUG, transformations, Top @chapter Functions In The @code{mysys} Library Functions in @code{mysys}: (For flags see @file{my_sys.h}) @@ -1211,6 +1262,16 @@ Print query. * fieldtype codes:: * protocol functions:: * protocol version 2:: +* 4.1 protocol changes:: +* 4.1 field packet:: +* 4.1 field desc:: +* 4.1 ok packet:: +* 4.1 end packet:: +* 4.1 error packet:: +* 4.1 prep init:: +* 4.1 long data:: +* 4.1 execute:: +* 4.1 binary result:: @end menu @node raw packet without compression, raw packet with compression, protocol, protocol @@ -1332,6 +1393,7 @@ For details, see @file{sql/net_pkg.cc::send_ok()}. @node communication, fieldtype codes, basic packets, protocol @section Communication +@example > Packet from server to client < Paket from client tor server @@ -1419,7 +1481,7 @@ For details, see @file{sql/net_pkg.cc::send_ok()}. 4 byte header 1-8 byte length of data n data - +@end example @node fieldtype codes, protocol functions, communication, protocol @section Fieldtype Codes @@ -1448,7 +1510,9 @@ Date 03 0A 00 00 |01 0A |03 00 00 00 @node protocol functions, protocol version 2, fieldtype codes, protocol @section Functions used to implement the protocol -This should be merged with the above one and changed to texi format +@c This should be merged with the above one and changed to texi format + +@example Raw packets ----------- @@ -1553,12 +1617,14 @@ The encrypted message is sent to the server which uses the stored random number password to encrypt the random string sent to the client. If this is equal to the new message the client sends to the server then the password is accepted. +@end example -@node protocol version 2, , protocol functions, protocol +@node protocol version 2, 4.1 protocol changes, protocol functions, protocol @section Another description of the protocol -This should be merged with the above one and changed to texi format. +@c This should be merged with the above one and changed to texi format. +@example ***************************** * * PROTOCOL OVERVIEW @@ -2233,7 +2299,7 @@ one packet is sent from the server, for simplicity's sake): Followed immediately by one 'LAST DATA' packet: fe 00 . . - +@end example @c The Index was empty, and ugly, so I removed it. (jcole, Sep 7, 2000) @@ -2246,7 +2312,7 @@ fe 00 . . @c @node 4.1 protocol,,, @c @chapter MySQL 4.1 protocol -@node 4.1 protocol changes,,, +@node 4.1 protocol changes, 4.1 field packet, protocol version 2, protocol @section Changes to 4.0 protocol in 4.1 All basic packet handling is identical to 4.0. When communication @@ -2281,7 +2347,7 @@ results will sent as binary (low-byte-first). @end itemize -@node 4.1 field packet,,, +@node 4.1 field packet, 4.1 field desc, 4.1 protocol changes, protocol @section 4.1 field description packet The field description packet is sent as a response to a query that @@ -2301,7 +2367,7 @@ uses this to send the number of rows in the table) This packet is always followed by a field description set. @xref{4.1 field desc}. -@node 4.1 field desc,,, +@node 4.1 field desc, 4.1 ok packet, 4.1 field packet, protocol @section 4.1 field description result set The field description result set contains the meta info for a result set. @@ -2326,7 +2392,7 @@ The field description result set contains the meta info for a result set. @end multitable -@node 4.1 ok packet,,, +@node 4.1 ok packet, 4.1 end packet, 4.1 field desc, protocol @section 4.1 ok packet The ok packet is the first that is sent as an response for a query @@ -2352,7 +2418,7 @@ The message is optional. For example for multi line INSERT it contains a string for how many rows was inserted / deleted. -@node 4.1 end packet,,, +@node 4.1 end packet, 4.1 error packet, 4.1 ok packet, protocol @section 4.1 end packet The end packet is sent as the last packet for @@ -2381,7 +2447,7 @@ by checking the packet length < 9 bytes (in which case it's and end packet). -@node 4.1 error packet +@node 4.1 error packet, 4.1 prep init, 4.1 end packet, protocol @section 4.1 error packet. The error packet is sent when something goes wrong. @@ -2398,7 +2464,7 @@ The client/server protocol is designed in such a way that a packet can only start with 255 if it's an error packet. -@node 4.1 prep init,,, +@node 4.1 prep init, 4.1 long data, 4.1 error packet, protocol @section 4.1 prepared statement init packet This is the return packet when one sends a query with the COM_PREPARE @@ -2433,7 +2499,7 @@ prepared statement will contain a result set. In this case the packet is followed by a field description result set. @xref{4.1 field desc}. -@node 4.1 long data,,, +@node 4.1 long data, 4.1 execute, 4.1 prep init, protocol @section 4.1 long data handling This is used by mysql_send_long_data() to set any parameter to a string @@ -2460,7 +2526,7 @@ The server will NOT send an @code{ok} or @code{error} packet in responce for this. If there is any errors (like to big string), one will get the error when calling execute. -@node 4.1 execute,,, +@node 4.1 execute, 4.1 binary result, 4.1 long data, protocol @section 4.1 execute On execute we send all parameters to the server in a COM_EXECUTE @@ -2498,7 +2564,7 @@ The parameters are stored the following ways: The result for this will be either an ok packet or a binary result set. -@node 4.1 binary result,,, +@node 4.1 binary result, , 4.1 execute, protocol @section 4.1 binary result set A binary result are sent the following way. @@ -2589,7 +2655,7 @@ When you say: @* MySQL creates files named Table1.MYD ("MySQL Data"), Table1.MYI -("MySQL Index"), and Table1.FRM ("Format"). These files will be in the +("MySQL Index"), and Table1.frm ("Format"). These files will be in the directory: @* /<datadir>/<database>/ @* @@ -2604,12 +2670,15 @@ And if you use Windows, you might find the files in this directory: @* @*@* Let's look at the .MYD Data file (MyISAM SQL Data file) more closely. +There are three possible formats -- fixed, dynamic, and packed. First, +let's discuss the fixed format. + @table @strong @item Page Size Unlike most DBMSs, MySQL doesn't store on disk using pages. Therefore you will not see filler space between rows. (Reminder: This does not -refer to BDB and INNODB tables, which do use pages). +refer to BDB and InnoDB tables, which do use pages). @* @item Record Header @@ -2625,6 +2694,12 @@ The minimal record header is a set of flags: @end table @* +The length of the record header is thus:@* +(1 + number of NULL columns + 7) / 8 bytes@* +After the header, all columns are stored in +the order that they were created, which is the +same order that you would get from SHOW COLUMNS. + Here's an example. Suppose you say: @* @@ -2667,10 +2742,73 @@ right is @code{on}, and (b) remember that the first flag bit is the X bit.) There are complications -- the record header is more complex if there are variable-length fields -- but the simple display shown in the -example is exactly what you'd see if you took a debugger and looked -at the MySQL Data file. +example is exactly what you'd see if you looked at the MySQL Data file +with a debugger or a hexadecimal file dumper. +@* + +So much for the fixed format. Now, let's discuss the dynamic format. +@* + +The dynamic file format is necessary if rows can vary in size. That will +be the case if there are BLOB columns, or "true" VARCHAR columns. (Remember +that MySQL may treat VARCHAR columns as if they're CHAR columns, in which +case the fixed format is used.) A dynamic row has more fields in the header. +The important ones are "the actual length", "the unused length", and "the +overflow pointer". The actual length is the total number of bytes in all the +columns. The unused length is the total number of bytes between one physical +record and the next one. The overflow pointer is the location of the rest of +the record if there are multiple parts. +@* + +For example, here is a dynamic row: +@* +@example +03, 00 start of header +04 actual length +0c unused length +01, fc flags + overflow pointer +**** data in the row +************ unused bytes + <-- next row starts here) +@end example + +In the example, the actual length and the unused length +are short (one byte each) because the table definition +says that the columns are short -- if the columns were +potentially large, then the actual length and the unused +length could be two bytes each, three bytes each, and so +on. In this case, actual length plus unused length is 10 +hexadecimal (sixteen decimal), which is a minimum. + +As for the third format -- packed -- we will only say +briefly that: +@itemize @bullet +@item +Numeric values are stored in a form that depends on the +range (start/end values) for the data type. +@item +All columns are packed using either Huffman or enum coding. +@end itemize + +For details, see the source files /myisam/mi_statrec.c +(for fixed format), /myisam/mi_dynrec.c (for dynamic +format), and /myisam/mi_packrec.c (for packed format). + +Note: Internally, MySQL uses a format much like the fixed format +which it uses for disk storage. The main differences are: +@enumerate +@item +BLOBs have a length and a memory pointer rather than being stored inline. +@item +"True VARCHAR" (a column storage which will be fully implemented in +version 5.0) will have a 16-bit length plus the data. +@item +All integer or floating-point numbers are stored with the low byte first. +Point (3) does not apply for ISAM storage or internals. +@end enumerate @* + @section Physical Attributes of Columns Next I'll describe the physical attributes of each column in a row. @@ -2701,8 +2839,8 @@ Example: a VARCHAR(7) column containing 'A' looks like:@* @item The numeric data types -Important: MySQL stores all multi-byte binary numbers with the -high byte first. This is called "little-endian" numeric storage; +Important: MySQL almost always stores multi-byte binary numbers with +the low byte first. This is called "little-endian" numeric storage; it's normal on Intel x86 machines; MySQL uses it even for non-Intel machines so that databases will be portable. @* @@ -2877,7 +3015,7 @@ Example: a SET('A','B','C') column containing 'A' looks like:@* Storage: one byte if less than 256 alternatives, else two bytes. @item This is an index. The value 1 corresponds to the first listed -alternative. (Note: ENUM always reserves 0 for a blank '' value. This +alternative. (Note: ENUM always reserves 0 for an erroneous value. This explains why 'A' is 1 instead of 0.) @item Example: an ENUM('A','B','C') column containing 'A' looks like:@* @@ -2893,9 +3031,6 @@ of correspondence between the BLOB and the INT types. There isn't -- a BLOB's preceding length is not four bytes long (the size of an INT). @* -(NOTE TO SELF: BLOB storage has not been fully addressed here.) -@* - @strong{TINYBLOB} @itemize @bullet @item @@ -2962,10 +3097,13 @@ Storage: same as LONGBLOB. @strong{References:} @* Most of the formatting work for MyISAM columns is visible -in the program /sql/field.cc in the source code directory. +in the program /sql/field.cc in the source code directory. +And in the MyISAM directory, the files that do formatting +work for different record formats are: /myisam/mi_statrec.c, +/myisam/mi_dynrec.c, and /myisam/mi_packrec.c. @* -@node InnoDB Record Structure,InnoDB Page Structure,MyISAM Record Structure,Top +@node InnoDB Record Structure, InnoDB Page Structure, MyISAM Record Structure, Top @chapter InnoDB Record Structure This page contains: @@ -3271,7 +3409,7 @@ shorter because the NULLs take no space. The most relevant InnoDB source-code files are rem0rec.c, rem0rec.ic, and rem0rec.h in the rem ("Record Manager") directory. -@node InnoDB Page Structure,Files in MySQL Sources,InnoDB Record Structure,Top +@node InnoDB Page Structure, Files in MySQL Sources, InnoDB Record Structure, Top @chapter InnoDB Page Structure InnoDB stores all records inside a fixed-size unit which is commonly called a @@ -3702,12 +3840,12 @@ header. The most relevant InnoDB source-code files are page0page.c, page0page.ic, and page0page.h in \page directory. -@node Files in MySQL Sources,Files in InnoDB Sources,InnoDB Page Structure,Top +@node Files in MySQL Sources, Files in InnoDB Sources, InnoDB Page Structure, Top @chapter Annotated List Of Files in the MySQL Source Code Distribution This is a description of the files that you get when you download the source code of MySQL. This description begins with a list -of the 43 directories and a short comment about each one. Then, for +of the main directories and a short comment about each one. Then, for each directory, in alphabetical order, a longer description is supplied. When a directory contains significant program files, a list of each C program is given along with an explanation of its intended function. @@ -3717,47 +3855,37 @@ program is given along with an explanation of its intended function. @strong{Directory -- Short Comment} @itemize @bullet @item -bdb -- The Berkeley Database table handler -@item -BitKeeper -- BitKeeper administration -@item -BUILD -- Build switches -@item -Build-tools -- Build tools +bdb -- The Berkeley Database table handler @item -client -- Client library +BitKeeper -- BitKeeper administration (not part of the source distribution) @item -cmd-line-utils -- Command-line utilities +BUILD -- Frequently used build scripts @item -dbug -- Fred Fish's dbug library +Build-tools -- Build tools (not part of the source distribution) @item -div -- Deadlock test +client -- Client library @item -Docs -- Preliminary documents about internals and new modules +cmd-line-utils -- Command-line utilities (libedit and readline) @item -extra -- Eight minor standalone utility programs +dbug -- Fred Fish's dbug library @item -fs -- File System +Docs -- Preliminary documents about internals and new modules; will eventually be moved to the mysqldoc repository @item -heap -- The HEAP table handler +extra -- Some minor standalone utility programs @item -Images -- Empty directory +heap -- The HEAP table handler @item -include -- Include (*.h) files +include -- Header (*.h) files for most libraries; includes all header files distributed with the MySQL binary distribution @item -innobase -- The Innobase (InnoDB) table handler +innobase -- The Innobase (InnoDB) table handler @item -isam -- The ISAM (MySQL) table handler +libmysql -- For producing MySQL as a library (e.g. a Windows .DLL) @item -libmysql -- For producing MySQL as a library (e.g. a Windows DLL) +libmysql_r -- For building a thread-safe libmysql library @item -libmysql_r -- Only one file, a makefile +libmysqld -- The MySQL Server as an embeddable library @item -libmysqld -- The MySQL Library -@item -man -- Manual pages -@item -merge -- The MERGE table handler (see Reference Manual section 7.2) +man -- Some user-contributed manual pages @item myisam -- The MyISAM table handler @item @@ -3765,45 +3893,41 @@ myisammrg -- The MyISAM Merge table handler @item mysql-test -- A test suite for mysqld @item -mysys -- MySQL system library (Low level routines for file access -etc.) +mysys -- MySQL system library (Low level routines for file access etc.) @item netware -- Files related to the Novell NetWare version of MySQL @item -NEW-RPMS -- New "RPM Package Manager" files +NEW-RPMS -- Directory to place RPMs while making a distribution @item -os2 -- Routines for working with the OS/2 operating system +os2 -- Routines for working with the OS/2 operating system @item -pstack -- Process stack display +pstack -- Process stack display (not currently used) @item -regex -- Regular Expression library for support of REGEXP function +regex -- Henry Spencer's Regular Expression library for support of REGEXP function @item -repl-tests -- Test cases for replication +SCCS -- Source Code Control System (not part of source distribution) @item -SCCS -- Source Code Control System +scripts -- SQL batches, e.g. mysqlbug and mysql_install_db @item -scripts -- SQL batches, e.g. for converting msql to MySQL -@item -sql -- Programs for handling SQL commands. The "core" of MySQL +sql -- Programs for handling SQL commands; the "core" of MySQL @item sql-bench -- The MySQL benchmarks @item -SSL -- Secure Sockets Layer +SSL -- Secure Sockets Layer; includes an example certification one can use to test an SSL (secure) database connection @item strings -- Library for C string routines, e.g. atof, strchr @item -support-files -- 15 files used for building, containing switches? +support-files -- Files used to build MySQL on different systems @item -tests -- Tests in Perl +tests -- Tests in Perl and in C @item -tools -- mysqlmanager.c +tools -- mysqlmanager.c (tool under development, not yet useful) @item -VC++Files -- Includes this entire directory, repeated for VC++ -(Windows) use +VC++Files -- Includes this entire directory, repeated for VC++ (Windows) use @item vio -- Virtual I/O Library @item -zlib -- data compression library +zlib -- Data compression library, used on Windows @end itemize @subsection bdb @@ -3812,6 +3936,8 @@ The Berkeley Database table handler. @*@* The Berkeley Database (BDB) is maintained by Sleepycat Software. +MySQL AB maintains only a few small patches to make BDB work +better with MySQL. @*@* The documentation for BDB is available at @@ -3825,15 +3951,21 @@ in this document. BitKeeper administration. @*@* -This directory may be present if you downloaded the MySQL source using +Bitkeeper administration is not part of the source distribution. This +directory may be present if you downloaded the MySQL source using BitKeeper rather than via the mysql.com site. The files in the BitKeeper directory are for maintenance purposes only -- they are not part of the MySQL package. @*@* +The MySQL Reference Manual explains how to use Bitkeeper to get the +MySQL source. Please see @url{http://www.mysql.com/doc/en/Installing_source_tree.html} +for more information. +@*@* + @subsection BUILD -Build switches. +Frequently used build scripts. @*@* This directory contains the build switches for compilation on various @@ -3856,10 +3988,11 @@ solaris Build tools. @*@* -This directory contains batch files for extracting, making -directories, and making programs from source files. There are several -subdirectories -- for building Linux executables, for compiling, for -performing all build steps, etc. +Build-tools is not part of the source distribution. This directory +contains batch files for extracting, making directories, and making +programs from source files. There are several subdirectories with +different scripts -- for building Linux executables, for compiling, +for performing all build steps, and so on. @*@* @subsection client @@ -3877,56 +4010,40 @@ server. The C program files in the directory are: @itemize @bullet @item -connect_test.c -- test that a connect is possible -@item -get_password.c -- ask for a password from the console -@item -insert_test.c -- test that an insert is possible -@item -list_test.c -- test that a select is possible +get_password.c -- ask for a password from the console @item -mysql.cc -- "The MySQL command tool" +mysql.cc -- "The MySQL command tool" @item -mysqladmin.c -- maintenance of MYSQL databases +mysqladmin.c -- maintenance of MySQL databases @item -mysqlcheck.c -- check all databases, check connect, etc. +mysqlcheck.c -- check all databases, check connect, etc. @item -mysqldump.c -- dump table's contents in ascii +mysqldump.c -- dump table's contents as SQL statements, suitable to backup a MySQL database @item -mysqlimport.c -- import file into a table +mysqlimport.c -- import text files in different formats into tables @item -mysqlmanager-pwgen.c -- pwgen seems to stand for "password -generation" +mysqlmanager-pwgen.c -- pwgen stands for "password generation" (not currently maintained) @item -mysqlmanagerc.c -- entry point for mysql manager +mysqlmanagerc.c -- entry point for mysql manager (not currently maintained) @item mysqlshow.c -- show databases, tables or columns @item -mysqltest.c -- test program +mysqltest.c -- test program used by the mysql-test suite, mysql-test-run @item -password.c -- password checking routines -@item -select_test.c -- test that a select is possible -@item -showdb_test.c -- test that a show-databases is possible -@item -ssl_test.c -- test that SSL is possible -@item -thread_test.c -- test that threading is possible +password.c -- password checking routines (version 4.1 and up) @end itemize @*@* @subsection cmd-line-utils -Command-line utilities. +Command-line utilities (libedit and readline). @*@* There are two subdirectories: \readline and \libedit. All the files -here are "non-MYSQL" files, in the sense that MySQL AB didn't produce +here are "non-MySQL" files, in the sense that MySQL AB didn't produce them, it just uses them. It should be unnecessary to study the -programs in these files unless -you are writing or debugging a tty-like client for MySQL, such as -mysql.exe. +programs in these files unless you are writing or debugging a tty-like +client for MySQL, such as mysql.exe. @*@* The \readline subdirectory contains the files of the GNU Readline @@ -3936,51 +4053,54 @@ Software Foundation. @*@* The \libedit (library of edit functions) subdirectory has files -written by Christos Zoulas. They are for editing the line contents. +written by Christos Zoulas. They are distributed and modifed under +the BSD License. These files are for editing the line contents. +@*@* + These are the program files in the \libedit subdirectory: @itemize @bullet @item -chared.c -- character editor +chared.c -- character editor @item -common.c -- common editor functions +common.c -- common editor functions @item -el.c -- editline interface functions +el.c -- editline interface functions @item -emacs.c -- emacs functions +emacs.c -- emacs functions @item -fgetln.c -- get line +fgetln.c -- get line @item -hist.c -- history access functions +hist.c -- history access functions @item -history.c -- more history access functions +history.c -- more history access functions @item -key.c -- procedures for maintaining the extended-key map +key.c -- procedures for maintaining the extended-key map @item -map.c -- editor function definitions +map.c -- editor function definitions @item -parse.c -- parse an editline extended command +parse.c -- parse an editline extended command @item -prompt.c -- prompt printing functions +prompt.c -- prompt printing functions @item -read.c -- terminal read functions +read.c -- terminal read functions @item -readline.c -- read line +readline.c -- read line @item -refresh.c -- "lower level screen refreshing functions" +refresh.c -- "lower level screen refreshing functions" @item -search.c -- "history and character search functions" +search.c -- "history and character search functions" @item -sig.c -- for signal handling +sig.c -- for signal handling @item -strlcpy.c -- string copy +strlcpy.c -- string copy @item -term.c -- "editor/termcap-curses interface" +term.c -- "editor/termcap-curses interface" @item -tokenizer.c -- Bourne shell line tokenizer +tokenizer.c -- Bourne shell line tokenizer @item -tty.c -- for a tty interface +tty.c -- for a tty interface @item -vi.c -- commands used when in the vi (editor) mode +vi.c -- commands used when in the vi (editor) mode @end itemize @*@* @@ -3991,6 +4111,8 @@ Fred Fish's dbug library. This is not really part of the MySQL package. Rather, it's a set of public-domain routines which are useful for debugging MySQL programs. +The MySQL Server and all .c and .cc programs support the use of this +package. @*@* How it works: One inserts a function call that begins with DBUG_* in @@ -4000,68 +4122,62 @@ DBUG_ENTER("get_tty_password"); @* at the start of a routine, and this line: @* DBUG_RETURN(my_strdup(to,MYF(MY_FAE))); @* at the end of the routine. These lines don't affect production code. -Features of the dbug library include profiling and state pushing. +Features of the dbug library include extensive reporting and profiling +(the latter has not been used by the MySQL team). @*@* The C programs in this directory are: @itemize @bullet @item -dbug.c -- The main module +dbug.c -- The main module @item -dbug_analyze.c -- Reads a file produced by trace functions +dbug_analyze.c -- Reads a file produced by trace functions @item -example1.c -- A tiny example +example1.c -- A tiny example @item -example2.c -- A tiny example +example2.c -- A tiny example @item -example3.c -- A tiny example +example3.c -- A tiny example @item -factorial.c -- A tiny example +factorial.c -- A tiny example @item -main.c -- A tiny example +main.c -- A tiny example @item -sanity.c -- Declaration of a variable +sanity.c -- Declaration of a variable @end itemize @*@* -@subsection div - -Deadlock test. -@*@* - -This file contains only one program, deadlock_test.c. -@*@* - @subsection Docs -Preliminary documents about internals and new modules. +Preliminary documents about internals and new modules, which will eventually +be moved to the mysqldoc repository. @*@* This directory doesn't have much at present that's very useful to the student, but the plan is that some documentation related to the source files and the internal workings of MySQL, including perhaps some -documentation from developers themselves, will be placed here. +documentation from developers themselves, will be placed here. Files in +this directory will eventually be moved to the MySQL documentation repository. @*@* These sub-directories are part of this directory: @itemize @bullet @item -books -- .gif images and empty .txt files; no real information +books -- .gif images and empty .txt files; no real information @item -flags -- images of flags of countries +flags -- images of flags of countries @item -images -- flag backgrounds and the MySQL dolphin logo +images -- flag backgrounds and the MySQL dolphin logo @item -mysql-logos -- more MySQL-related logos, some of them moving +mysql-logos -- more MySQL-related logos, some of them moving @item -raw-flags -- more country flags, all .gif files +raw-flags -- more country flags, all .gif files @item -support -- various files for generating texinfo/docbook -documentation +support -- various files for generating texinfo/docbook documentation @item -to-be-included... -- an empty subdirectory +to-be-included... -- contains a MySQL-for-dummies file @item -translations -- some Portuguese myodbc documentation +translations -- some Portuguese myodbc documentation @end itemize @*@* @@ -4072,74 +4188,38 @@ has any importance -- internals.texi -- The "MySQL Internals" document. @*@* -Despite the name, internals.texi is not really much of a description -of MySQL internals. However, there is some useful description of the -functions in the mysys directory (see below), and of the structure of -client/server messages (doubtless very useful for people who want to -make their own JDBC drivers, or just sniff). +Despite the name, internals.texi is not yet much of a description of MySQL +internals although work is in progress to make it so. However, there is +some useful description of the functions in the mysys directory (see below), +and of the structure of client/server messages (doubtless very useful for +eople who want to make their own JDBC drivers, or just sniff). @*@* @subsection extra -Eight minor standalone utility programs. +Some minor standalone utility programs. @*@* -These eight programs are all standalone utilities, that is, they have +These programs are all standalone utilities, that is, they have a main() function and their main role is to show information that the MySQL server needs or produces. Most are unimportant. They are as follows: @itemize @bullet @item -my_print_defaults.c -- print all parameters in a default file -@item -mysql_install.c -- startup: install MySQL server +my_print_defaults.c -- print parameters from my.ini files. Can also be used in scripts to enable processing of my.ini files. @item -mysql_waitpid.c -- wait for a program to terminate +mysql_waitpid.c -- wait for a program to terminate. Useful for shell scripts when one needs to wait until a process terminates. @item -perror.c -- "print error" -- given error number, display message +perror.c -- "print error" -- given error number, display message @item -replace.c -- replace strings in text files +replace.c -- replace strings in text files or pipe @item -resolve_stack_dump.c -- show symbolic info from a stack dump +resolve_stack_dump.c -- show symbolic information from a MySQL stack dump, normally found in the mysql.err file @item -resolveip.c -- convert an IP address to a hostname, or vice versa +resolveip.c -- convert an IP address to a hostname, or vice versa @end itemize @*@* -@subsection fs - -File System. -@*@* - -Here the word "File System" does not refer to the mere idea of a -directory of files on a disk drive, but to object-based access. The -concept has been compared with Oracle's Internet File System (iFS). -@*@* - -The original developer of the files on this directory is Tonu Samuel, -a former MySQL AB employee. Here is a quote (somewhat edited) from -Tonu Samuel's web page (http://no.spam.ee/~tonu/index.php): -"Question: What is it? -Answer: Actually this is not filesystem in common terms. MySQL FS -makes it possible to make SQL tables and some functions available over -a filesystem. MySQL does not require disk space, it uses an ordinary -MySQL daemon to store data." -The descriptions imply that this is a development project. -@*@* - -There are four program files in the directory: -@itemize @bullet -@item -database.c -- "emulate filesystem behaviour on top of SQL database" -@item -libmysqlfs.c -- Search/replace, show-functions, and parse routines -@item -mysqlcorbafs.c -- Connection with the CORBA "Object Request Broker" -@item -mysqlcorbafs_test.c -- Utility to test the working of mysqlcorbafs.c - -@*@* - @subsection heap The HEAP table handler. @@ -4151,59 +4231,63 @@ produces) have files with similar names and functions. Thus, this (for the MyISAM table handler). Such duplicates have been marked with an "*" in the following list. For example, you will find that \heap\hp_extra.c has a close equivalent in the myisam directory -(\myisam\mi_extra.c) with the same descriptive comment. +(\myisam\mi_extra.c) with the same descriptive comment. (Some of the +differences arise because HEAP has different structures. HEAP does not +need to use the sort of B-tree indexing that ISAM and MyISAM use; instead +there is a hash index. Most importantly, HEAP is entirely in memory. +File-I/O routines lose some of their vitality in such a context.) @*@* +@itemize @item hp_block.c -- Read/write a block (i.e. a page) @item -hp_clear.c -- Remove all records in the database +hp_clear.c -- Remove all records in the table @item -hp_close.c -- * close database +hp_close.c -- * close database @item -hp_create.c -- * create a table +hp_create.c -- * create a table @item -hp_delete.c -- * delete a row +hp_delete.c -- * delete a row @item hp_extra.c -- * for setting options and buffer sizes when optimizing @item -hp_hash.c -- Hash functions used for saving keys +hp_hash.c -- Hash functions used for saving keys @item -hp_info.c -- * Information about database status +hp_info.c -- * Information about database status @item -hp_open.c -- * open database +hp_open.c -- * open database @item -hp_panic.c -- * the hp_panic routine, probably for sudden shutdowns +hp_panic.c -- * the hp_panic routine, for shutdowns and flushes @item -hp_rename.c -- * rename a table +hp_rename.c -- * rename a table @item hp_rfirst.c -- * read first row through a specific key (very short) @item -hp_rkey.c -- * read record using a key +hp_rkey.c -- * read record using a key @item hp_rlast.c -- * read last row with same key as previously-read row @item hp_rnext.c -- * read next row with same key as previously-read row @item -hp_rprev.c -- * read previous row with same key as previously-read -row +hp_rprev.c -- * read previous row with same key as previously-read row @item -hp_rrnd.c -- * read a row based on position +hp_rrnd.c -- * read a row based on position @item hp_rsame.c -- * find current row using positional read or key-based -read +read @item -hp_scan.c -- * read all rows sequentially +hp_scan.c -- * read all rows sequentially @item hp_static.c -- * static variables (very short) @item -hp_test1.c -- * testing basic functions +hp_test1.c -- * testing basic functions @item -hp_test2.c -- * testing database and storing results +hp_test2.c -- * testing database and storing results @item -hp_update.c -- * update an existing row +hp_update.c -- * update an existing row @item -hp_write.c -- * insert a new row +hp_write.c -- * insert a new row @end itemize @*@* @@ -4213,17 +4297,10 @@ for a \myisam\mi_cache.c equivalent (to cache reads) or a \myisam\log.c equivalent (to log statements). @*@* -@subsection Images - -Empty directory. -@*@* - -There are no files in this directory. -@*@* - @subsection include -Include (*.h) files. +Header (*.h) files for most libraries; includes all header files distributed +with the MySQL binary distribution. @*@* These files may be included in C program files. Note that each @@ -4238,7 +4315,7 @@ rijndael.h. Looking further, you'll find that rijndael.h is also included in other places: by my_aes.c and my_aes.h. @*@* -The include directory contains 51 *.h (include) files. +The include directory contains 51 *.h (header) files. @*@* @subsection innobase @@ -4250,100 +4327,6 @@ A full description of these files can be found elsewhere in this document. @*@* -@subsection isam - -The ISAM table handler. -@*@* - -The C files in this directory are: -@itemize @bullet -@item -_cache.c -- for reading records from a cache -@item -changed.c -- a single routine for setting a "changed" flag (very -short) -@item -close.c -- close database -@item -create.c -- create a table -@item -_dbug.c -- support routines for use with "dbug" (see the \dbug -description) -@item -delete.c -- delete a row -@item -_dynrec.c -- functions to handle space-packed records and blobs -@item -extra.c -- setting options and buffer sizes when optimizing table -handling -@item -info.c -- Information about database status -@item -_key.c -- for handling keys -@item -_locking.c -- lock database -@item -log.c -- save commands in log file which myisamlog program can read -@item -_packrec.c -- compress records -@item -_page.c -- read and write pages containing keys -@item -panic.c -- the mi_panic routine, probably for sudden shutdowns -@item -range.c -- approximate count of how many records lie between two -keys -@item -rfirst.c -- read first row through a specific key (very short) -@item -rkey.c -- read a record using a key -@item -rlast.c -- read last row with same key as previously-read row -@item -rnext.c -- read next row with same key as previously-read row -@item -rprev.c -- read previous row with same key as previously-read row -@item -rrnd.c -- read a row based on position -@item -rsame.c -- find current row using positional read or key-based read -@item -rsamepos.c -- positional read -@item -_search.c -- key-handling functions -@item -static.c -- static variables (very short) -@item -_statrec.c -- functions to handle fixed-length records -@item -test1.c -- testing basic functions -@item -test2.c -- testing database and storing results -@item -test3.c -- testing locking -@item -update.c -- update an existing row -@item -write.c -- insert a new row -@item -pack_isam.c -- pack isam file (NOTE TO SELF ?? equivalent to -\myisam\myisampack.c) -@end itemize -@*@* - -Except for one minor C file (pack_isam.c) every program in the ISAM -directory has a counterpart in the MyISAM directory. For example -\isam\update.c corresponds to \myisam\mi_update.c. However, the -reverse is not true -- there are many files in the MyISAM directory -which have no counterpart in the ISAM directory. -@*@* - -The reason is simple -- it's because the ISAM files are becoming -obsolete. When MySQL programmers add new features, they add them for -MyISAM only. The student can therefore ignore all files in this -directory and study the MyISAM programs instead. -@*@* - @subsection libmysql The MySQL Library, Part 1. @@ -4357,25 +4340,33 @@ sending messages, the client part merely calls the server part. The libmysql files are split into three directories: libmysql (this one), libmysql_r (the next one), and libmysqld (the next one after -that). It may be that the original intention was that the libmysql -directory would hold the "client part" files, and the libmysqld -directory would hold the "server part" files. +that). +@*@* + +The "library of mysql" has some client-connection +modules. For example, as described in an earlier +section of this manual, there is a discussion of +libmysql/libmysql.c which sends packets from the +client to the server. Many of the entries in the +libmysql directory (and in the following libmysqld +directory) are 'symlinks' on Linux, that is, they +are in fact pointers to files in other directories. @*@* The program files on this directory are: @itemize @bullet @item -conf_to_src.c -- has to do with charsets +conf_to_src.c -- has to do with charsets @item -dll.c -- initialization of the dll library +dll.c -- initialization of the dll library @item -errmsg.c -- English error messages, compare \mysys\errors.c +errmsg.c -- English error messages, compare \mysys\errors.c @item -get_password.c -- get password +get_password.c -- get password @item -libmysql.c -- the main "packet-sending emulation" program +libmysql.c -- the code that implements the MySQL API, i.e. the functions a client that wants to connect to MySQL will call @item -manager.c -- initialize/connect/fetch with MySQL manager +manager.c -- initialize/connect/fetch with MySQL manager @end itemize @*@* @@ -4384,8 +4375,7 @@ manager.c -- initialize/connect/fetch with MySQL manager The MySQL Library, Part 2. @*@* -This is a continuation of the libmysql directory. There is only one -file here: +There is only one file here, used to build a thread-safe libmysql library: @itemize @bullet @item makefile.am @@ -4397,83 +4387,27 @@ makefile.am The MySQL library, Part 3. @*@* -This is a continuation of the libmysql directory. The program files on -this directory are: +The Embedded MySQL Server Library. The product of libmysqld +is not a client/server affair, but a library. There is a wrapper +to emulate the client calls. The program files on this directory +are: @itemize @bullet @item -libmysqld.c -- The called side, compare the mysqld.exe source +libmysqld.c -- The called side, compare the mysqld.exe source @item -lib_vio.c -- Emulate the vio directory's communication buffer +lib_vio.c -- Emulate the vio directory's communication buffer @end itemize @*@* @subsection man -Manual pages. +Some user-contributed manual pages @*@* -These are not the actual "man" (manual) pages, they are switches for -the production. -@*@* - -@subsection merge - -The MERGE table handler. -@*@* - -For a description of the MERGE table handler, see the MySQL Reference -Manual, section 7.2. -@*@* - -You'll notice that there seem to be several directories with -similar-sounding names of C files in them. That's because the MySQL -table handlers are all quite similar. -@*@* - -The related directories are: -@itemize @bullet -@item -\isam -- for ISAM -@item -\myisam -- for MyISAM -@item -\merge -- for ISAM MERGE (mostly call functions in \isam programs) -@item -\myisammrg -- for MyISAM MERGE (mostly call functions in \myisam -programs) -@end itemize -@*@* - -To avoid duplication, only the \myisam program versions are discussed. -@*@* - -The C programs in this (merge) directory are: -@itemize @bullet -@item -mrg_close.c -- compare \isam's close.c -@item -mrg_create.c -- "" create.c -@item -mrg_delete.c -- "" delete.c -@item -mrg_extra.c -- "" extra.c -@item -mrg_info.c -- "" info.c -@item -mrg_locking.c -- "" locking.c -@item -mrg_open.c -- "" open.c -@item -mrg_panic.c -- "" panic.c -@item -mrg_rrnd.c -- "" rrnd.c -@item -mrg_rsame.c -- "" rsame.c -@item -mrg_static.c -- "" static.c -@item -mrg_update.c -- "" update.c -@end itemize +These are user-contributed "man" (manual) pages in a special markup +format. The format is described in a document with a heading like +"man page for man" or "macros to format man pages" which you can find +in a Linux directory or on the Internet. @*@* @subsection myisam @@ -4484,23 +4418,17 @@ The MyISAM table handler. The C files in this subdirectory come in six main groups: @itemize @bullet @item -ft*.c files -- ft stands for "Full Text", code contributed by Sergei -Golubchik +ft*.c files -- ft stands for "Full Text", code contributed by Sergei Golubchik @item -mi*.c files -- mi stands for "My Isam", these are the main programs -for Myisam +mi*.c files -- mi stands for "My Isam", these are the main programs for Myisam @item -myisam*.c files -- for example, "myisamchk" utility routine -functions source +myisam*.c files -- for example, "myisamchk" utility routine functions source @item -rt*.c files -- rt stands for "rtree", some code was written by -Alexander Barkov +rt*.c files -- rt stands for "rtree", some code was written by Alexander Barkov @item -sp*.c files -- sp stands for "spatial", some code was written by -Ramil Kalimullin +sp*.c files -- sp stands for "spatial", some code was written by Ramil Kalimullin @item -sort.c -- this is a single file that sorts keys for index-create -purposes +sort.c -- this is a single file that sorts keys for index-create purposes @end itemize @*@* @@ -4511,10 +4439,9 @@ programs. They are: @item mi_cache.c -- for reading records from a cache @item -mi_changed.c -- a single routine for setting a "changed" flag (very -short) +mi_changed.c -- a single routine for setting a "changed" flag (very short) @item -mi_check.c -- doesn't just do checks, ?? for myisamchk program? +mi_check.c -- for checking and repairing tables. Used by the myisamchk program and by the MySQL server. @item mi_checksum.c -- calculates a checksum for a row @item @@ -4522,8 +4449,7 @@ mi_close.c -- close database @item mi_create.c -- create a table @item -mi_dbug.c -- support routines for use with "dbug" (see \dbug -description) +mi_dbug.c -- support routines for use with "dbug" (see \dbug description) @item mi_delete.c -- delete a row @item @@ -4535,66 +4461,63 @@ mi_dynrec.c -- functions to handle space-packed records and blobs @item mi_extra.c -- setting options and buffer sizes when optimizing @item -mi_info.c -- "Ger tillbaka en struct med information om isam-filen" +mi_info.c -- return useful base information for an open table @item -mi_key.c -- for handling keys +mi_key.c -- for handling keys @item mi_locking.c -- lock database @item -mi_log.c -- save commands in log file which myisamlog program can -read +mi_log.c -- save commands in a log file which myisamlog program can read. Can be used to exactly replay a set of changes to a table. @item mi_open.c -- open database @item -mi_packrec.c -- compress records +mi_packrec.c -- read from a data file compresed with myisampack @item -mi_page.c -- read and write pages containing keys +mi_page.c -- read and write pages containing keys @item -mi_panic.c -- the mi_panic routine, probably for sudden shutdowns +mi_panic.c -- the mi_panic routine, probably for sudden shutdowns @item -mi_range.c -- approximate count of how many records lie between two -keys +mi_range.c -- approximate count of how many records lie between two keys @item -mi_rename.c -- rename a table +mi_rename.c -- rename a table @item mi_rfirst.c -- read first row through a specific key (very short) @item -mi_rkey.c -- read a record using a key +mi_rkey.c -- read a record using a key @item -mi_rlast.c -- read last row with same key as previously-read row +mi_rlast.c -- read last row with same key as previously-read row @item -mi_rnext.c -- read next row with same key as previously-read row +mi_rnext.c -- read next row with same key as previously-read row @item -mi_rnext_same.c -- same as mi_rnext.c, but abort if the key changes +mi_rnext_same.c -- same as mi_rnext.c, but abort if the key changes @item mi_rprev.c -- read previous row with same key as previously-read row @item -mi_rrnd.c -- read a row based on position +mi_rrnd.c -- read a row based on position @item -mi_rsame.c -- find current row using positional read or key-based -read +mi_rsame.c -- find current row using positional read or key-based read @item -mi_rsamepos.c -- positional read +mi_rsamepos.c -- positional read @item -mi_scan.c -- read all rows sequentially +mi_scan.c -- read all rows sequentially @item -mi_search.c -- key-handling functions +mi_search.c -- key-handling functions @item mi_static.c -- static variables (very short) @item -mi_statrec.c -- functions to handle fixed-length records +mi_statrec.c -- functions to handle fixed-length records @item -mi_test1.c -- testing basic functions +mi_test1.c -- testing basic functions @item -mi_test2.c -- testing database and storing results +mi_test2.c -- testing database and storing results @item -mi_test3.c -- testing locking +mi_test3.c -- testing locking @item -mi_unique.c -- functions to check if a row is unique +mi_unique.c -- functions to check if a row is unique @item -mi_update.c -- update an existing row +mi_update.c -- update an existing row @item -mi_write.c -- insert a new row +mi_write.c -- insert a new row @end itemize @*@* @@ -4702,14 +4625,12 @@ There are other tests in these directories: @item sql-bench @item -repl-tests -@item tests @end itemize @subsection mysys -MySQL system library (Low level routines for file access etc.). +MySQL system library. Low level routines for file access and so on. @*@* There are 115 *.c programs in this directory: @@ -4717,13 +4638,11 @@ There are 115 *.c programs in this directory: @item array.c -- Dynamic array handling @item -charset.c -- Using dynamic character sets, set default character -set, ... +charset.c -- Using dynamic character sets, set default character set, ... @item -charset2html.c -- Checking what character set a browser is using +charset2html.c -- Check what character set a browser is using @item -checksum.c -- Calculate checksum for a memory block, used for -pack_isam +checksum.c -- Calculate checksum for a memory block, used for pack_isam @item default.c -- Find defaults from *.cnf or *.ini files @item @@ -4733,54 +4652,51 @@ hash.c -- Hash search/compare/free functions "for saving keys" @item list.c -- Double-linked lists @item -make-conf.c -- "Make a charset .conf file out of a ctype-charset.c -file" +make-conf.c -- "Make a charset .conf file out of a ctype-charset.c file" @item md5.c -- MD5 ("Message Digest 5") algorithm from RSA Data Security @item -mf_brkhant.c -- Prevent user from doing a Break during critical -execution +mf_brkhant.c -- Prevent user from doing a Break during critical execution (not used in MySQL; can be used by standalone MyISAM applications) @item -mf_cache.c -- "Open a temporary file and cache it with io_cache" +mf_cache.c -- "Open a temporary file and cache it with io_cache" @item -mf_dirname.c -- Parse/convert directory names +mf_dirname.c -- Parse/convert directory names @item -mf_fn_ext.c -- Get filename extension +mf_fn_ext.c -- Get filename extension @item -mf_format.c -- Format a filename +mf_format.c -- Format a filename @item -mf_getdate.c -- Get date, return in yyyy-mm-dd hh:mm:ss format +mf_getdate.c -- Get date, return in yyyy-mm-dd hh:mm:ss format @item -mf_iocache.c -- Cached read/write of files in fixed-size units +mf_iocache.c -- Cached read/write of files in fixed-size units @item -mf_iocache2.c -- Continuation of mf_iocache.c +mf_iocache2.c -- Continuation of mf_iocache.c @item -mf_keycache.c -- Key block caching for certain file types +mf_keycache.c -- Key block caching for certain file types @item mf_loadpath.c -- Return full path name (no ..\ stuff) @item mf_pack.c -- Packing/unpacking directory names for create purposes @item -mf_path.c -- Determine where a program can find its files +mf_path.c -- Determine where a program can find its files @item -mf_qsort.c -- Quicksort +mf_qsort.c -- Quicksort @item -mf_qsort2.c -- Quicksort, part 2 +mf_qsort2.c -- Quicksort, part 2 (allows the passing of an extra argument to the sort-compare routine) @item -mf_radix.c -- Radix sort +mf_radix.c -- Radix sort @item -mf_same.c -- Determine whether filenames are the same +mf_same.c -- Determine whether filenames are the same @item -mf_sort.c -- Sort with choice of Quicksort or Radix sort +mf_sort.c -- Sort with choice of Quicksort or Radix sort @item -mf_soundex.c -- Soundex algorithm derived from EDN Nov. 14, 1985 -(pg. 36) +mf_soundex.c -- Soundex algorithm derived from EDN Nov. 14, 1985 (pg. 36) @item -mf_strip.c -- Strip trail spaces from a string +mf_strip.c -- Strip trail spaces from a string @item -mf_tempdir.c -- Initialize/find/free temporary directory +mf_tempdir.c -- Initialize/find/free temporary directory @item -mf_tempfile.c -- Create a temporary file +mf_tempfile.c -- Create a temporary file @item mf_unixpath.c -- Convert filename to UNIX-style filename @item @@ -4870,8 +4786,7 @@ free" @item my_open.c -- Open a file @item -my_os2cond.c -- OS2-specific: "A simple implementation of posix -conditions" +my_os2cond.c -- OS2-specific: "A simple implementation of posix conditions" @item my_os2dirsrch.c -- OS2-specific: Emulate a Win32 directory search @item @@ -4885,12 +4800,11 @@ my_os2thread.c -- OS2-specific: For thread handling @item my_os2tls.c -- OS2-specific: For thread-local storage @item -my_port.c -- AIX-specific: my_ulonglong2double() +my_port.c -- OS/machine-dependent porting functions, e.g. AIX-specific my_ulonglong2double() @item my_pread.c -- Read a specified number of bytes from a file @item -my_pthread.c -- A wrapper for thread-handling functions in different -OSs +my_pthread.c -- A wrapper for thread-handling functions in different OSs @item my_quick.c -- Read/write (labelled a "quicker" interface, perhaps obsolete) @@ -4907,78 +4821,69 @@ my_rename.c -- Rename without delete @item my_seek.c -- Seek, i.e. point to a spot within a file @item -my_semaphore.c -- Semaphore routines, for use on OS that doesn't -support them +my_semaphore.c -- Semaphore routines, for use on OS that doesn't support them @item my_sleep.c -- Wait n microseconds @item -my_static.c -- Static-variable definitions +my_static.c -- Static variables used by the mysys library @item -my_symlink.c -- Read a symbolic link (symlinks are a UNIX thing, I -guess) +my_symlink.c -- Read a symbolic link (symlinks are a UNIX thing, I guess) @item -my_symlink2.c -- Part 2 of my_symlink.c +my_symlink2.c -- Part 2 of my_symlink.c @item -my_tempnam.c -- Obsolete temporary-filename routine used by ISAM -table handler +my_tempnam.c -- Obsolete temporary-filename routine used by ISAM table handler @item -my_thr_init.c -- initialize/allocate "all mysys & debug thread -variables" +my_thr_init.c -- initialize/allocate "all mysys & debug thread variables" @item -my_wincond.c -- Windows-specific: emulate Posix conditions +my_wincond.c -- Windows-specific: emulate Posix conditions @item -my_winsem.c -- Windows-specific: emulate Posix threads +my_winsem.c -- Windows-specific: emulate Posix threads @item -my_winthread.c -- Windows-specific: emulate Posix threads +my_winthread.c -- Windows-specific: emulate Posix threads @item -my_write.c -- Write a specified number of bytes to a file +my_write.c -- Write a specified number of bytes to a file @item -ptr_cmp.c -- Point to an optimal byte-comparison function +ptr_cmp.c -- Point to an optimal byte-comparison function @item -queues.c -- Handle priority queues as in Robert Sedgewick's book +queues.c -- Handle priority queues as in Robert Sedgewick's book @item raid2.c -- RAID support (the true implementation is in raid.cc) @item -rijndael.c -- "Optimised ANSI C code for the Rijndael cipher (now -AES") +rijndael.c -- "Optimised ANSI C code for the Rijndael cipher (now AES") @item -safemalloc.c -- A version of the standard malloc() with safety -checking +safemalloc.c -- A version of the standard malloc() with safety checking @item -sha1.c -- Implementation of Secure Hashing Algorithm 1 +sha1.c -- Implementation of Secure Hashing Algorithm 1 @item -string.c -- Initialize/append/free dynamically-sized strings +string.c -- Initialize/append/free dynamically-sized strings; see also sql_string.cc in the /sql directory @item -testhash.c -- Standalone program: test the hash library routines +testhash.c -- Standalone program: test the hash library routines @item -test_charset.c -- Standalone program: display character set -information +test_charset.c -- Standalone program: display character set information @item -test_dir.c -- Standalone program: placeholder for "test all -functions" idea +test_dir.c -- Standalone program: placeholder for "test all functions" idea @item -test_fn.c -- Standalone program: apparently tests a function +test_fn.c -- Standalone program: apparently tests a function @item -test_xml.c -- Standalone program: test XML routines +test_xml.c -- Standalone program: test XML routines @item -thr_alarm.c -- Thread alarms and signal handling +thr_alarm.c -- Thread alarms and signal handling @item -thr_lock.c -- "Read and write locks for Posix threads" +thr_lock.c -- "Read and write locks for Posix threads" @item -thr_mutex.c -- A wrapper for mutex functions +thr_mutex.c -- A wrapper for mutex functions @item -thr_rwlock.c -- Synchronizes the readers' thread locks with the -writer's lock +thr_rwlock.c -- Synchronizes the readers' thread locks with the writer's lock @item -tree.c -- Initialize/search/free binary trees +tree.c -- Initialize/search/free binary trees @item -typelib.c -- Determine what type a field has +typelib.c -- Find a string in a set of strings; returns the offset to the string found @end itemize @*@* You can find documentation for the main functions in these files -elsewhere in this document. -For example, the main functions in my_getwd.c are described thus: +elsewhere in this document. For example, the main functions in my_getwd.c +are described thus: @*@* @example @@ -5008,15 +4913,15 @@ testing. These are the five *.c files, all from Novell Inc.: @itemize @bullet @item -libmysqlmain.c -- Only one function: init_available_charsets() +libmysqlmain.c -- Only one function: init_available_charsets() @item -my_manage.c -- Standalone management utility +my_manage.c -- Standalone management utility @item -mysql_install_db.c -- Compare \scripts\mysql_install_db.sh +mysql_install_db.c -- Compare \scripts\mysql_install_db.sh @item -mysql_test_run.c -- Short test program +mysql_test_run.c -- Short test program @item -mysqld_safe.c -- Compare \scripts\mysqld_safe.sh +mysqld_safe.c -- Compare \scripts\mysqld_safe.sh @end itemize Perhaps the most important file is: @@ -5028,18 +4933,17 @@ netware.patch -- NetWare-specific build instructions and switches @*@* For instructions about basic installation, see "Deployment Guide For -NetWare AMP" at: +NetWare AMP" at: @url{http://developer.novell.com/ndk/whitepapers/namp.htm} @* @subsection NEW-RPMS -New "RPM Package Manager" files. +Directory to place RPMs while making a distribution. @*@* -This directory is not part of the Windows distribution. Perhaps in -MYSQL's Linux distribution it has files for use with Red Hat -installations -- a point that needs checking someday. +This directory is not part of the Windows distribution. It is +a temporary directory used during RPM builds with Linux distributions. @*@* @subsection os2 @@ -5052,10 +4956,10 @@ people from outside MySQL: Yuri Dario, Timo Maier, and John M Alfredsson. There are no .C program files in this directory. @*@* -The contents of \os2 are: +The contents of \os2 are: @itemize @bullet @item -A Readme.Txt file +A Readme.Txt file @item An \include subdirectory containing .h files which are for OS/2 only @item @@ -5070,7 +4974,7 @@ there have been no updates for MySQL 4.0 for this section. @subsection pstack -Process stack display. +Process stack display (not currently used). @*@* This is a set of publicly-available debugging aids which all do pretty @@ -5088,7 +4992,7 @@ and it crashes. @subsection regex -Regular Expression library for support of REGEXP function. +Henry Spencer's Regular Expression library for support of REGEXP function. @*@* This is the copyrighted product of Henry Spencer from the University @@ -5112,31 +5016,9 @@ This program calls the 'regcomp' function, which is the entry point in \regex\regexp.c. @*@* -@subsection repl-tests - -Test cases for replication. -@*@* - -There are six short and trivial-looking tests in these subdirectories: -@itemize @bullet -@item -\test-auto-inc -- Do auto-Increment columns work? -@item -\test-bad-query -- Does insert in PK column work? -@item -\test-dump -- Do LOAD statements work? -@item -\test-repl -- Does replication work? -@item -\test-repl-alter -- Does ALTER TABLE work? -@item -\test-repl-ts -- Does TIMESTAMP column work? -@end itemize -@*@* - @subsection SCCS -Source Code Control System. +Source Code Control System (not part of source distribution). @*@* You will see this directory if and only if you used BitKeeper for @@ -5146,63 +5028,57 @@ administration and are not of interest to application programmers. @subsection scripts -SQL batches, e.g. for converting msql to MySQL. +SQL batches, e.g. mysqlbug and mysql_install_db. @*@* -The *.sh filename extension apparently stands for "shell script". -Linux programmers use it where Windows programmers would use a *.bat +The *.sh filename extension stands for "shell script". Linux +programmers use it where Windows programmers would use a *.bat (batch filename extension). @*@* The *.sh files on this directory are: @itemize @bullet @item -fill_help_tables.sh -- Create help-information tables and insert +fill_help_tables.sh -- Create help-information tables and insert @item -make_binary_distribution.sh -- Get configure information, make, -produce tar +make_binary_distribution.sh -- Get configure information, make, produce tar @item -msql2mysql.sh -- Convert mSQL to MySQL +msql2mysql.sh -- Convert (partly) mSQL programs and scripts to MySQL @item -mysqlbug.sh -- Create a bug report and mail it +mysqlbug.sh -- Create a bug report and mail it @item -mysqld_multi.sh -- Start/stop any number of mysqld instances +mysqld_multi.sh -- Start/stop any number of mysqld instances @item -mysqld_safe-watch.sh -- Start/restart in safe mode +mysqld_safe-watch.sh -- Start/restart in safe mode @item -mysqld_safe.sh -- Start/restart in safe mode +mysqld_safe.sh -- Start/restart in safe mode @item -mysqldumpslow.sh -- Parse and summarize the slow query log +mysqldumpslow.sh -- Parse and summarize the slow query log @item -mysqlhotcopy.sh -- Hot backup +mysqlhotcopy.sh -- Hot backup @item -mysql_config.sh -- Get configure information that client might need +mysql_config.sh -- Get configuration information that might be needed to compile a client @item -mysql_convert_table_format.sh -- Conversion, e.g. from ISAM to -MyISAM +mysql_convert_table_format.sh -- Conversion, e.g. from ISAM to MyISAM @item -mysql_explain_log.sh -- Put a log (made with --log) into a MySQL -table +mysql_explain_log.sh -- Put a log (made with --log) into a MySQL table @item -mysql_find_rows.sh -- Search for queries containing <regexp> +mysql_find_rows.sh -- Search for queries containing <regexp> @item -mysql_fix_extensions.sh -- Renames some file extensions, not -recommended +mysql_fix_extensions.sh -- Renames some file extensions, not recommended @item -mysql_fix_privilege_tables.sh -- Fix mysql.user etc. if upgrading to -MySQL 3.23.14+ +mysql_fix_privilege_tables.sh -- Fix mysql.user etc. when upgrading. Can be safely run during any upgrade to get the newest +MySQL privilege tables @item -mysql_install_db.sh -- Create privilege tables and func table +mysql_install_db.sh -- Create privilege tables and func table @item -mysql_secure_installation.sh -- Disallow remote root login, -eliminate test, etc. +mysql_secure_installation.sh -- Disallow remote root login, eliminate test, etc. @item -mysql_setpermission.sh -- Aid to add users or databases, sets -privileges +mysql_setpermission.sh -- Aid to add users or databases, sets privileges @item mysql_tableinfo.sh -- Puts info re MySQL tables into a MySQL table @item -mysql_zap.sh -- Kill processes which match pattern +mysql_zap.sh -- Kill processes which match pattern @end itemize @*@* @@ -5214,197 +5090,191 @@ Programs for handling SQL commands. The "core" of MySQL. These are the .c and .cc files in the sql directory: @itemize @bullet @item -cache_manager.cc -- manages a number of blocks +convert.cc -- convert tables between different character sets @item -convert.cc -- convert tables between different character sets +derror.cc -- read language-dependent message file @item -derror.cc -- read language-dependent message file +des_key_file.cc -- load DES keys from plaintext file @item -des_key_file.cc -- load DES keys from plaintext file +field.cc -- "implement classes defined in field.h" (long); defines all storage methods MySQL uses to store field information +into records that are then passed to handlers @item -field.cc -- "implement classes defined in field.h" (long) +field_conv.cc -- functions to copy data between fields @item -field_conv.cc -- functions to copy data to or from fields +filesort.cc -- sort a result set, using memory or temporary files @item -filesort.cc -- sort file +frm_crypt.cc -- contains only one short function: get_crypt_for_frm @item -frm_crypt.cc -- contains only one short function: get_crypt_for_frm +gen_lex_hash.cc -- Knuth's algorithm from Vol 3 Sorting and Searching, Chapter 6.3; used to search for SQL keywords in a query @item -gen_lex_hash.cc -- Knuth's algorithm from Vol 3 Sorting and -Searching, Chapter 6.3 +gstream.cc -- GTextReadStream, used to read GIS objects @item -gstream.cc -- GTextReadStream +handler.cc -- handler-calling functions @item -handler.cc -- handler-calling functions +hash_filo.cc -- static-sized hash tables, used to store info like hostname -> ip tables in a FIFO manner @item -hash_filo.cc -- static-sized hash tables +ha_berkeley.cc -- Handler: BDB @item -ha_berkeley.cc -- Handler: BDB +ha_heap.cc -- Handler: Heap @item -ha_heap.cc -- Handler: Heap +ha_innodb.cc -- Handler: InnoDB @item -ha_innodb.cc -- Handler: InnoDB -@item -ha_isam.cc -- Handler: ISAM +ha_isam.cc -- Handler: ISAM @item ha_isammrg.cc -- Handler: (ISAM MERGE) @item -ha_myisam.cc -- Handler: MyISAM +ha_myisam.cc -- Handler: MyISAM @item ha_myisammrg.cc -- Handler: (MyISAM MERGE) @item -hostname.cc -- Given IP, return hostname +hostname.cc -- Given IP, return hostname @item -init.cc -- Init and dummy functions for interface with unireg +init.cc -- Init and dummy functions for interface with unireg @item -item.cc -- Item functions +item.cc -- Item functions @item -item_buff.cc -- Buffers to save and compare item values +item_buff.cc -- Buffers to save and compare item values @item -item_cmpfunc.cc -- Definition of all compare functions +item_cmpfunc.cc -- Definition of all compare functions @item -item_create.cc -- Create an item. Used by lex.h. +item_create.cc -- Create an item. Used by lex.h. @item -item_func.cc -- Numerical functions +item_func.cc -- Numerical functions @item -item_row.cc -- Row items for comparing rows and for IN on rows +item_row.cc -- Row items for comparing rows and for IN on rows @item -item_sum.cc -- Set functions (sum, avg, etc.) +item_sum.cc -- Set functions (SUM, AVG, etc.) @item -item_strfunc.cc -- String functions +item_strfunc.cc -- String functions @item -item_subselect.cc -- Item subselect +item_subselect.cc -- Item subselect @item -item_timefunc.cc -- Date/time functions, e.g. week of year +item_timefunc.cc -- Date/time functions, e.g. week of year @item -item_uniq.cc -- Empty file, here for compatibility reasons +item_uniq.cc -- Empty file, here for compatibility reasons @item -key.cc -- Functions to handle keys and fields in forms +key.cc -- Functions to create keys from records and compare a key to a key in a record @item -lock.cc -- Locks +lock.cc -- Locks @item -log.cc -- Logs +log.cc -- Logs @item -log_event.cc -- Log event +log_event.cc -- Log event (a binary log consists of a stream of log events) @item -matherr.c -- Handling overflow, underflow, etc. +matherr.c -- Handling overflow, underflow, etc. @item -mf_iocache.cc -- Caching of (sequential) reads +mf_iocache.cc -- Caching of (sequential) reads and writes @item -mini_client.cc -- Client included in server for server-server -messaging +mini_client.cc -- Client included in server for server-server messaging; used by the replication code @item -mysqld.cc -- Source of mysqld.exe +mysqld.cc -- Source of mysqld.exe; includes the main() program that starts mysqld, handling of signals and connections @item -my_lock.c -- Lock part of a file +my_lock.c -- Lock part of a file (like /mysys/my_lock.c, but with timeout handling for threads) @item -net_serv.cc -- Read/write of packets on a network socket +net_serv.cc -- Read/write of packets on a network socket @item -nt_servc.cc -- Initialize/register/remove an NT service +nt_servc.cc -- Initialize/register/remove an NT service @item opt_ft.cc -- Create a FT or QUICK RANGE based on a key (very short) -* opt_range.cc -- Range of keys +@item +opt_range.cc -- Range of keys @item opt_sum.cc -- Optimize functions in presence of (implied) GROUP BY @item -password.c -- Password checking +password.c -- Password checking @item -procedure.cc -- Procedure +procedure.cc -- Procedure interface, as used in SELECT * FROM Table_name PROCEDURE ANALYSE @item -protocol.cc -- Low level functions for storing data to be sent to -client +protocol.cc -- Low level functions for PACKING data that is sent to client; actual sending done with net_serv.cc @item -records.cc -- Functions to read, write, and lock records +records.cc -- Functions for easy reading of records, possible through a cache @item -repl_failsafe.cc -- Replication fail-save +repl_failsafe.cc -- Replication fail-save (not yet implemented) @item -set_var.cc -- MySQL variables +set_var.cc -- Set and retrieve MySQL user variables @item -slave.cc -- Procedures for a slave in a master/slave (replication?) -relation +slave.cc -- Procedures for a slave in a master/slave (replication) relation @item spatial.cc -- Geometry stuff (lines, points, etc.) @item -sql_acl.cc -- Functions related to ACL security +sql_acl.cc -- Functions related to ACL security; checks, stores, retrieves, and deletes MySQL user level privileges @item -sql_analyse.cc -- Analyse an input string (?) +sql_analyse.cc -- Implements the PROCEDURE analyse, which analyses a query result and returns the 'optimal' data type for each result column @item -sql_base.cc -- Basic functions needed by many modules +sql_base.cc -- Basic functions needed by many modules, like opening and closing tables with table cache management @item -sql_cache.cc -- SQL cache, with long comments about how caching -works +sql_cache.cc -- SQL query cache, with long comments about how caching works @item -sql_class.cc -- SQL class +sql_class.cc -- SQL class; implements the SQL base classes, of which THD (THREAD object) is the most important @item -sql_crypt.cc -- Encode / decode, very short +sql_crypt.cc -- Encode / decode, very short @item -sql_db.cc -- Create / drop database +sql_db.cc -- Create / drop database @item -sql_delete.cc -- The DELETE statement +sql_delete.cc -- The DELETE statement @item -sql_derived.cc -- Derived tables, with long comments +sql_derived.cc -- Derived tables, with long comments @item -sql_do.cc -- The DO statement +sql_do.cc -- The DO statement @item -sql_error.cc -- Errors and warnings +sql_error.cc -- Errors and warnings @item -sql_handler.cc -- Direct access to ISAM +sql_handler.cc -- Implements the HANDLER interface, which gives direct access to rows in MyISAM and InnoDB @item -sql_help.cc -- The HELP statement (if there is one?) +sql_help.cc -- The HELP statement @item -sql_insert.cc -- The INSERT statement +sql_insert.cc -- The INSERT statement @item -sql_lex.cc -- Related to lex or yacc +sql_lex.cc -- Does lexical analysis of a query; i.e. breaks a query string into pieces and determines the basic type (number, +string, keyword, etc.) of each piece @item -sql_list.cc -- Only list_node_end_of_list, short +sql_list.cc -- Only list_node_end_of_list, short (the rest of the list class is implemented in sql_list.h) @item -sql_load.cc -- The LOAD DATA statement? +sql_load.cc -- The LOAD DATA statement @item -sql_map.cc -- Memory-mapped files? +sql_map.cc -- Memory-mapped files (not yet in use) @item -sql_manager.cc -- Maintenance tasks, e.g. flushing the buffers -periodically +sql_manager.cc -- Maintenance tasks, e.g. flushing the buffers periodically; used with BDB table logs @item -sql_olap.cc -- ROLLUP +sql_olap.cc -- ROLLUP @item -sql_parse.cc -- Parse an SQL statement +sql_parse.cc -- Parse an SQL statement; do initial checks and then jump to the function that should execute the statement @item -sql_prepare.cc -- Prepare an SQL statement +sql_prepare.cc -- Prepare an SQL statement, or use a prepared statement @item -sql_repl.cc -- Replication +sql_repl.cc -- Replication @item -sql_rename.cc -- Rename table +sql_rename.cc -- Rename table @item -sql_select.cc -- Select and join optimisation +sql_select.cc -- Select and join optimisation @item -sql_show.cc -- The SHOW statement +sql_show.cc -- The SHOW statement @item -sql_string.cc -- String functions: alloc, realloc, copy, convert, -etc. +sql_string.cc -- String functions: alloc, realloc, copy, convert, etc. @item -sql_table.cc -- The DROP TABLE and ALTER TABLE statements +sql_table.cc -- The DROP TABLE and ALTER TABLE statements @item -sql_test.cc -- Some debugging information +sql_test.cc -- Some debugging information @item -sql_udf.cc -- User-defined functions +sql_udf.cc -- User-defined functions @item -sql_union.cc -- The UNION operator +sql_union.cc -- The UNION operator @item -sql_update.cc -- The UPDATE statement +sql_update.cc -- The UPDATE statement @item -stacktrace.c -- Display stack trace (Linux/Intel only?) +stacktrace.c -- Display stack trace (Linux/Intel only) @item -table.cc -- Table metadata retrieval, mostly +table.cc -- Table metadata retrieval; read the table definition from a .frm file and store it in a TABLE object @item -thr_malloc.cc -- Mallocs used in threads +thr_malloc.cc -- Thread-safe interface to /mysys/my_alloc.c @item -time.cc -- Date and time functions +time.cc -- Date and time functions @item -udf_example.cc -- Example file of user-defined functions +udf_example.cc -- Example file of user-defined functions @item -uniques.cc -- Function to handle quick removal of duplicates +uniques.cc -- Function to handle quick removal of duplicates @item -unireg.cc -- Create a unireg form file from a FIELD and field-info struct +unireg.cc -- Create a unireg form file (.frm) from a FIELD and field-info struct @end itemize @*@* @@ -5422,17 +5292,15 @@ available all the material necessary to reproduce all the tests. There are five subdirectories and sub-subdirectories: @itemize @bullet @item -\Comments -- Comments about results from tests of Access, Adabas, -etc. +\Comments -- Comments about results from tests of Access, Adabas, etc. @item -\Data\ATIS -- .txt files containing input data for the "ATIS" tests +\Data\ATIS -- .txt files containing input data for the "ATIS" tests @item -\Data\Wisconsin -- .txt files containing input data for the -"Wisconsin" tests +\Data\Wisconsin -- .txt files containing input data for the "Wisconsin" tests @item -\Results -- old test results +\Results -- old test results @item -\Results-win32 -- old test results from Windows 32-bit tests +\Results-win32 -- old test results from Windows 32-bit tests @end itemize @*@* @@ -5448,7 +5316,8 @@ There is one README file and one TODO file. @subsection SSL -Secure Sockets Layer. +Secure Sockets Layer; includes an example certification one can use +test an SSL (secure) database connection. @*@* This isn't a code directory. It contains a short note from Tonu Samuel @@ -5477,7 +5346,7 @@ recent Pentium class processors, though. The .C files are: @itemize @bullet @item -atof.c -- ascii-to-float, MySQL version +atof.c -- ascii-to-float, MySQL version @item bchange.c -- short replacement routine written by Monty Widenius in 1987 @@ -5499,8 +5368,7 @@ bmove_upp.c -- bmove.c variant, starting with last byte @item bzero.c -- something like bfill with an argument of 0 @item -conf_to_src.c -- reading a configuration file (NOTE TO SELF ? what's -this doing here?) +conf_to_src.c -- reading a configuration file @item ctype*.c -- string handling programs for each char type MySQL handles @@ -5526,7 +5394,7 @@ r_strinstr.c -- see if one string is within another @item str2int.c -- convert string to integer @item -strappend.c -- append one string to another +strappend.c -- fill up a string to n characters @item strcat.c -- concatenate strings @item @@ -5546,11 +5414,11 @@ strinstr.c -- find string within string @item strlen.c -- return length of string in bytes @item -strmake.c -- move n characters, or move till end +strmake.c -- create new string from old string with fixed length, append end \0 if needed @item -strmov.c -- move source to dest and return pointer to end +strmov.c -- move source to dest and return pointer to end @item -strnlen.c -- return length of string, or return n +strnlen.c -- return min(length of string, n) @item strnmov.c -- move source to dest for source size, or for n bytes @item @@ -5574,9 +5442,9 @@ strxnmov.c -- like strxmov.c but with a maximum length n @item str_test.c -- test of all the string functions encoded in assembler @item -udiv.c -- unsigned long divide +udiv.c -- unsigned long divide, for operating systems that don't support these @item -xml.c -- read and parse XML strings +xml.c -- read and parse XML strings; used to read character definition information stored in /sql/share/charsets @end itemize @*@* @@ -5588,21 +5456,41 @@ members of the Intel processor family. @subsection support-files -Support files. +Files used to build MySQL on different systems. @*@* The files here are for building ("making") MySQL given a package manager, compiler, linker, and other build tools. The support files -provide instructions and switches for the build processes. +provide instructions and switches for the build processes. They +include example my.cnf files one can use as a default setup for +MySQL. @*@* @subsection tests -Tests in Perl. +Tests in Perl and in C. @*@* -These are tests that were run once to check for bugs in various -scenarios: forks, locks, big records, exporting, truncating, etc. +The files in this directory are test programs that can be used +as a base to write a program to simulate problems in MySQL in various +scenarios: forks, locks, big records, exporting, truncating, and so on. +Some examples are: +@itemize @bullet +@item +connect_test.c -- test that a connect is possible +@item +insert_test.c -- test that an insert is possible +@item +list_test.c -- test that a select is possible +@item +select_test.c -- test that a select is possible +@item +showdb_test.c -- test that a show-databases is possible +@item +ssl_test.c -- test that SSL is possible +@item +thread_test.c -- test that threading is possible +@end itemize @*@* @subsection tools @@ -5613,7 +5501,9 @@ Tools -- well, actually, one tool. The only file is: @itemize @bullet @item -mysqlmanager.c -- A "server management daemon" by Sasha Pachev +mysqlmanager.c -- A "server management daemon" by Sasha Pachev. This +is a tool under development and is not yet useful. Related to fail-safe +replication. @end itemize @*@* @@ -5625,11 +5515,16 @@ Visual C++ Files. Includes this entire directory, repeated for VC++ (Windows) use. @*@* -VC++Files has subdirectories which are copies of the main directories. -For example there is a subdirectory \VC++Files\heap, which has the -same files as \heap. So for a description of the files in -\VC++Files\heap, see the description of the files in \heap. The same -applies for almost all of VC++Files's subdirectories (bdb, client, +VC++Files includes a complete environment to compile MySQL with the VC++ +compiler. To use it, just copy the files on this directory; the make_win_src_distribution.sh +script uses these files to create a Windows source installation. +@*@* + +This directory has subdirectories which are copies of the main directories. +For example, there is a subdirectory \VC++Files\heap, which has the Microsoft +developer studio project file to compile \heap with VC++. So for a description +of the files in \VC++Files\heap, see the description of the files in \heap. The +same applies for almost all of VC++Files's subdirectories (bdb, client, isam, libmysql, etc.). The difference is that the \VC++Files variants are specifically for compilation with Microsoft Visual C++ in 32-bit Windows environments. @@ -5640,54 +5535,60 @@ directories", VC++Files contains these subdirectories, which are not duplicates: @itemize @bullet @item -comp_err -- (nearly empty) +comp_err -- (nearly empty) @item -contrib -- (nearly empty) +contrib -- (nearly empty) @item -InstallShield script files +InstallShield -- script files @item -isamchk -- (nearly empty) +isamchk -- (nearly empty) @item -libmysqltest -- one small non-MySQL test program: mytest.c +libmysqltest -- one small non-MySQL test program: mytest.c @item -myisamchk -- (nearly empty) +myisamchk -- (nearly empty) @item -myisamlog -- (nearly empty) +myisamlog -- (nearly empty) @item -myisammrg -- (nearly empty) +myisammrg -- (nearly empty) @item -mysqlbinlog -- (nearly empty) +mysqlbinlog -- (nearly empty) @item -mysqlmanager -- MFC foundation class files created by AppWizard +mysqlmanager -- MFC foundation class files created by AppWizard @item -mysqlserver -- (nearly empty) +mysqlserver -- (nearly empty) @item -mysqlshutdown -- one short program, mysqlshutdown.c +mysqlshutdown -- one short program, mysqlshutdown.c @item -mysqlwatch.c -- Windows service initialization and monitoring +mysqlwatch.c -- Windows service initialization and monitoring @item -my_print_defaults -- (nearly empty) +my_print_defaults -- (nearly empty) @item -pack_isam -- (nearly empty) +pack_isam -- (nearly empty) @item -perror -- (nearly empty) +perror -- (nearly empty) @item -prepare -- (nearly empty) +prepare -- (nearly empty) @item -replace -- (nearly empty) +replace -- (nearly empty) @item -SCCS -- source code control system +SCCS -- source code control system @item -test1 -- tests connecting via X threads +test1 -- tests connecting via X threads @item -thr_insert_test -- (nearly empty) +thr_insert_test -- (nearly empty) @item thr_test -- one short program used to test for memory-allocation bug @item -winmysqladmin -- the winmysqladmin.exe source. machine-generated? +winmysqladmin -- the winmysqladmin.exe source @end itemize @*@* +The "nearly empty" subdirectories noted above (e.g. comp_err and isamchk) +are needed because VC++ requires one directory per project (i.e. executable). +We are trying to keep to the MySQL standard source layout and compile only +to different directories. +@*@* + @subsection vio Virtual I/O Library. @@ -5735,7 +5636,12 @@ obsolete. @subsection zlib -Data compression library. +Data compression library, used on Windows. +@*@* + +zlib is a data compression library used to support the compressed +protocol and the COMPRESS/UNCOMPRESS functions under Windows. +On Unix, MySQL uses the system libgz.a library for this purpose. @*@* Zlib -- which presumably stands for "Zip Library" -- is not a MySQL @@ -5745,11 +5651,11 @@ variation of the famous "Lempel-Ziv" method, which is also used by bytes is as follows: @itemize @bullet @item -Find a substring which occurs twice in the string. +Find a substring which occurs twice in the string. @item Replace the second occurrence of the substring with (a) a pointer to the first occurrence, plus (b) an indication of the length of the -first occurrence. +first occurrence. @end itemize There is a full description of the library's functions in the gzip @@ -5758,11 +5664,11 @@ manual at: @* There is therefore no need to list the modules in this document. @*@* -The MySQL program that uses zlib is \mysys\my_compress.c. The use is -for packet compression. The client sends messages to the server which -are compressed by zlib. See also: \sql\net_serv.cc. +The MySQL program \mysys\my_compress.c uses zlib for packet compression. +The client sends messages to the server which are compressed by zlib. +See also: \sql\net_serv.cc. -@node Files in InnoDB Sources,,Files in MySQL Sources,Top +@node Files in InnoDB Sources, , Files in MySQL Sources, Top @chapter Annotated List Of Files in the InnoDB Source Code Distribution ERRATUM BY HEIKKI TUURI (START) diff --git a/Docs/manual_toc.html b/Docs/manual_toc.html new file mode 100644 index 00000000000..b9014e5efb9 --- /dev/null +++ b/Docs/manual_toc.html @@ -0,0 +1,9 @@ +<html> +<head> +<title>Place holder for manual_toc.html</title> +</head> +<body> +This is just a place holder for the autogenerated manual_toc.html +to make "make dist" happy. +</body> +</html> diff --git a/Images/.cvsignore b/Images/.cvsignore deleted file mode 100644 index 6d0d61a83d5..00000000000 --- a/Images/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -logo_nusphere_b.tif diff --git a/VC++Files/libmysql/libmysql.dsp b/VC++Files/libmysql/libmysql.dsp index f14c1e6871c..bccb6d57c7f 100644 --- a/VC++Files/libmysql/libmysql.dsp +++ b/VC++Files/libmysql/libmysql.dsp @@ -25,7 +25,7 @@ CFG=libmysql - Win32 Debug # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" -CPP=cl.exe +CPP=xicl6.exe MTL=midl.exe RSC=rc.exe @@ -52,7 +52,7 @@ RSC=rc.exe BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo -LINK32=link.exe +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:windows /dll /machine:I386 # ADD LINK32 wsock32.lib 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:windows /dll /machine:I386 /def:"libmysql.def" /out:"..\lib_release\libmysql.dll" /libpath:"." /libpath:"..\lib_release" # SUBTRACT LINK32 /pdb:none @@ -85,7 +85,7 @@ PostBuild_Cmds=xcopy release\libmysql.lib ..\lib_release /y BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo -LINK32=link.exe +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:windows /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 zlib.lib wsock32.lib 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:windows /dll /incremental:no /map /debug /machine:I386 /def:"libmysql.def" /out:"..\lib_debug\libmysql.dll" /pdbtype:sept /libpath:"." /libpath:"..\lib_debug" # SUBTRACT LINK32 /pdb:none @@ -255,6 +255,10 @@ SOURCE=..\mysys\mf_pack.c # End Source File # Begin Source File +SOURCE=..\mysys\mf_path.c +# End Source File +# Begin Source File + SOURCE=..\mysys\mf_unixpath.c # End Source File # Begin Source File diff --git a/VC++Files/mysql.dsw b/VC++Files/mysql.dsw index eef82588fa8..9903c91ba1b 100644 --- a/VC++Files/mysql.dsw +++ b/VC++Files/mysql.dsw @@ -605,6 +605,9 @@ Package=<5> Package=<4> {{{ + Begin Project Dependency + Project_Dep_Name strings + End Project Dependency }}} ############################################################################### diff --git a/acinclude.m4 b/acinclude.m4 index 970620d9be7..269b505386c 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -78,7 +78,7 @@ AC_LANG_SAVE AC_LANG_CPLUSPLUS if test "$ac_cv_prog_gxx" = "yes" then - CXXFLAGS="$CXXFLAGS -Werror" + CXXFLAGS=`echo $CXXFLAGS -Werror | sed 's/-fbranch-probabilities//'` fi mysql_cv_btype_last_arg_accept=none [AC_TRY_COMPILE([#if defined(inline) diff --git a/client/mysql.cc b/client/mysql.cc index 2623660033b..155d8b03231 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1091,7 +1091,7 @@ static bool add_line(String &buffer,char *line,char *in_string, { // Add found char to buffer if (inchar == *in_string) *in_string=0; - else if (!*in_string && (inchar == '\'' || inchar == '"')) + else if (!*in_string && (inchar == '\'' || inchar == '"' || inchar == '`')) *in_string=(char) inchar; if (!(*ml_comment)) *out++ = (char) inchar; @@ -2709,31 +2709,32 @@ select_limit, max_join_size); static int put_info(const char *str,INFO_TYPE info_type,uint error) { + FILE *file= (info_type == INFO_ERROR ? stderr : stdout); static int inited=0; if (status.batch) { if (info_type == INFO_ERROR) { - (void) fflush(stdout); - fprintf(stderr,"ERROR"); + (void) fflush(file); + fprintf(file,"ERROR"); if (error) - (void) fprintf(stderr," %d",error); + (void) fprintf(file," %d",error); if (status.query_start_line && line_numbers) { - (void) fprintf(stderr," at line %lu",status.query_start_line); + (void) fprintf(file," at line %lu",status.query_start_line); if (status.file_name) - (void) fprintf(stderr," in file: '%s'", status.file_name); + (void) fprintf(file," in file: '%s'", status.file_name); } - (void) fprintf(stderr,": %s\n",str); - (void) fflush(stderr); + (void) fprintf(file,": %s\n",str); + (void) fflush(file); if (!ignore_errors) return 1; } else if (info_type == INFO_RESULT && verbose > 1) - tee_puts(str, stdout); + tee_puts(str, file); if (unbuffered) - fflush(stdout); + fflush(file); return info_type == INFO_ERROR ? -1 : 0; } if (!opt_silent || info_type == INFO_ERROR) @@ -2751,17 +2752,17 @@ put_info(const char *str,INFO_TYPE info_type,uint error) putchar('\007'); /* This should make a bell */ vidattr(A_STANDOUT); if (error) - (void) tee_fprintf(stderr, "ERROR %d: ", error); + (void) tee_fprintf(file, "ERROR %d: ", error); else - tee_puts("ERROR: ", stdout); + tee_puts("ERROR: ", file); } else vidattr(A_BOLD); - (void) tee_puts(str, stdout); + (void) tee_puts(str, file); vidattr(A_NORMAL); } if (unbuffered) - fflush(stdout); + fflush(file); return info_type == INFO_ERROR ? -1 : 0; } diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index a5f769c0782..ff86882bad3 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -45,6 +45,7 @@ static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace"; void sql_print_error(const char *format, ...); static bool one_database = 0; +static bool force_opt= 0; static const char* database; static bool short_form = 0; static ulonglong offset = 0; @@ -201,6 +202,9 @@ static struct my_option my_long_options[] = {"database", 'd', "List entries for just this database (local log only)", (gptr*) &database, (gptr*) &database, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"force-read", 'f', "Force reading unknown binlog events", + (gptr*) &force_opt, (gptr*) &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + 0, 0}, {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"host", 'h', "Get the binlog from server", (gptr*) &host, (gptr*) &host, diff --git a/client/mysqldump.c b/client/mysqldump.c index b5e596ba072..17780458a2a 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1613,7 +1613,7 @@ int main(int argc, char **argv) else { row = mysql_fetch_row(master); - if (row[0] && row[1]) + if (row && row[0] && row[1]) { fprintf(md_result_file, "\n--\n-- Position to start replication from\n--\n\n"); diff --git a/client/mysqltest.c b/client/mysqltest.c index fb2104f43f4..9889d365335 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -939,16 +939,16 @@ int do_system(struct st_query* q) var_init(&v, 0, 0, 0, 0); eval_expr(&v, p, 0); /* NULL terminated */ if (v.str_val_len) - { - char expr_buf[512]; - if ((uint)v.str_val_len > sizeof(expr_buf) - 1) - v.str_val_len = sizeof(expr_buf) - 1; - memcpy(expr_buf, v.str_val, v.str_val_len); - expr_buf[v.str_val_len] = 0; - DBUG_PRINT("info", ("running system command '%s'", expr_buf)); - if (system(expr_buf) && q->abort_on_error) - die("system command '%s' failed", expr_buf); - } + { + char expr_buf[512]; + if ((uint)v.str_val_len > sizeof(expr_buf) - 1) + v.str_val_len = sizeof(expr_buf) - 1; + memcpy(expr_buf, v.str_val, v.str_val_len); + expr_buf[v.str_val_len] = 0; + DBUG_PRINT("info", ("running system command '%s'", expr_buf)); + if (system(expr_buf) && q->abort_on_error) + die("system command '%s' failed", expr_buf); + } var_free(&v); return 0; } @@ -2284,7 +2284,7 @@ void get_query_type(struct st_query* q) q->type=(enum enum_commands) type; /* Found command */ } -static byte* get_var_key(const byte* var, uint* len, +static byte *get_var_key(const byte* var, uint* len, my_bool __attribute__((unused)) t) { register char* key; @@ -2293,11 +2293,11 @@ static byte* get_var_key(const byte* var, uint* len, return (byte*)key; } -static VAR* var_init(VAR* v, const char* name, int name_len, const char* val, +static VAR *var_init(VAR *v, const char *name, int name_len, const char *val, int val_len) { int val_alloc_len; - VAR* tmp_var; + VAR *tmp_var; if (!name_len && name) name_len = strlen(name); if (!val_len && val) @@ -2327,7 +2327,7 @@ static VAR* var_init(VAR* v, const char* name, int name_len, const char* val, return tmp_var; } -static void var_free(void* v) +static void var_free(void *v) { my_free(((VAR*) v)->str_val, MYF(MY_WME)); if (((VAR*)v)->alloced) @@ -2335,10 +2335,10 @@ static void var_free(void* v) } -static void var_from_env(const char* name, const char* def_val) +static void var_from_env(const char *name, const char *def_val) { - const char* tmp; - VAR* v; + const char *tmp; + VAR *v; if (!(tmp = getenv(name))) tmp = def_val; @@ -2347,9 +2347,9 @@ static void var_from_env(const char* name, const char* def_val) } -static void init_var_hash() +static void init_var_hash(MYSQL *mysql) { - VAR* v; + VAR *v; DBUG_ENTER("init_var_hash"); if (hash_init(&var_hash, charset_info, 1024, 0, 0, get_var_key, var_free, MYF(0))) @@ -2358,16 +2358,19 @@ static void init_var_hash() var_from_env("SLAVE_MYPORT", "9307"); var_from_env("MYSQL_TEST_DIR", "/tmp"); var_from_env("BIG_TEST", opt_big_test ? "1" : "0"); - v=var_init(0,"MAX_TABLES", 0, (sizeof(ulong) == 4) ? "31" : "63",0); - hash_insert(&var_hash, (byte*)v); + v= var_init(0,"MAX_TABLES", 0, (sizeof(ulong) == 4) ? "31" : "62",0); + hash_insert(&var_hash, (byte*) v); + v= var_init(0,"SERVER_VERSION", 0, mysql_get_server_info(mysql), 0); + hash_insert(&var_hash, (byte*) v); + DBUG_VOID_RETURN; } -int main(int argc, char** argv) +int main(int argc, char **argv) { int error = 0; - struct st_query* q; + struct st_query *q; my_bool require_file=0, q_send_flag=0; char save_file[FN_REFLEN]; MY_INIT(argv[0]); @@ -2402,7 +2405,6 @@ int main(int argc, char** argv) embedded_server_args, (char**) embedded_server_groups)) die("Can't initialize MySQL server"); - init_var_hash(); if (cur_file == file_stack) *++cur_file = stdin; *lineno=1; @@ -2421,14 +2423,14 @@ int main(int argc, char** argv) opt_ssl_capath, opt_ssl_cipher); #endif - cur_con->name = my_strdup("default", MYF(MY_WME)); - if (!cur_con->name) + if (!(cur_con->name = my_strdup("default", MYF(MY_WME)))) die("Out of memory"); - if (safe_connect(&cur_con->mysql, host, - user, pass, db, port, unix_sock)) + if (safe_connect(&cur_con->mysql, host, user, pass, db, port, unix_sock)) die("Failed in mysql_real_connect(): %s", mysql_error(&cur_con->mysql)); + init_var_hash(&cur_con->mysql); + while (!read_query(&q)) { int current_line_inc = 1, processed = 0; @@ -2596,7 +2598,7 @@ int main(int argc, char** argv) */ -static int read_server_arguments(const char* name) +static int read_server_arguments(const char *name) { char argument[1024],buff[FN_REFLEN], *str=0; FILE *file; diff --git a/configure.in b/configure.in index 90c8e81bd47..c0ce5221832 100644 --- a/configure.in +++ b/configure.in @@ -1005,8 +1005,9 @@ case $SYSTEM_TYPE in *darwin5*) if test "$ac_cv_prog_gcc" = "yes" then - CFLAGS="$CFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH -DFN_NO_CASE_SENCE" - CXXFLAGS="$CXXFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DFN_NO_CASE_SENCE" + FLAGS="-traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH -DFN_NO_CASE_SENCE" + CFLAGS="$CFLAGS $FLAGS" + CXXFLAGS="$CXXFLAGS $FLAGS" MAX_C_OPTIMIZE="-O" with_named_curses="" fi @@ -1014,8 +1015,9 @@ case $SYSTEM_TYPE in *darwin6*) if test "$ac_cv_prog_gcc" = "yes" then - CFLAGS="$CFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH -DFN_NO_CASE_SENCE" - CXXFLAGS="$CXXFLAGS -traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DFN_NO_CASE_SENCE" + FLAGS="-traditional-cpp -DHAVE_DARWIN_THREADS -D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DHAVE_BROKEN_REALPATH -DFN_NO_CASE_SENCE" + CFLAGS="$CFLAGS $FLAGS" + CXXFLAGS="$CXXFLAGS $FLAGS" MAX_C_OPTIMIZE="-O" fi ;; @@ -1365,10 +1367,8 @@ then with_named_thread="-Kthread -lsocket -lnsl" if expr "$SYSTEM_TYPE" : ".*unixware7.0.0" > /dev/null then -# AC_DEFINE(HAVE_OpenUNIX8_THREADS) AC_DEFINE(HAVE_UNIXWARE7_THREADS) else -# AC_DEFINE(HAVE_OpenUNIX8_POSIX) AC_DEFINE(HAVE_UNIXWARE7_POSIX) fi # We must have cc @@ -1377,10 +1377,8 @@ then then { echo "configure: error: On OpenUNIX8 and UnixWare7 MySQL must be compiled with cc. See the Installation chapter in the Reference Manual." 1>&2; exit 1; }; else -# CC="$CC -Kthread -DOpenUNIX8"; -# CXX="$CXX -Kthread -DOpenUNIX8"; - CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; - CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK" + CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; + CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; fi AC_MSG_RESULT("yes") else @@ -1877,7 +1875,7 @@ AC_LANG_SAVE AC_LANG_CPLUSPLUS if test "$ac_cv_prog_gxx" = "yes" -a "$with_other_libc" = "no" then - CXXFLAGS="$CXXFLAGS -Werror" + CXXFLAGS=`echo "$CXXFLAGS -Werror" | sed 's/-fbranch-probabilities//'` fi AC_TRY_COMPILE( [#undef inline @@ -1909,7 +1907,7 @@ AC_LANG_SAVE AC_LANG_CPLUSPLUS if test "$ac_cv_prog_gxx" = "yes" -a "$with_other_libc" = "no" then - CXXFLAGS="$CXXFLAGS -Werror" + CXXFLAGS=`echo "$CXXFLAGS -Werror" | sed 's/-fbranch-probabilities//'` fi AC_TRY_COMPILE( [#undef inline diff --git a/include/Makefile.am b/include/Makefile.am index 7372d3ab417..3a197c310aa 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -35,7 +35,7 @@ noinst_HEADERS = config-win.h config-os2.h config-netware.h \ SUPERCLEANFILES = mysql_version.h my_config.h # Some include files that may be moved and patched by configure -DISTCLEANFILES = sched.h +DISTCLEANFILES = sched.h $(SUPERCLEANFILES) clean: $(RM) -f readline/* diff --git a/include/config-win.h b/include/config-win.h index 0e01aa75570..b0a30353196 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -153,6 +153,9 @@ typedef uint rf_SetTimer; #define USE_MB_IDENT 1 #define USE_STRCOLL 1 +/* If LOAD DATA LOCAL INFILE should be enabled by default */ +#define ENABLED_LOCAL_INFILE 1 + /* Convert some simple functions to Posix */ #define sigset(A,B) signal((A),(B)) diff --git a/include/my_base.h b/include/my_base.h index b806436fe0e..ac41d9e50ef 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -225,6 +225,7 @@ enum ha_base_keytype { /* Errorcodes given by functions */ +/* opt_sum_query() assumes these codes are > 1 */ #define HA_ERR_KEY_NOT_FOUND 120 /* Didn't find key on read or update */ #define HA_ERR_FOUND_DUPP_KEY 121 /* Dupplicate key on write */ #define HA_ERR_RECORD_CHANGED 123 /* Uppdate with is recoverable */ diff --git a/include/my_global.h b/include/my_global.h index 510de43c9ee..86fb2a5ee4d 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -287,6 +287,10 @@ C_MODE_END #include <asm/atomic.h> #endif #include <errno.h> /* Recommended by debian */ +/* We need the following to go around a problem with openssl on solaris */ +#if defined(HAVE_CRYPT_H) +#include <crypt.h> +#endif /* Go around some bugs in different OS and compilers */ #if defined(_HPUX_SOURCE) && defined(HAVE_SYS_STREAM_H) @@ -306,9 +310,7 @@ C_MODE_END /* This has to be after include limits.h */ #define HAVE_ERRNO_AS_DEFINE #define HAVE_FCNTL_LOCK -#undef HAVE_SYS_UN_H #undef HAVE_FINITE -#undef HAVE_RINT #undef LONGLONG_MIN /* These get wrongly defined in QNX 6.2 */ #undef LONGLONG_MAX /* standard system library 'limits.h' */ #endif @@ -377,7 +379,7 @@ typedef unsigned short ushort; #define set_bits(type, bit_count) (sizeof(type)*8 <= (bit_count) ? ~(type) 0 : ((((type) 1) << (bit_count)) - (type) 1)) #define array_elements(A) ((uint) (sizeof(A)/sizeof(A[0]))) #ifndef HAVE_RINT -#define rint(A) floor((A)+0.5) +#define rint(A) floor((A)+(((A) < 0)? -0.5 : 0.5)) #endif /* Define some general constants */ diff --git a/include/my_pthread.h b/include/my_pthread.h index 58f89517679..bff82ef7320 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -248,6 +248,11 @@ extern int my_sigwait(const sigset_t *set,int *sig); #error Requires at least rev 2 of EMX pthreads library. #endif +#ifdef __NETWARE__ +void my_pthread_exit(void *status); +#define pthread_exit(A) my_pthread_exit(A) +#endif + extern int my_pthread_getprio(pthread_t thread_id); #define pthread_key(T,V) pthread_key_t V diff --git a/include/my_semaphore.h b/include/my_semaphore.h index 3431212ec82..7f182bea6bf 100644 --- a/include/my_semaphore.h +++ b/include/my_semaphore.h @@ -31,6 +31,8 @@ #ifndef _my_semaphore_h_ #define _my_semaphore_h_ +#ifdef THREAD + C_MODE_START #ifdef HAVE_SEMAPHORE_H #include <semaphore.h> @@ -56,4 +58,7 @@ int sem_getvalue(sem_t * sem, unsigned int * sval); #endif /* !__bsdi__ */ C_MODE_END + +#endif /* THREAD */ + #endif /* !_my_semaphore_h_ */ diff --git a/include/my_sys.h b/include/my_sys.h index 5a769791955..b4fc20e8471 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -743,6 +743,7 @@ extern my_bool my_uncompress(byte *, ulong *, ulong *); extern byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen); extern ulong checksum(const byte *mem, uint count); extern uint my_bit_log2(ulong value); +uint my_count_bits(ulonglong v); extern void my_sleep(ulong m_seconds); #ifdef __WIN__ diff --git a/include/violite.h b/include/violite.h index a5c063700b4..3b61fbf344e 100644 --- a/include/violite.h +++ b/include/violite.h @@ -165,7 +165,7 @@ my_bool vio_ssl_should_retry(Vio* vio); int vio_ssl_close(Vio* vio); /* Return last error number */ int vio_ssl_errno(Vio *vio); -my_bool vio_ssl_peer_addr(Vio* vio, char *buf); +my_bool vio_ssl_peer_addr(Vio* vio, char *buf, uint16 *port); void vio_ssl_in_addr(Vio *vio, struct in_addr *in); int vio_ssl_blocking(Vio * vio, my_bool set_blocking_mode, my_bool *old_mode); @@ -242,7 +242,7 @@ struct st_vio my_bool (*is_blocking)(Vio*); int (*viokeepalive)(Vio*, my_bool); int (*fastsend)(Vio*); - my_bool (*peer_addr)(Vio*, gptr, uint16*); + my_bool (*peer_addr)(Vio*, char *, uint16*); void (*in_addr)(Vio*, struct in_addr*); my_bool (*should_retry)(Vio*); int (*vioclose)(Vio*); diff --git a/innobase/btr/Makefile.am b/innobase/btr/Makefile.am index 6e3dd4fb007..ed61facb695 100644 --- a/innobase/btr/Makefile.am +++ b/innobase/btr/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libbtr.a +noinst_LIBRARIES = libbtr.a libbtr_a_SOURCES = btr0btr.c btr0cur.c btr0pcur.c btr0sea.c diff --git a/innobase/buf/Makefile.am b/innobase/buf/Makefile.am index b1463c2220e..3f56c8b02d7 100644 --- a/innobase/buf/Makefile.am +++ b/innobase/buf/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libbuf.a +noinst_LIBRARIES = libbuf.a libbuf_a_SOURCES = buf0buf.c buf0flu.c buf0lru.c buf0rea.c diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index 14d538a14bc..1cdddaf6cb4 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -597,8 +597,9 @@ buf_pool_init( /* Wipe contents of frame to eliminate a Purify warning */ +#ifdef HAVE_purify memset(block->frame, '\0', UNIV_PAGE_SIZE); - +#endif if (srv_use_awe) { /* Add to the list of blocks mapped to frames */ @@ -1837,7 +1838,7 @@ buf_pool_invalidate(void) freed = TRUE; while (freed) { - freed = buf_LRU_search_and_free_block(0); + freed = buf_LRU_search_and_free_block(100); } mutex_enter(&(buf_pool->mutex)); @@ -2057,6 +2058,29 @@ buf_get_n_pending_ios(void) } /************************************************************************* +Returns the ratio in percents of modified pages in the buffer pool / +database pages in the buffer pool. */ + +ulint +buf_get_modified_ratio_pct(void) +/*============================*/ +{ + ulint ratio; + + mutex_enter(&(buf_pool->mutex)); + + ratio = (100 * UT_LIST_GET_LEN(buf_pool->flush_list)) + / (1 + UT_LIST_GET_LEN(buf_pool->LRU) + + UT_LIST_GET_LEN(buf_pool->free)); + + /* 1 + is there to avoid division by zero */ + + mutex_exit(&(buf_pool->mutex)); + + return(ratio); +} + +/************************************************************************* Prints info of the buffer i/o. */ void @@ -2109,8 +2133,10 @@ buf_print_io( buf += sprintf(buf, "Pending writes: LRU %lu, flush list %lu, single page %lu\n", - buf_pool->n_flush[BUF_FLUSH_LRU], - buf_pool->n_flush[BUF_FLUSH_LIST], + buf_pool->n_flush[BUF_FLUSH_LRU] + + buf_pool->init_flush[BUF_FLUSH_LRU], + buf_pool->n_flush[BUF_FLUSH_LIST] + + buf_pool->init_flush[BUF_FLUSH_LIST], buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]); current_time = time(NULL); @@ -2144,7 +2170,7 @@ buf_print_io( / (buf_pool->n_page_gets - buf_pool->n_page_gets_old))); } else { buf += sprintf(buf, - "No buffer pool activity since the last printout\n"); + "No buffer pool page gets since the last printout\n"); } buf_pool->n_page_gets_old = buf_pool->n_page_gets; diff --git a/innobase/buf/buf0flu.c b/innobase/buf/buf0flu.c index 02587487a92..47ac9c6b041 100644 --- a/innobase/buf/buf0flu.c +++ b/innobase/buf/buf0flu.c @@ -107,7 +107,7 @@ buf_flush_ready_for_replace( BUF_BLOCK_FILE_PAGE and in the LRU list */ { ut_ad(mutex_own(&(buf_pool->mutex))); - ut_ad(block->state == BUF_BLOCK_FILE_PAGE); + ut_a(block->state == BUF_BLOCK_FILE_PAGE); if ((ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) > 0) || (block->buf_fix_count != 0) @@ -227,7 +227,9 @@ buf_flush_buffered_writes(void) } for (i = 0; i < trx_doublewrite->first_free; i++) { + block = trx_doublewrite->buf_block_arr[i]; + ut_a(block->state == BUF_BLOCK_FILE_PAGE); if (block->check_index_page_at_flush && !page_simple_validate(block->frame)) { @@ -236,10 +238,12 @@ buf_flush_buffered_writes(void) ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB: Apparent corruption of an index page\n" + " InnoDB: Apparent corruption of an index page n:o %lu in space %lu\n" "InnoDB: to be written to data file. We intentionally crash server\n" "InnoDB: to prevent corrupt data from ending up in data\n" - "InnoDB: files.\n"); + "InnoDB: files.\n", + block->offset, block->space); + ut_a(0); } } @@ -394,7 +398,7 @@ buf_flush_write_block_low( "Warning: cannot force log to disk in the log debug version!\n"); #else /* Force the log to the disk before writing the modified block */ - log_flush_up_to(block->newest_modification, LOG_WAIT_ALL_GROUPS); + log_write_up_to(block->newest_modification, LOG_WAIT_ALL_GROUPS, TRUE); #endif buf_flush_init_for_writing(block->frame, block->newest_modification, block->space, block->offset); @@ -432,6 +436,8 @@ buf_flush_try_page( block = buf_page_hash_get(space, offset); + ut_a(block->state == BUF_BLOCK_FILE_PAGE); + if (flush_type == BUF_FLUSH_LIST && block && buf_flush_ready_for_flush(block, flush_type)) { @@ -567,7 +573,8 @@ buf_flush_try_page( rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE); if (buf_debug_prints) { - printf("Flushing single page space %lu, page no %lu \n", + printf( + "Flushing single page space %lu, page no %lu \n", block->space, block->offset); } @@ -608,15 +615,7 @@ buf_flush_try_neighbors( low = offset; high = offset + 1; - } else if (flush_type == BUF_FLUSH_LIST) { - /* Since semaphore waits require us to flush the - doublewrite buffer to disk, it is best that the - search area is just the page itself, to minimize - chances for semaphore waits */ - - low = offset; - high = offset + 1; - } + } /* printf("Flush area: low %lu high %lu\n", low, high); */ @@ -633,13 +632,20 @@ buf_flush_try_neighbors( if (block && flush_type == BUF_FLUSH_LRU && i != offset && !block->old) { - /* We avoid flushing 'non-old' blocks in an LRU flush, - because the flushed blocks are soon freed */ + /* We avoid flushing 'non-old' blocks in an LRU flush, + because the flushed blocks are soon freed */ - continue; + continue; } - if (block && buf_flush_ready_for_flush(block, flush_type)) { + if (block && buf_flush_ready_for_flush(block, flush_type) + && (i == offset || block->buf_fix_count == 0)) { + /* We only try to flush those neighbors != offset + where the buf fix count is zero, as we then know that + we probably can latch the page without a semaphore + wait. Semaphore waits are expensive because we must + flush the doublewrite buffer before we start + waiting. */ mutex_exit(&(buf_pool->mutex)); @@ -758,7 +764,6 @@ buf_flush_batch( page_count += buf_flush_try_neighbors(space, offset, flush_type); - /* printf( "Flush type %lu, page no %lu, neighb %lu\n", flush_type, offset, @@ -884,11 +889,19 @@ buf_flush_free_margin(void) /*=======================*/ { ulint n_to_flush; + ulint n_flushed; n_to_flush = buf_flush_LRU_recommendation(); if (n_to_flush > 0) { - buf_flush_batch(BUF_FLUSH_LRU, n_to_flush, ut_dulint_zero); + n_flushed = buf_flush_batch(BUF_FLUSH_LRU, n_to_flush, + ut_dulint_zero); + if (n_flushed == ULINT_UNDEFINED) { + /* There was an LRU type flush batch already running; + let us wait for it to end */ + + buf_flush_wait_batch_end(BUF_FLUSH_LRU); + } } } diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c index 051aa0191f6..40f49f1fddc 100644 --- a/innobase/buf/buf0lru.c +++ b/innobase/buf/buf0lru.c @@ -104,12 +104,15 @@ ibool buf_LRU_search_and_free_block( /*==========================*/ /* out: TRUE if freed */ - ulint n_iterations __attribute__((unused))) /* in: how many times - this has been called repeatedly without - result: a high value means that we should - search farther */ + ulint n_iterations) /* in: how many times this has been called + repeatedly without result: a high value means + that we should search farther; if value is + k < 10, then we only search k/10 * [number + of pages in the buffer pool] from the end + of the LRU list */ { buf_block_t* block; + ulint distance = 0; ibool freed; mutex_enter(&(buf_pool->mutex)); @@ -152,6 +155,18 @@ buf_LRU_search_and_free_block( } block = UT_LIST_GET_PREV(LRU, block); + distance++; + + if (!freed && n_iterations <= 10 + && distance > 100 + (n_iterations * buf_pool->curr_size) + / 10) { + + buf_pool->LRU_flush_ended = 0; + + mutex_exit(&(buf_pool->mutex)); + + return(FALSE); + } } if (buf_pool->LRU_flush_ended > 0) { @@ -186,7 +201,7 @@ buf_LRU_try_free_flushed_blocks(void) mutex_exit(&(buf_pool->mutex)); - buf_LRU_search_and_free_block(0); + buf_LRU_search_and_free_block(1); mutex_enter(&(buf_pool->mutex)); } @@ -208,7 +223,7 @@ buf_LRU_get_free_block(void) { buf_block_t* block = NULL; ibool freed; - ulint n_iterations = 0; + ulint n_iterations = 1; ibool mon_value_was = 0; /* remove bug */ ibool started_monitor = FALSE; loop: @@ -236,9 +251,12 @@ loop: fprintf(stderr, " InnoDB: WARNING: over 4 / 5 of the buffer pool is occupied by\n" "InnoDB: lock heaps or the adaptive hash index! Check that your\n" -"InnoDB: transactions do not set too many row locks. Starting InnoDB\n" -"InnoDB: Monitor to print diagnostics, including lock heap and hash index\n" -"InnoDB: sizes.\n"); +"InnoDB: transactions do not set too many row locks.\n" +"InnoDB: Your buffer pool size is %lu MB. Maybe you should make\n" +"InnoDB: the buffer pool bigger?\n" +"InnoDB: Starting the InnoDB Monitor to print diagnostics, including\n" +"InnoDB: lock heap and hash index sizes.\n", + buf_pool->curr_size / (1024 * 1024 / UNIV_PAGE_SIZE)); srv_print_innodb_monitor = TRUE; @@ -251,14 +269,6 @@ loop: srv_print_innodb_monitor = FALSE; } - - if (buf_pool->LRU_flush_ended > 0) { - mutex_exit(&(buf_pool->mutex)); - - buf_LRU_try_free_flushed_blocks(); - - mutex_enter(&(buf_pool->mutex)); - } /* If there is a block in the free list, take it */ if (UT_LIST_GET_LEN(buf_pool->free) > 0) { @@ -340,6 +350,20 @@ loop: os_aio_simulated_wake_handler_threads(); + mutex_enter(&(buf_pool->mutex)); + + if (buf_pool->LRU_flush_ended > 0) { + /* We have written pages in an LRU flush. To make the insert + buffer more efficient, we try to move these pages to the free + list. */ + + mutex_exit(&(buf_pool->mutex)); + + buf_LRU_try_free_flushed_blocks(); + } else { + mutex_exit(&(buf_pool->mutex)); + } + if (n_iterations > 10) { os_thread_sleep(500000); diff --git a/innobase/com/Makefile.am b/innobase/com/Makefile.am index 27ae396bc6e..a3d2f8a76c6 100644 --- a/innobase/com/Makefile.am +++ b/innobase/com/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libcom.a +noinst_LIBRARIES = libcom.a libcom_a_SOURCES = com0com.c com0shm.c diff --git a/innobase/data/Makefile.am b/innobase/data/Makefile.am index 0e502708e85..eeb6f129de0 100644 --- a/innobase/data/Makefile.am +++ b/innobase/data/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libdata.a +noinst_LIBRARIES = libdata.a libdata_a_SOURCES = data0data.c data0type.c diff --git a/innobase/dict/Makefile.am b/innobase/dict/Makefile.am index 693048b6784..0034d2f8f1e 100644 --- a/innobase/dict/Makefile.am +++ b/innobase/dict/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libdict.a +noinst_LIBRARIES = libdict.a libdict_a_SOURCES = dict0boot.c dict0crea.c dict0dict.c dict0load.c\ dict0mem.c diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c index b0f84e5663a..3619ac02f4d 100644 --- a/innobase/dict/dict0crea.c +++ b/innobase/dict/dict0crea.c @@ -1173,6 +1173,7 @@ dict_create_add_foreigns_to_dictionary( if (NULL == dict_table_get_low((char *) "SYS_FOREIGN")) { fprintf(stderr, "InnoDB: table SYS_FOREIGN not found from internal data dictionary\n"); + return(DB_ERROR); } @@ -1259,6 +1260,13 @@ loop: "InnoDB: at http://www.innodb.com/ibman.html\n"); } + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Internal error in foreign key constraint creation for table %.500s.\n" +"See the MySQL .err log in the datadir for more information.\n", table->name); + mutex_exit(&dict_foreign_err_mutex); + return(error); } diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index 9be10fe70d8..c11a5f76d94 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -185,6 +185,14 @@ dict_foreign_free( /*==============*/ dict_foreign_t* foreign); /* in, own: foreign key struct */ +/* Buffers for storing detailed information about the latest foreign key +and unique key errors */ +char* dict_foreign_err_buf = NULL; +char* dict_unique_err_buf = NULL; +mutex_t dict_foreign_err_mutex; /* mutex protecting the foreign + and unique error buffers */ + + /************************************************************************ Checks if the database name in two table names is the same. */ static @@ -573,6 +581,13 @@ dict_init(void) rw_lock_create(&dict_operation_lock); rw_lock_set_level(&dict_operation_lock, SYNC_DICT_OPERATION); + + dict_foreign_err_buf = mem_alloc(DICT_FOREIGN_ERR_BUF_LEN); + dict_foreign_err_buf[0] = '\0'; + dict_unique_err_buf = mem_alloc(DICT_FOREIGN_ERR_BUF_LEN); + dict_unique_err_buf[0] = '\0'; + mutex_create(&dict_foreign_err_mutex); + mutex_set_level(&dict_foreign_err_mutex, SYNC_ANY_LATCH); } /************************************************************************** @@ -1818,6 +1833,7 @@ dict_foreign_add_to_cache( dict_foreign_t* for_in_cache = NULL; dict_index_t* index; ibool added_to_referenced_list = FALSE; + char* buf = dict_foreign_err_buf; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -1850,9 +1866,29 @@ dict_foreign_add_to_cache( for_in_cache->foreign_index); if (index == NULL) { + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Error in foreign key constraint of table %.500s:\n" +"there is no index in referenced table which would contain\n" +"the columns as the first columns, or the data types in the\n" +"referenced table do not match to the ones in table. Constraint:\n", + for_in_cache->foreign_table_name); + dict_print_info_on_foreign_key_in_create_format( + for_in_cache, buf + strlen(buf)); + if (for_in_cache->foreign_index) { + sprintf(buf + strlen(buf), +"\nThe index in the foreign key in table is %.500s\n" +"See http://www.innodb.com/ibman.html about correct foreign key definition.\n", + for_in_cache->foreign_index->name); + } + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + if (for_in_cache == foreign) { mem_heap_free(foreign->heap); } + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -1871,6 +1907,25 @@ dict_foreign_add_to_cache( for_in_cache->referenced_index); if (index == NULL) { + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Error in foreign key constraint of table %.500s:\n" +"there is no index in the table which would contain\n" +"the columns as the first columns, or the data types in the\n" +"table do not match to the ones in the referenced table. Constraint:\n", + for_in_cache->foreign_table_name); + dict_print_info_on_foreign_key_in_create_format( + for_in_cache, buf + strlen(buf)); + if (for_in_cache->foreign_index) { + sprintf(buf + strlen(buf), +"\nIndex of the foreign key in the referenced table is %.500s\n" +"See http://www.innodb.com/ibman.html about correct foreign key definition.\n", + for_in_cache->referenced_index->name); + } + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + if (for_in_cache == foreign) { if (added_to_referenced_list) { UT_LIST_REMOVE(referenced_list, @@ -2038,7 +2093,7 @@ dict_scan_col( if (*ptr == '`') { ptr++; } - + return(ptr); } @@ -2141,18 +2196,21 @@ dict_scan_table_name( } /************************************************************************* -Skips one 'word', like an id. For the lexical definition of 'word', see the -code below. */ +Scans an id. For the lexical definition of an 'id', see the code below. +Strips backquotes from around the id. */ static char* -dict_skip_word( -/*===========*/ +dict_scan_id( +/*=========*/ /* out: scanned to */ char* ptr, /* in: scanned to */ - ibool* success)/* out: TRUE if success, FALSE if just spaces left in - string */ + char** start, /* out: start of the id; NULL if no id was + scannable */ + ulint* len) /* out: length of the id */ { - *success = FALSE; + ibool scanned_backquote = FALSE; + + *start = NULL; while (isspace(*ptr)) { ptr++; @@ -2164,24 +2222,61 @@ dict_skip_word( } if (*ptr == '`') { + scanned_backquote = TRUE; ptr++; } - while (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && *ptr != '`' - && *ptr != '\0') { + *start = ptr; + + while (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && *ptr != ')' + && *ptr != '\0' && *ptr != '`') { ptr++; } - *success = TRUE; + *len = (ulint) (ptr - *start); + + if (scanned_backquote) { + if (*ptr == '`') { + ptr++; + } else { + /* Syntax error */ + *start = NULL; + } + } return(ptr); } /************************************************************************* +Skips one id. */ +static +char* +dict_skip_word( +/*===========*/ + /* out: scanned to */ + char* ptr, /* in: scanned to */ + ibool* success)/* out: TRUE if success, FALSE if just spaces left in + string or a syntax error */ +{ + char* start; + ulint len; + + *success = FALSE; + + ptr = dict_scan_id(ptr, &start, &len); + + if (start) { + *success = TRUE; + } + + return(ptr); +} + +#ifdef currentlynotused +/************************************************************************* Returns the number of opening brackets '(' subtracted by the number of closing brackets ')' between string and ptr. */ -#ifdef NOT_USED static int dict_bracket_count( @@ -2206,16 +2301,116 @@ dict_bracket_count( return(count); } #endif + +/************************************************************************* +Removes MySQL comments from an SQL string. A comment is either +(a) '#' to the end of the line, +(b) '--<space>' to the end of the line, or +(c) '<slash><asterisk>' till the next '<asterisk><slash>' (like the familiar +C comment syntax). */ +static +char* +dict_strip_comments( +/*================*/ + /* out, own: SQL string stripped from + comments; the caller must free this + with mem_free()! */ + char* sql_string) /* in: SQL string */ +{ + char* str; + char* sptr; + char* ptr; + + str = mem_alloc(strlen(sql_string) + 1); + + sptr = sql_string; + ptr = str; + + for (;;) { + if (*sptr == '\0') { + *ptr = '\0'; + + return(str); + } + + if (*sptr == '#' + || (strlen(sptr) >= 3 && 0 == memcmp("-- ", sptr, 3))) { + for (;;) { + /* In Unix a newline is 0x0D while in Windows + it is 0x0A followed by 0x0D */ + + if (*sptr == (char)0x0A + || *sptr == (char)0x0D + || *sptr == '\0') { + + break; + } + + sptr++; + } + } + + if (strlen(sptr) >= 2 && *sptr == '/' && *(sptr + 1) == '*') { + for (;;) { + if (strlen(sptr) >= 2 + && *sptr == '*' && *(sptr + 1) == '/') { + + sptr += 2; + + break; + } + + if (*sptr == '\0') { + + break; + } + + sptr++; + } + } + + *ptr = *sptr; + + ptr++; + sptr++; + } +} + +/************************************************************************* +Reports a simple foreign key create clause syntax error. */ +static +void +dict_foreign_report_syntax_err( +/*===========================*/ + char* name, /* in: table name */ + char* start_of_latest_foreign,/* in: start of the foreign key clause + in the SQL string */ + char* ptr) /* in: place of the syntax error */ +{ + char* buf = dict_foreign_err_buf; + + mutex_enter(&dict_foreign_err_mutex); + + ut_sprintf_timestamp(buf); + + sprintf(buf + strlen(buf), +" Error in foreign key constraint of table %.500s,\n%.500s.\n" +"Syntax error close to:\n%.500s\n", name, start_of_latest_foreign, ptr); + + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); +} + /************************************************************************* Scans a table create SQL string and adds to the data dictionary the foreign key constraints declared in the string. This function should be called after the indexes for a table have been created. Each foreign key constraint must be accompanied with indexes in both participating tables. The indexes are allowed to contain more fields than mentioned in the constraint. */ - +static ulint -dict_create_foreign_constraints( -/*============================*/ +dict_create_foreign_constraints_low( +/*================================*/ /* out: error code or DB_SUCCESS */ trx_t* trx, /* in: transaction */ char* sql_string, /* in: table create or ALTER TABLE @@ -2231,7 +2426,9 @@ dict_create_foreign_constraints( dict_table_t* referenced_table; dict_index_t* index; dict_foreign_t* foreign; - char* ptr = sql_string; + char* ptr = sql_string; + char* start_of_latest_foreign = sql_string; + char* buf = dict_foreign_err_buf; ibool success; ulint error; ulint i; @@ -2249,6 +2446,15 @@ dict_create_foreign_constraints( table = dict_table_get_low(name); if (table == NULL) { + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Error in foreign key constraint of table %.500s.\n" +"Cannot find the table from the internal data dictionary of InnoDB.\n" +"Create table statement:\n%.2000\n", name, sql_string); + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + return(DB_ERROR); } loop: @@ -2264,6 +2470,8 @@ loop: return(error); } + start_of_latest_foreign = ptr; + ptr = dict_accept(ptr, (char *) "FOREIGN", &success); if (!isspace(*ptr)) { @@ -2284,13 +2492,19 @@ loop: ptr = dict_skip_word(ptr, &success); if (!success) { + dict_foreign_report_syntax_err(name, + start_of_latest_foreign, ptr); + return(DB_CANNOT_ADD_CONSTRAINT); } ptr = dict_accept(ptr, (char *) "(", &success); if (!success) { - return(DB_CANNOT_ADD_CONSTRAINT); + /* We do not flag a syntax error here because in an + ALTER TABLE we may also have DROP FOREIGN KEY abc */ + + goto loop; } } @@ -2301,6 +2515,15 @@ col_loop1: ptr = dict_scan_col(ptr, &success, table, columns + i, column_names + i, column_name_lens + i); if (!success) { + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Error in foreign key constraint of table %.500s,\n%.500s.\n" +"Cannot resolve column name close to:\n%.500s\n", name, + start_of_latest_foreign, ptr); + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -2315,6 +2538,8 @@ col_loop1: ptr = dict_accept(ptr, (char *) ")", &success); if (!success) { + dict_foreign_report_syntax_err(name, start_of_latest_foreign, + ptr); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -2324,12 +2549,24 @@ col_loop1: index = dict_foreign_find_index(table, column_names, i, NULL); if (!index) { + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Error in foreign key constraint of table %.500s:\n" +"There is no index in the table %.500s where the columns appear\n" +"as the first columns. Constraint:\n%.500s\n" +"See http://www.innodb.com/ibman.html for correct foreign key definition.\n", + name, name, start_of_latest_foreign); + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + return(DB_CANNOT_ADD_CONSTRAINT); } - ptr = dict_accept(ptr, (char *) "REFERENCES", &success); if (!success || !isspace(*ptr)) { + dict_foreign_report_syntax_err(name, start_of_latest_foreign, + ptr); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -2359,6 +2596,15 @@ col_loop1: if (!success || (!referenced_table && trx->check_foreigns)) { dict_foreign_free(foreign); + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Error in foreign key constraint of table %.500s,\n%.500s.\n" +"Cannot resolve table name close to:\n" +"%.500s\n", name, start_of_latest_foreign, ptr); + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -2366,7 +2612,8 @@ col_loop1: if (!success) { dict_foreign_free(foreign); - + dict_foreign_report_syntax_err(name, start_of_latest_foreign, + ptr); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -2381,6 +2628,15 @@ col_loop2: if (!success) { dict_foreign_free(foreign); + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Error in foreign key constraint of table %.500s,\n%.500s\n" +"Cannot resolve column name close to:\n" +"%.500s\n", name, start_of_latest_foreign, ptr); + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -2395,6 +2651,8 @@ col_loop2: if (!success || foreign->n_fields != i) { dict_foreign_free(foreign); + dict_foreign_report_syntax_err(name, start_of_latest_foreign, + ptr); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -2417,9 +2675,10 @@ scan_on_conditions: ptr = dict_accept(ptr, "UPDATE", &success); if (!success) { - dict_foreign_free(foreign); + dict_foreign_report_syntax_err(name, + start_of_latest_foreign, ptr); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -2455,6 +2714,8 @@ scan_on_conditions: if (!success) { dict_foreign_free(foreign); + dict_foreign_report_syntax_err(name, + start_of_latest_foreign, ptr); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -2472,7 +2733,8 @@ scan_on_conditions: if (!success) { dict_foreign_free(foreign); - + dict_foreign_report_syntax_err(name, start_of_latest_foreign, + ptr); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -2480,7 +2742,8 @@ scan_on_conditions: if (!success) { dict_foreign_free(foreign); - + dict_foreign_report_syntax_err(name, start_of_latest_foreign, + ptr); return(DB_CANNOT_ADD_CONSTRAINT); } @@ -2494,6 +2757,15 @@ scan_on_conditions: dict_foreign_free(foreign); + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Error in foreign key constraint of table %.500s,\n%.500s.\n" +"You have defined a SET NULL condition though some of the\n" +"columns is defined as NOT NULL.\n", name, start_of_latest_foreign); + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + return(DB_CANNOT_ADD_CONSTRAINT); } } @@ -2512,6 +2784,15 @@ try_find_index: dict_foreign_free(foreign); + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Error in foreign key constraint of table %.500s,\n%.500s.\n" +"You have twice an ON DELETE clause or twice an ON UPDATE clause.\n", + name, start_of_latest_foreign); + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + return(DB_CANNOT_ADD_CONSTRAINT); } @@ -2525,6 +2806,18 @@ try_find_index: foreign->foreign_index); if (!index) { dict_foreign_free(foreign); + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Error in foreign key constraint of table %.500s:\n" +"Cannot find an index in the referenced table where the\n" +"referenced columns appear as the first columns, or column types\n" +"in the table and the referenced table do not match for constraint:\n%.500s\n" +"See http://www.innodb.com/ibman.html for correct foreign key definition.\n", + name, start_of_latest_foreign); + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + return(DB_CANNOT_ADD_CONSTRAINT); } } else { @@ -2565,6 +2858,165 @@ try_find_index: goto loop; } +/************************************************************************* +Scans a table create SQL string and adds to the data dictionary the foreign +key constraints declared in the string. This function should be called after +the indexes for a table have been created. Each foreign key constraint must +be accompanied with indexes in both participating tables. The indexes are +allowed to contain more fields than mentioned in the constraint. */ + +ulint +dict_create_foreign_constraints( +/*============================*/ + /* out: error code or DB_SUCCESS */ + trx_t* trx, /* in: transaction */ + char* sql_string, /* in: table create or ALTER TABLE + statement where foreign keys are declared like: + FOREIGN KEY (a, b) REFERENCES table2(c, d), + table2 can be written also with the database + name before it: test.table2; the default + database id the database of parameter name */ + char* name) /* in: table full name in the normalized form + database_name/table_name */ +{ + char* str; + ulint err; + + str = dict_strip_comments(sql_string); + + err = dict_create_foreign_constraints_low(trx, str, name); + + mem_free(str); + + return(err); +} + +/************************************************************************** +Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */ + +ulint +dict_foreign_parse_drop_constraints( +/*================================*/ + /* out: DB_SUCCESS or + DB_CANNOT_DROP_CONSTRAINT if + syntax error or the constraint + id does not match */ + mem_heap_t* heap, /* in: heap from which we can + allocate memory */ + trx_t* trx, /* in: transaction */ + dict_table_t* table, /* in: table */ + ulint* n, /* out: number of constraints + to drop */ + char*** constraints_to_drop) /* out: id's of the + constraints to drop */ +{ + dict_foreign_t* foreign; + ibool success; + char* str; + char* ptr; + char* buf = dict_foreign_err_buf; + char* start; + char* id; + ulint len; + + *n = 0; + + *constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*)); + + str = dict_strip_comments(*(trx->mysql_query_str)); + ptr = str; + + ut_ad(mutex_own(&(dict_sys->mutex))); +loop: + ptr = dict_scan_to(ptr, (char *) "DROP"); + + if (*ptr == '\0') { + ut_a(*n < 1000); + + mem_free(str); + + return(DB_SUCCESS); + } + + ptr = dict_accept(ptr, (char *) "DROP", &success); + + if (!isspace(*ptr)) { + + goto loop; + } + + ptr = dict_accept(ptr, (char *) "FOREIGN", &success); + + if (!success) { + + goto loop; + } + + ptr = dict_accept(ptr, (char *) "KEY", &success); + + if (!success) { + + goto syntax_error; + } + + ptr = dict_scan_id(ptr, &start, &len); + + if (start == NULL) { + + goto syntax_error; + } + + id = mem_heap_alloc(heap, len + 1); + ut_memcpy(id, start, len); + id[len] = '\0'; + (*constraints_to_drop)[*n] = id; + (*n)++; + + /* Look for the given constraint id */ + + foreign = UT_LIST_GET_FIRST(table->foreign_list); + + while (foreign != NULL) { + if (0 == ut_strcmp(foreign->id, id)) { + + /* Found */ + break; + } + + foreign = UT_LIST_GET_NEXT(foreign_list, foreign); + } + + if (foreign == NULL) { + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Error in dropping of a foreign key constraint of table %.500s,\n" +"just before:\n%s\n in SQL command\n%s\nCannot find a constraint with the\n" +"given id %s.\n", table->name, ptr, str, id); + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + + mem_free(str); + + return(DB_CANNOT_DROP_CONSTRAINT); + } + + goto loop; + +syntax_error: + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), +" Syntax error in dropping of a foreign key constraint of table %.500s,\n" +"close to:\n%s\n in SQL command\n%s\n", table->name, ptr, str); + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + + mem_free(str); + + return(DB_CANNOT_DROP_CONSTRAINT); +} + /*==================== END OF FOREIGN KEY PROCESSING ====================*/ /************************************************************************** @@ -3286,7 +3738,6 @@ dict_index_print_low( n_vals = index->stat_n_diff_key_vals[1]; } - printf( " INDEX: name %s, table name %s, id %lu %lu, fields %lu/%lu, type %lu\n", index->name, index->table_name, @@ -3328,6 +3779,99 @@ dict_field_print_low( } /************************************************************************** +Sprintfs to a string info on a foreign key of a table in a format suitable +for CREATE TABLE. */ + +char* +dict_print_info_on_foreign_key_in_create_format( +/*============================================*/ + /* out: how far in buf we printed */ + dict_foreign_t* foreign,/* in: foreign key constraint */ + char* buf) /* in: buffer of at least 5000 bytes */ +{ + char* buf2 = buf; + ulint i; + + buf2 += sprintf(buf2, ",\n CONSTRAINT `%s` FOREIGN KEY (", + foreign->id); + for (i = 0; i < foreign->n_fields; i++) { + if ((ulint)(buf2 - buf) >= 4000) { + + goto no_space; + } + buf2 += sprintf(buf2, "`%.250s`", + foreign->foreign_col_names[i]); + + if (i + 1 < foreign->n_fields) { + buf2 += sprintf(buf2, ", "); + } + } + + if (dict_tables_have_same_db(foreign->foreign_table_name, + foreign->referenced_table_name)) { + /* Do not print the database name of the referenced + table */ + buf2 += sprintf(buf2, ") REFERENCES `%.500s` (", + dict_remove_db_name( + foreign->referenced_table_name)); + } else { + buf2 += sprintf(buf2, ") REFERENCES `%.500s` (", + foreign->referenced_table_name); + /* Change the '/' in the table name to '.' */ + + for (i = ut_strlen(buf); i > 0; i--) { + if (buf[i] == '/') { + + buf[i] = '.'; + + break; + } + } + } + + for (i = 0; i < foreign->n_fields; i++) { + if ((ulint)(buf2 - buf) >= 4000) { + + goto no_space; + } + buf2 += sprintf(buf2, "`%.250s`", + foreign->referenced_col_names[i]); + if (i + 1 < foreign->n_fields) { + buf2 += sprintf(buf2, ", "); + } + } + + buf2 += sprintf(buf2, ")"); + + if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) { + buf2 += sprintf(buf2, " ON DELETE CASCADE"); + } + + if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) { + buf2 += sprintf(buf2, " ON DELETE SET NULL"); + } + + if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) { + buf2 += sprintf(buf2, " ON DELETE NO ACTION"); + } + + if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) { + buf2 += sprintf(buf2, " ON UPDATE CASCADE"); + } + + if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) { + buf2 += sprintf(buf2, " ON UPDATE SET NULL"); + } + + if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) { + buf2 += sprintf(buf2, " ON UPDATE NO ACTION"); + } + +no_space: + return(buf2); +} + +/************************************************************************** Sprintfs to a string info on foreign keys of a table in a format suitable for CREATE TABLE. */ static @@ -3336,13 +3880,12 @@ dict_print_info_on_foreign_keys_in_create_format( /*=============================================*/ char* buf, /* in: auxiliary buffer */ char* str, /* in/out: pointer to a string */ - ulint len, /* in: str has to be a buffer at least - len + 5000 bytes */ + ulint len, /* in: buf has to be a buffer of at least + len + 5000 bytes; str must have at least + len + 1 bytes */ dict_table_t* table) /* in: table */ { - dict_foreign_t* foreign; - ulint i; char* buf2; buf2 = buf; @@ -3358,78 +3901,12 @@ dict_print_info_on_foreign_keys_in_create_format( } while (foreign != NULL) { - buf2 += sprintf(buf2, ",\n FOREIGN KEY ("); - - for (i = 0; i < foreign->n_fields; i++) { - if ((ulint)(buf2 - buf) >= len) { - goto no_space; - } - buf2 += sprintf(buf2, "`%s`", - foreign->foreign_col_names[i]); - - if (i + 1 < foreign->n_fields) { - buf2 += sprintf(buf2, ", "); - } - } - - if (dict_tables_have_same_db(table->name, - foreign->referenced_table_name)) { - /* Do not print the database name of the referenced - table */ - buf2 += sprintf(buf2, ") REFERENCES `%s` (", - dict_remove_db_name( - foreign->referenced_table_name)); - } else { - buf2 += sprintf(buf2, ") REFERENCES `%s` (", - foreign->referenced_table_name); - /* Change the '/' in the table name to '.' */ - - for (i = ut_strlen(buf); i > 0; i--) { - if (buf[i] == '/') { + if ((ulint)(buf2 - buf) >= len) { + goto no_space; + } - buf[i] = '.'; - - break; - } - } - } - - for (i = 0; i < foreign->n_fields; i++) { - if ((ulint)(buf2 - buf) >= len) { - goto no_space; - } - buf2 += sprintf(buf2, "`%s`", - foreign->referenced_col_names[i]); - if (i + 1 < foreign->n_fields) { - buf2 += sprintf(buf2, ", "); - } - } - - buf2 += sprintf(buf2, ")"); - - if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) { - buf2 += sprintf(buf2, " ON DELETE CASCADE"); - } - - if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) { - buf2 += sprintf(buf2, " ON DELETE SET NULL"); - } - - if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) { - buf2 += sprintf(buf2, " ON DELETE NO ACTION"); - } - - if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) { - buf2 += sprintf(buf2, " ON UPDATE CASCADE"); - } - - if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) { - buf2 += sprintf(buf2, " ON UPDATE SET NULL"); - } - - if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) { - buf2 += sprintf(buf2, " ON UPDATE NO ACTION"); - } + buf2 = dict_print_info_on_foreign_key_in_create_format( + foreign, buf2); foreign = UT_LIST_GET_NEXT(foreign_list, foreign); } @@ -3490,7 +3967,7 @@ dict_print_info_on_foreign_keys( goto no_space; } - buf2 += sprintf(buf2, "%s", + buf2 += sprintf(buf2, "%.500s", foreign->foreign_col_names[i]); if (i + 1 < foreign->n_fields) { @@ -3498,14 +3975,14 @@ dict_print_info_on_foreign_keys( } } - buf2 += sprintf(buf2, ") REFER %s(", + buf2 += sprintf(buf2, ") REFER %.500s(", foreign->referenced_table_name); for (i = 0; i < foreign->n_fields; i++) { if ((ulint)(buf2 - buf) >= len) { goto no_space; } - buf2 += sprintf(buf2, "%s", + buf2 += sprintf(buf2, "%.500s", foreign->referenced_col_names[i]); if (i + 1 < foreign->n_fields) { buf2 += sprintf(buf2, " "); diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index 1070a8f5426..999eb55bb20 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -456,7 +456,7 @@ dict_load_indexes( ut_ad(len == 8); id = mach_read_from_8(field); - ut_a(0 == ut_strcmp((void*) "NAME", + ut_a(0 == ut_strcmp((char*) "NAME", dict_field_get_col( dict_index_get_nth_field( dict_table_get_first_index(sys_indexes), 4))->name)); @@ -515,7 +515,7 @@ dict_load_indexes( && ((type & DICT_CLUSTERED) || ((table == dict_sys->sys_tables) && (name_len == ut_strlen("ID_IND")) - && (0 == ut_memcmp(name_buf, (void*) "ID_IND", + && (0 == ut_memcmp(name_buf, (char*) "ID_IND", name_len))))) { /* The index was created in memory already in @@ -566,6 +566,7 @@ dict_load_table( char* buf; ulint space; ulint n_cols; + ulint err; mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -674,8 +675,25 @@ dict_load_table( dict_load_indexes(table, heap); - ut_a(DB_SUCCESS == dict_load_foreigns(table->name)); + err = dict_load_foreigns(table->name); +/* + if (err != DB_SUCCESS) { + + mutex_enter(&dict_foreign_err_mutex); + ut_print_timestamp(stderr); + + fprintf(stderr, +" InnoDB: Error: could not make a foreign key definition to match\n" +"InnoDB: the foreign key table or the referenced table!\n" +"InnoDB: The data dictionary of InnoDB is corrupt. You may need to drop\n" +"InnoDB: and recreate the foreign key table or the referenced table.\n" +"InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n" +"InnoDB: Latest foreign key error printout:\n%s\n", dict_foreign_err_buf); + + mutex_exit(&dict_foreign_err_mutex); + } +*/ mem_heap_free(heap); return(table); @@ -978,8 +996,8 @@ dict_load_foreign( field = rec_get_nth_field(rec, 4, &len); - foreign->referenced_table_name = mem_heap_alloc(foreign->heap, 1 + len); - + foreign->referenced_table_name = mem_heap_alloc(foreign->heap, + 1 + len); ut_memcpy(foreign->referenced_table_name, field, len); foreign->referenced_table_name[len] = '\0'; @@ -988,10 +1006,19 @@ dict_load_foreign( dict_load_foreign_cols(id, foreign); + /* If the foreign table is not yet in the dictionary cache, we + have to load it so that we are able to make type comparisons + in the next function call. */ + + dict_table_get_low(foreign->foreign_table_name); + /* Note that there may already be a foreign constraint object in the dictionary cache for this constraint: then the following call only sets the pointers in it to point to the appropriate table - and index objects and frees the newly created object foreign. */ + and index objects and frees the newly created object foreign. + Adding to the cache should always succeed since we are not creating + a new foreign key constraint but loading one from the data + dictionary. */ err = dict_foreign_add_to_cache(foreign); diff --git a/innobase/dyn/Makefile.am b/innobase/dyn/Makefile.am index 79c0000868c..ec33a3c18a9 100644 --- a/innobase/dyn/Makefile.am +++ b/innobase/dyn/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libdyn.a +noinst_LIBRARIES = libdyn.a libdyn_a_SOURCES = dyn0dyn.c diff --git a/innobase/eval/Makefile.am b/innobase/eval/Makefile.am index 5dd0eab4c9b..aebffb91be3 100644 --- a/innobase/eval/Makefile.am +++ b/innobase/eval/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libeval.a +noinst_LIBRARIES = libeval.a libeval_a_SOURCES = eval0eval.c eval0proc.c diff --git a/innobase/fil/Makefile.am b/innobase/fil/Makefile.am index a9473fdb762..dc0baff7d1a 100644 --- a/innobase/fil/Makefile.am +++ b/innobase/fil/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libfil.a +noinst_LIBRARIES = libfil.a libfil_a_SOURCES = fil0fil.c diff --git a/innobase/fsp/Makefile.am b/innobase/fsp/Makefile.am index b3e9ab44d9b..edf06bda0d6 100644 --- a/innobase/fsp/Makefile.am +++ b/innobase/fsp/Makefile.am @@ -18,7 +18,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libfsp.a +noinst_LIBRARIES = libfsp.a libfsp_a_SOURCES = fsp0fsp.c diff --git a/innobase/fut/Makefile.am b/innobase/fut/Makefile.am index a4b1e30e03c..839fdb1580e 100644 --- a/innobase/fut/Makefile.am +++ b/innobase/fut/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libfut.a +noinst_LIBRARIES = libfut.a libfut_a_SOURCES = fut0fut.c fut0lst.c diff --git a/innobase/ha/Makefile.am b/innobase/ha/Makefile.am index ce846d37622..121bafe167d 100644 --- a/innobase/ha/Makefile.am +++ b/innobase/ha/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libha.a +noinst_LIBRARIES = libha.a libha_a_SOURCES = ha0ha.c hash0hash.c diff --git a/innobase/ibuf/Makefile.am b/innobase/ibuf/Makefile.am index 1c1d196c40c..fb813d38ee5 100644 --- a/innobase/ibuf/Makefile.am +++ b/innobase/ibuf/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libibuf.a +noinst_LIBRARIES = libibuf.a libibuf_a_SOURCES = ibuf0ibuf.c diff --git a/innobase/ibuf/ibuf0ibuf.c b/innobase/ibuf/ibuf0ibuf.c index 5cd066afc27..187afa17047 100644 --- a/innobase/ibuf/ibuf0ibuf.c +++ b/innobase/ibuf/ibuf0ibuf.c @@ -2391,7 +2391,7 @@ ibuf_delete_rec( ut_ad(ibuf_inside()); - success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr); + success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr); if (success) { #ifdef UNIV_IBUF_DEBUG @@ -2401,7 +2401,7 @@ ibuf_delete_rec( return(FALSE); } - /* We have to resort to a pessimistic delete from ibuf */ + /* We have to resort to a pessimistic delete from ibuf */ btr_pcur_store_position(pcur, mtr); btr_pcur_commit_specify_mtr(pcur, mtr); @@ -2420,17 +2420,22 @@ ibuf_delete_rec( fprintf(stderr, "InnoDB: ibuf cursor restoration fails!\n"); fprintf(stderr, "InnoDB: ibuf record inserted to page %lu\n", page_no); + fflush(stderr); + rec_print(btr_pcur_get_rec(pcur)); rec_print(pcur->old_rec); dtuple_print(search_tuple); rec_print(page_rec_get_next(btr_pcur_get_rec(pcur))); + fflush(stdout); mtr_commit(mtr); fprintf(stderr, "InnoDB: Validating insert buffer tree:\n"); - ut_a(btr_validate_tree(ibuf_data->index->tree)); - fprintf(stderr, "InnoDB: Ibuf tree ok\n"); + ut_a(btr_validate_tree(ibuf_data->index->tree)); + + fprintf(stderr, "InnoDB: ibuf tree ok\n"); + fflush(stderr); } ut_a(success); diff --git a/innobase/include/Makefile.i b/innobase/include/Makefile.i index 985ec525950..f3e3fbe989e 100644 --- a/innobase/include/Makefile.i +++ b/innobase/include/Makefile.i @@ -1,7 +1,5 @@ # Makefile included in Makefile.am in every subdirectory -libsdir = ../libs - INCLUDES = -I$(srcdir)/../include -I$(srcdir)/../../include -I../../include # Don't update the files from bitkeeper diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h index 81eeb7fced8..b613d60ebf7 100644 --- a/innobase/include/buf0buf.h +++ b/innobase/include/buf0buf.h @@ -496,6 +496,13 @@ buf_print_io( /*=========*/ char* buf, /* in/out: buffer where to print */ char* buf_end);/* in: buffer end */ +/************************************************************************* +Returns the ratio in percents of modified pages in the buffer pool / +database pages in the buffer pool. */ + +ulint +buf_get_modified_ratio_pct(void); +/*============================*/ /************************************************************************** Refreshes the statistics used to print per-second averages. */ diff --git a/innobase/include/buf0lru.h b/innobase/include/buf0lru.h index 6a3c948507d..5c995b259bf 100644 --- a/innobase/include/buf0lru.h +++ b/innobase/include/buf0lru.h @@ -46,6 +46,20 @@ buf_LRU_get_recent_limit(void); /*==========================*/ /* out: the limit; zero if could not determine it */ /********************************************************************** +Look for a replaceable block from the end of the LRU list and put it to +the free list if found. */ + +ibool +buf_LRU_search_and_free_block( +/*==========================*/ + /* out: TRUE if freed */ + ulint n_iterations); /* in: how many times this has been called + repeatedly without result: a high value means + that we should search farther; if value is + k < 10, then we only search k/10 * number + of pages in the buffer pool from the end + of the LRU list */ +/********************************************************************** Returns a free block from the buf_pool. The block is taken off the free list. If it is empty, blocks are moved from the end of the LRU list to the free list. */ @@ -88,17 +102,6 @@ void buf_LRU_make_block_old( /*===================*/ buf_block_t* block); /* in: control block */ -/********************************************************************** -Look for a replaceable block from the end of the LRU list and put it to -the free list if found. */ - -ibool -buf_LRU_search_and_free_block( -/*==========================*/ - /* out: TRUE if freed */ - ulint n_iterations); /* in: how many times this has been called - repeatedly without result: a high value - means that we should search farther */ /************************************************************************** Validates the LRU list. */ diff --git a/innobase/include/db0err.h b/innobase/include/db0err.h index c67c09bad27..ab7d0caa35c 100644 --- a/innobase/include/db0err.h +++ b/innobase/include/db0err.h @@ -44,6 +44,8 @@ Created 5/24/1996 Heikki Tuuri #define DB_CORRUPTION 39 /* data structure corruption noticed */ #define DB_COL_APPEARS_TWICE_IN_INDEX 40 /* InnoDB cannot handle an index where same column appears twice */ +#define DB_CANNOT_DROP_CONSTRAINT 40 /* dropping a foreign key constraint + from a table failed */ /* The following are partial failure codes */ #define DB_FAIL 1000 diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index b5e6e04a1de..97486a7c2f6 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -219,6 +219,24 @@ dict_create_foreign_constraints( char* name); /* in: table full name in the normalized form database_name/table_name */ /************************************************************************** +Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */ + +ulint +dict_foreign_parse_drop_constraints( +/*================================*/ + /* out: DB_SUCCESS or + DB_CANNOT_DROP_CONSTRAINT if + syntax error or the constraint + id does not match */ + mem_heap_t* heap, /* in: heap from which we can + allocate memory */ + trx_t* trx, /* in: transaction */ + dict_table_t* table, /* in: table */ + ulint* n, /* out: number of constraints + to drop */ + char*** constraints_to_drop); /* out: id's of the + constraints to drop */ +/************************************************************************** Returns a table object and memoryfixes it. NOTE! This is a high-level function to be used mainly from outside the 'dict' directory. Inside this directory dict_table_get_low is usually the appropriate function. */ @@ -333,6 +351,16 @@ dict_print_info_on_foreign_keys( char* str, /* in/out: pointer to a string */ ulint len, /* in: space in str available for info */ dict_table_t* table); /* in: table */ +/************************************************************************** +Sprintfs to a string info on a foreign key of a table in a format suitable +for CREATE TABLE. */ + +char* +dict_print_info_on_foreign_key_in_create_format( +/*============================================*/ + /* out: how far in buf we printed */ + dict_foreign_t* foreign,/* in: foreign key constraint */ + char* buf); /* in: buffer of at least 5000 bytes */ /************************************************************************ Gets the first index on the table (the clustered index). */ UNIV_INLINE @@ -808,6 +836,14 @@ void dict_mutex_exit_for_mysql(void); /*===========================*/ +/* The following len must be at least 10000 bytes! */ +#define DICT_FOREIGN_ERR_BUF_LEN 10000 + +/* Buffers for storing detailed information about the latest foreign key +and unique key errors */ +extern char* dict_foreign_err_buf; +extern char* dict_unique_err_buf; +extern mutex_t dict_foreign_err_mutex; /* mutex protecting the buffers */ extern dict_sys_t* dict_sys; /* the dictionary system */ extern rw_lock_t dict_operation_lock; diff --git a/innobase/include/log0log.h b/innobase/include/log0log.h index f200371de9d..4e1404b15fe 100644 --- a/innobase/include/log0log.h +++ b/innobase/include/log0log.h @@ -20,7 +20,7 @@ typedef struct log_group_struct log_group_t; extern ibool log_do_write; extern ibool log_debug_writes; -/* Wait modes for log_flush_up_to */ +/* Wait modes for log_write_up_to */ #define LOG_NO_WAIT 91 #define LOG_WAIT_ONE_GROUP 92 #define LOG_WAIT_ALL_GROUPS 93 @@ -157,26 +157,21 @@ log_io_complete( /*============*/ log_group_t* group); /* in: log group */ /********************************************************** -Flushes the log files to the disk, using, for example, the Unix fsync. -This function does the flush even if the user has set -srv_flush_log_at_trx_commit = FALSE. */ - -void -log_flush_to_disk(void); -/*===================*/ -/********************************************************** This function is called, e.g., when a transaction wants to commit. It checks -that the log has been flushed to disk up to the last log entry written by the -transaction. If there is a flush running, it waits and checks if the flush -flushed enough. If not, starts a new flush. */ +that the log has been written to the log file up to the last log entry written +by the transaction. If there is a flush running, it waits and checks if the +flush flushed enough. If not, starts a new flush. */ void -log_flush_up_to( +log_write_up_to( /*============*/ dulint lsn, /* in: log sequence number up to which the log should - be flushed, ut_dulint_max if not specified */ - ulint wait); /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP, + be written, ut_dulint_max if not specified */ + ulint wait, /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP, or LOG_WAIT_ALL_GROUPS */ + ibool flush_to_disk); + /* in: TRUE if we want the written log also to be + flushed to disk */ /******************************************************************** Advances the smallest lsn for which there are unflushed dirty blocks in the buffer pool and also may make a new checkpoint. NOTE: this function may only @@ -741,27 +736,37 @@ struct log_struct{ be advanced, it is enough that the write i/o has been completed for all log groups */ - dulint flush_lsn; /* end lsn for the current flush */ - ulint flush_end_offset;/* the data in buffer has been flushed + dulint write_lsn; /* end lsn for the current running + write */ + ulint write_end_offset;/* the data in buffer has been written up to this offset when the current - flush ends: this field will then + write ends: this field will then be copied to buf_next_to_write */ - ulint n_pending_writes;/* number of currently pending flush - writes */ + dulint current_flush_lsn;/* end lsn for the current running + write + flush operation */ + dulint flushed_to_disk_lsn; + /* how far we have written the log + AND flushed to disk */ + ulint n_pending_writes;/* number of currently pending flushes + or writes */ + /* NOTE on the 'flush' in names of the fields below: starting from + 4.0.14, we separate the write of the log file and the actual fsync() + or other method to flush it to disk. The names below shhould really + be 'flush_or_write'! */ os_event_t no_flush_event; /* this event is in the reset state - when a flush is running; a thread - should wait for this without owning - the log mutex, but NOTE that to set or - reset this event, the thread MUST own - the log mutex! */ + when a flush or a write is running; + a thread should wait for this without + owning the log mutex, but NOTE that + to set or reset this event, the + thread MUST own the log mutex! */ ibool one_flushed; /* during a flush, this is first FALSE and becomes TRUE when one log group - has been flushed */ + has been written or flushed */ os_event_t one_flushed_event;/* this event is reset when the - flush has not yet completed for any - log group; e.g., this means that a - transaction has been committed when - this is set; a thread should wait + flush or write has not yet completed + for any log group; e.g., this means + that a transaction has been committed + when this is set; a thread should wait for this without owning the log mutex, but NOTE that to set or reset this event, the thread MUST own the log diff --git a/innobase/include/row0ins.h b/innobase/include/row0ins.h index cc3b9fa7e9a..a5b4b74e7fc 100644 --- a/innobase/include/row0ins.h +++ b/innobase/include/row0ins.h @@ -35,7 +35,6 @@ row_ins_check_foreign_constraint( dictionary cache if they exist at all */ dict_table_t* table, /* in: if check_ref is TRUE, then the foreign table, else the referenced table */ - dict_index_t* index, /* in: index in table */ dtuple_t* entry, /* in: index entry for index */ que_thr_t* thr); /* in: query thread */ /************************************************************************* diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 972fabc74cf..1964f53dabb 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -427,13 +427,21 @@ struct row_prebuilt_struct { index where the ordering column is the row id: in this case this flag is set to TRUE */ - dict_index_t* index; /* current index for a search, if any */ + dict_index_t* index; /* current index for a search, if + any */ ulint read_just_key; /* set to 1 when MySQL calls ha_innobase::extra with the argument HA_EXTRA_KEYREAD; it is enough to read just columns defined in the index (i.e., no read of the clustered index record necessary) */ + ibool used_in_HANDLER;/* TRUE if we have been using this + handle in a MySQL HANDLER low level + index cursor command: then we must + store the pcur position even in a + unique search from a clustered index, + because HANDLER allows NEXT and PREV + in such a situation */ ulint template_type; /* ROW_MYSQL_WHOLE_ROW, ROW_MYSQL_REC_FIELDS, ROW_MYSQL_DUMMY_TEMPLATE, or diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index bc0960ae023..121e9c44a24 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -75,6 +75,9 @@ extern ulint srv_lock_wait_timeout; extern char* srv_file_flush_method_str; extern ulint srv_unix_file_flush_method; extern ulint srv_win_file_flush_method; + +extern ulint srv_max_dirty_pages_pct; + extern ulint srv_force_recovery; extern ulint srv_thread_concurrency; diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 34f820f03e7..39229923375 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -157,6 +157,15 @@ trx_commit_for_mysql( /* out: 0 or error number */ trx_t* trx); /* in: trx handle */ /************************************************************************** +If required, flushes the log to disk if we called trx_commit_for_mysql() +with trx->flush_log_later == TRUE. */ + +ulint +trx_commit_complete_for_mysql( +/*==========================*/ + /* out: 0 or error number */ + trx_t* trx); /* in: trx handle */ +/************************************************************************** Marks the latest SQL statement ended. */ void @@ -343,6 +352,11 @@ struct trx_struct{ dulint no; /* transaction serialization number == max trx id when the transaction is moved to COMMITTED_IN_MEMORY state */ + ibool flush_log_later;/* when we commit the transaction + in MySQL's binlog write, we will + flush the log to disk later in + a separate call */ + dulint commit_lsn; /* lsn at the time of the commit */ ibool dict_operation; /* TRUE if the trx is used to create a table, create an index, or drop a table */ @@ -418,10 +432,6 @@ 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 ignore_duplicates_in_insert; - /* in an insert roll back only insert - of the latest row in case - of a duplicate key error */ UT_LIST_NODE_T(trx_t) trx_list; /* list of transactions */ UT_LIST_NODE_T(trx_t) diff --git a/innobase/include/univ.i b/innobase/include/univ.i index bf606efcf64..e29f3ec92e1 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -100,6 +100,15 @@ memory is read outside the allocated blocks. */ #define YYDEBUG 1 +#ifdef HAVE_purify +/* The following sets all new allocated memory to zero before use: +this can be used to eliminate unnecessary Purify warnings, but note that +it also masks many bugs Purify could detect. For detailed Purify analysis it +is best to remove the define below and look through the warnings one +by one. */ +#define UNIV_SET_MEM_TO_ZERO +#endif + /* #define UNIV_SQL_DEBUG #define UNIV_LOG_DEBUG diff --git a/innobase/include/ut0dbg.h b/innobase/include/ut0dbg.h index 3407483696c..e99dc8c09d6 100644 --- a/innobase/include/ut0dbg.h +++ b/innobase/include/ut0dbg.h @@ -20,7 +20,6 @@ extern ibool ut_dbg_stop_threads; extern ulint* ut_dbg_null_ptr; - #define ut_a(EXPR)\ {\ ulint dbg_i;\ @@ -31,8 +30,10 @@ extern ulint* ut_dbg_null_ptr; " InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\ os_thread_pf(os_thread_get_curr_id()), IB__FILE__,\ (ulint)__LINE__);\ + fprintf(stderr,\ + "InnoDB: Failing assertion: " #EXPR);\ fprintf(stderr,\ - "InnoDB: We intentionally generate a memory trap.\n");\ + "\nInnoDB: We intentionally generate a memory trap.\n");\ fprintf(stderr,\ "InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n");\ ut_dbg_stop_threads = TRUE;\ diff --git a/innobase/lock/Makefile.am b/innobase/lock/Makefile.am index f9e1b227f3c..549eb2604e3 100644 --- a/innobase/lock/Makefile.am +++ b/innobase/lock/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = liblock.a +noinst_LIBRARIES = liblock.a liblock_a_SOURCES = lock0lock.c diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index d4329c4873c..74dc4aea515 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -3092,8 +3092,7 @@ lock_deadlock_recursive( err_buf += strlen(err_buf); err_buf += sprintf(err_buf, - " LATEST DETECTED DEADLOCK:\n" - "*** (1) TRANSACTION:\n"); + "\n*** (1) TRANSACTION:\n"); trx_print(err_buf, wait_lock->trx); err_buf += strlen(err_buf); @@ -3935,24 +3934,15 @@ lock_print_info( return; } - - buf += sprintf(buf, "Trx id counter %lu %lu\n", - ut_dulint_get_high(trx_sys->max_trx_id), - ut_dulint_get_low(trx_sys->max_trx_id)); - - buf += sprintf(buf, - "Purge done for trx's n:o < %lu %lu undo n:o < %lu %lu\n", - ut_dulint_get_high(purge_sys->purge_trx_no), - ut_dulint_get_low(purge_sys->purge_trx_no), - ut_dulint_get_high(purge_sys->purge_undo_no), - ut_dulint_get_low(purge_sys->purge_undo_no)); lock_mutex_enter_kernel(); - buf += sprintf(buf, - "Total number of lock structs in row lock hash table %lu\n", - lock_get_n_rec_locks()); if (lock_deadlock_found) { + + buf += sprintf(buf, +"------------------------\n" +"LATEST DETECTED DEADLOCK\n" +"------------------------\n"); if ((ulint)(buf_end - buf) < 100 + strlen(lock_latest_err_buf)) { @@ -3973,6 +3963,26 @@ lock_print_info( return; } + buf += sprintf(buf, +"------------\n" +"TRANSACTIONS\n" +"------------\n"); + + buf += sprintf(buf, "Trx id counter %lu %lu\n", + ut_dulint_get_high(trx_sys->max_trx_id), + ut_dulint_get_low(trx_sys->max_trx_id)); + + buf += sprintf(buf, + "Purge done for trx's n:o < %lu %lu undo n:o < %lu %lu\n", + ut_dulint_get_high(purge_sys->purge_trx_no), + ut_dulint_get_low(purge_sys->purge_trx_no), + ut_dulint_get_high(purge_sys->purge_undo_no), + ut_dulint_get_low(purge_sys->purge_undo_no)); + + buf += sprintf(buf, + "Total number of lock structs in row lock hash table %lu\n", + lock_get_n_rec_locks()); + buf += sprintf(buf, "LIST OF TRANSACTIONS FOR EACH SESSION:\n"); /* First print info on non-active transactions */ diff --git a/innobase/log/Makefile.am b/innobase/log/Makefile.am index 3910a25ab1a..2dbaf93e6d9 100644 --- a/innobase/log/Makefile.am +++ b/innobase/log/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = liblog.a +noinst_LIBRARIES = liblog.a liblog_a_SOURCES = log0log.c log0recv.c diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index bdfce783a43..e717d897e41 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -178,7 +178,7 @@ loop: /* Not enough free space, do a syncronous flush of the log buffer */ - log_flush_up_to(ut_dulint_max, LOG_WAIT_ALL_GROUPS); + log_write_up_to(ut_dulint_max, LOG_WAIT_ALL_GROUPS, TRUE); count++; @@ -675,7 +675,9 @@ log_init(void) log_sys->buf_next_to_write = 0; - log_sys->flush_lsn = ut_dulint_zero; + log_sys->write_lsn = ut_dulint_zero; + log_sys->current_flush_lsn = ut_dulint_zero; + log_sys->flushed_to_disk_lsn = ut_dulint_zero; log_sys->written_to_some_lsn = log_sys->lsn; log_sys->written_to_all_lsn = log_sys->lsn; @@ -867,7 +869,7 @@ log_group_check_flush_completion( printf("Log flushed first to group %lu\n", group->id); } - log_sys->written_to_some_lsn = log_sys->flush_lsn; + log_sys->written_to_some_lsn = log_sys->write_lsn; log_sys->one_flushed = TRUE; return(LOG_UNLOCK_NONE_FLUSHED_LOCK); @@ -896,15 +898,15 @@ log_sys_check_flush_completion(void) if (log_sys->n_pending_writes == 0) { - log_sys->written_to_all_lsn = log_sys->flush_lsn; - log_sys->buf_next_to_write = log_sys->flush_end_offset; + log_sys->written_to_all_lsn = log_sys->write_lsn; + log_sys->buf_next_to_write = log_sys->write_end_offset; - if (log_sys->flush_end_offset > log_sys->max_buf_free / 2) { + if (log_sys->write_end_offset > log_sys->max_buf_free / 2) { /* Move the log buffer content to the start of the buffer */ move_start = ut_calc_align_down( - log_sys->flush_end_offset, + log_sys->write_end_offset, OS_FILE_LOG_BLOCK_SIZE); move_end = ut_calc_align(log_sys->buf_free, OS_FILE_LOG_BLOCK_SIZE); @@ -982,57 +984,6 @@ log_io_complete( } /********************************************************** -Flushes the log files to the disk, using, for example, the Unix fsync. -This function does the flush even if the user has set -srv_flush_log_at_trx_commit = FALSE. */ - -void -log_flush_to_disk(void) -/*===================*/ -{ - log_group_t* group; -loop: - mutex_enter(&(log_sys->mutex)); - - if (log_sys->n_pending_writes > 0) { - /* A log file write is running */ - - mutex_exit(&(log_sys->mutex)); - - /* Wait for the log file write to complete and try again */ - - os_event_wait(log_sys->no_flush_event); - - goto loop; - } - - group = UT_LIST_GET_FIRST(log_sys->log_groups); - - log_sys->n_pending_writes++; - group->n_pending_writes++; - - os_event_reset(log_sys->no_flush_event); - os_event_reset(log_sys->one_flushed_event); - - mutex_exit(&(log_sys->mutex)); - - fil_flush(group->space_id); - - mutex_enter(&(log_sys->mutex)); - - ut_a(group->n_pending_writes == 1); - ut_a(log_sys->n_pending_writes == 1); - - group->n_pending_writes--; - log_sys->n_pending_writes--; - - os_event_set(log_sys->no_flush_event); - os_event_set(log_sys->one_flushed_event); - - mutex_exit(&(log_sys->mutex)); -} - -/********************************************************** Writes a log file header to a log file space. */ static void @@ -1205,12 +1156,15 @@ by the transaction. If there is a flush running, it waits and checks if the flush flushed enough. If not, starts a new flush. */ void -log_flush_up_to( +log_write_up_to( /*============*/ dulint lsn, /* in: log sequence number up to which the log should be written, ut_dulint_max if not specified */ - ulint wait) /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP, + ulint wait, /* in: LOG_NO_WAIT, LOG_WAIT_ONE_GROUP, or LOG_WAIT_ALL_GROUPS */ + ibool flush_to_disk) + /* in: TRUE if we want the written log also to be + flushed to disk */ { log_group_t* group; ulint start_offset; @@ -1239,9 +1193,18 @@ loop: mutex_enter(&(log_sys->mutex)); - if ((ut_dulint_cmp(log_sys->written_to_all_lsn, lsn) >= 0) - || ((ut_dulint_cmp(log_sys->written_to_some_lsn, lsn) >= 0) - && (wait != LOG_WAIT_ALL_GROUPS))) { + if (flush_to_disk + && ut_dulint_cmp(log_sys->flushed_to_disk_lsn, lsn) >= 0) { + + mutex_exit(&(log_sys->mutex)); + + return; + } + + if (!flush_to_disk + && (ut_dulint_cmp(log_sys->written_to_all_lsn, lsn) >= 0 + || (ut_dulint_cmp(log_sys->written_to_some_lsn, lsn) >= 0 + && wait != LOG_WAIT_ALL_GROUPS))) { mutex_exit(&(log_sys->mutex)); @@ -1249,10 +1212,19 @@ loop: } if (log_sys->n_pending_writes > 0) { - /* A flush is running */ + /* A write (+ possibly flush to disk) is running */ + + if (flush_to_disk + && ut_dulint_cmp(log_sys->current_flush_lsn, lsn) >= 0) { + /* The write + flush will write enough: wait for it to + complete */ + + goto do_waits; + } - if (ut_dulint_cmp(log_sys->flush_lsn, lsn) >= 0) { - /* The flush will flush enough: wait for it to + if (!flush_to_disk + && ut_dulint_cmp(log_sys->write_lsn, lsn) >= 0) { + /* The write will write enough: wait for it to complete */ goto do_waits; @@ -1260,16 +1232,17 @@ loop: mutex_exit(&(log_sys->mutex)); - /* Wait for the flush to complete and try to start a new - flush */ + /* Wait for the write to complete and try to start a new + write */ os_event_wait(log_sys->no_flush_event); goto loop; } - if (log_sys->buf_free == log_sys->buf_next_to_write) { - /* Nothing to flush */ + if (!flush_to_disk + && log_sys->buf_free == log_sys->buf_next_to_write) { + /* Nothing to write and no flush to disk requested */ mutex_exit(&(log_sys->mutex)); @@ -1277,7 +1250,7 @@ loop: } if (log_debug_writes) { - printf("Flushing log from %lu %lu up to lsn %lu %lu\n", + printf("Writing log from %lu %lu up to lsn %lu %lu\n", ut_dulint_get_high(log_sys->written_to_all_lsn), ut_dulint_get_low(log_sys->written_to_all_lsn), ut_dulint_get_high(log_sys->lsn), @@ -1301,7 +1274,12 @@ loop: ut_ad(area_end - area_start > 0); - log_sys->flush_lsn = log_sys->lsn; + log_sys->write_lsn = log_sys->lsn; + + if (flush_to_disk) { + log_sys->current_flush_lsn = log_sys->lsn; + } + log_sys->one_flushed = FALSE; log_block_set_flush_bit(log_sys->buf + area_start, TRUE); @@ -1318,10 +1296,12 @@ loop: OS_FILE_LOG_BLOCK_SIZE); log_sys->buf_free += OS_FILE_LOG_BLOCK_SIZE; - log_sys->flush_end_offset = log_sys->buf_free; + log_sys->write_end_offset = log_sys->buf_free; group = UT_LIST_GET_FIRST(log_sys->log_groups); + /* Do the write to the log files */ + while (group) { log_group_write_buf(LOG_FLUSH, group, log_sys->buf + area_start, @@ -1330,20 +1310,25 @@ loop: OS_FILE_LOG_BLOCK_SIZE), start_offset - area_start); - log_group_set_fields(group, log_sys->flush_lsn); + log_group_set_fields(group, log_sys->write_lsn); group = UT_LIST_GET_NEXT(log_groups, group); } mutex_exit(&(log_sys->mutex)); - if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC - && srv_unix_file_flush_method != SRV_UNIX_NOSYNC - && srv_flush_log_at_trx_commit != 2) { + if (srv_unix_file_flush_method == SRV_UNIX_O_DSYNC) { + /* O_DSYNC means the OS did not buffer the log file at all: + so we have also flushed to disk what we have written */ + + log_sys->flushed_to_disk_lsn = log_sys->write_lsn; + + } else if (flush_to_disk) { group = UT_LIST_GET_FIRST(log_sys->log_groups); fil_flush(group->space_id); + log_sys->flushed_to_disk_lsn = log_sys->write_lsn; } mutex_enter(&(log_sys->mutex)); @@ -1403,7 +1388,7 @@ log_flush_margin(void) mutex_exit(&(log->mutex)); if (do_flush) { - log_flush_up_to(ut_dulint_max, LOG_NO_WAIT); + log_write_up_to(ut_dulint_max, LOG_NO_WAIT, FALSE); } } @@ -1555,7 +1540,8 @@ log_group_checkpoint( buf = group->checkpoint_buf; mach_write_to_8(buf + LOG_CHECKPOINT_NO, log_sys->next_checkpoint_no); - mach_write_to_8(buf + LOG_CHECKPOINT_LSN, log_sys->next_checkpoint_lsn); + mach_write_to_8(buf + LOG_CHECKPOINT_LSN, + log_sys->next_checkpoint_lsn); mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET, log_group_calc_lsn_offset( @@ -1664,8 +1650,10 @@ log_reset_first_header_and_checkpoint( lsn = ut_dulint_add(start, LOG_BLOCK_HDR_SIZE); /* Write the label of ibbackup --restore */ - sprintf((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, "ibbackup "); - ut_sprintf_timestamp((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP + sprintf((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, + "ibbackup "); + ut_sprintf_timestamp( + (char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP + strlen("ibbackup ")); buf = hdr_buf + LOG_CHECKPOINT_1; @@ -1773,7 +1761,7 @@ log_checkpoint( write-ahead-logging algorithm ensures that the log has been flushed up to oldest_lsn. */ - log_flush_up_to(oldest_lsn, LOG_WAIT_ALL_GROUPS); + log_write_up_to(oldest_lsn, LOG_WAIT_ALL_GROUPS, TRUE); mutex_enter(&(log_sys->mutex)); @@ -2466,7 +2454,7 @@ loop: mutex_exit(&(log_sys->mutex)); - log_flush_up_to(limit_lsn, LOG_WAIT_ALL_GROUPS); + log_write_up_to(limit_lsn, LOG_WAIT_ALL_GROUPS, TRUE); calc_new_limit = FALSE; @@ -3104,8 +3092,8 @@ log_print( "Last checkpoint at %lu %lu\n", ut_dulint_get_high(log_sys->lsn), ut_dulint_get_low(log_sys->lsn), - ut_dulint_get_high(log_sys->written_to_some_lsn), - ut_dulint_get_low(log_sys->written_to_some_lsn), + ut_dulint_get_high(log_sys->flushed_to_disk_lsn), + ut_dulint_get_low(log_sys->flushed_to_disk_lsn), ut_dulint_get_high(log_sys->last_checkpoint_lsn), ut_dulint_get_low(log_sys->last_checkpoint_lsn)); diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c index 3945b47933d..4efe4e7b23d 100644 --- a/innobase/log/log0recv.c +++ b/innobase/log/log0recv.c @@ -1833,7 +1833,12 @@ recv_report_corrupt_log( "InnoDB: WARNING: the log file may have been corrupt and it\n" "InnoDB: is possible that the log scan did not proceed\n" "InnoDB: far enough in recovery! Please run CHECK TABLE\n" - "InnoDB: on your InnoDB tables to check that they are ok!\n"); + "InnoDB: on your InnoDB tables to check that they are ok!\n" + "InnoDB: If mysqld crashes after this recovery, look at\n" + "InnoDB: section 6.1 of http://www.innodb.com/ibman.html\n" + "InnoDB: about forcing recovery.\n"); + + fflush(stderr); } /*********************************************************** @@ -2470,7 +2475,7 @@ recv_recovery_from_checkpoint_start( log_hdr_buf, max_cp_group); if (0 == ut_memcmp(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, - "ibbackup", ut_strlen("ibbackup"))) { + (byte*)"ibbackup", ut_strlen((char*)"ibbackup"))) { /* This log file was created by ibbackup --restore: print a note to the user about it */ @@ -2481,7 +2486,7 @@ recv_recovery_from_checkpoint_start( /* Wipe over the label now */ ut_memcpy(log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, - " ", 4); + (char*)" ", 4); /* Write to the log file to wipe over the label */ fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, max_cp_group->space_id, diff --git a/innobase/mach/Makefile.am b/innobase/mach/Makefile.am index 8195831e92e..ce827c8033f 100644 --- a/innobase/mach/Makefile.am +++ b/innobase/mach/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libmach.a +noinst_LIBRARIES = libmach.a libmach_a_SOURCES = mach0data.c diff --git a/innobase/mem/Makefile.am b/innobase/mem/Makefile.am index 84f642e4469..10b7771b580 100644 --- a/innobase/mem/Makefile.am +++ b/innobase/mem/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libmem.a +noinst_LIBRARIES = libmem.a libmem_a_SOURCES = mem0mem.c mem0pool.c diff --git a/innobase/mtr/Makefile.am b/innobase/mtr/Makefile.am index 972dcaca80e..1e93a34ce23 100644 --- a/innobase/mtr/Makefile.am +++ b/innobase/mtr/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libmtr.a +noinst_LIBRARIES = libmtr.a libmtr_a_SOURCES = mtr0mtr.c mtr0log.c diff --git a/innobase/odbc/Makefile.am b/innobase/odbc/Makefile.am index d1a47bd8c18..f4282ba3907 100644 --- a/innobase/odbc/Makefile.am +++ b/innobase/odbc/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libodbc.a +noinst_LIBRARIES = libodbc.a libodbc_a_SOURCES = odbc0odbc.c diff --git a/innobase/os/Makefile.am b/innobase/os/Makefile.am index b06670bc703..132ce07c83b 100644 --- a/innobase/os/Makefile.am +++ b/innobase/os/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libos.a +noinst_LIBRARIES = libos.a libos_a_SOURCES = os0proc.c os0shm.c os0sync.c os0thread.c os0file.c diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 5ffcabf6fe6..53224eb59c5 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -214,9 +214,14 @@ os_file_get_last_error(void) "InnoDB: the directory. It may also be you have created a subdirectory\n" "InnoDB: of the same name as a data file.\n"); } else { - fprintf(stderr, - "InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n" - "InnoDB: what the error number means.\n"); + if (strerror((int)err) != NULL) { + fprintf(stderr, + "InnoDB: Error number %lu means '%s'.\n", err, strerror((int)err)); + } + + fprintf(stderr, + "InnoDB: See also section 13.2 at http://www.innodb.com/ibman.html\n" + "InnoDB: about operating system error numbers.\n"); } } @@ -252,9 +257,14 @@ os_file_get_last_error(void) "InnoDB: The error means mysqld does not have the access rights to\n" "InnoDB: the directory.\n"); } else { - fprintf(stderr, - "InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n" - "InnoDB: what the error number means or use the perror program of MySQL.\n"); + if (strerror((int)err) != NULL) { + fprintf(stderr, + "InnoDB: Error number %lu means '%s'.\n", err, strerror((int)err)); + } + + fprintf(stderr, + "InnoDB: See also section 13.2 at http://www.innodb.com/ibman.html\n" + "InnoDB: about operating system error numbers.\n"); } } @@ -511,10 +521,11 @@ try_again: } #endif #ifdef UNIV_NON_BUFFERED_IO - if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) { + if (type == OS_LOG_FILE) { /* Do not use unbuffered i/o to log files because - value 2 denotes that we do not flush the log at every - commit, but only once per second */ + to allow group commit to work when MySQL binlogging + is used we must separate log file write and log + file flush to disk. */ } else { if (srv_win_file_flush_method == SRV_WIN_IO_UNBUFFERED) { @@ -741,7 +752,12 @@ os_file_set_size( offset = 0; low = (ib_longlong)size + (((ib_longlong)size_high) << 32); + + if (low >= (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); @@ -757,9 +773,24 @@ os_file_set_size( ut_free(buf2); goto error_handling; } + + /* Print about progress for each 100 MB written */ + if ((offset + n_bytes) / (ib_longlong)(100 * 1024 * 1024) + != offset / (ib_longlong)(100 * 1024 * 1024)) { + + fprintf(stderr, " %lu00", + (ulint)((offset + n_bytes) + / (ib_longlong)(100 * 1024 * 1024))); + } + offset += n_bytes; } + if (low >= (ib_longlong)(100 * 1024 * 1024)) { + + fprintf(stderr, "\n"); + } + ut_free(buf2); ret = os_file_flush(file); diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index a9127e6310a..407b280f805 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -68,9 +68,10 @@ os_event_create( os_fast_mutex_init(&(event->os_mutex)); #if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) - pthread_cond_init(&(event->cond_var), pthread_condattr_default); + ut_a(0 == pthread_cond_init(&(event->cond_var), + pthread_condattr_default)); #else - pthread_cond_init(&(event->cond_var), NULL); + ut_a(0 == pthread_cond_init(&(event->cond_var), NULL)); #endif event->is_set = FALSE; @@ -130,7 +131,7 @@ os_event_set( /* Do nothing */ } else { event->is_set = TRUE; - pthread_cond_broadcast(&(event->cond_var)); + ut_a(0 == pthread_cond_broadcast(&(event->cond_var))); } os_fast_mutex_unlock(&(event->os_mutex)); @@ -182,7 +183,7 @@ os_event_free( ut_a(event); os_fast_mutex_free(&(event->os_mutex)); - pthread_cond_destroy(&(event->cond_var)); + ut_a(0 == pthread_cond_destroy(&(event->cond_var))); ut_free(event); #endif @@ -446,9 +447,9 @@ os_fast_mutex_init( InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex); #else #if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) - pthread_mutex_init(fast_mutex, pthread_mutexattr_default); + ut_a(0 == pthread_mutex_init(fast_mutex, pthread_mutexattr_default)); #else - pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST); + ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST)); #endif #endif } @@ -495,10 +496,7 @@ os_fast_mutex_free( ut_a(fast_mutex); DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex); -#elif defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) - pthread_mutex_destroy(fast_mutex); #else - UT_NOT_USED(fast_mutex); - + ut_a(0 == pthread_mutex_destroy(fast_mutex)); #endif } diff --git a/innobase/page/Makefile.am b/innobase/page/Makefile.am index 85fe585a633..2e260787438 100644 --- a/innobase/page/Makefile.am +++ b/innobase/page/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libpage.a +noinst_LIBRARIES = libpage.a libpage_a_SOURCES = page0page.c page0cur.c diff --git a/innobase/pars/Makefile.am b/innobase/pars/Makefile.am index e5611f9dfc6..2356f330486 100644 --- a/innobase/pars/Makefile.am +++ b/innobase/pars/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libpars.a +noinst_LIBRARIES = libpars.a noinst_HEADERS = pars0grm.h diff --git a/innobase/que/Makefile.am b/innobase/que/Makefile.am index b74d4dbf6a0..d9c046b4f4c 100644 --- a/innobase/que/Makefile.am +++ b/innobase/que/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libque.a +noinst_LIBRARIES = libque.a libque_a_SOURCES = que0que.c diff --git a/innobase/read/Makefile.am b/innobase/read/Makefile.am index 16224f4f7f4..7edf2a5a2e1 100644 --- a/innobase/read/Makefile.am +++ b/innobase/read/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libread.a +noinst_LIBRARIES = libread.a libread_a_SOURCES = read0read.c diff --git a/innobase/rem/Makefile.am b/innobase/rem/Makefile.am index ef0cde9bd7a..e2b2fdaf669 100644 --- a/innobase/rem/Makefile.am +++ b/innobase/rem/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = librem.a +noinst_LIBRARIES = librem.a librem_a_SOURCES = rem0rec.c rem0cmp.c diff --git a/innobase/row/Makefile.am b/innobase/row/Makefile.am index e4fcbe8f715..bd09f9a237d 100644 --- a/innobase/row/Makefile.am +++ b/innobase/row/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = librow.a +noinst_LIBRARIES = librow.a librow_a_SOURCES = row0ins.c row0mysql.c row0purge.c row0row.c row0sel.c\ row0uins.c row0umod.c row0undo.c row0upd.c row0vers.c diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 990ef99b2a4..3af9e1b752b 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -323,7 +323,7 @@ row_ins_clust_index_entry_by_modify( /************************************************************************* Returns TRUE if in a cascaded update/delete an ancestor node of node -updates table. */ +updates (not DELETE, but UPDATE) table. */ static ibool row_ins_cascade_ancestor_updates_table( @@ -341,7 +341,7 @@ row_ins_cascade_ancestor_updates_table( upd_node = parent; - if (upd_node->table == table) { + if (upd_node->table == table && upd_node->is_delete == FALSE) { return(TRUE); } @@ -438,6 +438,111 @@ row_ins_cascade_calc_update_vec( } /************************************************************************* +Reports a foreign key error associated with an update or a delete of a +parent table index entry. */ +static +void +row_ins_foreign_report_err( +/*=======================*/ + char* errstr, /* in: error string from the viewpoint + of the parent table */ + que_thr_t* thr, /* in: query thread whose run_node + is an update node */ + dict_foreign_t* foreign, /* in: foreign key constraint */ + rec_t* rec, /* in: a matching index record in the + child table */ + dtuple_t* entry) /* in: index entry in the parent + table */ +{ + char* buf = dict_foreign_err_buf; + + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), " Transaction:\n"); + trx_print(buf + strlen(buf), thr_get_trx(thr)); + + sprintf(buf + strlen(buf), +"Foreign key constraint fails for table %.500s:\n", + foreign->foreign_table_name); + dict_print_info_on_foreign_key_in_create_format( + foreign, buf + strlen(buf)); + sprintf(buf + strlen(buf), "\n%s", errstr); + sprintf(buf + strlen(buf), +" in parent table, in index %.500s tuple:\n", + foreign->referenced_index->name); + if (entry) { + dtuple_sprintf(buf + strlen(buf), 1000, entry); + } + sprintf(buf + strlen(buf), +"\nBut in child table %.500s, in index %.500s, there is a record:\n", + foreign->foreign_table_name, foreign->foreign_index->name); + if (rec) { + rec_sprintf(buf + strlen(buf), 1000, rec); + } + sprintf(buf + strlen(buf), "\n"); + + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + + mutex_exit(&dict_foreign_err_mutex); +} + +/************************************************************************* +Reports a foreign key error to dict_foreign_err_buf when we are trying +to add an index entry to a child table. Note that the adding may be the result +of an update, too. */ +static +void +row_ins_foreign_report_add_err( +/*===========================*/ + que_thr_t* thr, /* in: query thread whose run_node + is an insert node */ + dict_foreign_t* foreign, /* in: foreign key constraint */ + rec_t* rec, /* in: a record in the parent table: + it does not match entry because we + have an error! */ + dtuple_t* entry) /* in: index entry to insert in the + child table */ +{ + char* buf = dict_foreign_err_buf; + + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), " Transaction:\n"); + trx_print(buf + strlen(buf), thr_get_trx(thr)); + sprintf(buf + strlen(buf), +"Foreign key constraint fails for table %.500s:\n", + foreign->foreign_table_name); + dict_print_info_on_foreign_key_in_create_format( + foreign, buf + strlen(buf)); + sprintf(buf + strlen(buf), +"\nTrying to add in child table, in index %.500s tuple:\n", + foreign->foreign_index->name); + if (entry) { + dtuple_sprintf(buf + strlen(buf), 1000, entry); + } + sprintf(buf + strlen(buf), +"\nBut in parent table %.500s, in index %.500s,\n" +"the closest match we can find is record:\n", + foreign->referenced_table_name, + foreign->referenced_index->name); + if (rec && page_rec_is_supremum(rec)) { + /* If the cursor ended on a supremum record, it is better + to report the previous record in the error message, so that + the user gets a more descriptive error message. */ + rec = page_rec_get_prev(rec); + } + + if (rec) { + rec_sprintf(buf + strlen(buf), 1000, rec); + } + sprintf(buf + strlen(buf), "\n"); + + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + + mutex_exit(&dict_foreign_err_mutex); +} + +/************************************************************************* Perform referential actions or checks when a parent row is deleted or updated and the constraint had an ON DELETE or ON UPDATE condition which was not RESTRICT. */ @@ -453,6 +558,8 @@ row_ins_foreign_check_on_constraint( type is != 0 */ btr_pcur_t* pcur, /* in: cursor placed on a matching index record in the child table */ + dtuple_t* entry, /* in: index entry in the parent + table */ mtr_t* mtr) /* in: mtr holding the latch of pcur page */ { @@ -506,6 +613,10 @@ row_ins_foreign_check_on_constraint( return(DB_SUCCESS); } + row_ins_foreign_report_err((char*)"Trying to delete", + thr, foreign, + btr_pcur_get_rec(pcur), entry); + return(DB_ROW_IS_REFERENCED); } @@ -523,6 +634,10 @@ row_ins_foreign_check_on_constraint( return(DB_SUCCESS); } + row_ins_foreign_report_err((char*)"Trying to update", + thr, foreign, + btr_pcur_get_rec(pcur), entry); + return(DB_ROW_IS_REFERENCED); } @@ -563,14 +678,13 @@ row_ins_foreign_check_on_constraint( } } - /* We do not allow cyclic cascaded updating of the same - table. Check that we are not updating the same table which - is already being modified in this cascade chain. We have to - check this because the modification of the indexes of a - 'parent' table may still be incomplete, and we must avoid - seeing the indexes of the parent table in an inconsistent - state! In this way we also prevent possible infinite - update loops caused by cyclic cascaded updates. */ + /* We do not allow cyclic cascaded updating (DELETE is allowed, + but not UPDATE) of the same table, as this can lead to an infinite + cycle. Check that we are not updating the same table which is + already being modified in this cascade chain. We have to check + this also because the modification of the indexes of a 'parent' + table may still be incomplete, and we must avoid seeing the indexes + of the parent table in an inconsistent state! */ if (!cascade->is_delete && row_ins_cascade_ancestor_updates_table(cascade, table)) { @@ -580,6 +694,10 @@ row_ins_foreign_check_on_constraint( err = DB_ROW_IS_REFERENCED; + row_ins_foreign_report_err( +(char*)"Trying an update, possibly causing a cyclic cascaded update\n" +"in the child table,", thr, foreign, btr_pcur_get_rec(pcur), entry); + goto nonstandard_exit_func; } @@ -809,11 +927,10 @@ row_ins_check_foreign_constraint( dictionary cache if they exist at all */ dict_table_t* table, /* in: if check_ref is TRUE, then the foreign table, else the referenced table */ - dict_index_t* index __attribute__((unused)),/* in: index in table */ dtuple_t* entry, /* in: index entry for index */ que_thr_t* thr) /* in: query thread */ { - upd_node_t* upd_node; + upd_node_t* upd_node; dict_table_t* check_table; dict_index_t* check_index; ulint n_fields_cmp; @@ -824,6 +941,7 @@ row_ins_check_foreign_constraint( int cmp; ulint err; ulint i; + char* buf = dict_foreign_err_buf; mtr_t mtr; run_again: @@ -884,6 +1002,25 @@ run_again: if (check_table == NULL) { if (check_ref) { + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), " Transaction:\n"); + trx_print(buf + strlen(buf), thr_get_trx(thr)); + sprintf(buf + strlen(buf), +"Foreign key constraint fails for table %.500s:\n", + foreign->foreign_table_name); + dict_print_info_on_foreign_key_in_create_format( + foreign, buf + strlen(buf)); + sprintf(buf + strlen(buf), +"\nTrying to add to index %.500s tuple:\n", foreign->foreign_index->name); + dtuple_sprintf(buf + strlen(buf), 1000, entry); + sprintf(buf + strlen(buf), +"\nBut the parent table %.500s does not currently exist!\n", + foreign->referenced_table_name); + + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + mutex_exit(&dict_foreign_err_mutex); + return(DB_NO_REFERENCED_ROW); } @@ -949,7 +1086,8 @@ run_again: if (cmp == 0) { if (rec_get_deleted_flag(rec)) { - err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, + err = row_ins_set_shared_rec_lock( + LOCK_ORDINARY, rec, check_index, thr); if (err != DB_SUCCESS) { @@ -989,13 +1127,17 @@ run_again: err = row_ins_foreign_check_on_constraint( - thr, foreign, &pcur, &mtr); - + thr, foreign, &pcur, entry, + &mtr); if (err != DB_SUCCESS) { break; } } else { + row_ins_foreign_report_err( + (char*)"Trying to delete or update", + thr, foreign, rec, entry); + err = DB_ROW_IS_REFERENCED; break; } @@ -1012,6 +1154,8 @@ run_again: if (check_ref) { err = DB_NO_REFERENCED_ROW; + row_ins_foreign_report_add_err( + thr, foreign, rec, entry); } else { err = DB_SUCCESS; } @@ -1025,6 +1169,9 @@ next_rec: if (!moved) { if (check_ref) { + rec = btr_pcur_get_rec(&pcur); + row_ins_foreign_report_add_err( + thr, foreign, rec, entry); err = DB_NO_REFERENCED_ROW; } else { err = DB_SUCCESS; @@ -1100,7 +1247,7 @@ row_ins_check_foreign_constraints( } err = row_ins_check_foreign_constraint(TRUE, foreign, - table, index, entry, thr); + table, entry, thr); if (got_s_lock) { row_mysql_unfreeze_data_dictionary(trx); } @@ -1116,6 +1263,48 @@ row_ins_check_foreign_constraints( return(DB_SUCCESS); } +/************************************************************************* +Reports a UNIQUE key error to dict_unique_err_buf so that SHOW INNODB +STATUS can print it. */ +static +void +row_ins_unique_report_err( +/*======================*/ + que_thr_t* thr, /* in: query thread */ + rec_t* rec, /* in: a record in the index */ + dtuple_t* entry, /* in: index entry to insert in the index */ + dict_index_t* index) /* in: index */ +{ + char* buf = dict_unique_err_buf; + + /* The foreign err mutex protects also dict_unique_err_buf */ + + mutex_enter(&dict_foreign_err_mutex); + + ut_sprintf_timestamp(buf); + sprintf(buf + strlen(buf), " Transaction:\n"); + trx_print(buf + strlen(buf), thr_get_trx(thr)); + + sprintf(buf + strlen(buf), +"Unique key constraint fails for table %.500s.\n", index->table_name); + sprintf(buf + strlen(buf), +"Trying to add in index %.500s (%lu fields unique) tuple:\n", index->name, + dict_index_get_n_unique(index)); + + dtuple_sprintf(buf + strlen(buf), 1000, entry); + + sprintf(buf + strlen(buf), +"\nBut there is already a record:\n"); + + rec_sprintf(buf + strlen(buf), 1000, rec); + + sprintf(buf + strlen(buf), "\n"); + + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + + mutex_exit(&dict_foreign_err_mutex); +} + /******************************************************************* Checks if a unique key violation to rec would occur at the index entry insert. */ @@ -1246,10 +1435,8 @@ row_ins_scan_sec_index_for_duplicate( if (cmp == 0) { if (row_ins_dupl_error_with_rec(rec, entry, index)) { - /* printf("Duplicate key in index %s\n", - index->name); - dtuple_print(entry); */ - + row_ins_unique_report_err(thr, rec, entry, + index); err = DB_DUPLICATE_KEY; thr_get_trx(thr)->error_info = index; @@ -1344,7 +1531,8 @@ row_ins_duplicate_error_in_clust( if (row_ins_dupl_error_with_rec(rec, entry, cursor->index)) { trx->error_info = cursor->index; - + row_ins_unique_report_err(thr, rec, entry, + cursor->index); return(DB_DUPLICATE_KEY); } } @@ -1368,6 +1556,8 @@ row_ins_duplicate_error_in_clust( cursor->index)) { trx->error_info = cursor->index; + row_ins_unique_report_err(thr, rec, entry, + cursor->index); return(DB_DUPLICATE_KEY); } } diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 1bb33551da8..6d1f6f6e40e 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -6,7 +6,7 @@ Contains also create table and other data dictionary operations. Created 9/17/2000 Heikki Tuuri *******************************************************/ - + #include "row0mysql.h" #ifdef UNIV_NONINL @@ -289,6 +289,17 @@ handle_new_error: "InnoDB: my.cnf and restart the database.\n"); exit(1); + } else if (err == DB_CORRUPTION) { + + fprintf(stderr, + "InnoDB: We detected index corruption in an InnoDB type table.\n" + "InnoDB: You have to dump + drop + reimport the table or, in\n" + "InnoDB: a case of widespread corruption, dump all InnoDB\n" + "InnoDB: tables and recreate the whole InnoDB tablespace.\n" + "InnoDB: If the mysqld server crashes after the startup or when\n" + "InnoDB: you dump the tables, look at section 6.1 of\n" + "InnoDB: http://www.innodb.com/ibman.html for help.\n"); + } else { fprintf(stderr, "InnoDB: unknown error code %lu\n", err); ut_a(0); @@ -337,6 +348,9 @@ row_create_prebuilt( prebuilt->mysql_has_locked = FALSE; prebuilt->index = NULL; + + prebuilt->used_in_HANDLER = FALSE; + prebuilt->n_template = 0; prebuilt->mysql_template = NULL; @@ -1169,7 +1183,7 @@ row_mysql_recover_tmp_table( return(DB_ERROR); } - if (0 == ut_memcmp(ptr, "/rsql", 5)) { + if (0 == ut_memcmp(ptr, (char*)"/rsql", 5)) { ptr++; *ptr = '#'; @@ -1293,10 +1307,10 @@ row_create_table_for_mysql( } trx->op_info = (char *) "creating table"; - - if (0 == ut_strcmp(table->name, "mysql/host") - || 0 == ut_strcmp(table->name, "mysql/user") - || 0 == ut_strcmp(table->name, "mysql/db")) { + + if (0 == ut_strcmp(table->name, (char*)"mysql/host") + || 0 == ut_strcmp(table->name, (char*)"mysql/user") + || 0 == ut_strcmp(table->name, (char*)"mysql/db")) { fprintf(stderr, "InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.\n" @@ -1316,7 +1330,7 @@ row_create_table_for_mysql( if (namelen >= keywordlen && 0 == ut_memcmp(table->name + namelen - keywordlen, - "_recover_innodb_tmp_table", keywordlen)) { + (char*)"_recover_innodb_tmp_table", keywordlen)) { /* MySQL prevents accessing of tables whose name begins with #sql, that is temporary tables. If mysqld crashes in @@ -1384,7 +1398,7 @@ row_create_table_for_mysql( if (namelen >= keywordlen && 0 == ut_memcmp(table->name + namelen - keywordlen, - "innodb_mem_validate", keywordlen)) { + (char*)"innodb_mem_validate", keywordlen)) { /* We define here a debugging feature intended for developers */ @@ -1494,7 +1508,7 @@ row_create_index_for_mysql( if (namelen >= keywordlen && 0 == ut_memcmp( index->table_name + namelen - keywordlen, - "_recover_innodb_tmp_table", keywordlen)) { + (char*)"_recover_innodb_tmp_table", keywordlen)) { return(DB_SUCCESS); } @@ -1599,7 +1613,7 @@ row_table_add_foreign_constraints( if (namelen >= keywordlen && 0 == ut_memcmp( name + namelen - keywordlen, - "_recover_innodb_tmp_table", keywordlen)) { + (char*)"_recover_innodb_tmp_table", keywordlen)) { return(DB_SUCCESS); } @@ -1663,7 +1677,7 @@ row_drop_table_for_mysql_in_background( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); trx_commit_for_mysql(trx); @@ -1821,7 +1835,6 @@ row_drop_table_for_mysql( ulint len; ulint namelen; ulint keywordlen; - ulint rounds = 0; ibool locked_dictionary = FALSE; char buf[10000]; @@ -2168,7 +2181,7 @@ row_is_mysql_tmp_table_name( ulint i; for (i = 0; i <= ut_strlen(name) - 5; i++) { - if (ut_memcmp(name + i, "/#sql", 5) == 0) { + if (ut_memcmp(name + i, (char*)"/#sql", 5) == 0) { return(TRUE); } @@ -2190,12 +2203,16 @@ row_rename_table_for_mysql( { dict_table_t* table; que_thr_t* thr; - que_t* graph; + que_t* graph = NULL; ulint err; char* str1; char* str2; char* str3; + mem_heap_t* heap = NULL; + char** constraints_to_drop = NULL; + ulint n_constraints_to_drop = 0; ulint len; + ulint i; char buf[10000]; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); @@ -2213,10 +2230,10 @@ row_rename_table_for_mysql( trx_commit_for_mysql(trx); return(DB_ERROR); } - - if (0 == ut_strcmp(new_name, "mysql/host") - || 0 == ut_strcmp(new_name, "mysql/user") - || 0 == ut_strcmp(new_name, "mysql/db")) { + + if (0 == ut_strcmp(new_name, (char*)"mysql/host") + || 0 == ut_strcmp(new_name, (char*)"mysql/user") + || 0 == ut_strcmp(new_name, (char*)"mysql/db")) { fprintf(stderr, "InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.\n" @@ -2230,6 +2247,19 @@ row_rename_table_for_mysql( trx->op_info = (char *) "renaming table"; trx_start_if_not_started(trx); + /* Serialize data dictionary operations with dictionary mutex: + no deadlocks can occur then in these operations */ + + row_mysql_lock_data_dictionary(trx); + + table = dict_table_get_low(old_name); + + if (!table) { + err = DB_TABLE_NOT_FOUND; + + goto funct_exit; + } + str1 = (char *) "PROCEDURE RENAME_TABLE_PROC () IS\n" "new_table_name CHAR;\n" @@ -2242,14 +2272,43 @@ row_rename_table_for_mysql( if (row_is_mysql_tmp_table_name(new_name)) { - /* We want to preserve the original foreign key - constraint definitions despite the name change */ + /* MySQL is doing an ALTER TABLE command and it renames the + original table to a temporary table name. We want to preserve + the original foreign key constraint definitions despite the + name change. An exception is those constraints for which + the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/ - str3 = (char*) - "';\n" - "UPDATE SYS_TABLES SET NAME = new_table_name\n" - "WHERE NAME = old_table_name;\n" - "END;\n"; + heap = mem_heap_create(100); + + err = dict_foreign_parse_drop_constraints(heap, trx, + table, + &n_constraints_to_drop, + &constraints_to_drop); + if (err != DB_SUCCESS) { + + goto funct_exit; + } + + str3 = mem_heap_alloc(heap, + 1000 + 500 * n_constraints_to_drop); + *str3 = '\0'; + sprintf(str3, + "';\n" + "UPDATE SYS_TABLES SET NAME = new_table_name\n" + "WHERE NAME = old_table_name;\n"); + + for (i = 0; i < n_constraints_to_drop; i++) { + sprintf(str3 + strlen(str3), + "DELETE FROM SYS_FOREIGN_COLS WHERE ID = '%s';\n" + "DELETE FROM SYS_FOREIGN WHERE ID = '%s';\n", + constraints_to_drop[i], + constraints_to_drop[i]); + } + + sprintf(str3 + strlen(str3), + "END;\n"); + + ut_a(strlen(str3) < 1000 + 500 * n_constraints_to_drop); } else { str3 = (char*) "';\n" @@ -2280,13 +2339,6 @@ row_rename_table_for_mysql( ut_memcpy(buf + len, str3, ut_strlen(str3) + 1); - /* Serialize data dictionary operations with dictionary mutex: - no deadlocks can occur then in these operations */ - - row_mysql_lock_data_dictionary(trx); - - table = dict_table_get_low(old_name); - graph = pars_sql(buf); ut_a(graph); @@ -2296,12 +2348,6 @@ row_rename_table_for_mysql( graph->fork_type = QUE_FORK_MYSQL_INTERFACE; - if (!table) { - err = DB_TABLE_NOT_FOUND; - - goto funct_exit; - } - ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0)); que_run_threads(thr); @@ -2342,6 +2388,13 @@ row_rename_table_for_mysql( if (row_is_mysql_tmp_table_name(old_name)) { + /* MySQL is doing an ALTER TABLE command and it + renames the created temporary table to the name + of the original table. In the ALTER TABLE we maybe + created some FOREIGN KEY constraints for the temporary + table. But we want to load also the foreign key + constraint definitions for the original table name. */ + err = dict_load_foreigns(new_name); if (err != DB_SUCCESS) { @@ -2367,7 +2420,13 @@ row_rename_table_for_mysql( funct_exit: row_mysql_unlock_data_dictionary(trx); - que_graph_free(graph); + if (graph) { + que_graph_free(graph); + } + + if (heap) { + mem_heap_free(heap); + } trx_commit_for_mysql(trx); diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index fb508e7b1da..97a69f76eaa 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2620,6 +2620,24 @@ row_search_for_mysql( printf("N tables locked %lu\n", trx->mysql_n_tables_locked); */ /*-------------------------------------------------------------*/ + /* PHASE 0: Release a possible s-latch we are holding on the + adaptive hash index latch if there is someone waiting behind */ + + if (trx->has_search_latch + && btr_search_latch.writer != RW_LOCK_NOT_LOCKED) { + + /* There is an x-latch request on the adaptive hash index: + release the s-latch to reduce starvation and wait for + BTR_SEA_TIMEOUT rounds before trying to keep it again over + calls from MySQL */ + + rw_lock_s_unlock(&btr_search_latch); + trx->has_search_latch = FALSE; + + trx->search_latch_timeout = BTR_SEA_TIMEOUT; + } + + /*-------------------------------------------------------------*/ /* PHASE 1: Try to pop the row from the prefetch cache */ if (direction == 0) { @@ -2685,16 +2703,31 @@ row_search_for_mysql( mode = pcur->search_mode; } + if ((direction == ROW_SEL_NEXT || direction == ROW_SEL_PREV) + && pcur->old_stored != BTR_PCUR_OLD_STORED) { + + /* MySQL sometimes seems to do fetch next or fetch prev even + if the search condition is unique; this can, for example, + happen with the HANDLER commands; we do not always store the + pcur position in this case, so we cannot restore cursor + position, and must return immediately */ + + /* printf("%s record not found 1\n", index->name); */ + + trx->op_info = (char *) ""; + return(DB_RECORD_NOT_FOUND); + } + mtr_start(&mtr); /* In a search where at most one record in the index may match, we - can use a LOCK_REC_NOT_GAP type record lock when locking a non-delete + can use a LOCK_REC_NOT_GAP type record lock when locking a non-delete- marked matching record. - Note that in a unique secondary index there may be different delete + Note that in a unique secondary index there may be different delete- marked versions of a record where only the primary key values differ: thus in a secondary index we must use next-key locks when locking - delete marked records. */ + delete-marked records. */ if (match_mode == ROW_SEL_EXACT && index->type & DICT_UNIQUE @@ -2715,25 +2748,9 @@ row_search_for_mysql( if (unique_search && index->type & DICT_CLUSTERED && !prebuilt->templ_contains_blob + && !prebuilt->used_in_HANDLER && (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8)) { - if (direction == ROW_SEL_NEXT) { - /* MySQL sometimes seems to do fetch next even - if the search condition is unique; we do not store - pcur position in this case, so we cannot - restore cursor position, and must return - immediately */ - - mtr_commit(&mtr); - - /* printf("%s record not found 1\n", index->name); */ - - trx->op_info = (char *) ""; - return(DB_RECORD_NOT_FOUND); - } - - ut_a(direction == 0); /* We cannot do fetch prev, as we have - not stored the cursor position */ mode = PAGE_CUR_GE; unique_search_from_clust_index = TRUE; @@ -2754,23 +2771,7 @@ row_search_for_mysql( NOT prepared to inserts interleaved with the SELECT, and if we try that, we can deadlock on the adaptive hash index semaphore! */ - - if (btr_search_latch.writer != RW_LOCK_NOT_LOCKED) { - /* There is an x-latch request: release - a possible s-latch to reduce starvation - and wait for BTR_SEA_TIMEOUT rounds before - trying to keep it again over calls from - MySQL */ - - if (trx->has_search_latch) { - rw_lock_s_unlock(&btr_search_latch); - trx->has_search_latch = FALSE; - } - trx->search_latch_timeout = BTR_SEA_TIMEOUT; - - goto no_shortcut; - } #ifndef UNIV_SEARCH_DEBUG if (!trx->has_search_latch) { rw_lock_s_lock(&btr_search_latch); @@ -2806,6 +2807,10 @@ row_search_for_mysql( } trx->op_info = (char *) ""; + + /* NOTE that we do NOT store the cursor + position */ + return(DB_SUCCESS); } else if (shortcut == SEL_EXHAUSTED) { @@ -2825,6 +2830,10 @@ row_search_for_mysql( } trx->op_info = (char *) ""; + + /* NOTE that we do NOT store the cursor + position */ + return(DB_RECORD_NOT_FOUND); } @@ -2833,7 +2842,6 @@ row_search_for_mysql( } } -no_shortcut: /*-------------------------------------------------------------*/ /* PHASE 3: Open or restore index cursor position */ @@ -3206,6 +3214,7 @@ rec_loop: && prebuilt->select_lock_type == LOCK_NONE && !prebuilt->templ_contains_blob && !prebuilt->clust_index_was_generated + && !prebuilt->used_in_HANDLER && prebuilt->template_type != ROW_MYSQL_DUMMY_TEMPLATE) { @@ -3214,7 +3223,9 @@ rec_loop: update, that is why we require ...lock_type == LOCK_NONE. Since we keep space in prebuilt only for the BLOBs of a single row, we cannot cache rows in the case there - are BLOBs in the fields to be fetched. */ + are BLOBs in the fields to be fetched. In HANDLER we do + not cache rows because there the cursor is a scrollable + cursor. */ row_sel_push_cache_row_for_mysql(prebuilt, rec); @@ -3243,11 +3254,16 @@ rec_loop: } } got_row: - /* TODO: should we in every case store the cursor position, even - if this is just a join, for example? */ + /* We have an optimization to save CPU time: if this is a consistent + read on a unique condition on the clustered index, then we do not + store the pcur position, because any fetch next or prev will anyway + return 'end of file'. An exception is the MySQL HANDLER command + where the user can move the cursor with PREV or NEXT even after + a unique search. */ if (!unique_search_from_clust_index - || prebuilt->select_lock_type == LOCK_X) { + || prebuilt->select_lock_type == LOCK_X + || prebuilt->used_in_HANDLER) { /* Inside an update always store the cursor position */ diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c index 64569bf3f96..5fce1c1861b 100644 --- a/innobase/row/row0upd.c +++ b/innobase/row/row0upd.c @@ -218,7 +218,7 @@ row_upd_check_references_constraints( being dropped while the check is running. */ err = row_ins_check_foreign_constraint(FALSE, foreign, - table, index, entry, thr); + table, entry, thr); if (foreign->foreign_table) { mutex_enter(&(dict_sys->mutex)); diff --git a/innobase/srv/Makefile.am b/innobase/srv/Makefile.am index b4bdeb7c03b..752683b82b8 100644 --- a/innobase/srv/Makefile.am +++ b/innobase/srv/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libsrv.a +noinst_LIBRARIES = libsrv.a libsrv_a_SOURCES = srv0srv.c srv0que.c srv0start.c diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index af11516e9f0..7cd831fe239 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -162,6 +162,13 @@ char* srv_file_flush_method_str = NULL; ulint srv_unix_file_flush_method = SRV_UNIX_FDATASYNC; ulint srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED; +/* The InnoDB main thread tries to keep the ratio of modified pages +in the buffer pool to all database pages in the buffer pool smaller than +the following number. But it is not guaranteed that the value stays below +that during a time of heavy update/insert activity. */ + +ulint srv_max_buf_pool_modified_pct = 90; + /* If the following is != 0 we do not allow inserts etc. This protects the user from forgetting the innodb_force_recovery keyword to my.cnf */ @@ -1881,11 +1888,11 @@ retry: /* Go to wait for the event; when a thread leaves InnoDB it will release this thread */ - trx->op_info = "waiting in InnoDB queue"; + trx->op_info = (char*)"waiting in InnoDB queue"; os_event_wait(slot->event); - trx->op_info = ""; + trx->op_info = (char*)""; os_fast_mutex_lock(&srv_conc_mutex); @@ -2368,12 +2375,35 @@ srv_sprintf_innodb_monitor( buf = buf + strlen(buf); ut_a(buf < buf_end + 1500); - buf += sprintf(buf, "------------\n" - "TRANSACTIONS\n" - "------------\n"); + if (*dict_foreign_err_buf != '\0') { + buf += sprintf(buf, + "------------------------\n" + "LATEST FOREIGN KEY ERROR\n" + "------------------------\n"); + + if (buf_end - buf > 6000) { + buf+= sprintf(buf, "%.4000s", dict_foreign_err_buf); + } + } + + ut_a(buf < buf_end + 1500); + + if (*dict_unique_err_buf != '\0') { + buf += sprintf(buf, +"---------------------------------------------------------------\n" +"LATEST UNIQUE KEY ERROR (is masked in REPLACE or INSERT IGNORE)\n" +"---------------------------------------------------------------\n"); + + if (buf_end - buf > 6000) { + buf+= sprintf(buf, "%.4000s", dict_unique_err_buf); + } + } + + ut_a(buf < buf_end + 1500); + lock_print_info(buf, buf_end); buf = buf + strlen(buf); - + buf += sprintf(buf, "--------\n" "FILE I/O\n" "--------\n"); @@ -2777,6 +2807,7 @@ srv_master_thread( ulint n_ios_old; ulint n_ios_very_old; ulint n_pend_ios; + ibool skip_sleep = FALSE; ulint i; UT_NOT_USED(arg); @@ -2794,24 +2825,42 @@ srv_master_thread( os_event_set(srv_sys->operational); loop: + /*****************************************************************/ + /* ---- When there is database activity by users, we cycle in this + loop */ + srv_main_thread_op_info = (char*) "reserving kernel mutex"; n_ios_very_old = log_sys->n_log_ios + buf_pool->n_pages_read + buf_pool->n_pages_written; mutex_enter(&kernel_mutex); + /* Store the user activity counter at the start of this loop */ old_activity_count = srv_activity_count; mutex_exit(&kernel_mutex); - /* We run purge and a batch of ibuf_contract every 10 seconds, even - if the server were active: */ + if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) { + + goto suspend_thread; + } + + /* ---- We run the following loop approximately once per second + when there is database activity */ + + skip_sleep = FALSE; for (i = 0; i < 10; i++) { n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read + buf_pool->n_pages_written; srv_main_thread_op_info = (char*)"sleeping"; - os_thread_sleep(1000000); + + if (!skip_sleep) { + + os_thread_sleep(1000000); + } + + skip_sleep = FALSE; /* ALTER TABLE in MySQL requires on Unix that the table handler can drop tables lazily after there no longer are SELECT @@ -2824,9 +2873,9 @@ loop: srv_main_thread_op_info = (char*)""; - if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) { + if (srv_fast_shutdown && srv_shutdown_state > 0) { - goto suspend_thread; + goto background_loop; } /* We flush the log once in a second even if no commit @@ -2834,10 +2883,9 @@ loop: at transaction commit */ srv_main_thread_op_info = (char*)"flushing log"; - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); - log_flush_to_disk(); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); - /* If there were less than 10 i/os during the + /* If there were less than 5 i/os during the one second sleep, we assume that there is free disk i/o capacity available, and it makes sense to do an insert buffer merge. */ @@ -2846,35 +2894,45 @@ loop: + log_sys->n_pending_writes; n_ios = log_sys->n_log_ios + buf_pool->n_pages_read + buf_pool->n_pages_written; - if (n_pend_ios < 3 && (n_ios - n_ios_old < 10)) { + if (n_pend_ios < 3 && (n_ios - n_ios_old < 5)) { srv_main_thread_op_info = (char*)"doing insert buffer merge"; ibuf_contract_for_n_pages(TRUE, 5); srv_main_thread_op_info = (char*)"flushing log"; - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); - log_flush_to_disk(); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, + TRUE); } - - if (srv_fast_shutdown && srv_shutdown_state > 0) { - goto background_loop; + if (buf_get_modified_ratio_pct() > + srv_max_buf_pool_modified_pct) { + + /* Try to keep the number of modified pages in the + buffer pool under the limit wished by the user */ + + n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, + ut_dulint_max); + + /* If we had to do the flush, it may have taken + even more than 1 second, and also, there may be more + to flush. Do not sleep 1 second during the next + iteration of this loop. */ + + skip_sleep = TRUE; } if (srv_activity_count == old_activity_count) { - if (srv_print_thread_releases) { - printf("Master thread wakes up!\n"); - } + /* There is no user activity at the moment, go to + the background loop */ goto background_loop; } } - if (srv_print_thread_releases) { - printf("Master thread wakes up!\n"); - } + /* ---- We perform the following code approximately once per + 10 seconds when there is database activity */ #ifdef MEM_PERIODIC_CHECK /* Check magic numbers of every allocated mem block once in 10 @@ -2883,7 +2941,7 @@ loop: #endif /* If there were less than 200 i/os during the 10 second period, we assume that there is free disk i/o capacity available, and it - makes sense to do a buffer pool flush. */ + makes sense to flush 100 pages. */ n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes; n_ios = log_sys->n_log_ios + buf_pool->n_pages_read @@ -2891,11 +2949,10 @@ loop: if (n_pend_ios < 3 && (n_ios - n_ios_very_old < 200)) { srv_main_thread_op_info = (char*) "flushing buffer pool pages"; - buf_flush_batch(BUF_FLUSH_LIST, 50, ut_dulint_max); + buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max); srv_main_thread_op_info = (char*) "flushing log"; - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); - log_flush_to_disk(); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); } /* We run a batch of insert buffer merge every 10 seconds, @@ -2905,8 +2962,7 @@ loop: ibuf_contract_for_n_pages(TRUE, 5); srv_main_thread_op_info = (char*)"flushing log"; - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); - log_flush_to_disk(); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); /* We run a full purge every 10 seconds, even if the server were active */ @@ -2930,27 +2986,32 @@ loop: if (difftime(current_time, last_flush_time) > 1) { srv_main_thread_op_info = (char*) "flushing log"; - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); - log_flush_to_disk(); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, + TRUE); last_flush_time = current_time; } } + + srv_main_thread_op_info = (char*)"flushing buffer pool pages"; -background_loop: - /* In this loop we run background operations when the server - is quiet and we also come here about once in 10 seconds */ + /* Flush a few oldest pages to make a new checkpoint younger */ - srv_main_thread_op_info = (char*)"doing background drop tables"; + if (buf_get_modified_ratio_pct() > 70) { - n_tables_to_drop = row_drop_tables_for_mysql_in_background(); + /* If there are lots of modified pages in the buffer pool + (> 70 %), we assume we can afford reserving the disk(s) for + the time it requires to flush 100 pages */ - srv_main_thread_op_info = (char*)""; - - srv_main_thread_op_info = (char*)"flushing buffer pool pages"; - - /* Flush a few oldest pages to make the checkpoint younger */ + n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, + ut_dulint_max); + } else { + /* Otherwise, we only flush a small number of pages so that + we do not unnecessarily use much disk i/o capacity from + other work */ - n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 10, ut_dulint_max); + n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 10, + ut_dulint_max); + } srv_main_thread_op_info = (char*)"making checkpoint"; @@ -2961,16 +3022,31 @@ background_loop: srv_main_thread_op_info = (char*)"reserving kernel mutex"; mutex_enter(&kernel_mutex); + + /* ---- When there is database activity, we jump from here back to + the start of loop */ + if (srv_activity_count != old_activity_count) { mutex_exit(&kernel_mutex); goto loop; } - old_activity_count = srv_activity_count; + mutex_exit(&kernel_mutex); + /* If the database is quiet, we enter the background loop */ + + /*****************************************************************/ +background_loop: + /* ---- In this loop we run background operations when the server + is quiet from user activity */ + /* The server has been quiet for a while: start running background operations */ + srv_main_thread_op_info = (char*)"doing background drop tables"; + + n_tables_to_drop = row_drop_tables_for_mysql_in_background(); + srv_main_thread_op_info = (char*)"purging"; if (srv_fast_shutdown && srv_shutdown_state > 0) { @@ -3005,6 +3081,7 @@ background_loop: } mutex_exit(&kernel_mutex); +flush_loop: srv_main_thread_op_info = (char*)"flushing buffer pool pages"; n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max); @@ -3017,13 +3094,22 @@ background_loop: } mutex_exit(&kernel_mutex); - srv_main_thread_op_info = (char*) "waiting for buffer pool flush to end"; + srv_main_thread_op_info = + (char*) "waiting for buffer pool flush to end"; buf_flush_wait_batch_end(BUF_FLUSH_LIST); srv_main_thread_op_info = (char*)"making checkpoint"; log_checkpoint(TRUE, FALSE); + if (buf_get_modified_ratio_pct() > srv_max_buf_pool_modified_pct) { + + /* Try to keep the number of modified pages in the + buffer pool under the limit wished by the user */ + + goto flush_loop; + } + srv_main_thread_op_info = (char*)"reserving kernel mutex"; mutex_enter(&kernel_mutex); @@ -3038,15 +3124,24 @@ background_loop: log_archive_do(FALSE, &n_bytes_archived); + /* Keep looping in the background loop if still work to do */ + if (srv_fast_shutdown && srv_shutdown_state > 0) { if (n_tables_to_drop + n_pages_flushed + n_bytes_archived != 0) { + /* If we are doing a fast shutdown (= the default) + we do not do purge or insert buffer merge. But we + flush the buffer pool completely to disk. */ + goto background_loop; } } else if (n_tables_to_drop + - n_pages_purged + n_bytes_merged + n_pages_flushed + n_pages_purged + n_bytes_merged + n_pages_flushed + n_bytes_archived != 0) { + /* In a 'slow' shutdown we run purge and the insert buffer + merge to completion */ + goto background_loop; } @@ -3078,6 +3173,9 @@ suspend_thread: os_event_wait(event); + /* When there is user activity, InnoDB will set the event and the main + thread goes back to loop: */ + goto loop; #ifndef __WIN__ diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 33d4a30e227..536aa5b67e4 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -161,13 +161,13 @@ srv_parse_data_file_paths_and_sizes( } if (strlen(str) >= ut_strlen(":autoextend") - && 0 == ut_memcmp(str, ":autoextend", + && 0 == ut_memcmp(str, (char*)":autoextend", ut_strlen(":autoextend"))) { str += ut_strlen(":autoextend"); if (strlen(str) >= ut_strlen(":max:") - && 0 == ut_memcmp(str, ":max:", + && 0 == ut_memcmp(str, (char*)":max:", ut_strlen(":max:"))) { str += ut_strlen(":max:"); @@ -265,7 +265,7 @@ srv_parse_data_file_paths_and_sizes( (*data_file_sizes)[i] = size; if (strlen(str) >= ut_strlen(":autoextend") - && 0 == ut_memcmp(str, ":autoextend", + && 0 == ut_memcmp(str, (char*)":autoextend", ut_strlen(":autoextend"))) { *is_auto_extending = TRUE; @@ -273,7 +273,7 @@ srv_parse_data_file_paths_and_sizes( str += ut_strlen(":autoextend"); if (strlen(str) >= ut_strlen(":max:") - && 0 == ut_memcmp(str, ":max:", + && 0 == ut_memcmp(str, (char*)":max:", ut_strlen(":max:"))) { str += ut_strlen(":max:"); @@ -864,6 +864,7 @@ open_or_create_data_files( return(DB_SUCCESS); } +#ifdef notdefined /********************************************************************* This thread is used to measure contention of latches. */ static @@ -935,6 +936,7 @@ test_measure_cont( return(0); } +#endif /******************************************************************** Starts InnoDB and creates a new database if database files @@ -1053,20 +1055,24 @@ innobase_start_or_create_for_mysql(void) srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED; #ifndef __WIN__ - } else if (0 == ut_strcmp(srv_file_flush_method_str, "fdatasync")) { + } else if (0 == ut_strcmp(srv_file_flush_method_str, + (char*)"fdatasync")) { srv_unix_file_flush_method = SRV_UNIX_FDATASYNC; - } else if (0 == ut_strcmp(srv_file_flush_method_str, "O_DSYNC")) { + } else if (0 == ut_strcmp(srv_file_flush_method_str, + (char*)"O_DSYNC")) { srv_unix_file_flush_method = SRV_UNIX_O_DSYNC; } else if (0 == ut_strcmp(srv_file_flush_method_str, - "littlesync")) { + (char*)"littlesync")) { srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC; - } else if (0 == ut_strcmp(srv_file_flush_method_str, "nosync")) { + } else if (0 == ut_strcmp(srv_file_flush_method_str, + (char*)"nosync")) { srv_unix_file_flush_method = SRV_UNIX_NOSYNC; #else - } else if (0 == ut_strcmp(srv_file_flush_method_str, "normal")) { + } else if (0 == ut_strcmp(srv_file_flush_method_str, + (char*)"normal")) { srv_win_file_flush_method = SRV_WIN_IO_NORMAL; os_aio_use_native_aio = FALSE; @@ -1196,7 +1202,14 @@ innobase_start_or_create_for_mysql(void) &max_flushed_lsn, &max_arch_log_no, &sum_of_new_sizes); if (err != DB_SUCCESS) { - fprintf(stderr, "InnoDB: Could not open data files\n"); + fprintf(stderr, +"InnoDB: Could not open or create data files.\n" +"InnoDB: If you tried to add new data files, and it failed here,\n" +"InnoDB: you should now edit innodb_data_file_path in my.cnf back\n" +"InnoDB: to what it was, and remove the new ibdata files InnoDB created\n" +"InnoDB: in this failed attempt. InnoDB only wrote those files full of\n" +"InnoDB: zeros, but did not yet use them in any way. But be careful: do not\n" +"InnoDB: remove old data files which contain your precious data!\n"); return((int) err); } @@ -1207,7 +1220,10 @@ innobase_start_or_create_for_mysql(void) and restore them from the doublewrite buffer if possible */ - trx_sys_doublewrite_restore_corrupt_pages(); + if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) { + + trx_sys_doublewrite_restore_corrupt_pages(); + } } srv_normalize_path_for_win(srv_arch_dir); @@ -1478,7 +1494,9 @@ innobase_start_or_create_for_mysql(void) fprintf(stderr, "InnoDB: !!! innodb_force_recovery is set to %lu !!!\n", srv_force_recovery); - } + } + + fflush(stderr); return((int) DB_SUCCESS); } diff --git a/innobase/sync/Makefile.am b/innobase/sync/Makefile.am index 7504525bf84..4acd4516e35 100644 --- a/innobase/sync/Makefile.am +++ b/innobase/sync/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libsync.a +noinst_LIBRARIES = libsync.a libsync_a_SOURCES = sync0arr.c sync0ipm.c sync0rw.c sync0sync.c diff --git a/innobase/thr/Makefile.am b/innobase/thr/Makefile.am index 5f42138e734..62c39492c07 100644 --- a/innobase/thr/Makefile.am +++ b/innobase/thr/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libthr.a +noinst_LIBRARIES = libthr.a libthr_a_SOURCES = thr0loc.c diff --git a/innobase/trx/Makefile.am b/innobase/trx/Makefile.am index 63b2c52da33..9e2b3c398e3 100644 --- a/innobase/trx/Makefile.am +++ b/innobase/trx/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libtrx.a +noinst_LIBRARIES = libtrx.a libtrx_a_SOURCES = trx0purge.c trx0rec.c trx0roll.c trx0rseg.c\ trx0sys.c trx0trx.c trx0undo.c diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c index 1ae9f00ae1f..b9e4a9fea4b 100644 --- a/innobase/trx/trx0sys.c +++ b/innobase/trx/trx0sys.c @@ -340,7 +340,6 @@ trx_sys_doublewrite_restore_corrupt_pages(void) /* It is an unwritten doublewrite buffer page: do nothing */ - } else { /* Read in the actual page from the data files */ @@ -357,9 +356,19 @@ trx_sys_doublewrite_restore_corrupt_pages(void) "InnoDB: Trying to recover it from the doublewrite buffer.\n"); if (buf_page_is_corrupted(page)) { + fprintf(stderr, + "InnoDB: Dump of the page:\n"); + buf_page_print(read_buf); + fprintf(stderr, + "InnoDB: Dump of corresponding page in doublewrite buffer:\n"); + buf_page_print(page); + fprintf(stderr, "InnoDB: Also the page in the doublewrite buffer is corrupt.\n" - "InnoDB: Cannot continue operation.\n"); + "InnoDB: Cannot continue operation.\n" + "InnoDB: You can try to recover the database with the my.cnf\n" + "InnoDB: option:\n" + "InnoDB: set-variable=innodb_force_recovery=6\n"); exit(1); } diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 5ac49397c90..5753b5b338e 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -89,6 +89,8 @@ trx_create( trx->check_foreigns = TRUE; trx->check_unique_secondary = TRUE; + trx->flush_log_later = FALSE; + trx->dict_operation = FALSE; trx->mysql_thd = NULL; @@ -102,8 +104,6 @@ trx_create( trx->mysql_master_log_file_name = ""; trx->mysql_master_log_pos = 0; - trx->ignore_duplicates_in_insert = FALSE; - mutex_create(&(trx->undo_mutex)); mutex_set_level(&(trx->undo_mutex), SYNC_TRX_UNDO); @@ -782,13 +782,26 @@ trx_commit_off_kernel( /*-------------------------------------*/ - /* Most MySQL users run with srv_flush_.. set to FALSE: */ + /* Most MySQL users run with srv_flush_.. set to 0: */ - if (srv_flush_log_at_trx_commit) { - - log_flush_up_to(lsn, LOG_WAIT_ONE_GROUP); + if (srv_flush_log_at_trx_commit != 0) { + if (srv_unix_file_flush_method != SRV_UNIX_NOSYNC + && srv_flush_log_at_trx_commit != 2 + && !trx->flush_log_later) { + + /* Write the log to the log files AND flush + them to disk */ + + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE); + } else { + /* Write the log but do not flush it to disk */ + + log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE); + } } + trx->commit_lsn = lsn; + /*-------------------------------------*/ mutex_enter(&kernel_mutex); @@ -1470,6 +1483,33 @@ trx_commit_for_mysql( } /************************************************************************** +If required, flushes the log to disk if we called trx_commit_for_mysql() +with trx->flush_log_later == TRUE. */ + +ulint +trx_commit_complete_for_mysql( +/*==========================*/ + /* out: 0 or error number */ + trx_t* trx) /* in: trx handle */ +{ + ut_a(trx); + + if (srv_flush_log_at_trx_commit == 1 + && srv_unix_file_flush_method != SRV_UNIX_NOSYNC) { + + trx->op_info = (char *) "flushing log"; + + /* Flush the log files to disk */ + + log_write_up_to(trx->commit_lsn, LOG_WAIT_ONE_GROUP, TRUE); + + trx->op_info = (char *) ""; + } + + return(0); +} + +/************************************************************************** Marks the latest SQL statement ended. */ void diff --git a/innobase/usr/Makefile.am b/innobase/usr/Makefile.am index a71d0d41ac0..bdcc832a76e 100644 --- a/innobase/usr/Makefile.am +++ b/innobase/usr/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libusr.a +noinst_LIBRARIES = libusr.a libusr_a_SOURCES = usr0sess.c diff --git a/innobase/ut/Makefile.am b/innobase/ut/Makefile.am index de3cf41b767..2fdbb99e0f3 100644 --- a/innobase/ut/Makefile.am +++ b/innobase/ut/Makefile.am @@ -17,7 +17,7 @@ include ../include/Makefile.i -libs_LIBRARIES = libut.a +noinst_LIBRARIES = libut.a libut_a_SOURCES = ut0byte.c ut0dbg.c ut0mem.c ut0rnd.c ut0ut.c diff --git a/innobase/ut/ut0ut.c b/innobase/ut/ut0ut.c index 31a137b5fac..c503cda54b9 100644 --- a/innobase/ut/ut0ut.c +++ b/innobase/ut/ut0ut.c @@ -206,7 +206,7 @@ ut_get_year_month_day( cal_tm_ptr = localtime(&tm); - *year = (ulint)cal_tm_ptr->tm_year; + *year = (ulint)cal_tm_ptr->tm_year + 1900; *month = (ulint)cal_tm_ptr->tm_mon + 1; *day = (ulint)cal_tm_ptr->tm_mday; #endif diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 5aa12a800c4..bc12e01e420 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -133,12 +133,7 @@ EXPORTS mysql_autocommit load_defaults free_defaults - - - - - - + my_path diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index 8cf4e2fbe7e..e6166f6bbe5 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -66,7 +66,7 @@ TYPELIB sql_protocol_typelib = {array_elements(sql_protocol_names_lib)-1,"", #define closesocket(A) close(A) #endif -void mysql_once_init(void); +void mysqld_once_init(void); static void end_server(MYSQL *mysql); static void append_wild(char *to,char *end,const char *wild); static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to, @@ -373,7 +373,7 @@ static void mysql_read_default_options(struct st_mysql_options *options, MYSQL * STDCALL mysql_init(MYSQL *mysql) { - mysql_once_init(); + mysqld_once_init(); if (!mysql) { if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL)))) @@ -386,7 +386,7 @@ mysql_init(MYSQL *mysql) } -void mysql_once_init() +void mysqld_once_init() { if (!mysql_client_init) { diff --git a/man/Makefile.am b/man/Makefile.am index 7019d2aa865..9f919e77b8f 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -19,7 +19,7 @@ man_MANS = mysql.1 isamchk.1 isamlog.1 mysql_zap.1 mysqlaccess.1 \ mysqladmin.1 mysqld.1 mysqld_multi.1 mysqldump.1 mysqlshow.1 \ - perror.1 replace.1 mysqld_safe.1 + perror.1 replace.1 mysqld_safe.1 mysql_fix_privilege_tables.1 EXTRA_DIST = $(man_MANS) diff --git a/man/isamchk.1 b/man/isamchk.1 index bfc4ccd9c08..341e968a131 100644 --- a/man/isamchk.1 +++ b/man/isamchk.1 @@ -1,4 +1,4 @@ -.TH isamchk 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH isamchk 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME .BR isamchk \- Description, check and repair of ISAM tables. diff --git a/man/isamlog.1 b/man/isamlog.1 index a386f11c010..402c3052ad8 100644 --- a/man/isamlog.1 +++ b/man/isamlog.1 @@ -1,4 +1,4 @@ -.TH isamlog 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH isamlog 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME isamlog - Write info about whats in a nisam log file. .SH USAGE diff --git a/man/mysql.1 b/man/mysql.1 index 6664581072f..c0c37716b14 100644 --- a/man/mysql.1 +++ b/man/mysql.1 @@ -1,4 +1,4 @@ -.TH mysql 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH mysql 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME mysql \- text-based client for mysqld, a SQL-based relational database daemon .SH SYNOPSIS diff --git a/man/mysql_fix_privilege_tables.1 b/man/mysql_fix_privilege_tables.1 new file mode 100644 index 00000000000..bf4e0e15dfa --- /dev/null +++ b/man/mysql_fix_privilege_tables.1 @@ -0,0 +1,23 @@ +.TH mysql 1 "17 March 2003" "MySQL 4.0" "MySQL database" +.SH NAME +mysql_fix_privilege_tables \- Fixes MySQL privilege tables. +.SH SYNOPSIS +mysql_fix_privilege_tables [options] +.SH DESCRIPTION +This scripts updates the mysql.user, mysql.db, mysql.host and the +mysql.func tables to MySQL 3.22.14 and above. + +This is needed if you want to use the new GRANT functions, +CREATE AGGREGATE FUNCTION or want to use the more secure passwords in 3.23 + +If you get 'Access denied' errors, you should run this script again +and give the MySQL root user password as an argument! + +For more information start the program with '--help'. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers <ch@debian.org>. + +MySQL is available at http://www.mysql.com/. +.\" end of man page diff --git a/man/mysql_zap.1 b/man/mysql_zap.1 index 144fc212372..71931c03db6 100644 --- a/man/mysql_zap.1 +++ b/man/mysql_zap.1 @@ -1,4 +1,4 @@ -.TH zap 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH zap 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME zap - a perl script used to kill processes .SH USAGE diff --git a/man/mysqlaccess.1 b/man/mysqlaccess.1 index c1c61d4a8a7..fc7c185e050 100644 --- a/man/mysqlaccess.1 +++ b/man/mysqlaccess.1 @@ -1,4 +1,4 @@ -.TH mysqlaccess 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH mysqlaccess 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME .BR mysqlaccess \- Create new users to mysql. diff --git a/man/mysqladmin.1 b/man/mysqladmin.1 index 9d7d73aad21..693e8aa5a72 100644 --- a/man/mysqladmin.1 +++ b/man/mysqladmin.1 @@ -1,4 +1,4 @@ -.TH mysqladmin 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH mysqladmin 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME mysqladmin [OPTIONS] command command.... \- A utility for performing administrative operations .SH OPTION SYNOPSIS diff --git a/man/mysqld.1 b/man/mysqld.1 index 0a6fcccbef2..98247cd9445 100644 --- a/man/mysqld.1 +++ b/man/mysqld.1 @@ -1,4 +1,4 @@ -.TH mysqld 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH mysqld 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME .BR mysqld \- Starts the MySQL server demon diff --git a/man/mysqld_multi.1 b/man/mysqld_multi.1 index 68b9d1e876f..47418835939 100644 --- a/man/mysqld_multi.1 +++ b/man/mysqld_multi.1 @@ -1,4 +1,4 @@ -.TH mysqld_multi 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH mysqld_multi 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME mysqld_multi - is meant for managing several mysqld processes running in different UNIX sockets and TCP/IP ports. .SH USAGE diff --git a/man/mysqld_safe.1 b/man/mysqld_safe.1 index b8271c848cc..3679346d7db 100644 --- a/man/mysqld_safe.1 +++ b/man/mysqld_safe.1 @@ -1,4 +1,4 @@ -.TH safe_mysqld 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH safe_mysqld 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME mysqld_safe \- start the mysqld daemon on Unix. .SH SYNOPSIS diff --git a/man/mysqldump.1 b/man/mysqldump.1 index b4aba2ade13..af50366f24c 100644 --- a/man/mysqldump.1 +++ b/man/mysqldump.1 @@ -1,4 +1,4 @@ -.TH mysqldump 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH mysqldump 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME mysqldump \- text-based client for dumping or backing up mysql databases , tables and or data. diff --git a/man/mysqlshow.1 b/man/mysqlshow.1 index b6aceec82e3..39590b54375 100644 --- a/man/mysqlshow.1 +++ b/man/mysqlshow.1 @@ -1,4 +1,4 @@ -.TH mysqlshow 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH mysqlshow 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME .BR mysqlshow \- Shows the structure of a mysql database (databases,tables and columns) diff --git a/man/perror.1 b/man/perror.1 index 2c5dd9a295f..b8eec8af318 100644 --- a/man/perror.1 +++ b/man/perror.1 @@ -1,4 +1,4 @@ -.TH perror 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH perror 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME perror \- describes a system or MySQL error code. .SH SYNOPSIS diff --git a/man/replace.1 b/man/replace.1 index 7c3b79f605b..46d542d57f4 100644 --- a/man/replace.1 +++ b/man/replace.1 @@ -1,4 +1,4 @@ -.TH replace 1 "19 December 2000" "MySQL 3.23" "MySQL database" +.TH replace 1 "19 December 2000" "MySQL 4.0" "MySQL database" .SH NAME .TP replace - A utility program that is used by msql2mysql, but that has more general applicability as well. replace changes strings in place in files or on the standard input. Uses a finite state machine to match longer strings first. Can be used to swap strings. diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 6fa71348002..c59d140da85 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -321,10 +321,10 @@ static void _ftb_init_index_search(FT_INFO *ftb) else /* 3 */ { if (!is_tree_inited(& ftb->no_dupes)) - { init_tree(&ftb->no_dupes,0,0,sizeof(my_off_t), _ftb_no_dupes_cmp, 0, NULL, NULL); - } + else + reset_tree(& ftb->no_dupes); } } diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 75f2a6c83c4..019222fdf22 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -858,15 +858,19 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) { if (b_type & BLOCK_LAST) { - mi_check_print_error(param,"Record link to short for record at %s", - llstr(start_recpos,llbuff)); + mi_check_print_error(param, + "Wrong record length %s of %s at %s", + llstr(block_info.rec_len-left_length,llbuff), + llstr(block_info.rec_len, llbuff2), + llstr(start_recpos,llbuff3)); got_error=1; break; } if (info->state->data_file_length < block_info.next_filepos) { - mi_check_print_error(param,"Found next-recordlink that points outside datafile at %s", - llstr(block_info.filepos,llbuff)); + mi_check_print_error(param, + "Found next-recordlink that points outside datafile at %s", + llstr(block_info.filepos,llbuff)); got_error=1; break; } @@ -2233,7 +2237,17 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, else rec_length=share->base.pack_reclength; sort_info.max_records= - ((param->testflag & T_CREATE_MISSING_KEYS) ? info->state->records : + /* +1 below is required hack for parallel repair mode. + The info->state->records value, that is compared later + to sort_info.max_records and cannot exceed it, is + increased in sort_key_write. In mi_repair_by_sort, sort_key_write + is called after sort_key_read, where the comparison is performed, + but in parallel mode master thread can call sort_key_write + before some other repair thread calls sort_key_read. + Furthermore I'm not even sure +1 would be enough. + May be sort_info.max_records shold be always set to max value in + parallel mode. */ + ((param->testflag & T_CREATE_MISSING_KEYS) ? info->state->records + 1: (ha_rows) (sort_info.filelength/rec_length+1)); del=info->state->del; @@ -3681,12 +3695,14 @@ int update_state_info(MI_CHECK *param, MI_INFO *info,uint update) } if (update & UPDATE_STAT) { - uint key_parts= mi_uint2korr(share->state.header.key_parts); + uint i, key_parts= mi_uint2korr(share->state.header.key_parts); share->state.rec_per_key_rows=info->state->records; - memcpy((char*) share->state.rec_per_key_part, - (char*) param->rec_per_key_part, - sizeof(*param->rec_per_key_part)*key_parts); share->state.changed&= ~STATE_NOT_ANALYZED; + for (i=0; i<key_parts; i++) + { + if (!(share->state.rec_per_key_part[i]=param->rec_per_key_part[i])) + share->state.changed|= STATE_NOT_ANALYZED; + } } if (update & (UPDATE_STAT | UPDATE_SORT | UPDATE_TIME | UPDATE_AUTO_INC)) { diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index dc51269ac35..faf86c3ffbd 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -485,7 +485,7 @@ int _mi_write_part_record(MI_INFO *info, { info->update&= ~HA_STATE_EXTEND_BLOCK; if (my_block_write(&info->rec_cache,(byte*) *record-head_length, - length+extra_length+del_length,filepos)) + length+extra_length+del_length,filepos)) goto err; } else if (my_b_write(&info->rec_cache,(byte*) *record-head_length, @@ -1412,10 +1412,7 @@ uint _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos) VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0))); if (my_read(file,(char*) header,sizeof(info->header),MYF(0)) != sizeof(info->header)) - { - my_errno=HA_ERR_WRONG_IN_RECORD; - return BLOCK_FATAL_ERROR; - } + goto err; } DBUG_DUMP("header",(byte*) header,MI_BLOCK_INFO_HEADER_LENGTH); if (info->second_read) @@ -1435,10 +1432,7 @@ uint _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos) if ((info->block_len=(uint) mi_uint3korr(header+1)) < MI_MIN_BLOCK_LENGTH || (info->block_len & (MI_DYN_ALIGN_SIZE -1))) - { - my_errno=HA_ERR_WRONG_IN_RECORD; - return BLOCK_ERROR; - } + goto err; info->filepos=filepos; info->next_filepos=mi_sizekorr(header+4); info->prev_filepos=mi_sizekorr(header+12); @@ -1449,7 +1443,7 @@ uint _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos) (mi_uint4korr(header+12) != 0 && (mi_uint4korr(header+12) != (ulong) ~0 || info->prev_filepos != (ulong) ~0))) - return BLOCK_FATAL_ERROR; + goto err; #endif return return_val | BLOCK_DELETED; /* Deleted block */ @@ -1529,8 +1523,9 @@ uint _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos) info->second_read=1; info->filepos=filepos+12; return return_val; - default: - my_errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */ - return BLOCK_ERROR; } + +err: + my_errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */ + return BLOCK_ERROR; } diff --git a/myisam/mi_info.c b/myisam/mi_info.c index 0be3cc44d80..32767e73bb1 100644 --- a/myisam/mi_info.c +++ b/myisam/mi_info.c @@ -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 */ -/* Ger tillbaka en struct med information om isam-filen */ +/* Return useful base information for an open table */ #include "myisamdef.h" #ifdef __WIN__ diff --git a/myisam/mi_key.c b/myisam/mi_key.c index 00a64bca269..a375a415103 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -145,11 +145,26 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key, } /* _mi_make_key */ - /* Pack a key to intern format from given format (c_rkey) */ - /* returns length of packed key */ +/* + Pack a key to intern format from given format (c_rkey) + + SYNOPSIS + _mi_pack_key() + info MyISAM handler + uint keynr key number + key Store packed key here + old Not packed key + k_length Length of 'old' to use + last_used_keyseg out parameter. May be NULL + + RETURN + length of packed key + + last_use_keyseg Store pointer to the keyseg after the last used one +*/ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, - uint k_length) + uint k_length, HA_KEYSEG **last_used_keyseg) { uint length; uchar *pos,*end,*start_key=key; @@ -220,6 +235,8 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, key+= length; k_length-=length; } + if (last_used_keyseg) + *last_used_keyseg= keyseg; #ifdef NOT_USED if (keyseg->type) diff --git a/myisam/mi_open.c b/myisam/mi_open.c index a1ce135f02f..178365577aa 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -116,8 +116,10 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) errpos=1; if (my_read(kfile,(char*) share->state.header.file_version,head_length, MYF(MY_NABP))) + { + my_errno= HA_ERR_NOT_A_TABLE; goto err; - + } if (memcmp((byte*) share->state.header.file_version, (byte*) myisam_file_magic, 4)) { @@ -166,7 +168,10 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) } errpos=3; if (my_read(kfile,disk_cache,info_length,MYF(MY_NABP))) + { + my_errno=HA_ERR_CRASHED; goto err; + } len=mi_uint2korr(share->state.header.state_info_length); keys= (uint) share->state.header.keys; uniques= (uint) share->state.header.uniques; diff --git a/myisam/mi_range.c b/myisam/mi_range.c index 4b98b48199a..379ffba135a 100644 --- a/myisam/mi_range.c +++ b/myisam/mi_range.c @@ -59,7 +59,8 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, const byte *start_key, if (start_key_len == 0) start_key_len=USE_WHOLE_KEY; key_buff=info->lastkey+info->s->base.max_key_length; - start_key_len=_mi_pack_key(info,inx,key_buff,(uchar*) start_key,start_key_len); + start_key_len= _mi_pack_key(info,inx,key_buff,(uchar*) start_key, + start_key_len, (HA_KEYSEG**) 0); res=rtree_estimate(info, inx, key_buff, start_key_len, myisam_read_vec[start_search_flag]); res=res?res:1; break; @@ -103,7 +104,8 @@ static ha_rows _mi_record_pos(MI_INFO *info, const byte *key, uint key_len, if (key_len == 0) key_len=USE_WHOLE_KEY; key_buff=info->lastkey+info->s->base.max_key_length; - key_len=_mi_pack_key(info,inx,key_buff,(uchar*) key,key_len); + key_len=_mi_pack_key(info,inx,key_buff,(uchar*) key,key_len, + (HA_KEYSEG**) 0); DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg, (uchar*) key_buff,key_len);); nextflag=myisam_read_vec[search_flag]; diff --git a/myisam/mi_rkey.c b/myisam/mi_rkey.c index 4a3c76809e8..ddfac0a39a2 100644 --- a/myisam/mi_rkey.c +++ b/myisam/mi_rkey.c @@ -23,10 +23,12 @@ /* Ordinary search_flag is 0 ; Give error if no record with key */ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, - enum ha_rkey_function search_flag) + enum ha_rkey_function search_flag) { uchar *key_buff; MYISAM_SHARE *share=info->s; + MI_KEYDEF *keyinfo; + HA_KEYSEG *last_used_keyseg; uint pack_key_length, use_key_length, nextflag; DBUG_ENTER("mi_rkey"); DBUG_PRINT("enter",("base: %lx inx: %d search_flag: %d", @@ -36,25 +38,29 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, DBUG_RETURN(my_errno); info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); - info->last_key_func=search_flag; + info->last_key_func= search_flag; + keyinfo= share->keyinfo + inx; if (info->once_flags & USE_PACKED_KEYS) { - /* key is already packed! */ + info->once_flags&= ~USE_PACKED_KEYS; /* Reset flag */ + /* + key is already packed!; This happens when we are using a MERGE TABLE + */ key_buff=info->lastkey+info->s->base.max_key_length; - info->last_rkey_length=pack_key_length=key_len; + pack_key_length= key_len; bmove(key_buff,key,key_len); - info->once_flags&= ~USE_PACKED_KEYS; + last_used_keyseg= 0; } else { if (key_len == 0) key_len=USE_WHOLE_KEY; key_buff=info->lastkey+info->s->base.max_key_length; - pack_key_length=_mi_pack_key(info,(uint) inx,key_buff,(uchar*) key,key_len); - info->last_rkey_length=pack_key_length; - DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,share->keyinfo[inx].seg, - key_buff,pack_key_length);); + pack_key_length=_mi_pack_key(info,(uint) inx, key_buff, (uchar*) key, + key_len, &last_used_keyseg); + DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE, keyinfo->seg, + key_buff, pack_key_length);); } if (fast_mi_readinfo(info)) @@ -67,9 +73,9 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST))) use_key_length=USE_WHOLE_KEY; - switch(info->s->keyinfo[inx].key_alg){ + switch (info->s->keyinfo[inx].key_alg) { case HA_KEY_ALG_RTREE: - if(rtree_find_first(info,inx,key_buff,use_key_length,nextflag)<0) + if (rtree_find_first(info,inx,key_buff,use_key_length,nextflag) < 0) { my_errno=HA_ERR_CRASHED; goto err; @@ -77,8 +83,8 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, break; case HA_KEY_ALG_BTREE: default: - if (!_mi_search(info,info->s->keyinfo+inx,key_buff,use_key_length, - myisam_read_vec[search_flag],info->s->state.key_root[inx])) + if (!_mi_search(info, keyinfo, key_buff, use_key_length, + myisam_read_vec[search_flag], info->s->state.key_root[inx])) { while (info->lastpos >= info->state->data_file_length) { @@ -88,7 +94,7 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, exact key, because the keys are sorted according to position */ - if (_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, + if (_mi_search_next(info, keyinfo, info->lastkey, info->lastkey_length, myisam_readnext_vec[search_flag], info->s->state.key_root[inx])) @@ -99,8 +105,17 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, if (share->concurrent_insert) rw_unlock(&share->key_root_lock[inx]); + /* Calculate length of the found key; Used by mi_rnext_same */ + if ((keyinfo->flag & HA_VAR_LENGTH_KEY) && last_used_keyseg && + info->lastpos != HA_OFFSET_ERROR) + info->last_rkey_length= _mi_keylength_part(keyinfo, info->lastkey, + last_used_keyseg); + else + info->last_rkey_length= pack_key_length; + + /* Check if we don't want to have record back, only error message */ if (!buf) - DBUG_RETURN(info->lastpos==HA_OFFSET_ERROR ? my_errno : 0); + DBUG_RETURN(info->lastpos == HA_OFFSET_ERROR ? my_errno : 0); if (!(*info->read_record)(info,info->lastpos,buf)) { @@ -110,8 +125,9 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, info->lastpos = HA_OFFSET_ERROR; /* Didn't find key */ - /* Store key for read next */ + /* Store last used key as a base for read next */ memcpy(info->lastkey,key_buff,pack_key_length); + info->last_rkey_length= pack_key_length; bzero((char*) info->lastkey+pack_key_length,info->s->base.rec_reflength); info->lastkey_length=pack_key_length+info->s->base.rec_reflength; diff --git a/myisam/mi_search.c b/myisam/mi_search.c index 04803d7a901..7e8577c0656 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -1033,6 +1033,37 @@ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key) } /* _mi_keylength */ +/* + Calculate length of part key. + + Used in mi_rkey() to find the key found for the key-part that was used. + This is needed in case of multi-byte character sets where we may search + after '0xDF' but find 'ss' +*/ + +uint _mi_keylength_part(MI_KEYDEF *keyinfo, register uchar *key, + HA_KEYSEG *end) +{ + reg1 HA_KEYSEG *keyseg; + uchar *start= key; + + for (keyseg=keyinfo->seg ; keyseg != end ; keyseg++) + { + if (keyseg->flag & HA_NULL_PART) + if (!*key++) + continue; + if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH)) + { + uint length; + get_key_length(length,key); + key+=length; + } + else + key+= keyseg->length; + } + return (uint) (key-start); +} + /* Move a key */ uchar *_mi_move_key(MI_KEYDEF *keyinfo, uchar *to, uchar *from) diff --git a/myisam/mi_test2.c b/myisam/mi_test2.c index 8c7713c4b4d..75adf74294f 100644 --- a/myisam/mi_test2.c +++ b/myisam/mi_test2.c @@ -645,14 +645,14 @@ int main(int argc, char *argv[]) if ((long) range_records < (long) records*7/10-2 || (long) range_records > (long) records*14/10+2) { - printf("mi_records_range for key: %d returned %ld; Should be about %ld\n", - i, (long) range_records, (long) records); + printf("mi_records_range for key: %d returned %lu; Should be about %lu\n", + i, (ulong) range_records, (ulong) records); goto end; } if (verbose && records) { - printf("mi_records_range returned %ld; Exact is %ld (diff: %4.2g %%)\n", - (long) range_records, (long) records, + printf("mi_records_range returned %lu; Exact is %lu (diff: %4.2g %%)\n", + (ulong) range_records, (ulong) records, labs((long) range_records-(long) records)*100.0/records); } @@ -666,8 +666,8 @@ int main(int argc, char *argv[]) || info.keys != keys) { puts("Wrong info from mi_info"); - printf("Got: records: %ld delete: %ld i_keys: %d\n", - (long) info.records, (long) info.deleted,info.keys); + printf("Got: records: %lu delete: %lu i_keys: %d\n", + (ulong) info.records, (ulong) info.deleted, info.keys); } if (verbose) { diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 104b344a9e2..834ad818972 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -44,6 +44,8 @@ static const char *load_default_groups[]= { "myisamchk", 0 }; static const char *set_charset_name, *opt_tmpdir; static CHARSET_INFO *set_charset; static long opt_myisam_block_size; +static const char *my_progname_short; +static int stopwords_inited= 0; static MY_TMPDIR myisamchk_tmpdir; static const char *type_names[]= @@ -86,6 +88,7 @@ int main(int argc, char **argv) { int error; MY_INIT(argv[0]); + my_progname_short= my_progname+dirname_length(my_progname); #ifdef __EMX__ _wildcard (&argc, &argv); @@ -332,7 +335,7 @@ static void usage(void) puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n"); puts("Description, check and repair of MyISAM tables."); puts("Used without options all tables on the command will be checked for errors"); - printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname); + printf("Usage: %s [OPTIONS] tables[.MYI]\n", my_progname_short); puts("\nGlobal options:\n\ -#, --debug=... Output debug log. Often this is 'd:t:o,filename'\n\ -?, --help Display this help and exit.\n\ @@ -689,7 +692,7 @@ static void get_options(register int *argc,register char ***argv) { VOID(fprintf(stderr, "%s: --unpack can't be used with --quick or --sort-records\n", - my_progname)); + my_progname_short)); exit(1); } if ((check_param.testflag & T_READONLY) && @@ -699,7 +702,7 @@ static void get_options(register int *argc,register char ***argv) { VOID(fprintf(stderr, "%s: Can't use --readonly when repairing or sorting\n", - my_progname)); + my_progname_short)); exit(1); } @@ -874,7 +877,7 @@ static int myisamchk(MI_CHECK *param, my_string filename) } else { - if (share->state.header.fulltext_keys) + if (share->state.header.fulltext_keys && !stopwords_inited++) ft_init_stopwords(); if (!(param->testflag & T_READONLY)) @@ -1674,13 +1677,13 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...) if (!param->warning_printed && !param->error_printed) { if (param->testflag & T_SILENT) - fprintf(stderr,"%s: MyISAM file %s\n",my_progname, + fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short, param->isam_file_name); param->out_flag|= O_DATA_LOST; } param->warning_printed=1; va_start(args,fmt); - fprintf(stderr,"%s: warning: ",my_progname); + fprintf(stderr,"%s: warning: ",my_progname_short); VOID(vfprintf(stderr, fmt, args)); VOID(fputc('\n',stderr)); fflush(stderr); @@ -1700,12 +1703,12 @@ void mi_check_print_error(MI_CHECK *param, const char *fmt,...) if (!param->warning_printed && !param->error_printed) { if (param->testflag & T_SILENT) - fprintf(stderr,"%s: MyISAM file %s\n",my_progname,param->isam_file_name); + fprintf(stderr,"%s: MyISAM file %s\n",my_progname_short,param->isam_file_name); param->out_flag|= O_DATA_LOST; } param->error_printed|=1; va_start(args,fmt); - fprintf(stderr,"%s: error: ",my_progname); + fprintf(stderr,"%s: error: ",my_progname_short); VOID(vfprintf(stderr, fmt, args)); VOID(fputc('\n',stderr)); fflush(stderr); diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 50320f1ecbd..c986c483902 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -537,6 +537,8 @@ extern uchar *_mi_get_last_key(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *keypos, extern uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key, uchar *keypos, uint *return_key_length); extern uint _mi_keylength(MI_KEYDEF *keyinfo,uchar *key); +extern uint _mi_keylength_part(MI_KEYDEF *keyinfo, register uchar *key, + HA_KEYSEG *end); extern uchar *_mi_move_key(MI_KEYDEF *keyinfo,uchar *to,uchar *from); extern int _mi_search_next(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key, uint key_length,uint nextflag,my_off_t pos); @@ -551,7 +553,7 @@ extern my_off_t _mi_new(MI_INFO *info,MI_KEYDEF *keyinfo); extern uint _mi_make_key(MI_INFO *info,uint keynr,uchar *key, const byte *record,my_off_t filepos); extern uint _mi_pack_key(MI_INFO *info,uint keynr,uchar *key,uchar *old, - uint key_length); + uint key_length, HA_KEYSEG **last_used_keyseg); extern int _mi_read_key_record(MI_INFO *info,my_off_t filepos,byte *buf); extern int _mi_read_cache(IO_CACHE *info,byte *buff,my_off_t pos, uint length,int re_read_if_possibly); diff --git a/myisam/sort.c b/myisam/sort.c index 09e487e1165..a41713f750f 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -185,8 +185,8 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, if (maxbuffer == 0) { if (!no_messages) - printf(" - Dumping %lu keys\n",records); - if (write_index(info,sort_keys,(uint) records)) + printf(" - Dumping %lu keys\n", (ulong) records); + if (write_index(info,sort_keys, (uint) records)) goto err; /* purecov: inspected */ } else @@ -195,7 +195,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, if (maxbuffer >= MERGEBUFF2) { if (!no_messages) - printf(" - Merging %lu keys\n",records); /* purecov: tested */ + printf(" - Merging %lu keys\n", (ulong) records); /* purecov: tested */ if (merge_many_buff(info,keys,sort_keys, dynamic_element(&buffpek,0,BUFFPEK *),&maxbuffer,&tempfile)) goto err; /* purecov: inspected */ @@ -308,6 +308,8 @@ pthread_handler_decl(thr_find_all_keys,arg) uint idx, maxbuffer; uchar **sort_keys=0; + LINT_INIT(keys); + error=1; if (my_thread_init()) diff --git a/myisammrg/myrg_extra.c b/myisammrg/myrg_extra.c index d375b45df99..62cf5f01aba 100644 --- a/myisammrg/myrg_extra.c +++ b/myisammrg/myrg_extra.c @@ -33,7 +33,7 @@ int myrg_extra(MYRG_INFO *info,enum ha_extra_function function, if (function == HA_EXTRA_CACHE) { info->cache_in_use=1; - info->cache_size= (extra_arg ? *(long*) extra_arg : + info->cache_size= (extra_arg ? *(ulong*) extra_arg : my_default_record_cache_size); } else diff --git a/mysql-test/include/not_embedded.inc b/mysql-test/include/not_embedded.inc index 52ae026ece3..fcc1756caab 100644 --- a/mysql-test/include/not_embedded.inc +++ b/mysql-test/include/not_embedded.inc @@ -1,5 +1,5 @@ -- require r/not_embedded.require disable_query_log; -select version() like "%embedded%" as "have_embedded"; +select version() like N'%embedded%' as 'have_embedded'; enable_query_log; diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index a3343b8e019..81e3f866709 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -110,11 +110,11 @@ GREP=grep if test $? != 0; then exit 1; fi PRINTF=printf RM=rm -TIME=`which time` if test $? != 0; then exit 1; fi TR=tr XARGS=`which xargs` if test $? != 0; then exit 1; fi +SORT=sort # Are we using a source or a binary distribution? @@ -413,7 +413,7 @@ fi if test ${COLUMNS:-0} -lt 80 ; then COLUMNS=80 ; fi E=`$EXPR $COLUMNS - 8` -DASH72=`$ECHO '------------------------------------------------------------------------'|$CUT -c 1-$E` +DASH72=`$ECHO '------------------------------------------'|$CUT -c 1-$E` # on source dist, we pick up freshly build executables # on binary, use what is installed @@ -592,9 +592,8 @@ skip_test() { USERT=" ...." SYST=" ...." REALT=" ...." - timestr="$USERT $SYST $REALT" pname=`$ECHO "$1 "|$CUT -c 1-24` - RES="$pname $timestr" + RES="$pname" skip_inc $ECHO "$RES$RES_SPACE [ skipped ]" } @@ -1221,31 +1220,15 @@ run_testcase () $RM -f r/$tname.*reject mysql_test_args="-R r/$tname.result $EXTRA_MYSQL_TEST_OPT" if [ -z "$DO_CLIENT_GDB" ] ; then - mytime=`$TIME -p $MYSQL_TEST $mysql_test_args < $tf 2> $TIMEFILE` + `$MYSQL_TEST $mysql_test_args < $tf 2> $TIMEFILE`; else do_gdb_test "$mysql_test_args" "$tf" fi res=$? - if [ $res = 0 ]; then - mytime=`$CAT $TIMEFILE | $TAIL -3 | $TR '\n' ':'` - - USERT=`$ECHO $mytime | $CUT -d : -f 2 | $CUT -d ' ' -f 2` - USERT=`prefix_to_8 $USERT` - SYST=`$ECHO $mytime | $CUT -d : -f 3 | $CUT -d ' ' -f 2` - SYST=`prefix_to_8 $SYST` - REALT=`$ECHO $mytime | $CUT -d : -f 1 | $CUT -d ' ' -f 2` - REALT=`prefix_to_8 $REALT` - else - USERT=" ...." - SYST=" ...." - REALT=" ...." - fi - - timestr="$USERT $SYST $REALT" pname=`$ECHO "$tname "|$CUT -c 1-24` - RES="$pname $timestr" + RES="$pname" if [ x$many_slaves = x1 ] ; then stop_slave 1 @@ -1380,7 +1363,7 @@ then fi $ECHO -$ECHO " TEST USER SYSTEM ELAPSED RESULT" +$ECHO " TEST RESULT" $ECHO $DASH72 if [ -z "$1" ] ; @@ -1389,7 +1372,7 @@ then $ECHO "Will not run in record mode without a specific test case." else if [ x$TEST_REPLICATION = x1 ]; then - for tf in $TESTDIR/rpl*.$TESTSUFFIX + for tf in `ls -1 $TESTDIR/*.$TESTSUFFIX | $SORT` do run_testcase $tf done diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index aadb35c32e8..ec2f7220a3d 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -92,6 +92,25 @@ key (n2, n3, n4, n1), key (n3, n4, n1, n2), key (n4, n1, n2, n3) ); alter table t1 disable keys; +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 n1 1 n1 A 0 NULL NULL BTREE +t1 1 n1_2 1 n1 A NULL NULL NULL BTREE disabled +t1 1 n1_2 2 n2 A NULL NULL NULL YES BTREE disabled +t1 1 n1_2 3 n3 A NULL NULL NULL YES BTREE disabled +t1 1 n1_2 4 n4 A NULL NULL NULL YES BTREE disabled +t1 1 n2 1 n2 A NULL NULL NULL YES BTREE disabled +t1 1 n2 2 n3 A NULL NULL NULL YES BTREE disabled +t1 1 n2 3 n4 A NULL NULL NULL YES BTREE disabled +t1 1 n2 4 n1 A NULL NULL NULL BTREE disabled +t1 1 n3 1 n3 A NULL NULL NULL YES BTREE disabled +t1 1 n3 2 n4 A NULL NULL NULL YES BTREE disabled +t1 1 n3 3 n1 A NULL NULL NULL BTREE disabled +t1 1 n3 4 n2 A NULL NULL NULL YES BTREE disabled +t1 1 n4 1 n4 A NULL NULL NULL YES BTREE disabled +t1 1 n4 2 n1 A NULL NULL NULL BTREE disabled +t1 1 n4 3 n2 A NULL NULL NULL YES BTREE disabled +t1 1 n4 4 n3 A NULL NULL NULL YES BTREE disabled insert into t1 values(10,RAND()*1000,RAND()*1000,RAND()); insert into t1 values(9,RAND()*1000,RAND()*1000,RAND()); insert into t1 values(8,RAND()*1000,RAND()*1000,RAND()); @@ -103,6 +122,25 @@ insert into t1 values(3,RAND()*1000,RAND()*1000,RAND()); insert into t1 values(2,RAND()*1000,RAND()*1000,RAND()); insert into t1 values(1,RAND()*1000,RAND()*1000,RAND()); alter table t1 enable keys; +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 n1 1 n1 A 10 NULL NULL BTREE +t1 1 n1_2 1 n1 A 10 NULL NULL BTREE +t1 1 n1_2 2 n2 A 10 NULL NULL YES BTREE +t1 1 n1_2 3 n3 A 10 NULL NULL YES BTREE +t1 1 n1_2 4 n4 A 10 NULL NULL YES BTREE +t1 1 n2 1 n2 A 10 NULL NULL YES BTREE +t1 1 n2 2 n3 A 10 NULL NULL YES BTREE +t1 1 n2 3 n4 A 10 NULL NULL YES BTREE +t1 1 n2 4 n1 A 10 NULL NULL BTREE +t1 1 n3 1 n3 A 10 NULL NULL YES BTREE +t1 1 n3 2 n4 A 10 NULL NULL YES BTREE +t1 1 n3 3 n1 A 10 NULL NULL BTREE +t1 1 n3 4 n2 A 10 NULL NULL YES BTREE +t1 1 n4 1 n4 A 10 NULL NULL YES BTREE +t1 1 n4 2 n1 A 10 NULL NULL BTREE +t1 1 n4 3 n2 A 10 NULL NULL YES BTREE +t1 1 n4 4 n3 A 10 NULL NULL YES BTREE drop table t1; create table t1 (i int unsigned not null auto_increment primary key); insert into t1 values (null),(null),(null),(null); @@ -122,3 +160,119 @@ Field Type Collation Null Key Default Extra i int(10) unsigned binary PRI NULL auto_increment c char(10) latin1_swedish_ci YES NULL drop table t1; +create table t1 (a int, b int); +insert into t1 values(1,100), (2,100), (3, 100); +insert into t1 values(1,99), (2,99), (3, 99); +insert into t1 values(1,98), (2,98), (3, 98); +insert into t1 values(1,97), (2,97), (3, 97); +insert into t1 values(1,96), (2,96), (3, 96); +insert into t1 values(1,95), (2,95), (3, 95); +insert into t1 values(1,94), (2,94), (3, 94); +insert into t1 values(1,93), (2,93), (3, 93); +insert into t1 values(1,92), (2,92), (3, 92); +insert into t1 values(1,91), (2,91), (3, 91); +insert into t1 values(1,90), (2,90), (3, 90); +insert into t1 values(1,89), (2,89), (3, 89); +insert into t1 values(1,88), (2,88), (3, 88); +insert into t1 values(1,87), (2,87), (3, 87); +insert into t1 values(1,86), (2,86), (3, 86); +insert into t1 values(1,85), (2,85), (3, 85); +insert into t1 values(1,84), (2,84), (3, 84); +insert into t1 values(1,83), (2,83), (3, 83); +insert into t1 values(1,82), (2,82), (3, 82); +insert into t1 values(1,81), (2,81), (3, 81); +insert into t1 values(1,80), (2,80), (3, 80); +insert into t1 values(1,79), (2,79), (3, 79); +insert into t1 values(1,78), (2,78), (3, 78); +insert into t1 values(1,77), (2,77), (3, 77); +insert into t1 values(1,76), (2,76), (3, 76); +insert into t1 values(1,75), (2,75), (3, 75); +insert into t1 values(1,74), (2,74), (3, 74); +insert into t1 values(1,73), (2,73), (3, 73); +insert into t1 values(1,72), (2,72), (3, 72); +insert into t1 values(1,71), (2,71), (3, 71); +insert into t1 values(1,70), (2,70), (3, 70); +insert into t1 values(1,69), (2,69), (3, 69); +insert into t1 values(1,68), (2,68), (3, 68); +insert into t1 values(1,67), (2,67), (3, 67); +insert into t1 values(1,66), (2,66), (3, 66); +insert into t1 values(1,65), (2,65), (3, 65); +insert into t1 values(1,64), (2,64), (3, 64); +insert into t1 values(1,63), (2,63), (3, 63); +insert into t1 values(1,62), (2,62), (3, 62); +insert into t1 values(1,61), (2,61), (3, 61); +insert into t1 values(1,60), (2,60), (3, 60); +insert into t1 values(1,59), (2,59), (3, 59); +insert into t1 values(1,58), (2,58), (3, 58); +insert into t1 values(1,57), (2,57), (3, 57); +insert into t1 values(1,56), (2,56), (3, 56); +insert into t1 values(1,55), (2,55), (3, 55); +insert into t1 values(1,54), (2,54), (3, 54); +insert into t1 values(1,53), (2,53), (3, 53); +insert into t1 values(1,52), (2,52), (3, 52); +insert into t1 values(1,51), (2,51), (3, 51); +insert into t1 values(1,50), (2,50), (3, 50); +insert into t1 values(1,49), (2,49), (3, 49); +insert into t1 values(1,48), (2,48), (3, 48); +insert into t1 values(1,47), (2,47), (3, 47); +insert into t1 values(1,46), (2,46), (3, 46); +insert into t1 values(1,45), (2,45), (3, 45); +insert into t1 values(1,44), (2,44), (3, 44); +insert into t1 values(1,43), (2,43), (3, 43); +insert into t1 values(1,42), (2,42), (3, 42); +insert into t1 values(1,41), (2,41), (3, 41); +insert into t1 values(1,40), (2,40), (3, 40); +insert into t1 values(1,39), (2,39), (3, 39); +insert into t1 values(1,38), (2,38), (3, 38); +insert into t1 values(1,37), (2,37), (3, 37); +insert into t1 values(1,36), (2,36), (3, 36); +insert into t1 values(1,35), (2,35), (3, 35); +insert into t1 values(1,34), (2,34), (3, 34); +insert into t1 values(1,33), (2,33), (3, 33); +insert into t1 values(1,32), (2,32), (3, 32); +insert into t1 values(1,31), (2,31), (3, 31); +insert into t1 values(1,30), (2,30), (3, 30); +insert into t1 values(1,29), (2,29), (3, 29); +insert into t1 values(1,28), (2,28), (3, 28); +insert into t1 values(1,27), (2,27), (3, 27); +insert into t1 values(1,26), (2,26), (3, 26); +insert into t1 values(1,25), (2,25), (3, 25); +insert into t1 values(1,24), (2,24), (3, 24); +insert into t1 values(1,23), (2,23), (3, 23); +insert into t1 values(1,22), (2,22), (3, 22); +insert into t1 values(1,21), (2,21), (3, 21); +insert into t1 values(1,20), (2,20), (3, 20); +insert into t1 values(1,19), (2,19), (3, 19); +insert into t1 values(1,18), (2,18), (3, 18); +insert into t1 values(1,17), (2,17), (3, 17); +insert into t1 values(1,16), (2,16), (3, 16); +insert into t1 values(1,15), (2,15), (3, 15); +insert into t1 values(1,14), (2,14), (3, 14); +insert into t1 values(1,13), (2,13), (3, 13); +insert into t1 values(1,12), (2,12), (3, 12); +insert into t1 values(1,11), (2,11), (3, 11); +insert into t1 values(1,10), (2,10), (3, 10); +insert into t1 values(1,9), (2,9), (3, 9); +insert into t1 values(1,8), (2,8), (3, 8); +insert into t1 values(1,7), (2,7), (3, 7); +insert into t1 values(1,6), (2,6), (3, 6); +insert into t1 values(1,5), (2,5), (3, 5); +insert into t1 values(1,4), (2,4), (3, 4); +insert into t1 values(1,3), (2,3), (3, 3); +insert into t1 values(1,2), (2,2), (3, 2); +insert into t1 values(1,1), (2,1), (3, 1); +alter table t1 add unique (a,b), add key (b); +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 0 a 2 b A NULL NULL NULL YES BTREE +t1 1 b 1 b A 100 NULL NULL YES BTREE +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 0 a 1 a A 3 NULL NULL YES BTREE +t1 0 a 2 b A 300 NULL NULL YES BTREE +t1 1 b 1 b A 100 NULL NULL YES BTREE +drop table t1; diff --git a/mysql-test/r/ansi.result b/mysql-test/r/ansi.result new file mode 100644 index 00000000000..f9f96310b73 --- /dev/null +++ b/mysql-test/r/ansi.result @@ -0,0 +1,10 @@ +drop table if exists t1; +SELECT 'A' || 'B'; +'A' || 'B' +AB +CREATE TABLE t1 (id INT, id2 int); +SELECT id,NULL,1,1.1,'a' FROM t1 GROUP BY id; +id NULL 1 1.1 a +SELECT id FROM t1 GROUP BY id2; +'t1.id' isn't in GROUP BY +drop table t1; diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index f711c8960bc..b39bb96e36a 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -29,13 +29,9 @@ The used storage engine can't index column 'b' create table t1 (a int not null auto_increment,primary key (a)) type=heap; create table t1 (a int not null,b text) type=heap; The used table type doesn't support BLOB/TEXT columns -create table t1 (a int ,primary key(a)) type=heap; -All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead drop table if exists t1; create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=heap; Incorrect table definition; There can only be one auto column and it must be defined as a key -create table t1 (ordid int(8), primary key (ordid)); -All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead create table not_existing_database.test (a int); Got one of the listed errors create table `a/a` (a int); @@ -180,6 +176,40 @@ select * from t1; if('2002'='2002','Y','N') Y drop table if exists t1; +SET SESSION table_type="heap"; +SELECT @@table_type; +@@table_type +HEAP +CREATE TABLE t1 (a int not null); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL default '0' +) TYPE=HEAP CHARSET=latin1 +drop table t1; +SET SESSION table_type="gemini"; +SELECT @@table_type; +@@table_type +GEMINI +CREATE TABLE t1 (a int not null); +Warnings: +Warning 1259 Using storage engine MYISAM for table 't1' +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL default '0' +) TYPE=MyISAM CHARSET=latin1 +SET SESSION table_type=default; +drop table t1; +create table t1 ( k1 varchar(2), k2 int, primary key(k1,k2)); +insert into t1 values ("a", 1), ("b", 2); +insert into t1 values ("c", NULL); +Column 'k2' cannot be null +insert into t1 values (NULL, 3); +Column 'k1' cannot be null +insert into t1 values (NULL, NULL); +Column 'k1' cannot be null +drop table t1; create table t1 (a int, key(a)); create table t2 (b int, foreign key(b) references t1(a), key(b)); drop table if exists t1,t2; diff --git a/mysql-test/r/ctype_latin1_de.result b/mysql-test/r/ctype_latin1_de.result index b79bc67138c..630fef9b679 100644 --- a/mysql-test/r/ctype_latin1_de.result +++ b/mysql-test/r/ctype_latin1_de.result @@ -212,3 +212,55 @@ select * from t1 where match a against ("te*" in boolean mode)+0; a test drop table t1; +create table t1 (word varchar(255) not null, word2 varchar(255) not null, index(word)); +insert into t1 (word) values ('ss'),(0xDF),(0xE4),('ae'); +update t1 set word2=word; +select word, word=0xdf as t from t1 having t > 0; +word t +ß 1 +select word, word=cast(0xdf AS CHAR) as t from t1 having t > 0; +word t +ss 1 +ß 1 +select * from t1 where word=0xDF; +word word2 +ß ß +select * from t1 where word=CAST(0xDF as CHAR); +word word2 +ss ss +ß ß +select * from t1 where word2=0xDF; +word word2 +ß ß +select * from t1 where word2=CAST(0xDF as CHAR); +word word2 +ss ss +ß ß +select * from t1 where word='ae'; +word word2 +ä ä +ae ae +select * from t1 where word= 0xe4 or word=CAST(0xe4 as CHAR); +word word2 +ä ä +ae ae +select * from t1 where word between 0xDF and 0xDF; +word word2 +ß ß +select * from t1 where word between CAST(0xDF AS CHAR) and CAST(0xDF AS CHAR); +word word2 +ss ss +ß ß +select * from t1 where word like 'ae'; +word word2 +ae ae +select * from t1 where word like 'AE'; +word word2 +ae ae +select * from t1 where word like 0xDF; +word word2 +ß ß +select * from t1 where word like CAST(0xDF as CHAR); +word word2 +ß ß +drop table t1; diff --git a/mysql-test/r/ctype_recoding.result b/mysql-test/r/ctype_recoding.result index fb813e394f4..815445150cd 100644 --- a/mysql-test/r/ctype_recoding.result +++ b/mysql-test/r/ctype_recoding.result @@ -41,3 +41,4 @@ Field Type Collation Null Key Default Extra поле char(32) character set koi8r koi8r_general_ci SET CHARACTER SET koi8r; DROP TABLE ÔÁÂÌÉÃÁ; +SET CHARACTER SET default; diff --git a/mysql-test/r/ctype_ujis.result b/mysql-test/r/ctype_ujis.result new file mode 100644 index 00000000000..223a18f19e9 --- /dev/null +++ b/mysql-test/r/ctype_ujis.result @@ -0,0 +1,8 @@ +drop table if exists t1; +create table t1 (c text); +insert into t1 values (0xa4a2),(0xa4a3); +select hex(left(c,1)) from t1 group by c; +hex(left(c,1)) +A4A2 +A4A3 +drop table t1; diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index ae216f9b380..c87fa8fb927 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -46,4 +46,15 @@ NULL d 7 delete from t1 where misc > 5 and bool is null; select * from t1 where misc > 5 and bool is null; bool not_null misc +select count(*) from t1; +count(*) +2 +delete from t1 where 1 > 2; +select count(*) from t1; +count(*) +2 +delete from t1 where 3 > 2; +select count(*) from t1; +count(*) +0 drop table t1; diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index c40e9d9bfa2..5b410396390 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -216,3 +216,13 @@ test.t1 repair status OK select * from t1 where match (a) against ('aaaa'); a drop table t1; +create table t1 ( ref_mag text not null, fulltext (ref_mag)); +insert into t1 values ('test'); +select ref_mag from t1 where match ref_mag against ('+test' in boolean mode); +ref_mag +test +alter table t1 change ref_mag ref_mag char (255) not null; +select ref_mag from t1 where match ref_mag against ('+test' in boolean mode); +ref_mag +test +drop table t1; diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index b7bf3a5cd80..99d7bd2d087 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -47,7 +47,7 @@ sum(all a) count(all a) avg(all a) std(all a) variance(all a) bit_or(all a) bit_ 21 6 3.5000 1.7078 2.9167 7 0 1 6 E select grp, sum(a),count(a),avg(a),std(a),variance(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1 group by grp; grp sum(a) count(a) avg(a) std(a) variance(a) bit_or(a) bit_and(a) min(a) max(a) min(c) max(c) -NULL 0 0 NULL NULL NULL 0 0 NULL NULL +NULL NULL 0 NULL NULL NULL 0 0 NULL NULL 1 1 1 1.0000 0.0000 0.0000 1 1 1 1 a a 2 5 2 2.5000 0.5000 0.2500 3 2 2 3 b c 3 15 3 5.0000 0.8165 0.6667 7 4 4 6 C E @@ -561,4 +561,45 @@ select concat(min(t1.a1),min(t2.a4)) from t1, t2 where t2.a4 <> 'AME'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL PRIMARY 3 NULL 14 Using index 1 SIMPLE t2 index NULL k2 4 NULL 6 Using where; Using index -drop table if exists t1, t2; +drop table t1, t2; +CREATE TABLE t1 (a int, b int); +select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1; +count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +0 NULL NULL NULL NULL NULL 18446744073709551615 0 +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +insert into t1 values (1,null); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +insert into t1 values (1,null); +insert into t1 values (2,null); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 0 0 +2 0 NULL NULL NULL NULL NULL 0 0 +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +insert into t1 values (2,1); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 0 0 +2 1 1 1.0000 0.0000 1 1 0 1 +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 1 1 1.0000 0.0000 1 1 1 1 +insert into t1 values (3,1); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 0 0 +2 1 1 1.0000 0.0000 1 1 0 1 +3 1 1 1.0000 0.0000 1 1 1 1 +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b) +1 0 NULL NULL NULL NULL NULL 18446744073709551615 0 +2 1 1 1.0000 0.0000 1 1 1 1 +3 1 1 1.0000 0.0000 1 1 1 1 +drop table t1; diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index 4eed80c4cc9..8d05adcc1ba 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -10,3 +10,6 @@ inet_aton("255.255.255.255.255") inet_aton("255.255.1.255") inet_aton("0.1.255") select inet_ntoa(1099511627775),inet_ntoa(4294902271),inet_ntoa(511); inet_ntoa(1099511627775) inet_ntoa(4294902271) inet_ntoa(511) NULL 255.255.1.255 0.0.1.255 +select length(format('nan', 2)) > 0; +length(format('nan', 2)) > 0 +1 diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 3b8a8850cc9..9e89f2c0e5a 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -29,6 +29,8 @@ PRIMARY KEY (userID) INSERT INTO t2 VALUES (1,'name','pass','mail','Y','v','n','adr','1','1','1'); INSERT INTO t2 VALUES (2,'name','pass','mail','Y','v','n','adr','1','1','1'); INSERT INTO t2 VALUES (3,'name','pass','mail','Y','v','n','adr','1','1','1'); +INSERT INTO t2 VALUES (4,'name','pass','mail','Y','v','n','adr','1','1','1'); +INSERT INTO t2 VALUES (5,'name','pass','mail','Y','v','n','adr','1','1','1'); SELECT t2.userid, MIN(t1.score) FROM t1, t2 WHERE t1.userID=t2.userID GROUP BY t2.userid; userid MIN(t1.score) 1 1 @@ -49,8 +51,12 @@ userid MIN(t1.score+0.0) 2 2.0 SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid ORDER BY NULL; userid MIN(t1.score+0.0) -1 1.0 2 2.0 +1 1.0 +EXPLAIN SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid ORDER BY NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using where; Using temporary +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 t1.userID 1 Using index drop table t1,t2; CREATE TABLE t1 ( PID int(10) unsigned NOT NULL auto_increment, @@ -302,34 +308,32 @@ score smallint(5) unsigned, key (spid), key (score) ); -INSERT INTO t1 VALUES (1,1,1),(2,2,2),(2,1,1),(3,3,3),(4,3,3),(5,3,3); +INSERT INTO t1 VALUES (1,1,1),(2,2,2),(2,1,1),(3,3,3),(4,3,3),(5,3,3),(6,3,3),(7,3,3); explain select userid,count(*) from t1 group by userid desc; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using temporary; Using filesort +1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using temporary; Using filesort explain select userid,count(*) from t1 group by userid desc order by null; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using temporary +1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using temporary select userid,count(*) from t1 group by userid desc; userid count(*) -3 3 +3 5 2 1 1 2 select userid,count(*) from t1 group by userid desc having (count(*)+1) IN (4,3); userid count(*) -3 3 1 2 select userid,count(*) from t1 group by userid desc having 3 IN (1,COUNT(*)); userid count(*) -3 3 explain select spid,count(*) from t1 where spid between 1 and 2 group by spid desc; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range spID spID 5 NULL 2 Using where; Using index +1 SIMPLE t1 range spID spID 5 NULL 3 Using where; Using index explain select spid,count(*) from t1 where spid between 1 and 2 group by spid; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range spID spID 5 NULL 2 Using where; Using index +1 SIMPLE t1 range spID spID 5 NULL 3 Using where; Using index explain select spid,count(*) from t1 where spid between 1 and 2 group by spid order by null; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range spID spID 5 NULL 2 Using where; Using index +1 SIMPLE t1 range spID spID 5 NULL 3 Using where; Using index select spid,count(*) from t1 where spid between 1 and 2 group by spid; spid count(*) 1 1 @@ -340,12 +344,14 @@ spid count(*) 1 1 explain select sql_big_result spid,sum(userid) from t1 group by spid desc; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort +1 SIMPLE t1 ALL NULL NULL NULL NULL 8 Using filesort explain select sql_big_result spid,sum(userid) from t1 group by spid desc order by null; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 6 +1 SIMPLE t1 ALL NULL NULL NULL NULL 8 select sql_big_result spid,sum(userid) from t1 group by spid desc; spid sum(userid) +7 3 +6 3 5 3 4 3 3 3 @@ -353,13 +359,13 @@ spid sum(userid) 1 1 explain select sql_big_result score,count(*) from t1 group by score desc; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL score 3 NULL 6 Using index +1 SIMPLE t1 index NULL score 3 NULL 8 Using index explain select sql_big_result score,count(*) from t1 group by score desc order by null; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL score 3 NULL 6 Using index +1 SIMPLE t1 index NULL score 3 NULL 8 Using index select sql_big_result score,count(*) from t1 group by score desc; score count(*) -3 3 +3 5 2 1 1 2 drop table t1; @@ -594,15 +600,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL a NULL NULL NULL 4 Using where drop table t1,t2; create table t1 (a int, b int); -insert into t1 values (1, 4); -insert into t1 values (10, 40); -insert into t1 values (1, 4); -insert into t1 values (10, 43); -insert into t1 values (1, 4); -insert into t1 values (10, 41); -insert into t1 values (1, 4); -insert into t1 values (10, 43); -insert into t1 values (1, 4); +insert into t1 values (1, 4),(10, 40),(1, 4),(10, 43),(1, 4),(10, 41),(1, 4),(10, 43),(1, 4); select a, MAX(b), INTERVAL (MAX(b), 1,3,10,30,39,40,50,60,100,1000) from t1 group by a; a MAX(b) INTERVAL (MAX(b), 1,3,10,30,39,40,50,60,100,1000) 1 4 2 diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result index bd1bd523964..fc0b3c652ef 100644 --- a/mysql-test/r/having.result +++ b/mysql-test/r/having.result @@ -67,3 +67,18 @@ Fld1 max(Fld2) 1 20 3 50 drop table t1; +create table t1 (id int not null, qty int not null); +insert into t1 values (1,2),(1,3),(2,4),(2,5); +select id, sum(qty) as sqty from t1 group by id having sqty>2; +id sqty +1 5 +2 9 +select sum(qty) as sqty from t1 group by id having count(id) > 0; +sqty +5 +9 +select sum(qty) as sqty from t1 group by id having count(distinct id) > 0; +sqty +5 +9 +drop table t1; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 51669f563de..98613dad628 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -138,15 +138,6 @@ id parent_id level 1008 102 2 1010 102 2 1015 102 2 -explain select level from t1 where level=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref level level 1 const # Using where; Using index -explain select level,id from t1 where level=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref level level 1 const # Using where; Using index -explain select level,id,parent_id from t1 where level=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref level level 1 const # Using where select level,id from t1 where level=1; level id 1 1002 @@ -208,7 +199,7 @@ create index skr on t1 (a); insert into t1 values (3,""), (4,"testing"); analyze table t1; Table Op Msg_type Msg_text -test.t1 analyze error The storage enginge for the table doesn't support analyze +test.t1 analyze status OK show keys from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 skr 1 a A 3 NULL NULL YES BTREE @@ -595,9 +586,6 @@ id parent_id level 1009 102 2 1025 102 2 1016 102 2 -explain select level from t1 where level=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref level level 1 const 6 Using where; Using index select level,id from t1 where level=1; level id 1 1004 @@ -1141,7 +1129,7 @@ a b drop table t1; CREATE TABLE t1 (a int not null primary key, b int not null, key (b)) type=innodb; CREATE TABLE t2 (a int not null primary key, b int not null, key (b)) type=innodb; -INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); +INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12); INSERT INTO t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); update t1,t2 set t1.a=t1.a+100; select * from t1; @@ -1155,6 +1143,9 @@ a b 107 7 108 8 109 9 +110 10 +111 11 +112 12 update t1,t2 set t1.a=t1.a+100 where t1.a=101; select * from t1; a b @@ -1167,6 +1158,9 @@ a b 107 7 108 8 109 9 +110 10 +111 11 +112 12 update t1,t2 set t1.b=t1.b+10 where t1.b=2; select * from t1; a b @@ -1178,8 +1172,11 @@ a b 107 7 108 8 109 9 +110 10 +111 11 102 12 -update t1,t2 set t1.b=t1.b+2,t2.b=t1.b where t1.b between 3 and 5; +112 12 +update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t1.a=t2.a+100; select * from t1; a b 201 1 @@ -1190,19 +1187,107 @@ a b 107 7 108 8 109 9 +110 10 +111 11 102 12 +112 12 select * from t2; a b -1 5 -2 5 -3 5 -4 5 -5 5 -6 5 -7 5 -8 5 -9 5 +1 1 +2 2 +6 6 +7 7 +8 8 +9 9 +3 13 +4 14 +5 15 drop table t1,t2; +CREATE TABLE t2 ( NEXT_T BIGINT NOT NULL PRIMARY KEY) TYPE=MyISAM; +CREATE TABLE t1 ( B_ID INTEGER NOT NULL PRIMARY KEY) TYPE=InnoDB; +SET AUTOCOMMIT=0; +INSERT INTO t1 ( B_ID ) VALUES ( 1 ); +INSERT INTO t2 ( NEXT_T ) VALUES ( 1 ); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +SELECT * FROM t1; +B_ID +drop table t1,t2; +create table t1 ( pk int primary key, parent int not null, child int not null, index (parent) ) type = innodb; +insert into t1 values (1,0,4), (2,1,3), (3,2,1), (4,1,2); +select distinct parent,child from t1 order by parent; +parent child +0 4 +1 2 +1 3 +2 1 +drop table t1; +create table t1 (a int not null auto_increment primary key, b int, c int, key(c)) type=innodb; +create table t2 (a int not null auto_increment primary key, b int); +insert into t1 (b) values (null),(null),(null),(null),(null),(null),(null); +insert into t2 (a) select b from t1; +insert into t1 (b) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +select count(*) from t1; +count(*) +29267 +explain select * from t1 where c between 1 and 10000; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c c 5 NULL 1 Using where +update t1 set c=a; +explain select * from t1 where c between 1 and 10000; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL c NULL NULL NULL 29537 Using where +drop table t1,t2; +create table t1 (id int primary key auto_increment, fk int, index index_fk (fk)) type=innodb; +insert into t1 (id) values (null),(null),(null),(null),(null); +update t1 set fk=69 where fk is null order by id limit 1; +SELECT * from t1; +id fk +2 NULL +3 NULL +4 NULL +5 NULL +1 69 +drop table t1; +create table t1 (a int not null, b int not null, key (a)); +insert into t1 values (1,1),(1,2),(1,3),(3,1),(3,2),(3,3),(3,1),(3,2),(3,3),(2,1),(2,2),(2,3); +SET @tmp=0; +update t1 set b=(@tmp:=@tmp+1) order by a; +update t1 set b=99 where a=1 order by b asc limit 1; +update t1 set b=100 where a=1 order by b desc limit 2; +update t1 set a=a+10+b where a=1 order by b; +select * from t1 order by a,b; +a b +2 4 +2 5 +2 6 +3 7 +3 8 +3 9 +3 10 +3 11 +3 12 +13 2 +111 100 +111 100 +drop table t1; CREATE TABLE t1 (col1 int(1))TYPE=InnoDB; CREATE TABLE t2 (col1 int(1),stamp TIMESTAMP(+0),INDEX stamp_idx (stamp))TYPE=InnoDB; diff --git a/mysql-test/r/innodb_handler.result b/mysql-test/r/innodb_handler.result index 4ce104506f1..38c39e2936f 100644 --- a/mysql-test/r/innodb_handler.result +++ b/mysql-test/r/innodb_handler.result @@ -139,4 +139,13 @@ a b alter table t1 type=innodb; handler t2 read first; Unknown table 't2' in HANDLER -drop table if exists t1; +drop table t1; +CREATE TABLE t1 ( no1 smallint(5) NOT NULL default '0', no2 int(10) NOT NULL default '0', PRIMARY KEY (no1,no2)) TYPE=InnoDB; +INSERT INTO t1 VALUES (1,274),(1,275),(2,6),(2,8),(4,1),(4,2); +HANDLER t1 OPEN; +HANDLER t1 READ `primary` = (1, 1000); +no1 no2 +HANDLER t1 READ `primary` PREV; +no1 no2 +1 275 +DROP TABLE t1; diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 09b819888eb..4bc045aa2f7 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -274,3 +274,101 @@ SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (site rate_code base_rate cust 20 drop table t1,t2; +CREATE TABLE t1 (ID INTEGER NOT NULL PRIMARY KEY, Value1 VARCHAR(255)); +CREATE TABLE t2 (ID INTEGER NOT NULL PRIMARY KEY, Value2 VARCHAR(255)); +INSERT INTO t1 VALUES (1, 'A'); +INSERT INTO t2 VALUES (1, 'B'); +SELECT * FROM t1 NATURAL JOIN t2 WHERE 1 AND (Value1 = 'A' AND Value2 <> 'B'); +ID Value1 ID Value2 +SELECT * FROM t1 NATURAL JOIN t2 WHERE 1 AND Value1 = 'A' AND Value2 <> 'B'; +ID Value1 ID Value2 +SELECT * FROM t1 NATURAL JOIN t2 WHERE (Value1 = 'A' AND Value2 <> 'B') AND 1; +ID Value1 ID Value2 +drop table t1,t2; +create table t1 (i int); +create table t2 (i int); +create table t3 (i int); +insert into t1 values(1),(2); +insert into t2 values(2),(3); +insert into t3 values (2),(4); +select * from t1 natural left join t2; +i i +1 NULL +2 2 +select * from t1 left join t2 on (t1.i=t2.i); +i i +1 NULL +2 2 +select * from t1 natural left join t2 natural left join t3; +i i i +1 NULL NULL +2 2 2 +select * from t1 left join t2 on (t1.i=t2.i) left join t3 on (t2.i=t3.i); +i i i +1 NULL NULL +2 2 2 +select * from t3 natural right join t2; +i i +2 2 +NULL 3 +select * from t3 right join t2 on (t3.i=t2.i); +i i +2 2 +NULL 3 +select * from t3 natural right join t2 natural right join t1; +i i i +NULL NULL 1 +2 2 2 +select * from t3 right join t2 on (t3.i=t2.i) right join t1 on (t2.i=t1.i); +i i i +NULL NULL 1 +2 2 2 +select * from t1,t2 natural left join t3 order by t1.i,t2.i,t3.i; +i i i +1 2 2 +1 3 NULL +2 2 2 +2 3 NULL +select * from t1,t2 left join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; +i i i +1 2 2 +1 3 NULL +2 2 2 +2 3 NULL +select t1.i,t2.i,t3.i from t2 natural left join t3,t1 order by t1.i,t2.i,t3.i; +i i i +1 2 2 +1 3 NULL +2 2 2 +2 3 NULL +select t1.i,t2.i,t3.i from t2 left join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; +i i i +1 2 2 +1 3 NULL +2 2 2 +2 3 NULL +select * from t1,t2 natural right join t3 order by t1.i,t2.i,t3.i; +i i i +1 NULL 4 +1 2 2 +2 NULL 4 +2 2 2 +select * from t1,t2 right join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; +i i i +1 NULL 4 +1 2 2 +2 NULL 4 +2 2 2 +select t1.i,t2.i,t3.i from t2 natural right join t3,t1 order by t1.i,t2.i,t3.i; +i i i +1 NULL 4 +1 2 2 +2 NULL 4 +2 2 2 +select t1.i,t2.i,t3.i from t2 right join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; +i i i +1 NULL 4 +1 2 2 +2 NULL 4 +2 2 2 +drop table t1,t2,t3; diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 9ac44bec377..123de82fe09 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -350,12 +350,7 @@ select t1.name, t2.name, t2.id,t3.id from t1 right join t2 on (t1.id = t2.owner) name name id id Antonio Paz El Gato 1 1 Antonio Paz Perrito 2 1 -NULL Happy 3 1 -NULL El Gato 1 2 -NULL Perrito 2 2 -NULL Happy 3 2 -NULL El Gato 1 3 -NULL Perrito 2 3 +NULL NULL NULL 2 Thimble Smith Happy 3 3 select t1.name, t2.name, t2.id, t2.owner, t3.id from t1 left join t2 on (t1.id = t2.owner) right join t1 as t3 on t3.id=t2.owner; name name id owner id @@ -372,10 +367,10 @@ Thimble Smith Happy 3 3 3 drop table t1,t2; create table t1 (id int not null, str char(10), index(str)); insert into t1 values (1, null), (2, null), (3, "foo"), (4, "bar"); -select * from t1 where str is not null; +select * from t1 where str is not null order by id; id str -4 bar 3 foo +4 bar select * from t1 where str is null; id str 1 NULL @@ -651,3 +646,14 @@ fooID barID fooID 20 2 NULL 30 3 30 drop table t1,t2; +create table t1 (i int); +create table t2 (i int); +create table t3 (i int); +insert into t1 values(1),(2); +insert into t2 values(2),(3); +insert into t3 values(2),(4); +select * from t1 natural left join t2 natural left join t3; +i i i +1 NULL NULL +2 2 2 +drop table t1,t2,t3; diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index 168bc276c30..5060fbff5e8 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -47,7 +47,6 @@ price area type transityes shopsyes schoolsyes petsyes drop table t1; CREATE TABLE t1 (program enum('signup','unique','sliding') not null, type enum('basic','sliding','signup'), sites set('mt'), PRIMARY KEY (program)); ALTER TABLE t1 modify program enum('signup','unique','sliding'); -All parts of a PRIMARY KEY must be NOT NULL; If you need NULL in a key, use UNIQUE instead drop table t1; CREATE TABLE t1 ( name varchar(50) DEFAULT '' NOT NULL, diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result new file mode 100644 index 00000000000..d121a4e6c40 --- /dev/null +++ b/mysql-test/r/loaddata.result @@ -0,0 +1,11 @@ +drop table if exists t1; +create table t1 (a date, b date, c date not null, d date); +load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ','; +load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' IGNORE 2 LINES; +SELECT * from t1; +a b c d +0000-00-00 NULL 0000-00-00 0000-00-00 +0000-00-00 0000-00-00 0000-00-00 0000-00-00 +2003-03-03 2003-03-03 2003-03-03 NULL +2003-03-03 2003-03-03 2003-03-03 NULL +drop table t1; diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index da1c429df63..2aa7db1599e 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -300,7 +300,7 @@ a b 107 7 108 8 109 9 -update t1,t2 set t1.b=t1.b+2,t2.b=t1.b where t1.b between 3 and 5; +update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t2.a=t1.a-100; select * from t1; a b 201 1 @@ -314,13 +314,21 @@ a b 109 9 select * from t2; a b -1 3 -2 3 -3 3 -4 3 -5 3 -6 3 -7 3 -8 3 -9 3 +1 1 +2 2 +3 13 +4 14 +5 15 +6 6 +7 7 +8 8 +9 9 drop table t1,t2; +CREATE TABLE t3 ( KEY1 varchar(50) NOT NULL default '', PARAM_CORR_DISTANCE_RUSH double default NULL, PARAM_CORR_DISTANCE_GEM double default NULL, PARAM_AVG_TARE double default NULL, PARAM_AVG_NB_DAYS double default NULL, PARAM_DEFAULT_PROP_GEM_SRVC varchar(50) default NULL, PARAM_DEFAULT_PROP_GEM_NO_ETIK varchar(50) default NULL, PARAM_SCENARIO_COSTS varchar(50) default NULL, PARAM_DEFAULT_WAGON_COST double default NULL, tmp int(11) default NULL, PRIMARY KEY (KEY1)) TYPE=MyISAM; +INSERT INTO t3 VALUES ('A',1,1,22,3.2,'R','R','BASE2',0.24,NULL); +create table t1 (A varchar(1)); +insert into t1 values ("A") ,("B"),("C"),("D"); +create table t2(Z varchar(15)); +insert into t2(Z) select concat(a.a,b.a,c.a,d.a) from t1 as a, t1 as b, t1 as c, t1 as d; +update t2,t3 set Z =param_scenario_costs; +drop table t1,t2,t3; diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result index d5677f877ee..289290ba08c 100644 --- a/mysql-test/r/null_key.result +++ b/mysql-test/r/null_key.result @@ -84,7 +84,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range a,b a 5 NULL 5 Using where explain select * from t1 where (a is null or a = 7) and b=7 and c=0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a,b a 5 NULL 4 Using where +1 SIMPLE t1 ALL a,b NULL NULL NULL 12 Using where explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref a,b a 5 const 3 Using where diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 73caceedfdb..08176aeb2f8 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -521,6 +521,31 @@ SELECT titre,t1.numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,des titre numeropost auteur icone nbrep 0 date vue ouvert lastauteur dest test 1 joce 0 0 0 0000-00-00 00:00:00 0 1 bug drop table t1,t2; +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1, 2); +INSERT INTO t1 VALUES (3, 4); +INSERT INTO t1 VALUES (5, NULL); +SELECT * FROM t1 ORDER BY b; +a b +5 NULL +1 2 +3 4 +SELECT * FROM t1 ORDER BY b DESC; +a b +3 4 +1 2 +5 NULL +SELECT * FROM t1 ORDER BY (a + b); +a b +5 NULL +1 2 +3 4 +SELECT * FROM t1 ORDER BY (a + b) DESC; +a b +3 4 +1 2 +5 NULL +DROP TABLE t1; CREATE TABLE t1 ( FieldKey varchar(36) NOT NULL default '', LongVal bigint(20) default NULL, @@ -529,10 +554,10 @@ KEY FieldKey (FieldKey), KEY LongField (FieldKey,LongVal), KEY StringField (FieldKey,StringVal(32)) ); -INSERT INTO t1 VALUES ('0',3,'0'),('0',2,'1'),('0',1,'2'),('1',2,'1'),('1',1,'3'), ('1',0,'2'),('2',3,'0'),('2',2,'1'),('2',1,'2'),('3',2,'1'),('3',1,'2'),('3','3','3'); +INSERT INTO t1 VALUES ('0',3,'0'),('0',2,'1'),('0',1,'2'),('1',2,'1'),('1',1,'3'), ('1',0,'2'),('2',3,'0'),('2',2,'1'),('2',1,'2'),('2',3,'0'),('2',2,'1'),('2',1,'2'),('3',2,'1'),('3',1,'2'),('3','3','3'); EXPLAIN SELECT * FROM t1 WHERE FieldKey = '1' ORDER BY LongVal; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref FieldKey,LongField,StringField LongField 36 const 2 Using where +1 SIMPLE t1 ref FieldKey,LongField,StringField StringField 36 const 3 Using where; Using filesort SELECT * FROM t1 WHERE FieldKey = '1' ORDER BY LongVal; FieldKey LongVal StringVal 1 0 2 diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 46fa12dd9bc..1d46d1dcf25 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -238,13 +238,18 @@ a show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 -select sql_cache * from t1; +select sql_cache * from t1 union select * from t1; a 1 2 3 set query_cache_type=2; -select sql_cache * from t1; +select sql_cache * from t1 union select * from t1; +a +1 +2 +3 +select * from t1 union select sql_cache * from t1; a 1 2 @@ -254,7 +259,7 @@ Variable_name Value Qcache_hits 4 show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 1 +Qcache_queries_in_cache 2 set query_cache_type=on; reset query cache; show status like "Qcache_queries_in_cache"; @@ -377,14 +382,14 @@ a set CHARACTER SET cp1251_koi8; select * from t1; a -? +á set CHARACTER SET DEFAULT; show status like "Qcache_queries_in_cache"; Variable_name Value -Qcache_queries_in_cache 2 +Qcache_queries_in_cache 1 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 4 +Qcache_hits 5 drop table t1; create database if not exists mysqltest; create table mysqltest.t1 (i int not null); @@ -410,7 +415,7 @@ Variable_name Value Qcache_queries_in_cache 2 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 6 +Qcache_hits 7 drop database mysqltest; drop table t1; create table t1 (i int not null); @@ -424,7 +429,7 @@ FOUND_ROWS() 4 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 6 +Qcache_hits 7 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 1 @@ -436,7 +441,7 @@ FOUND_ROWS() 1 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 6 +Qcache_hits 7 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 2 @@ -449,7 +454,7 @@ FOUND_ROWS() 4 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 7 +Qcache_hits 8 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 2 @@ -461,7 +466,7 @@ FOUND_ROWS() 1 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 8 +Qcache_hits 9 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 2 @@ -530,7 +535,7 @@ a 3 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 11 +Qcache_hits 12 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 2 @@ -547,7 +552,7 @@ a 3 show status like "Qcache_hits"; Variable_name Value -Qcache_hits 12 +Qcache_hits 13 show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 2 @@ -636,3 +641,21 @@ show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 drop table t1; +create table t1 (a int); +insert into t1 values (1),(2); +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +select * from t1; +a +1 +2 +SET OPTION SQL_SELECT_LIMIT=1; +select * from t1; +a +1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 2 +SET OPTION SQL_SELECT_LIMIT=DEFAULT; +drop table t1; diff --git a/mysql-test/r/raid.result b/mysql-test/r/raid.result index 41af50851e9..fd47a9451f6 100644 --- a/mysql-test/r/raid.result +++ b/mysql-test/r/raid.result @@ -1,3 +1,6 @@ +create database test_raid; +create table test_raid.r1 (i int) raid_type=1; +drop database test_raid; DROP TABLE IF EXISTS t1,t2; CREATE TABLE t1 ( id int unsigned not null auto_increment primary key, diff --git a/mysql-test/r/repair.result b/mysql-test/r/repair.result index 8b50f9a92e8..eb46622dcc1 100644 --- a/mysql-test/r/repair.result +++ b/mysql-test/r/repair.result @@ -4,4 +4,12 @@ repair table t1 use_frm; Table Op Msg_type Msg_text test.t1 repair warning Number of rows changed from 0 to 1 test.t1 repair status OK -drop table if exists t1; +alter table t1 TYPE=HEAP; +repair table t1 use_frm; +Table Op Msg_type Msg_text +test.t1 repair error The storage enginge for the table doesn't support repair +drop table t1; +repair table t1 use_frm; +Table Op Msg_type Msg_text +test.t1 repair error Table 'test.t1' doesn't exist +create table t1 type=myisam SELECT 1,"table 1"; diff --git a/mysql-test/r/repair_part2.result b/mysql-test/r/repair_part2.result new file mode 100644 index 00000000000..77aa98c3da9 --- /dev/null +++ b/mysql-test/r/repair_part2.result @@ -0,0 +1,8 @@ +repair table t1; +Table Op Msg_type Msg_text +test.t1 repair error Can't open file: 't1.MYI'. (errno: 130) +repair table t1 use_frm; +Table Op Msg_type Msg_text +test.t1 repair warning Number of rows changed from 0 to 1 +test.t1 repair status OK +drop table t1; diff --git a/mysql-test/r/rpl_flush_tables.result b/mysql-test/r/rpl_flush_tables.result index 40a35f4e0ca..6353a6101d6 100644 --- a/mysql-test/r/rpl_flush_tables.result +++ b/mysql-test/r/rpl_flush_tables.result @@ -14,7 +14,7 @@ rename table t1 to t5, t2 to t1; flush no_write_to_binlog tables; show binlog events; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3 +master-bin.000001 4 Start 1 4 Server ver: SERVER_VERSION, Binlog ver: 3 master-bin.000001 79 Query 1 79 use `test`; create table t1 (a int) master-bin.000001 137 Query 1 137 use `test`; insert into t1 values (10) master-bin.000001 198 Query 1 198 use `test`; create table t2 (a int) @@ -27,7 +27,7 @@ a flush tables; show binlog events; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.000001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3 +master-bin.000001 4 Start 1 4 Server ver: SERVER_VERSION, Binlog ver: 3 master-bin.000001 79 Query 1 79 use `test`; create table t1 (a int) master-bin.000001 137 Query 1 137 use `test`; insert into t1 values (10) master-bin.000001 198 Query 1 198 use `test`; create table t2 (a int) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 0d1743d72b7..825a94c0ebf 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3411,13 +3411,7 @@ a a a select * from t1 natural left join (t1 as t2 left join t1 as t3 using (a)); a a a 1 1 1 -2 1 NULL -3 1 NULL -1 2 NULL 2 2 2 -3 2 NULL -1 3 NULL -2 3 NULL 3 3 3 select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1; a a a @@ -3473,13 +3467,7 @@ a a a select * from t1 natural join (t1 as t2 left join t1 as t3 using (a)); a a a 1 1 1 -2 1 NULL -3 1 NULL -1 2 NULL 2 2 2 -3 2 NULL -1 3 NULL -2 3 NULL 3 3 3 select * from (t1 as t2 left join t1 as t3 using (a)) natural join t1; a a a diff --git a/mysql-test/r/select_safe.result b/mysql-test/r/select_safe.result index e225a0e3995..3303f19d9c7 100644 --- a/mysql-test/r/select_safe.result +++ b/mysql-test/r/select_safe.result @@ -1,6 +1,6 @@ drop table if exists t1; SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=4, SQL_MAX_JOIN_SIZE=9; -create table t1 (a int primary key, b char(20)); +create table t1 (a int auto_increment primary key, b char(20)); insert into t1 values(1,"test"); SELECT SQL_BUFFER_RESULT * from t1; a b @@ -30,10 +30,34 @@ You are using safe update mode and you tried to update a table without a WHERE t delete from t1 where a+0=1; You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column select 1 from t1,t1 as t2,t1 as t3,t1 as t4,t1 as t5; -The SELECT would examine too many records and probably take a very long time. Check your WHERE and use SET OPTION SQL_BIG_SELECTS=1 if the SELECT is ok +The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok update t1 set b="a" limit 1; update t1 set b="a" where b="b" limit 2; delete from t1 where b="test" limit 1; delete from t1 where a+0=1 limit 2; +SET MAX_JOIN_SIZE=2; +SELECT @@MAX_JOIN_SIZE, @@SQL_BIG_SELECTS; +@@max_join_size @@sql_big_selects +2 0 +insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); +SELECT * from t1; +The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok +SET SQL_BIG_SELECTS=1; +SELECT * from t1; +a b +3 a +2 test2 +4 a +5 a +SET MAX_JOIN_SIZE=2; +SELECT * from t1; +The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok +SET MAX_JOIN_SIZE=DEFAULT; +SELECT * from t1; +a b +3 a +2 test2 +4 a +5 a drop table t1; SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT; diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index 0e973ae3501..c0e48fb42d8 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -435,3 +435,9 @@ select * from t1; a 99999999999 drop table t1; +CREATE TABLE t1 (a_dec DECIMAL(-1,0)); +Too big column length for column 'a_dec' (max = 255). Use BLOB instead +CREATE TABLE t1 (a_dec DECIMAL(-2,1)); +Too big column length for column 'a_dec' (max = 255). Use BLOB instead +CREATE TABLE t1 (a_dec DECIMAL(-1,1)); +Too big column length for column 'a_dec' (max = 255). Use BLOB instead diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 7b29a8fbcde..272ffdd330e 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -1,4 +1,4 @@ -drop table if exists t1,t2,t3; +drop table if exists t1,t2,t3,t4,t5,t6; CREATE TABLE t1 (a int not null, b char (10) not null); insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); CREATE TABLE t2 (a int not null, b char (10) not null); @@ -90,9 +90,6 @@ explain (select a,b from t1 limit 2) union all (select a,b from t2 order by a l id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 2 UNION t2 ALL NULL NULL NULL NULL 4 Using filesort -select found_rows(); -found_rows() -0 explain select a,b from t1 union all select a,b from t2; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 @@ -132,6 +129,23 @@ create table t3 select a,b from t1 union all select a,b from t2; insert into t3 select a,b from t1 union all select a,b from t2; replace into t3 select a,b as c from t1 union all select a,b from t2; drop table t1,t2,t3; +select * union select 1; +No tables used +select 1 as a,(select a union select a); +a (select a union select a) +1 1 +(select 1) union (select 2) order by 0; +Unknown column '0' in 'order clause' +SELECT @a:=1 UNION SELECT @a:=@a+1; +@a:=1 +1 +2 +(SELECT 1) UNION (SELECT 2) ORDER BY (SELECT a); +Unknown column 'a' in 'field list' +(SELECT 1,3) UNION (SELECT 2,1) ORDER BY (SELECT 2); +1 3 +1 3 +2 1 CREATE TABLE t1 ( `pseudo` char(35) NOT NULL default '', `pseudo1` char(35) NOT NULL default '', @@ -198,12 +212,63 @@ a 11 set SQL_SELECT_LIMIT=DEFAULT; drop table t1,t2; -select * union select 1; -No tables used -select 1 as a,(select a union select a); -a (select a union select a) -1 1 -drop table if exists t1,t2; +CREATE TABLE t1 ( +cid smallint(5) unsigned NOT NULL default '0', +cv varchar(250) NOT NULL default '', +PRIMARY KEY (cid), +UNIQUE KEY cv (cv) +) ; +INSERT INTO t1 VALUES (8,'dummy'); +CREATE TABLE t2 ( +cid bigint(20) unsigned NOT NULL auto_increment, +cap varchar(255) NOT NULL default '', +PRIMARY KEY (cid), +KEY cap (cap) +) ; +CREATE TABLE t3 ( +gid bigint(20) unsigned NOT NULL auto_increment, +gn varchar(255) NOT NULL default '', +must tinyint(4) default NULL, +PRIMARY KEY (gid), +KEY gn (gn) +) ; +INSERT INTO t3 VALUES (1,'V1',NULL); +CREATE TABLE t4 ( +uid bigint(20) unsigned NOT NULL default '0', +gid bigint(20) unsigned default NULL, +rid bigint(20) unsigned default NULL, +cid bigint(20) unsigned default NULL, +UNIQUE KEY m (uid,gid,rid,cid), +KEY uid (uid), +KEY rid (rid), +KEY cid (cid), +KEY container (gid,rid,cid) +) ; +INSERT INTO t4 VALUES (1,1,NULL,NULL); +CREATE TABLE t5 ( +rid bigint(20) unsigned NOT NULL auto_increment, +rl varchar(255) NOT NULL default '', +PRIMARY KEY (rid), +KEY rl (rl) +) ; +CREATE TABLE t6 ( +uid bigint(20) unsigned NOT NULL auto_increment, +un varchar(250) NOT NULL default '', +uc smallint(5) unsigned NOT NULL default '0', +PRIMARY KEY (uid), +UNIQUE KEY nc (un,uc), +KEY un (un) +) ; +INSERT INTO t6 VALUES (1,'test',8); +SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test"; +uid rl g1 cid gg +1 NULL V1 NULL 1 +SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t3.must IS NOT NULL AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test"; +uid rl g1 cid gg +(SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t3.must IS NOT NULL AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test") UNION (SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test"); +uid rl g1 cid gg +1 NULL V1 NULL 1 +drop table t1,t2,t3,t4,t5,t6; CREATE TABLE t1 ( id int(3) unsigned default '0') TYPE=MyISAM; INSERT INTO t1 (id) VALUES("1"); CREATE TABLE t2 ( id int(3) unsigned default '0', id_master int(5) default '0', text1 varchar(5) default NULL, text2 varchar(5) default NULL) TYPE=MyISAM; @@ -230,10 +295,6 @@ id_master id text1 text2 1 3 NULL bar3 1 4 foo4 bar4 drop table if exists t1,t2; -(SELECT 1,3) UNION (SELECT 2,1) ORDER BY (SELECT 2); -1 3 -1 3 -2 1 create table t1 (a int not null primary key auto_increment, b int, key(b)); create table t2 (a int not null primary key auto_increment, b int); insert into t1 (b) values (1),(2),(2),(3); @@ -267,11 +328,3 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 const PRIMARY PRIMARY 4 const 1 2 UNION t1 ref b b 5 const 1 Using where drop table t1,t2; -(select 1) union (select 2) order by 0; -Unknown column '0' in 'order clause' -SELECT @a:=1 UNION SELECT @a:=@a+1; -@a:=1 -1 -2 -(SELECT 1) UNION (SELECT 2) ORDER BY (SELECT a); -Unknown column 'a' in 'field list' diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index 9978e3cb29c..1d483da2c77 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -102,16 +102,70 @@ select status from t1; status 1 drop table t1; -create table t1 (a int not null, b int not null); -insert into t1 values (1,1),(1,2),(1,3); -update t1 set b=4 where a=1 order by b asc limit 1; -update t1 set b=4 where a=1 order by b desc limit 1; -create table t2 (a int not null, b int not null); -insert into t2 values (1,1),(1,2),(1,3); -select * from t1; +create table t1 (a int not null, b int not null, key (a)); +insert into t1 values (1,1),(1,2),(1,3),(3,1),(3,2),(3,3),(3,1),(3,2),(3,3),(2,1),(2,2),(2,3); +SET @tmp=0; +update t1 set b=(@tmp:=@tmp+1) order by a; +update t1 set b=99 where a=1 order by b asc limit 1; +select * from t1 order by a,b; a b -1 4 1 2 -1 4 +1 3 +1 99 +2 4 +2 5 +2 6 +3 7 +3 8 +3 9 +3 10 +3 11 +3 12 +update t1 set b=100 where a=1 order by b desc limit 2; +update t1 set a=a+10+b where a=1 order by b; +select * from t1 order by a,b; +a b +2 4 +2 5 +2 6 +3 7 +3 8 +3 9 +3 10 +3 11 +3 12 +13 2 +111 100 +111 100 +create table t2 (a int not null, b int not null); +insert into t2 values (1,1),(1,2),(1,3); update t1 set b=(select distinct 1 from (select * from t2) a); drop table t1,t2; +CREATE TABLE t1 ( +`id_param` smallint(3) unsigned NOT NULL default '0', +`nom_option` char(40) NOT NULL default '', +`valid` tinyint(1) NOT NULL default '0', +KEY `id_param` (`id_param`,`nom_option`) +) TYPE=MyISAM; +INSERT INTO t1 (id_param,nom_option,valid) VALUES (185,'600x1200',1); +UPDATE t1 SET nom_option='test' WHERE id_param=185 AND nom_option='600x1200' AND valid=1 LIMIT 1; +select * from t1; +id_param nom_option valid +185 test 1 +drop table t1; +create table t1 (F1 VARCHAR(30), F2 VARCHAR(30), F3 VARCHAR(30), cnt int, groupid int, KEY groupid_index (groupid)); +insert into t1 (F1,F2,F3,cnt,groupid) values ('0','0','0',1,6), +('0','1','2',1,5), ('0','2','0',1,3), ('1','0','1',1,2), +('1','2','1',1,1), ('1','2','2',1,1), ('2','0','1',2,4), +('2','2','0',1,7); +delete from t1 using t1 m1,t1 m2 where m1.groupid=m2.groupid and (m1.cnt < m2.cnt or m1.cnt=m2.cnt and m1.F3>m2.F3); +select * from t1; +F1 F2 F3 cnt groupid +0 0 0 1 6 +0 1 2 1 5 +0 2 0 1 3 +1 0 1 1 2 +1 2 1 1 1 +2 0 1 2 4 +2 2 0 1 7 +drop table t1; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index f1afcedac83..b5e05cf6953 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -108,17 +108,14 @@ show global variables like 'table_type'; Variable_name Value table_type INNODB set GLOBAL query_cache_size=100000; -set myisam_max_sort_file_size=10000, GLOBAL myisam_max_sort_file_size=20000; -show variables like 'myisam_max_sort_file_size'; -Variable_name Value -myisam_max_sort_file_size 10000 +set GLOBAL myisam_max_sort_file_size=2000000; show global variables like 'myisam_max_sort_file_size'; Variable_name Value -myisam_max_sort_file_size 20000 -set myisam_max_sort_file_size=default; +myisam_max_sort_file_size 1048576 +set GLOBAL myisam_max_sort_file_size=default; show variables like 'myisam_max_sort_file_size'; Variable_name Value -myisam_max_sort_file_size 20000 +myisam_max_sort_file_size FILE_SIZE set global net_retry_count=10, session net_retry_count=10; set global net_buffer_length=1024, net_write_timeout=200, net_read_timeout=300; set session net_buffer_length=2048, net_write_timeout=500, net_read_timeout=600; @@ -199,6 +196,10 @@ set @@global.sql_auto_is_null=1; Variable 'sql_auto_is_null' is a LOCAL variable and can't be used with SET GLOBAL select @@global.sql_auto_is_null; Variable 'sql_auto_is_null' is a LOCAL variable and can't be used with SET GLOBAL +set myisam_max_sort_file_size=100; +Variable 'myisam_max_sort_file_size' is a GLOBAL variable and should be set with SET GLOBAL +set myisam_max_extra_sort_file_size=100; +Variable 'myisam_max_extra_sort_file_size' is a GLOBAL variable and should be set with SET GLOBAL set autocommit=1; set big_tables=1; select @@autocommit, @@big_tables; @@ -252,11 +253,11 @@ select @@max_user_connections; @@max_user_connections 100 set global max_write_lock_count=100; -set myisam_max_extra_sort_file_size=100; +set global myisam_max_extra_sort_file_size=100; select @@myisam_max_extra_sort_file_size; @@myisam_max_extra_sort_file_size 100 -set myisam_max_sort_file_size=100; +set global myisam_max_sort_file_size=100; set myisam_sort_buffer_size=100; set net_buffer_length=100; set net_read_timeout=100; @@ -323,3 +324,8 @@ test.t1 check status OK test.t2 check status OK select max(a) +1, max(a) +2 into @xx,@yy from t1; drop table t1,t2; +select @@xxxxxxxxxx; +Unknown system variable 'xxxxxxxxxx' +select 1; +1 +1 diff --git a/mysql-test/std_data/loaddata1.dat b/mysql-test/std_data/loaddata1.dat new file mode 100644 index 00000000000..c9e8549b211 --- /dev/null +++ b/mysql-test/std_data/loaddata1.dat @@ -0,0 +1,3 @@ +,\N,NULL,, +00,0,000000,, +2003-03-03, 20030303,030303,\N diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 64b657f1146..fc22bc85aee 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -88,6 +88,7 @@ create table t1 (n1 int not null, n2 int, n3 int, n4 float, key (n3, n4, n1, n2), key (n4, n1, n2, n3) ); alter table t1 disable keys; +show keys from t1; #let $1=10000; let $1=10; while ($1) @@ -96,6 +97,7 @@ while ($1) dec $1; } alter table t1 enable keys; +show keys from t1; drop table t1; # @@ -117,3 +119,19 @@ alter table t1 rename t2; alter table t2 rename t1, add c char(10) comment "no comment"; show columns from t1; drop table t1; + +# implicit analyze + +create table t1 (a int, b int); +let $1=100; +while ($1) +{ + eval insert into t1 values(1,$1), (2,$1), (3, $1); + dec $1; +} +alter table t1 add unique (a,b), add key (b); +show keys from t1; +analyze table t1; +show keys from t1; +drop table t1; + diff --git a/mysql-test/t/ansi-master.opt b/mysql-test/t/ansi-master.opt new file mode 100644 index 00000000000..6bf7a4f30e2 --- /dev/null +++ b/mysql-test/t/ansi-master.opt @@ -0,0 +1 @@ +--ansi diff --git a/mysql-test/t/ansi.test b/mysql-test/t/ansi.test new file mode 100644 index 00000000000..da82b7a9e31 --- /dev/null +++ b/mysql-test/t/ansi.test @@ -0,0 +1,19 @@ +# +# Test of ansi mode +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# Test some functions that works different in ansi mode + +SELECT 'A' || 'B'; + +# Test GROUP BY behaviour + +CREATE TABLE t1 (id INT, id2 int); +SELECT id,NULL,1,1.1,'a' FROM t1 GROUP BY id; +--error 1055 +SELECT id FROM t1 GROUP BY id2; +drop table t1; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index cda9307804b..9bc37a0864d 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -27,11 +27,9 @@ drop table if exists t1,t2; !$1167 create table t1 (b char(0) not null, index(b)); create table t1 (a int not null auto_increment,primary key (a)) type=heap; !$1163 create table t1 (a int not null,b text) type=heap; -!$1171 create table t1 (a int ,primary key(a)) type=heap; drop table if exists t1; !$1075 create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=heap; -!$1171 create table t1 (ordid int(8), primary key (ordid)); -- error 1044,1 create table not_existing_database.test (a int); @@ -124,6 +122,41 @@ drop table t1; create table t1 select if('2002'='2002','Y','N'); select * from t1; drop table if exists t1; + +# +# Test default table type +# +SET SESSION table_type="heap"; +SELECT @@table_type; +CREATE TABLE t1 (a int not null); +show create table t1; +drop table t1; +# Test what happens when using a non existing table type +SET SESSION table_type="gemini"; +SELECT @@table_type; +CREATE TABLE t1 (a int not null); +show create table t1; +SET SESSION table_type=default; +drop table t1; + + +# +# ISO requires that primary keys are implicitly NOT NULL +# +create table t1 ( k1 varchar(2), k2 int, primary key(k1,k2)); +insert into t1 values ("a", 1), ("b", 2); +--error 1048 +insert into t1 values ("c", NULL); +--error 1048 +insert into t1 values (NULL, 3); +--error 1048 +insert into t1 values (NULL, NULL); +drop table t1; + +# +# Test create with foreign keys +# + create table t1 (a int, key(a)); create table t2 (b int, foreign key(b) references t1(a), key(b)); drop table if exists t1,t2; diff --git a/mysql-test/t/ctype_latin1_de.test b/mysql-test/t/ctype_latin1_de.test index e0591913f68..b63af87601b 100644 --- a/mysql-test/t/ctype_latin1_de.test +++ b/mysql-test/t/ctype_latin1_de.test @@ -47,3 +47,26 @@ select * from t1 where a like "test%"; select * from t1 where a like "te_t"; select * from t1 where match a against ("te*" in boolean mode)+0; drop table t1; + +# +# Test bug report #152 (problem with index on latin1_de) +# + +create table t1 (word varchar(255) not null, word2 varchar(255) not null, index(word)); +insert into t1 (word) values ('ss'),(0xDF),(0xE4),('ae'); +update t1 set word2=word; +select word, word=0xdf as t from t1 having t > 0; +select word, word=cast(0xdf AS CHAR) as t from t1 having t > 0; +select * from t1 where word=0xDF; +select * from t1 where word=CAST(0xDF as CHAR); +select * from t1 where word2=0xDF; +select * from t1 where word2=CAST(0xDF as CHAR); +select * from t1 where word='ae'; +select * from t1 where word= 0xe4 or word=CAST(0xe4 as CHAR); +select * from t1 where word between 0xDF and 0xDF; +select * from t1 where word between CAST(0xDF AS CHAR) and CAST(0xDF AS CHAR); +select * from t1 where word like 'ae'; +select * from t1 where word like 'AE'; +select * from t1 where word like 0xDF; +select * from t1 where word like CAST(0xDF as CHAR); +drop table t1; diff --git a/mysql-test/t/ctype_recoding.test b/mysql-test/t/ctype_recoding.test index 0330bbd23b4..68526806166 100644 --- a/mysql-test/t/ctype_recoding.test +++ b/mysql-test/t/ctype_recoding.test @@ -26,3 +26,4 @@ SHOW FIELDS FROM таблица; SET CHARACTER SET koi8r; DROP TABLE ÔÁÂÌÉÃÁ; +SET CHARACTER SET default; diff --git a/mysql-test/t/ctype_ujis-master.opt b/mysql-test/t/ctype_ujis-master.opt new file mode 100644 index 00000000000..1f4183d5027 --- /dev/null +++ b/mysql-test/t/ctype_ujis-master.opt @@ -0,0 +1 @@ +--default-character-set=ujis diff --git a/mysql-test/t/ctype_ujis.test b/mysql-test/t/ctype_ujis.test new file mode 100644 index 00000000000..7308f26a8cf --- /dev/null +++ b/mysql-test/t/ctype_ujis.test @@ -0,0 +1,15 @@ +# +# Tests with the ujis character set +# +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Test problem with LEFT() +# + +create table t1 (c text); +insert into t1 values (0xa4a2),(0xa4a3); +select hex(left(c,1)) from t1 group by c; +drop table t1; diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index 91216ff9c3a..f1f751d728b 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -64,4 +64,10 @@ select * from t1 where misc > 5 and bool is null; delete from t1 where misc > 5 and bool is null; select * from t1 where misc > 5 and bool is null; +select count(*) from t1; +delete from t1 where 1 > 2; +select count(*) from t1; +delete from t1 where 3 > 2; +select count(*) from t1; + drop table t1; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 214236268fa..40ac7f905c7 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -175,3 +175,14 @@ repair table t1; select * from t1 where match (a) against ('aaaa'); drop table t1; +# +# bug 283 by jocelyn fournier <joc@presence-pc.com> +# FULLTEXT index on a TEXT filed converted to a CHAR field doesn't work anymore +# + +create table t1 ( ref_mag text not null, fulltext (ref_mag)); +insert into t1 values ('test'); +select ref_mag from t1 where match ref_mag against ('+test' in boolean mode); +alter table t1 change ref_mag ref_mag char (255) not null; +select ref_mag from t1 where match ref_mag against ('+test' in boolean mode); +drop table t1; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index c78509d3869..aca9530ffc3 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -326,6 +326,26 @@ explain select min(a4) from t1 where (a4 + 0.01) between 0.07 and 0.08; explain select concat(min(t1.a1),min(t2.a4)) from t1, t2 where t2.a4 <> 'AME'; +drop table t1, t2; -# Clean up -drop table if exists t1, t2;
\ No newline at end of file + +# +# Test of group function and NULL values +# + +CREATE TABLE t1 (a int, b int); +select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1; +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +insert into t1 values (1,null); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +insert into t1 values (1,null); +insert into t1 values (2,null); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +insert into t1 values (2,1); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +insert into t1 values (3,1); +select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a; +drop table t1; diff --git a/mysql-test/t/func_misc.test b/mysql-test/t/func_misc.test index d48b17e87af..be64c170fa1 100644 --- a/mysql-test/t/func_misc.test +++ b/mysql-test/t/func_misc.test @@ -7,3 +7,8 @@ select format(1.5555,0),format(123.5555,1),format(1234.5555,2),format(12345.5555 select inet_ntoa(inet_aton("255.255.255.255.255.255.255.255")); select inet_aton("255.255.255.255.255"),inet_aton("255.255.1.255"),inet_aton("0.1.255"); select inet_ntoa(1099511627775),inet_ntoa(4294902271),inet_ntoa(511); + +# +# Test for core dump with nan +# +select length(format('nan', 2)) > 0; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 912bed1955c..d99c7a87f88 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -44,12 +44,15 @@ CREATE TABLE t2 ( INSERT INTO t2 VALUES (1,'name','pass','mail','Y','v','n','adr','1','1','1'); INSERT INTO t2 VALUES (2,'name','pass','mail','Y','v','n','adr','1','1','1'); INSERT INTO t2 VALUES (3,'name','pass','mail','Y','v','n','adr','1','1','1'); +INSERT INTO t2 VALUES (4,'name','pass','mail','Y','v','n','adr','1','1','1'); +INSERT INTO t2 VALUES (5,'name','pass','mail','Y','v','n','adr','1','1','1'); SELECT t2.userid, MIN(t1.score) FROM t1, t2 WHERE t1.userID=t2.userID GROUP BY t2.userid; SELECT t2.userid, MIN(t1.score) FROM t1, t2 WHERE t1.userID=t2.userID GROUP BY t2.userid ORDER BY NULL; SELECT t2.userid, MIN(t1.score) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid; SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid; SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid ORDER BY NULL; +EXPLAIN SELECT t2.userid, MIN(t1.score+0.0) FROM t1, t2 WHERE t1.userID=t2.userID AND t1.spID=2 GROUP BY t2.userid ORDER BY NULL; drop table t1,t2; # @@ -246,7 +249,7 @@ CREATE TABLE t1 ( key (score) ); -INSERT INTO t1 VALUES (1,1,1),(2,2,2),(2,1,1),(3,3,3),(4,3,3),(5,3,3); +INSERT INTO t1 VALUES (1,1,1),(2,2,2),(2,1,1),(3,3,3),(4,3,3),(5,3,3),(6,3,3),(7,3,3); explain select userid,count(*) from t1 group by userid desc; explain select userid,count(*) from t1 group by userid desc order by null; select userid,count(*) from t1 group by userid desc; @@ -265,8 +268,6 @@ explain select sql_big_result score,count(*) from t1 group by score desc order b select sql_big_result score,count(*) from t1 group by score desc; drop table t1; -# - # not purely group_by bug, but group_by is involved... create table t1 (a date default null, b date default null); @@ -275,7 +276,6 @@ select a,min(b) c,count(distinct rand()) from t1 group by a having c<a + interva drop table t1; # Compare with hash keys -# CREATE TABLE t1 (a char(1)); INSERT INTO t1 VALUES ('A'),('B'),('A'),('B'),('A'),('B'),(NULL),('a'),('b'),(NULL),('A'),('B'),(NULL); @@ -410,15 +410,7 @@ drop table t1,t2; # create table t1 (a int, b int); -insert into t1 values (1, 4); -insert into t1 values (10, 40); -insert into t1 values (1, 4); -insert into t1 values (10, 43); -insert into t1 values (1, 4); -insert into t1 values (10, 41); -insert into t1 values (1, 4); -insert into t1 values (10, 43); -insert into t1 values (1, 4); +insert into t1 values (1, 4),(10, 40),(1, 4),(10, 43),(1, 4),(10, 41),(1, 4),(10, 43),(1, 4); select a, MAX(b), INTERVAL (MAX(b), 1,3,10,30,39,40,50,60,100,1000) from t1 group by a; select a, MAX(b), CASE MAX(b) when 4 then 4 when 43 then 43 else 0 end from t1 group by a; select a, MAX(b), FIELD(MAX(b), '43', '4', '5') from t1 group by a; diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test index 4bd56400f98..7d5fbee011f 100644 --- a/mysql-test/t/having.test +++ b/mysql-test/t/having.test @@ -64,3 +64,13 @@ select Fld1, max(Fld2) from t1 group by Fld1 having avg(Fld2) is not null; select Fld1, max(Fld2) from t1 group by Fld1 having std(Fld2) is not null; select Fld1, max(Fld2) from t1 group by Fld1 having variance(Fld2) is not null; drop table t1; + +# +# Test problem with count(distinct) in having +# +create table t1 (id int not null, qty int not null); +insert into t1 values (1,2),(1,3),(2,4),(2,5); +select id, sum(qty) as sqty from t1 group by id having sqty>2; +select sum(qty) as sqty from t1 group by id having count(id) > 0; +select sum(qty) as sqty from t1 group by id having count(distinct id) > 0; +drop table t1; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index bf1756ede5c..3736f4a2ddc 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -45,12 +45,9 @@ update ignore t1 set id=id+1; # This will change all rows select * from t1; update ignore t1 set id=1023 where id=1010; select * from t1 where parent_id=102; ---replace_result 12 # 6 # -explain select level from t1 where level=1; ---replace_result 12 # 6 # -explain select level,id from t1 where level=1; ---replace_result 12 # 6 # 5 # -explain select level,id,parent_id from t1 where level=1; +# explain select level from t1 where level=1; +# explain select level,id from t1 where level=1; +# explain select level,id,parent_id from t1 where level=1; select level,id from t1 where level=1; select level,id,parent_id from t1 where level=1; optimize table t1; @@ -348,7 +345,7 @@ update ignore t1 set id=id+1; # This will change all rows select * from t1; update ignore t1 set id=1023 where id=1010; select * from t1 where parent_id=102; -explain select level from t1 where level=1; +# explain select level from t1 where level=1; select level,id from t1 where level=1; select level,id,parent_id from t1 where level=1; select level,id from t1 where level=1 order by id; @@ -784,7 +781,7 @@ drop table t1; CREATE TABLE t1 (a int not null primary key, b int not null, key (b)) type=innodb; CREATE TABLE t2 (a int not null primary key, b int not null, key (b)) type=innodb; -INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); +INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12); INSERT INTO t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); # Full join, without key @@ -800,11 +797,76 @@ update t1,t2 set t1.b=t1.b+10 where t1.b=2; select * from t1; # Range key (in t1) -update t1,t2 set t1.b=t1.b+2,t2.b=t1.b where t1.b between 3 and 5; +update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t1.a=t2.a+100; select * from t1; select * from t2; drop table t1,t2; +CREATE TABLE t2 ( NEXT_T BIGINT NOT NULL PRIMARY KEY) TYPE=MyISAM; +CREATE TABLE t1 ( B_ID INTEGER NOT NULL PRIMARY KEY) TYPE=InnoDB; +SET AUTOCOMMIT=0; +INSERT INTO t1 ( B_ID ) VALUES ( 1 ); +INSERT INTO t2 ( NEXT_T ) VALUES ( 1 ); +ROLLBACK; +SELECT * FROM t1; +drop table t1,t2; +create table t1 ( pk int primary key, parent int not null, child int not null, index (parent) ) type = innodb; +insert into t1 values (1,0,4), (2,1,3), (3,2,1), (4,1,2); +select distinct parent,child from t1 order by parent; +drop table t1; + +# +# Test that MySQL priorities clustered indexes +# +create table t1 (a int not null auto_increment primary key, b int, c int, key(c)) type=innodb; +create table t2 (a int not null auto_increment primary key, b int); +insert into t1 (b) values (null),(null),(null),(null),(null),(null),(null); +insert into t2 (a) select b from t1; +insert into t1 (b) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +insert into t2 (a) select b from t1; +insert into t1 (a) select b from t2; +select count(*) from t1; +explain select * from t1 where c between 1 and 10000; +update t1 set c=a; +explain select * from t1 where c between 1 and 10000; +drop table t1,t2; + +# +# Test of UPDATE ... ORDER BY +# + +create table t1 (id int primary key auto_increment, fk int, index index_fk (fk)) type=innodb; + +insert into t1 (id) values (null),(null),(null),(null),(null); +update t1 set fk=69 where fk is null order by id limit 1; +SELECT * from t1; +drop table t1; + +create table t1 (a int not null, b int not null, key (a)); +insert into t1 values (1,1),(1,2),(1,3),(3,1),(3,2),(3,3),(3,1),(3,2),(3,3),(2,1),(2,2),(2,3); +SET @tmp=0; +update t1 set b=(@tmp:=@tmp+1) order by a; +update t1 set b=99 where a=1 order by b asc limit 1; +update t1 set b=100 where a=1 order by b desc limit 2; +update t1 set a=a+10+b where a=1 order by b; +select * from t1 order by a,b; +drop table t1; + + CREATE TABLE t1 (col1 int(1))TYPE=InnoDB; CREATE TABLE t2 (col1 int(1),stamp TIMESTAMP(+0),INDEX stamp_idx (stamp))TYPE=InnoDB; diff --git a/mysql-test/t/innodb_handler.test b/mysql-test/t/innodb_handler.test index 32c8741577c..cf6ac9870ce 100644 --- a/mysql-test/t/innodb_handler.test +++ b/mysql-test/t/innodb_handler.test @@ -75,5 +75,11 @@ alter table t1 type=innodb; --error 1109 handler t2 read first; -drop table if exists t1; +drop table t1; +CREATE TABLE t1 ( no1 smallint(5) NOT NULL default '0', no2 int(10) NOT NULL default '0', PRIMARY KEY (no1,no2)) TYPE=InnoDB; +INSERT INTO t1 VALUES (1,274),(1,275),(2,6),(2,8),(4,1),(4,2); +HANDLER t1 OPEN; +HANDLER t1 READ `primary` = (1, 1000); +HANDLER t1 READ `primary` PREV; +DROP TABLE t1; diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index 5fd96d6687c..882aec1006a 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -272,3 +272,49 @@ INSERT INTO t2 VALUES ('rivercats','cust',20); SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE emp.emp_id = 'psmith' AND lr.siteid = 'rivercats'; SELECT emp.rate_code, lr.base_rate FROM t1 AS emp LEFT JOIN t2 AS lr USING (siteid, rate_code) WHERE lr.siteid = 'rivercats' AND emp.emp_id = 'psmith'; drop table t1,t2; + +# +# Problem with internal list handling when reducing WHERE +# + +CREATE TABLE t1 (ID INTEGER NOT NULL PRIMARY KEY, Value1 VARCHAR(255)); +CREATE TABLE t2 (ID INTEGER NOT NULL PRIMARY KEY, Value2 VARCHAR(255)); +INSERT INTO t1 VALUES (1, 'A'); +INSERT INTO t2 VALUES (1, 'B'); + +SELECT * FROM t1 NATURAL JOIN t2 WHERE 1 AND (Value1 = 'A' AND Value2 <> 'B'); +SELECT * FROM t1 NATURAL JOIN t2 WHERE 1 AND Value1 = 'A' AND Value2 <> 'B'; +SELECT * FROM t1 NATURAL JOIN t2 WHERE (Value1 = 'A' AND Value2 <> 'B') AND 1; +drop table t1,t2; + +# +# Test combination of join methods +# + +create table t1 (i int); +create table t2 (i int); +create table t3 (i int); +insert into t1 values(1),(2); +insert into t2 values(2),(3); +insert into t3 values (2),(4); + +select * from t1 natural left join t2; +select * from t1 left join t2 on (t1.i=t2.i); +select * from t1 natural left join t2 natural left join t3; +select * from t1 left join t2 on (t1.i=t2.i) left join t3 on (t2.i=t3.i); + +select * from t3 natural right join t2; +select * from t3 right join t2 on (t3.i=t2.i); +select * from t3 natural right join t2 natural right join t1; +select * from t3 right join t2 on (t3.i=t2.i) right join t1 on (t2.i=t1.i); + +select * from t1,t2 natural left join t3 order by t1.i,t2.i,t3.i; +select * from t1,t2 left join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; +select t1.i,t2.i,t3.i from t2 natural left join t3,t1 order by t1.i,t2.i,t3.i; +select t1.i,t2.i,t3.i from t2 left join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; + +select * from t1,t2 natural right join t3 order by t1.i,t2.i,t3.i; +select * from t1,t2 right join t3 on (t2.i=t3.i) order by t1.i,t2.i,t3.i; +select t1.i,t2.i,t3.i from t2 natural right join t3,t1 order by t1.i,t2.i,t3.i; +select t1.i,t2.i,t3.i from t2 right join t3 on (t2.i=t3.i),t1 order by t1.i,t2.i,t3.i; +drop table t1,t2,t3; diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index c57fb8273fe..df7e5b1524d 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -249,7 +249,7 @@ drop table t1,t2; create table t1 (id int not null, str char(10), index(str)); insert into t1 values (1, null), (2, null), (3, "foo"), (4, "bar"); -select * from t1 where str is not null; +select * from t1 where str is not null order by id; select * from t1 where str is null; drop table t1; @@ -417,3 +417,12 @@ explain select * from t2 left join t1 on t1.fooID = t2.fooID and t1.fooID = 30; select * from t2 left join t1 on t1.fooID = t2.fooID and t1.fooID = 30; select * from t2 left join t1 ignore index(primary) on t1.fooID = t2.fooID and t1.fooID = 30; drop table t1,t2; + +create table t1 (i int); +create table t2 (i int); +create table t3 (i int); +insert into t1 values(1),(2); +insert into t2 values(2),(3); +insert into t3 values(2),(4); +select * from t1 natural left join t2 natural left join t3; +drop table t1,t2,t3; diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test index 4fd8cc86dd5..de97c639812 100644 --- a/mysql-test/t/key.test +++ b/mysql-test/t/key.test @@ -57,12 +57,12 @@ INSERT INTO t1 VALUES (900,'Vancouver','Shared/Roomate','Y','Y','Y','Y'); drop table t1; # -# problem med primary key +# No longer a problem with primary key # CREATE TABLE t1 (program enum('signup','unique','sliding') not null, type enum('basic','sliding','signup'), sites set('mt'), PRIMARY KEY (program)); -# The following should give an error for wrong primary key -!$1171 ALTER TABLE t1 modify program enum('signup','unique','sliding'); +# This no longer give an error for wrong primary key +ALTER TABLE t1 modify program enum('signup','unique','sliding'); drop table t1; # diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test new file mode 100644 index 00000000000..d7e84590dc0 --- /dev/null +++ b/mysql-test/t/loaddata.test @@ -0,0 +1,13 @@ +# +# Some simple test of load data +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a date, b date, c date not null, d date); +load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ','; +load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' IGNORE 2 LINES; +SELECT * from t1; +drop table t1; diff --git a/mysql-test/t/multi_update-master.opt b/mysql-test/t/multi_update-master.opt new file mode 100644 index 00000000000..9f1a29461ff --- /dev/null +++ b/mysql-test/t/multi_update-master.opt @@ -0,0 +1 @@ +--set-variable=tmp_table_size=1024 diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 390dd58d806..8e560cab455 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -255,8 +255,16 @@ update t1,t2 set t1.b=t1.b+10 where t1.b=2; select * from t1; # Range key (in t1) -update t1,t2 set t1.b=t1.b+2,t2.b=t1.b where t1.b between 3 and 5; +update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t2.a=t1.a-100; select * from t1; select * from t2; drop table t1,t2; +CREATE TABLE t3 ( KEY1 varchar(50) NOT NULL default '', PARAM_CORR_DISTANCE_RUSH double default NULL, PARAM_CORR_DISTANCE_GEM double default NULL, PARAM_AVG_TARE double default NULL, PARAM_AVG_NB_DAYS double default NULL, PARAM_DEFAULT_PROP_GEM_SRVC varchar(50) default NULL, PARAM_DEFAULT_PROP_GEM_NO_ETIK varchar(50) default NULL, PARAM_SCENARIO_COSTS varchar(50) default NULL, PARAM_DEFAULT_WAGON_COST double default NULL, tmp int(11) default NULL, PRIMARY KEY (KEY1)) TYPE=MyISAM; +INSERT INTO t3 VALUES ('A',1,1,22,3.2,'R','R','BASE2',0.24,NULL); +create table t1 (A varchar(1)); +insert into t1 values ("A") ,("B"),("C"),("D"); +create table t2(Z varchar(15)); +insert into t2(Z) select concat(a.a,b.a,c.a,d.a) from t1 as a, t1 as b, t1 as c, t1 as d; +update t2,t3 set Z =param_scenario_costs; +drop table t1,t2,t3; diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 8e1f304a5a5..702feedc3ce 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -334,9 +334,21 @@ SELECT titre,t1.numeropost,auteur,icone,nbrep,'0',date,vue,ouvert,lastauteur,des drop table t1,t2; # -# Test of test_if_subkey() function +# Test order by with NULL values # +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1, 2); +INSERT INTO t1 VALUES (3, 4); +INSERT INTO t1 VALUES (5, NULL); +SELECT * FROM t1 ORDER BY b; +SELECT * FROM t1 ORDER BY b DESC; +SELECT * FROM t1 ORDER BY (a + b); +SELECT * FROM t1 ORDER BY (a + b) DESC; +DROP TABLE t1; +# +# Test of test_if_subkey() function +# CREATE TABLE t1 ( FieldKey varchar(36) NOT NULL default '', LongVal bigint(20) default NULL, @@ -345,7 +357,7 @@ CREATE TABLE t1 ( KEY LongField (FieldKey,LongVal), KEY StringField (FieldKey,StringVal(32)) ); -INSERT INTO t1 VALUES ('0',3,'0'),('0',2,'1'),('0',1,'2'),('1',2,'1'),('1',1,'3'), ('1',0,'2'),('2',3,'0'),('2',2,'1'),('2',1,'2'),('3',2,'1'),('3',1,'2'),('3','3','3'); +INSERT INTO t1 VALUES ('0',3,'0'),('0',2,'1'),('0',1,'2'),('1',2,'1'),('1',1,'3'), ('1',0,'2'),('2',3,'0'),('2',2,'1'),('2',1,'2'),('2',3,'0'),('2',2,'1'),('2',1,'2'),('3',2,'1'),('3',1,'2'),('3','3','3'); EXPLAIN SELECT * FROM t1 WHERE FieldKey = '1' ORDER BY LongVal; SELECT * FROM t1 WHERE FieldKey = '1' ORDER BY LongVal; EXPLAIN SELECT * FROM t1 WHERE FieldKey > '2' ORDER BY LongVal; diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 56eda7fa104..1078d19533c 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -147,9 +147,10 @@ create table t1 (a int not null); insert into t1 values (1),(2),(3); select * from t1; show status like "Qcache_queries_in_cache"; -select sql_cache * from t1; +select sql_cache * from t1 union select * from t1; set query_cache_type=2; -select sql_cache * from t1; +select sql_cache * from t1 union select * from t1; +select * from t1 union select sql_cache * from t1; show status like "Qcache_hits"; show status like "Qcache_queries_in_cache"; set query_cache_type=on; @@ -429,7 +430,6 @@ select * from t1 where id=2; # # Load data invalidation test # - create table t1 (word char(20) not null); select * from t1; show status like "Qcache_queries_in_cache"; @@ -440,7 +440,6 @@ drop table t1; # # INTO OUTFILE/DUMPFILE test # - create table t1 (a int); insert into t1 values (1),(2),(3); show status like "Qcache_queries_in_cache"; @@ -448,3 +447,16 @@ select * from t1 into outfile "query_caceh.out.file"; select * from t1 limit 1 into dumpfile "query_cache.dump.file"; show status like "Qcache_queries_in_cache"; drop table t1; + +# +# test of SQL_SELECT_LIMIT +# +create table t1 (a int); +insert into t1 values (1),(2); +show status like "Qcache_queries_in_cache"; +select * from t1; +SET OPTION SQL_SELECT_LIMIT=1; +select * from t1; +show status like "Qcache_queries_in_cache"; +SET OPTION SQL_SELECT_LIMIT=DEFAULT; +drop table t1; diff --git a/mysql-test/t/raid.test b/mysql-test/t/raid.test index 38c740201bc..235add63c22 100644 --- a/mysql-test/t/raid.test +++ b/mysql-test/t/raid.test @@ -9,6 +9,14 @@ show variables like "have_raid"; DROP TABLE IF EXISTS t1,t2; --enable_warnings +# +# Test dropping database with raid tables +# + +create database test_$1; +create table test_$1.r1 (i int) raid_type=1; +drop database test_$1; + CREATE TABLE t1 ( id int unsigned not null auto_increment primary key, c char(255) not null diff --git a/mysql-test/t/repair.test b/mysql-test/t/repair.test index bdc5a57a07c..2657f91cd02 100644 --- a/mysql-test/t/repair.test +++ b/mysql-test/t/repair.test @@ -8,4 +8,15 @@ drop table if exists t1; create table t1 SELECT 1,"table 1"; repair table t1 use_frm; -drop table if exists t1; +alter table t1 TYPE=HEAP; +repair table t1 use_frm; +drop table t1; + +# non-existent table +repair table t1 use_frm; + +# +# Create test table for repair2 +# The following must be last in this file + +create table t1 type=myisam SELECT 1,"table 1"; diff --git a/mysql-test/t/repair_part2-master.sh b/mysql-test/t/repair_part2-master.sh new file mode 100644 index 00000000000..964bde06c18 --- /dev/null +++ b/mysql-test/t/repair_part2-master.sh @@ -0,0 +1 @@ +echo "1" > $MYSQL_TEST_DIR/var/master-data/test/t1.MYI diff --git a/mysql-test/t/repair_part2.test b/mysql-test/t/repair_part2.test new file mode 100644 index 00000000000..8c27e382dff --- /dev/null +++ b/mysql-test/t/repair_part2.test @@ -0,0 +1,7 @@ +# +# This test starts with a crashed t1.MYI file left over from repair.test +# + +repair table t1; +repair table t1 use_frm; +drop table t1; diff --git a/mysql-test/t/rpl_flush_tables.test b/mysql-test/t/rpl_flush_tables.test index 88a80911d89..67720343e83 100644 --- a/mysql-test/t/rpl_flush_tables.test +++ b/mysql-test/t/rpl_flush_tables.test @@ -5,7 +5,6 @@ # source include/master-slave.inc; -let $VERSION=`select version()`; create table t1 (a int); insert into t1 values (10); create table t2 (a int); @@ -18,14 +17,14 @@ rename table t1 to t5, t2 to t1; # first don't write it to the binlog, to test the NO_WRITE_TO_BINLOG keyword. flush no_write_to_binlog tables; # Check that it's not in the binlog. ---replace_result $VERSION VERSION +--replace_result $SERVER_VERSION SERVER_VERSION show binlog events; # Check that the master is not confused. select * from t3; # This FLUSH should go into the binlog to not confuse the slave. flush tables; # Check that it's in the binlog. ---replace_result $VERSION VERSION +--replace_result $SERVER_VERSION SERVER_VERSION show binlog events; save_master_pos; connection slave; diff --git a/mysql-test/t/select_safe.test b/mysql-test/t/select_safe.test index cd8bce6369c..be25c7c05d1 100644 --- a/mysql-test/t/select_safe.test +++ b/mysql-test/t/select_safe.test @@ -7,7 +7,7 @@ drop table if exists t1; --enable_warnings SET SQL_SAFE_UPDATES=1,SQL_SELECT_LIMIT=4, SQL_MAX_JOIN_SIZE=9; -create table t1 (a int primary key, b char(20)); +create table t1 (a int auto_increment primary key, b char(20)); insert into t1 values(1,"test"); SELECT SQL_BUFFER_RESULT * from t1; update t1 set b="a" where a=1; @@ -18,18 +18,40 @@ update t1 set b="a" where a=1; select 1 from t1,t1 as t2,t1 as t3,t1 as t4; # The following should give errors: -!$1175 update t1 set b="a"; -!$1175 update t1 set b="a" where b="test"; -!$1175 delete from t1; -!$1175 delete from t1 where b="test"; -!$1175 delete from t1 where a+0=1; -!$1104 select 1 from t1,t1 as t2,t1 as t3,t1 as t4,t1 as t5; +--error 1175 +update t1 set b="a"; +--error 1175 +update t1 set b="a" where b="test"; +--error 1175 +delete from t1; +--error 1175 +delete from t1 where b="test"; +--error 1175 +delete from t1 where a+0=1; +--error 1104 +select 1 from t1,t1 as t2,t1 as t3,t1 as t4,t1 as t5; # The following should be ok: update t1 set b="a" limit 1; update t1 set b="a" where b="b" limit 2; delete from t1 where b="test" limit 1; delete from t1 where a+0=1 limit 2; + +# Test SQL_BIG_SELECTS + +SET MAX_JOIN_SIZE=2; +SELECT @@MAX_JOIN_SIZE, @@SQL_BIG_SELECTS; +insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); +--error 1104 +SELECT * from t1; +SET SQL_BIG_SELECTS=1; +SELECT * from t1; +SET MAX_JOIN_SIZE=2; +--error 1104 +SELECT * from t1; +SET MAX_JOIN_SIZE=DEFAULT; +SELECT * from t1; + drop table t1; SET SQL_SAFE_UPDATES=0,SQL_SELECT_LIMIT=DEFAULT, SQL_MAX_JOIN_SIZE=DEFAULT; diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index 90d7f814359..30edcc79d9e 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -4,7 +4,7 @@ # This would work if mysqltest run would be threaded and handle each # connection in a separate thread. # --- source include/not_embedded.inc +--source include/not_embedded.inc connect (con1,localhost,root,,); connect (con2,localhost,root,,); diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 8e8a3dfe1d4..4a171c36293 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -396,6 +396,8 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 3); SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2); -- error 1093 INSERT INTO t2 VALUES ((SELECT * FROM t2)); +-- error 1093 +INSERT INTO t2 VALUES ((SELECT id FROM t2)); SELECT * FROM t2; CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) TYPE=MyISAM CHARSET=latin1; INSERT INTO t1 values (1),(1); diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 053d0517904..8653c06a644 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -233,3 +233,13 @@ insert into t1 values("1e4294967297"); select * from t1; drop table t1; +# +# Test of wrong decimal type +# + +--error 1074 +CREATE TABLE t1 (a_dec DECIMAL(-1,0)); +--error 1074 +CREATE TABLE t1 (a_dec DECIMAL(-2,1)); +--error 1074 +CREATE TABLE t1 (a_dec DECIMAL(-1,1)); diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 70e770cd2d3..6d857a4b40f 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -3,7 +3,7 @@ # --disable_warnings -drop table if exists t1,t2,t3; +drop table if exists t1,t2,t3,t4,t5,t6; --enable_warnings CREATE TABLE t1 (a int not null, b char (10) not null); @@ -19,7 +19,7 @@ select 0,'#' union select a,b from t1 union all select a,b from t2 union select select a,b from t1 union select a,b from t1; select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 group by b; -#test alternate syntax for unions +# Test alternate syntax for unions (select a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 4; (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1); (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; @@ -27,7 +27,7 @@ select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 g (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by t1.b; explain (select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc; #(select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2; -select found_rows(); +#select found_rows(); # # Test some error conditions with UNION @@ -73,6 +73,19 @@ replace into t3 select a,b as c from t1 union all select a,b from t2; drop table t1,t2,t3; # +# Test some unions without tables +# +--error 1096 +select * union select 1; +select 1 as a,(select a union select a); +--error 1054 +(select 1) union (select 2) order by 0; +SELECT @a:=1 UNION SELECT @a:=@a+1; +--error 1054 +(SELECT 1) UNION (SELECT 2) ORDER BY (SELECT a); +(SELECT 1,3) UNION (SELECT 2,1) ORDER BY (SELECT 2); + +# # Test bug reported by joc@presence-pc.com # @@ -104,12 +117,67 @@ set SQL_SELECT_LIMIT=2; set SQL_SELECT_LIMIT=DEFAULT; drop table t1,t2; ---error 1096 -select * union select 1; -select 1 as a,(select a union select a); ---disable_warnings -drop table if exists t1,t2; ---enable_warnings +# +# Test error with left join +# + +CREATE TABLE t1 ( + cid smallint(5) unsigned NOT NULL default '0', + cv varchar(250) NOT NULL default '', + PRIMARY KEY (cid), + UNIQUE KEY cv (cv) +) ; +INSERT INTO t1 VALUES (8,'dummy'); +CREATE TABLE t2 ( + cid bigint(20) unsigned NOT NULL auto_increment, + cap varchar(255) NOT NULL default '', + PRIMARY KEY (cid), + KEY cap (cap) +) ; +CREATE TABLE t3 ( + gid bigint(20) unsigned NOT NULL auto_increment, + gn varchar(255) NOT NULL default '', + must tinyint(4) default NULL, + PRIMARY KEY (gid), + KEY gn (gn) +) ; +INSERT INTO t3 VALUES (1,'V1',NULL); +CREATE TABLE t4 ( + uid bigint(20) unsigned NOT NULL default '0', + gid bigint(20) unsigned default NULL, + rid bigint(20) unsigned default NULL, + cid bigint(20) unsigned default NULL, + UNIQUE KEY m (uid,gid,rid,cid), + KEY uid (uid), + KEY rid (rid), + KEY cid (cid), + KEY container (gid,rid,cid) +) ; +INSERT INTO t4 VALUES (1,1,NULL,NULL); +CREATE TABLE t5 ( + rid bigint(20) unsigned NOT NULL auto_increment, + rl varchar(255) NOT NULL default '', + PRIMARY KEY (rid), + KEY rl (rl) +) ; +CREATE TABLE t6 ( + uid bigint(20) unsigned NOT NULL auto_increment, + un varchar(250) NOT NULL default '', + uc smallint(5) unsigned NOT NULL default '0', + PRIMARY KEY (uid), + UNIQUE KEY nc (un,uc), + KEY un (un) +) ; +INSERT INTO t6 VALUES (1,'test',8); + +SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test"; +SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t3.must IS NOT NULL AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test"; +(SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t3.must IS NOT NULL AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test") UNION (SELECT t4.uid, t5.rl, t3.gn as g1, t4.cid, t4.gid as gg FROM t3, t6, t1, t4 left join t5 on t5.rid = t4.rid left join t2 on t2.cid = t4.cid WHERE t3.gid=t4.gid AND t6.uid = t4.uid AND t6.uc = t1.cid AND t1.cv = "dummy" AND t6.un = "test"); +drop table t1,t2,t3,t4,t5,t6; + +# +# Test for another bug with UNION and LEFT JOIN +# CREATE TABLE t1 ( id int(3) unsigned default '0') TYPE=MyISAM; INSERT INTO t1 (id) VALUES("1"); CREATE TABLE t2 ( id int(3) unsigned default '0', id_master int(5) default '0', text1 varchar(5) default NULL, text2 varchar(5) default NULL) TYPE=MyISAM; @@ -124,7 +192,6 @@ INSERT INTO t2 (id, id_master, text1, text2) VALUES("4", "1", SELECT 1 AS id_master, 1 AS id, NULL AS text1, 'ABCDE' AS text2 UNION SELECT id_master, t2.id, text1, text2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id_master; SELECT 1 AS id_master, 1 AS id, 'ABCDE' AS text1, 'ABCDE' AS text2 UNION SELECT id_master, t2.id, text1, text2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id_master; drop table if exists t1,t2; -(SELECT 1,3) UNION (SELECT 2,1) ORDER BY (SELECT 2); # # Test of bug when using the same table multiple times @@ -142,9 +209,3 @@ explain (select * from t1 where a=1) union (select * from t2 where a=1); explain (select * from t1 where a=1 and b=10) union (select t1.a,t2.a from t1,t2 where t1.a=t2.a); explain (select * from t1 where a=1) union (select * from t1 where b=1); drop table t1,t2; ---error 1054 -(select 1) union (select 2) order by 0; - -SELECT @a:=1 UNION SELECT @a:=@a+1; ---error 1054 -(SELECT 1) UNION (SELECT 2) ORDER BY (SELECT a); diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 6a7eac41a96..485af981fb4 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -84,12 +84,48 @@ drop table t1; # Test of ORDER BY # -create table t1 (a int not null, b int not null); -insert into t1 values (1,1),(1,2),(1,3); -update t1 set b=4 where a=1 order by b asc limit 1; -update t1 set b=4 where a=1 order by b desc limit 1; +create table t1 (a int not null, b int not null, key (a)); +insert into t1 values (1,1),(1,2),(1,3),(3,1),(3,2),(3,3),(3,1),(3,2),(3,3),(2,1),(2,2),(2,3); +SET @tmp=0; +update t1 set b=(@tmp:=@tmp+1) order by a; +update t1 set b=99 where a=1 order by b asc limit 1; +select * from t1 order by a,b; +update t1 set b=100 where a=1 order by b desc limit 2; +update t1 set a=a+10+b where a=1 order by b; +select * from t1 order by a,b; create table t2 (a int not null, b int not null); insert into t2 values (1,1),(1,2),(1,3); -select * from t1; update t1 set b=(select distinct 1 from (select * from t2) a); drop table t1,t2; + +# +# Test with limit (Bug #393) +# + +CREATE TABLE t1 ( + `id_param` smallint(3) unsigned NOT NULL default '0', + `nom_option` char(40) NOT NULL default '', + `valid` tinyint(1) NOT NULL default '0', + KEY `id_param` (`id_param`,`nom_option`) + ) TYPE=MyISAM; + +INSERT INTO t1 (id_param,nom_option,valid) VALUES (185,'600x1200',1); + +UPDATE t1 SET nom_option='test' WHERE id_param=185 AND nom_option='600x1200' AND valid=1 LIMIT 1; +select * from t1; +drop table t1; + +# +# Multi table update test from bugs +# + +create table t1 (F1 VARCHAR(30), F2 VARCHAR(30), F3 VARCHAR(30), cnt int, groupid int, KEY groupid_index (groupid)); + +insert into t1 (F1,F2,F3,cnt,groupid) values ('0','0','0',1,6), +('0','1','2',1,5), ('0','2','0',1,3), ('1','0','1',1,2), +('1','2','1',1,1), ('1','2','2',1,1), ('2','0','1',2,4), +('2','2','0',1,7); + +delete from t1 using t1 m1,t1 m2 where m1.groupid=m2.groupid and (m1.cnt < m2.cnt or m1.cnt=m2.cnt and m1.F3>m2.F3); +select * from t1; +drop table t1; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 32e7db12136..7d4b25df0eb 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -72,10 +72,10 @@ show local variables like 'table_type'; show global variables like 'table_type'; set GLOBAL query_cache_size=100000; -set myisam_max_sort_file_size=10000, GLOBAL myisam_max_sort_file_size=20000; -show variables like 'myisam_max_sort_file_size'; +set GLOBAL myisam_max_sort_file_size=2000000; show global variables like 'myisam_max_sort_file_size'; -set myisam_max_sort_file_size=default; +set GLOBAL myisam_max_sort_file_size=default; +--replace_result 2147483647 FILE_SIZE 9223372036854775807 FILE_SIZE show variables like 'myisam_max_sort_file_size'; set global net_retry_count=10, session net_retry_count=10; @@ -132,6 +132,10 @@ set @@concurrent_insert=1; set @@global.sql_auto_is_null=1; --error 1228 select @@global.sql_auto_is_null; +--error 1229 +set myisam_max_sort_file_size=100; +--error 1229 +set myisam_max_extra_sort_file_size=100; # Test setting all variables @@ -176,9 +180,9 @@ set max_tmp_tables=100; set global max_user_connections=100; select @@max_user_connections; set global max_write_lock_count=100; -set myisam_max_extra_sort_file_size=100; +set global myisam_max_extra_sort_file_size=100; select @@myisam_max_extra_sort_file_size; -set myisam_max_sort_file_size=100; +set global myisam_max_sort_file_size=100; set myisam_sort_buffer_size=100; set net_buffer_length=100; set net_read_timeout=100; @@ -236,3 +240,10 @@ check table t1,t2; select max(a) +1, max(a) +2 into @xx,@yy from t1; drop table t1,t2; +# +# error conditions +# + +--error 1193 +select @@xxxxxxxxxx; +select 1; diff --git a/mysys/default.c b/mysys/default.c index 9fedfd795a5..17ee1b8c8da 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -251,7 +251,13 @@ static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, MY_STAT stat_info; if (!my_stat(name,&stat_info,MYF(0))) return 0; - if (stat_info.st_mode & S_IWOTH) /* ignore world-writeable files */ + /* + Ignore world-writable regular files. + This is mainly done to protect us to not read a file created by + the mysqld server, but the check is still valid in most context. + */ + if ((stat_info.st_mode & S_IWOTH) && + (stat_info.st_mode & S_IFMT) == S_IFREG) { fprintf(stderr, "warning: World-writeable config file %s is ignored\n", name); diff --git a/mysys/mf_path.c b/mysys/mf_path.c index 23eadd2acce..1ecd5fbb2b1 100644 --- a/mysys/mf_path.c +++ b/mysys/mf_path.c @@ -77,6 +77,9 @@ my_string my_path(my_string to, const char *progname, #define F_OK 0 #define PATH_SEP ';' #define PROGRAM_EXTENSION ".exe" +#elif defined(__NETWARE__) +#define PATH_SEP ';' +#define PROGRAM_EXTENSION ".nlm" #else #define PATH_SEP ':' #endif diff --git a/mysys/my_bit.c b/mysys/my_bit.c index 0ff487afe03..55dd72f5f76 100644 --- a/mysys/my_bit.c +++ b/mysys/my_bit.c @@ -29,3 +29,45 @@ uint my_bit_log2(ulong value) for (bit=0 ; value > 1 ; value>>=1, bit++) ; return bit; } + +static char nbits[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; + +uint my_count_bits(ulonglong v) +{ +#if SIZEOF_LONG_LONG > 4 + /* The following code is a bit faster on 16 bit machines than if we would + only shift v */ + ulong v2=(ulong) (v >> 32); + return (uint) (uchar) (nbits[(uchar) v] + + nbits[(uchar) (v >> 8)] + + nbits[(uchar) (v >> 16)] + + nbits[(uchar) (v >> 24)] + + nbits[(uchar) (v2)] + + nbits[(uchar) (v2 >> 8)] + + nbits[(uchar) (v2 >> 16)] + + nbits[(uchar) (v2 >> 24)]); +#else + return (uint) (uchar) (nbits[(uchar) v] + + nbits[(uchar) (v >> 8)] + + nbits[(uchar) (v >> 16)] + + nbits[(uchar) (v >> 24)]); +#endif +} + diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c index 1eb15d92bc9..4f472f61593 100644 --- a/mysys/my_pthread.c +++ b/mysys/my_pthread.c @@ -90,6 +90,29 @@ void *my_pthread_getspecific_imp(pthread_key_t key) } #endif +#ifdef __NETWARE__ +/* +don't kill the LibC Reaper thread or the main thread +*/ +#include <nks/thread.h> +#undef pthread_exit +void my_pthread_exit(void *status) +{ + NXThreadId_t tid = NXThreadGetId(); + NXContext_t ctx; + char name[PATH_MAX] = ""; + + NXThreadGetContext(tid, &ctx); + NXContextGetName(ctx, name, PATH_MAX); + + // "MYSQLD.NLM's LibC Reaper" or "MYSQLD.NLM's main thread" + // with a debug build of LibC the reaper can have different names + if (!strindex(name, "\'s")) + { + pthread_exit(status); + } +} +#endif /* Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7 (and DEC OSF/1 3.2 too) */ diff --git a/mysys/my_seek.c b/mysys/my_seek.c index 177a5cee953..ec24a26b3d9 100644 --- a/mysys/my_seek.c +++ b/mysys/my_seek.c @@ -15,6 +15,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mysys_priv.h" +#include <assert.h> /* Seek to position in file */ /*ARGSUSED*/ @@ -27,6 +28,8 @@ my_off_t my_seek(File fd, my_off_t pos, int whence, DBUG_PRINT("my",("Fd: %d Hpos: %lu Pos: %lu Whence: %d MyFlags: %d", fd, (ulong) (((ulonglong) pos) >> 32), (ulong) pos, whence, MyFlags)); + DBUG_ASSERT(pos != MY_FILEPOS_ERROR); /* safety check */ + newpos=lseek(fd, pos, whence); if (newpos == (os_off_t) -1) { diff --git a/mysys/my_semaphore.c b/mysys/my_semaphore.c index 2dd224cd99e..aa216cbc289 100644 --- a/mysys/my_semaphore.c +++ b/mysys/my_semaphore.c @@ -23,7 +23,7 @@ #include <my_semaphore.h> #include <errno.h> -#if !defined(__WIN__) && !defined(HAVE_SEMAPHORE_H) +#if !defined(__WIN__) && !defined(HAVE_SEMAPHORE_H) && defined(THREAD) int sem_init(sem_t * sem, int pshared, uint value) { @@ -101,4 +101,4 @@ int sem_getvalue(sem_t * sem, uint *sval) return 0; } -#endif /* !defined(__WIN__) && !defined(HAVE_SEMAPHORE_H) */ +#endif /* !defined(__WIN__) && !defined(HAVE_SEMAPHORE_H) && defined(THREAD) */ diff --git a/mysys/raid.cc b/mysys/raid.cc index d6359dc0f93..0b688464fb3 100644 --- a/mysys/raid.cc +++ b/mysys/raid.cc @@ -157,10 +157,10 @@ extern "C" { DBUG_PRINT("enter",("Fd: %d pos: %lu whence: %d MyFlags: %d", fd, (ulong) pos, whence, MyFlags)); - assert(pos != MY_FILEPOS_ERROR); - if (is_raid(fd)) { + assert(pos != MY_FILEPOS_ERROR); + RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**)); DBUG_RETURN(raid->Seek(pos,whence,MyFlags)); } diff --git a/netware/BUILD/compile-AUTOTOOLS b/netware/BUILD/compile-AUTOTOOLS index 0688ea5aaca..57213b1b3d0 100755 --- a/netware/BUILD/compile-AUTOTOOLS +++ b/netware/BUILD/compile-AUTOTOOLS @@ -1,5 +1,11 @@ #! /bin/sh +# debug +#set -x + +# stop on errors +set -e + for package in . ./innobase do (cd $package diff --git a/netware/BUILD/compile-linux-tools b/netware/BUILD/compile-linux-tools index 598be96ab66..3590a900338 100755 --- a/netware/BUILD/compile-linux-tools +++ b/netware/BUILD/compile-linux-tools @@ -1,8 +1,11 @@ #! /bin/sh -#debug +# debug #set -x +# stop on errors +set -e + if test ! -r ./sql/mysqld.cc then echo "you must start from the top source directory" diff --git a/netware/BUILD/compile-netware-END b/netware/BUILD/compile-netware-END index beb15fbeda3..e0097484500 100755 --- a/netware/BUILD/compile-netware-END +++ b/netware/BUILD/compile-netware-END @@ -1,5 +1,11 @@ #! /bin/sh +# debug +#set -x + +# stop on errors +set -e + path=`dirname $0` # clean diff --git a/netware/BUILD/compile-netware-START b/netware/BUILD/compile-netware-START index 2941d8868e4..7eef192a907 100755 --- a/netware/BUILD/compile-netware-START +++ b/netware/BUILD/compile-netware-START @@ -1,8 +1,11 @@ #! /bin/sh -#debug +# debug #set -x +# stop on errors +set -e + if test ! -r ./sql/mysqld.cc then echo "you must start from the top source directory" diff --git a/netware/BUILD/compile-netware-all b/netware/BUILD/compile-netware-all index f8dea0f7583..35d275f3b42 100755 --- a/netware/BUILD/compile-netware-all +++ b/netware/BUILD/compile-netware-all @@ -1,5 +1,11 @@ #! /bin/sh +# debug +#set -x + +# stop on errors +set -e + path=`dirname $0` $path/compile-netware-standard diff --git a/netware/BUILD/compile-netware-debug b/netware/BUILD/compile-netware-debug index 2cd292c82fd..e44d64e3074 100755 --- a/netware/BUILD/compile-netware-debug +++ b/netware/BUILD/compile-netware-debug @@ -1,5 +1,11 @@ #! /bin/sh +# debug +#set -x + +# stop on errors +set -e + path=`dirname $0` . $path/compile-netware-START diff --git a/netware/BUILD/compile-netware-standard b/netware/BUILD/compile-netware-standard index c09337b5fe0..12cae1f024e 100755 --- a/netware/BUILD/compile-netware-standard +++ b/netware/BUILD/compile-netware-standard @@ -1,5 +1,12 @@ #! /bin/sh +# debug +#set -x + +# stop on errors +set -e + + path=`dirname $0` . $path/compile-netware-START diff --git a/netware/BUILD/cron-build b/netware/BUILD/cron-build new file mode 100755 index 00000000000..26ccde28e2a --- /dev/null +++ b/netware/BUILD/cron-build @@ -0,0 +1,46 @@ +#! /bin/sh + +# debug +#set -x + +# stop on errors +set -e + +# repository direcotry +repo_dir=`pwd` + +# show usage +show_usage() +{ + cat << EOF + +usage: cron-patch + +EOF + exit 0; +} + +echo "starting build..." + +# check for bk and repo_dir +bk help > /dev/null +repo_dir=`bk root $repo_dir` +cd $repo_dir + +# pull latest code +echo 'y' | bk pull + +# determine version +version=`grep -e "AM_INIT_AUTOMAKE(mysql, .*)" < configure.in | sed -e "s/AM_INIT_AUTOMAKE(mysql, \(.*\))/\1/"` +echo "version: $version" + +# latest revision +rev=`bk changes -e -n -d':REV:' | head -1` +echo "latest revision: $rev" + +# run bootstrap +./netware/BUILD/nwbootstrap --revision=$rev --suffix=$rev --build=all + +echo "done" + + diff --git a/netware/BUILD/crontab b/netware/BUILD/crontab new file mode 100755 index 00000000000..0097f8acaaf --- /dev/null +++ b/netware/BUILD/crontab @@ -0,0 +1,4 @@ +00 23 * * * (export PATH='/usr/local/bin:/usr/bin:/bin'; export DISPLAY=':0'; cd ~/bk/mysqldoc; echo 'y' | bk pull) +00 00 * * * (export PATH='/usr/local/bin:/usr/bin:/bin'; export DISPLAY=':0'; cd ~/bk/mysql-4.0; ./netware/BUILD/cron-build) +00 04 * * * (export PATH='/usr/local/bin:/usr/bin:/bin'; export DISPLAY=':0'; cd ~/bk/mysql-4.1; ./netware/BUILD/cron-build) + diff --git a/netware/BUILD/mwasmnlm b/netware/BUILD/mwasmnlm index c3501112aa5..381f84ec0c8 100755 --- a/netware/BUILD/mwasmnlm +++ b/netware/BUILD/mwasmnlm @@ -1,5 +1,8 @@ #! /bin/sh +# stop on errors +set -e + args=" $*" wine --debugmsg -all -- mwasmnlm $args diff --git a/netware/BUILD/mwccnlm b/netware/BUILD/mwccnlm index 9e989485bd9..cb2d62fe8cf 100755 --- a/netware/BUILD/mwccnlm +++ b/netware/BUILD/mwccnlm @@ -1,5 +1,8 @@ #! /bin/sh +# stop on errors +set -e + # mwccnlm is having a hard time understanding "-I./../include" # convert it to "-I../include" args=" "`echo $* | sed -e 's/-I.\/../-I../g'` diff --git a/netware/BUILD/mwldnlm b/netware/BUILD/mwldnlm index 7ad2872ccbb..28566fc5cb1 100755 --- a/netware/BUILD/mwldnlm +++ b/netware/BUILD/mwldnlm @@ -1,5 +1,8 @@ #! /bin/sh +# stop on errors +set -e + args=" $*" wine --debugmsg -all -- mwldnlm $args diff --git a/netware/BUILD/nwbootstrap b/netware/BUILD/nwbootstrap index 002e19c8e49..5d068e4e4de 100755 --- a/netware/BUILD/nwbootstrap +++ b/netware/BUILD/nwbootstrap @@ -3,11 +3,11 @@ # debug #set -x -path=`dirname $0` - # stop on errors set -e +path=`dirname $0` + # repository direcotry repo_dir=`pwd` @@ -24,6 +24,7 @@ temp_dir="" revision="" rev="" build="" +suffix="" mwenv="" # show usage @@ -81,6 +82,7 @@ for arg do --wine-build-dir=*) wine_build_dir=`echo "$arg" | sed -e "s;--wine-build-dir=;;"` ;; --revision=*) revision=`echo "$arg" | sed -e "s;--revision=;;"` ;; --build=*) build=`echo "$arg" | sed -e "s;--build=;;"` ;; + --suffix=*) suffix=`echo "$arg" | sed -e "s;--suffix=;;"` ;; --doc-dir=*) doc_dir=`echo "$arg" | sed -e "s;--doc-dir=;;"` ;; *) show_usage ;; esac @@ -111,6 +113,12 @@ echo "version: $version" # build target directory target_dir="$build_dir/mysql-$version" +# add suffix +if test $suffix +then + target_dir="$target_dir-$suffix" +fi + # delete any old target if test -d $target_dir.old; then rm -rf $target_dir.old; fi diff --git a/repl-tests/README b/repl-tests/README deleted file mode 100644 index 95611c6538d..00000000000 --- a/repl-tests/README +++ /dev/null @@ -1,12 +0,0 @@ -This directory contains a set of test cases for replication. To get it -to work on your system, install this version of MySQL on the master and on -the slave, configure them according to the Replication HOWTO in the manual, -modify include/master-slave.inc to specify correct connection parameters -for the master and the slave and do - -sh run-all-tests - -If you would like to add your own test case, create a directory -test-your-test-case-name, write your own run.test following the examples -in the other test cases. Note that you can create the files containing -the expected output ( master files) by running mysqltest --record < run.test
\ No newline at end of file diff --git a/repl-tests/include/master-slave.inc b/repl-tests/include/master-slave.inc deleted file mode 100644 index ad2dea1f520..00000000000 --- a/repl-tests/include/master-slave.inc +++ /dev/null @@ -1,2 +0,0 @@ -connect (slave,localhost,root,,test,0,/var/lib/mysql/mysql.sock); -connect (master,sarochka,admin,,test,0,0); diff --git a/repl-tests/run-all-tests b/repl-tests/run-all-tests deleted file mode 100755 index d9f08d8a8fb..00000000000 --- a/repl-tests/run-all-tests +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/sh - -for d in test-*; do -cd $d -echo -n $d | sed -e s/test-// -echo -n "...." -../../client/mysqltest $@ < run.test -cd .. -done
\ No newline at end of file diff --git a/repl-tests/test-auto-inc/run.test b/repl-tests/test-auto-inc/run.test deleted file mode 100755 index 8405329f458..00000000000 --- a/repl-tests/test-auto-inc/run.test +++ /dev/null @@ -1,10 +0,0 @@ -source ../include/master-slave.inc; -connection master; -drop table if exists x; -create table x(n int auto_increment primary key); -set insert_id = 2000; -insert into x values (NULL),(NULL),(NULL); -connection slave; -sleep 3; -@x.master select * from x; - diff --git a/repl-tests/test-auto-inc/x.master b/repl-tests/test-auto-inc/x.master deleted file mode 100644 index c76fc46ae97..00000000000 --- a/repl-tests/test-auto-inc/x.master +++ /dev/null @@ -1,4 +0,0 @@ -n -2000 -2001 -2002 diff --git a/repl-tests/test-bad-query/run.test b/repl-tests/test-bad-query/run.test deleted file mode 100755 index a86aaf84096..00000000000 --- a/repl-tests/test-bad-query/run.test +++ /dev/null @@ -1,10 +0,0 @@ -source ../include/master-slave.inc; -connection master; -drop table if exists x; -create table x(n int primary key); -!insert into x values (1),(2),(2); -insert into x values (3); -connection slave; -sleep 3; -@x.master select * from x; - diff --git a/repl-tests/test-bad-query/x.master b/repl-tests/test-bad-query/x.master deleted file mode 100644 index c62967af0bb..00000000000 --- a/repl-tests/test-bad-query/x.master +++ /dev/null @@ -1,4 +0,0 @@ -n -1 -2 -3 diff --git a/repl-tests/test-dump/run.test b/repl-tests/test-dump/run.test deleted file mode 100644 index c714186a67b..00000000000 --- a/repl-tests/test-dump/run.test +++ /dev/null @@ -1,25 +0,0 @@ -source ../include/master-slave.inc; -connection slave; -!slave stop; -flush slave; -connection master; -flush master; -connection slave; -slave start; -connection master; -use test; -drop table if exists words; -create table words (word char(20) not null, index(word)); -load data infile '/usr/dict/words' into table words; -drop table if exists words1; -create table words1 (word char(20) not null); -load data infile '/usr/dict/words' into table words1; -sleep 20; -connection slave; -use test; -drop table if exists words; -load table words from master; -drop table if exists words1; -load table words1 from master; -@table-dump-check.master check table words; -@table-dump-select.master select count(*) from words1; diff --git a/repl-tests/test-dump/table-dump-check.master b/repl-tests/test-dump/table-dump-check.master deleted file mode 100644 index 4061fdb4a0d..00000000000 --- a/repl-tests/test-dump/table-dump-check.master +++ /dev/null @@ -1,2 +0,0 @@ -Table Op Msg_type Msg_text -test.words check status OK diff --git a/repl-tests/test-dump/table-dump-select.master b/repl-tests/test-dump/table-dump-select.master deleted file mode 100644 index ae93d31c066..00000000000 --- a/repl-tests/test-dump/table-dump-select.master +++ /dev/null @@ -1,2 +0,0 @@ -count(*) -45402 diff --git a/repl-tests/test-repl-alter/run.test b/repl-tests/test-repl-alter/run.test deleted file mode 100644 index 2e031010d5c..00000000000 --- a/repl-tests/test-repl-alter/run.test +++ /dev/null @@ -1,12 +0,0 @@ -source ../include/master-slave.inc; -connection master; -drop table if exists test; -CREATE TABLE test (name varchar(64), age smallint(3)); -INSERT INTO test SET name='Andy', age=31; -INSERT test SET name='Jacob', age=2; -INSERT into test SET name='Caleb', age=1; -ALTER TABLE test ADD id int(8) ZEROFILL AUTO_INCREMENT PRIMARY KEY; -@test.master select * from test; -connection slave; -sleep 3; -@test.master select * from test; diff --git a/repl-tests/test-repl-alter/test.master b/repl-tests/test-repl-alter/test.master deleted file mode 100644 index 763154b938e..00000000000 --- a/repl-tests/test-repl-alter/test.master +++ /dev/null @@ -1,4 +0,0 @@ -name age id -Andy 31 00000001 -Jacob 2 00000002 -Caleb 1 00000003 diff --git a/repl-tests/test-repl-ts/repl-timestamp.master b/repl-tests/test-repl-ts/repl-timestamp.master deleted file mode 100644 index c3e4a2326d0..00000000000 --- a/repl-tests/test-repl-ts/repl-timestamp.master +++ /dev/null @@ -1,2 +0,0 @@ -unix_timestamp(t) -200006 diff --git a/repl-tests/test-repl-ts/repl-timestamp.master.reject b/repl-tests/test-repl-ts/repl-timestamp.master.reject deleted file mode 100644 index 091b18351ed..00000000000 --- a/repl-tests/test-repl-ts/repl-timestamp.master.reject +++ /dev/null @@ -1,2 +0,0 @@ -unix_timestamp(t) -973999074 diff --git a/repl-tests/test-repl-ts/run.test b/repl-tests/test-repl-ts/run.test deleted file mode 100644 index 0a5224ce02a..00000000000 --- a/repl-tests/test-repl-ts/run.test +++ /dev/null @@ -1,17 +0,0 @@ -#! ../client/mysqltest -# tests if the replicaion preserves timestamp properly - -source ../include/master-slave.inc; -connection master; -set timestamp=200006; -drop table if exists foo; -create table foo(t timestamp not null,a char(1)); -insert into foo ( a) values ('F'); -@repl-timestamp.master select unix_timestamp(t) from foo; -sleep 3; -connection slave; -drop table if exists foo; -load table foo from master; -@repl-timestamp.master select unix_timestamp(t) from foo; - - diff --git a/repl-tests/test-repl/foo-dump-master.master b/repl-tests/test-repl/foo-dump-master.master deleted file mode 100644 index 982e0523cfb..00000000000 --- a/repl-tests/test-repl/foo-dump-master.master +++ /dev/null @@ -1,3 +0,0 @@ -n -1 -2 diff --git a/repl-tests/test-repl/foo-dump-slave.master b/repl-tests/test-repl/foo-dump-slave.master deleted file mode 100644 index 982e0523cfb..00000000000 --- a/repl-tests/test-repl/foo-dump-slave.master +++ /dev/null @@ -1,3 +0,0 @@ -n -1 -2 diff --git a/repl-tests/test-repl/run.test b/repl-tests/test-repl/run.test deleted file mode 100755 index cc93d964efa..00000000000 --- a/repl-tests/test-repl/run.test +++ /dev/null @@ -1,24 +0,0 @@ -source ../include/master-slave.inc; -connection slave; -!slave stop; -connection master; -flush master; -connection slave; -flush slave; -!slave start; -sleep 3; -connection master; -use test; -drop table if exists words; -create table words (word char(20) not null, index(word)); -load data infile '/usr/dict/words' into table words; -drop table if exists foo; -create table foo(n int); -insert into foo values(1),(2); -@foo-dump-master.master select * from foo; -@sum-wlen-master.master select sum(length(word)) from words; -connection slave; -sleep 15; -use test; -@sum-wlen-slave.master select sum(length(word)) from words; -@foo-dump-slave.master select * from foo; diff --git a/repl-tests/test-repl/sum-wlen-master.master b/repl-tests/test-repl/sum-wlen-master.master deleted file mode 100644 index e749ab4840a..00000000000 --- a/repl-tests/test-repl/sum-wlen-master.master +++ /dev/null @@ -1,2 +0,0 @@ -sum(length(word)) -363634 diff --git a/repl-tests/test-repl/sum-wlen-slave.master b/repl-tests/test-repl/sum-wlen-slave.master deleted file mode 100644 index e749ab4840a..00000000000 --- a/repl-tests/test-repl/sum-wlen-slave.master +++ /dev/null @@ -1,2 +0,0 @@ -sum(length(word)) -363634 diff --git a/scripts/mysql_fix_privilege_tables.sh b/scripts/mysql_fix_privilege_tables.sh index 83ee5023b89..05d6f3ffb71 100644 --- a/scripts/mysql_fix_privilege_tables.sh +++ b/scripts/mysql_fix_privilege_tables.sh @@ -1,14 +1,5 @@ #!/bin/sh -echo "This scripts updates the mysql.user, mysql.db, mysql.host and the" -echo "mysql.func tables to MySQL 3.22.14 and above." -echo "" -echo "This is needed if you want to use the new GRANT functions," -echo "CREATE AGGREGATE FUNCTION or want to use the more secure passwords in 3.23" -echo "" -echo "If you get 'Access denied' errors, you should run this script again" -echo "and give the MySQL root user password as an argument!" - root_password="$1" host="localhost" user="root" @@ -20,6 +11,21 @@ else cmd="@bindir@/mysql -f --user=$user --password=$root_password --host=$host mysql" fi +# Debian addition +if [ "$1" = "--sql-only" ]; then + root_password="" + cmd="/usr/share/mysql/echo_stderr" +fi + +echo "This scripts updates the mysql.user, mysql.db, mysql.host and the" +echo "mysql.func tables to MySQL 3.22.14 and above." +echo "" +echo "This is needed if you want to use the new GRANT functions," +echo "CREATE AGGREGATE FUNCTION or want to use the more secure passwords in 3.23" +echo "" +echo "If you get 'Access denied' errors, you should run this script again" +echo "and give the MySQL root user password as an argument!" + echo "Converting all privilege tables to MyISAM format" $cmd <<END_OF_DATA ALTER TABLE user type=MyISAM; diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index 1a969895f7f..b5048054832 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -147,7 +147,8 @@ then resolved=`$bindir/resolveip localhost 2>&1` if [ $? -eq 0 ] then - echo "Sorry, the host '$hostname' could not be looked up." + echo "Neither host '$hostname' and 'localhost' could not be looked up with" + echo "$bindir/resolveip" echo "Please configure the 'hostname' command to return a correct hostname." echo "If you want to solve this at a later stage, restart this script with" echo "the --force option" @@ -164,14 +165,12 @@ fi # Create database directories mysql & test if test "$in_rpm" -eq 0 || "$windows" -eq 0 -then if test ! -d $ldata; then mkdir $ldata; chmod 700 $ldata ; fi if test ! -d $ldata/mysql; then mkdir $ldata/mysql; chmod 700 $ldata/mysql ; fi if test ! -d $ldata/test; then mkdir $ldata/test; chmod 700 $ldata/test ; fi if test -w / -a ! -z "$user"; then chown $user $ldata $ldata/mysql $ldata/test; fi -fi # Initialize variables c_d="" i_d="" diff --git a/scripts/mysql_setpermission.sh b/scripts/mysql_setpermission.sh index 43bf8a14c06..9699cd28047 100644 --- a/scripts/mysql_setpermission.sh +++ b/scripts/mysql_setpermission.sh @@ -16,20 +16,25 @@ ## 1.2 begin screen now in a loop + quit is using 0 instead of 9 ## after ideas of Paul DuBois. ## 1.2a Add Grant, References, Index and Alter privilege handling (Monty) +## 1.3 Applied patch provided by Martin Mokrejs <mmokrejs@natur.cuni.cz> +## (General code cleanup, use the GRANT statement instead of updating +## the privilege tables directly, added option to revoke privileges) #### TODO # # empty ... suggestions ... mail them to me ... -$version="1.2"; +$version="1.3"; use DBI; use Getopt::Long; use strict; -use vars qw($dbh $hostname $opt_user $opt_password $opt_help $opt_host +use vars qw($dbh $sth $hostname $opt_user $opt_password $opt_help $opt_host $opt_socket $opt_port $host $version); +my $sqlhost = ""; +my $user = ""; $dbh=$host=$opt_user= $opt_password= $opt_help= $opt_host= $opt_socket= ""; $opt_port=0; @@ -42,11 +47,11 @@ usage() if ($opt_help); # the help function if ($opt_host eq '') { - $hostname = "localhost"; + $sqlhost = "localhost"; } else { - $hostname = $opt_host; + $sqlhost = $opt_host; } # ask for a password if no password is set already @@ -62,7 +67,7 @@ if ($opt_password eq '') # make the connection to MySQL -$dbh= DBI->connect("DBI:mysql:mysql:host=$hostname:port=$opt_port:mysql_socket=$opt_socket",$opt_user,$opt_password, {PrintError => 0}) || +$dbh= DBI->connect("DBI:mysql:mysql:host=$sqlhost:port=$opt_port:mysql_socket=$opt_socket",$opt_user,$opt_password, {PrintError => 0}) || die("Can't make a connection to the mysql server.\n The error: $DBI::errstr"); # the start of the program @@ -86,27 +91,44 @@ sub q1 { # first question ... print "#"x70; print "\n"; print "What would you like to do:\n"; - print " 1. Set password for a user.\n"; - print " 2. Add a database + user privilege for that database.\n"; - print " - user can do all except all admin functions\n"; - print " 3. Add user privilege for an existing database.\n"; - print " - user can do all except all admin functions\n"; - print " 4. Add user privilege for an existing database.\n"; - print " - user can do all except all admin functions + no create/drop\n"; - print " 5. Add user privilege for an existing database.\n"; - print " - user can do only selects (no update/delete/insert etc.)\n"; + print " 1. Set password for an existing user.\n"; + print " 2. Create a database + user privilege for that database\n"; + print " and host combination (user can only do SELECT)\n"; + print " 3. Create/append user privilege for an existing database\n"; + print " and host combination (user can only do SELECT)\n"; + print " 4. Create/append broader user privileges for an existing\n"; + print " database and host combination\n"; + print " (user can do SELECT,INSERT,UPDATE,DELETE)\n"; + print " 5. Create/append quite extended user privileges for an\n"; + print " existing database and host combination (user can do\n"; + print " SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,\n"; + print " LOCK TABLES,CREATE TEMPORARY TABLES)\n"; + print " 6. Create/append database administrative privileges for an\n"; + print " existing database and host combination (user can do\n"; + print " SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,LOCK TABLES,\n"; + print " CREATE TEMPORARY TABLES,SHOW DATABASES,PROCESS)\n"; + print " 7. Create/append full privileges for an existing database\n"; + print " and host combination (user has FULL privilege)\n"; + print " 8. Remove all privileges for for an existing database and\n"; + print " host combination.\n"; + print " (user will have all permission fields set to N)\n"; print " 0. exit this program\n"; - print "\nMake your choice [1,2,3,4,5,0]: "; + print "\nMake your choice [1,2,3,4,5,6,7,0]: "; while (<STDIN>) { $answer = $_; chomp($answer); - if ($answer =~ /1|2|3|4|5|0/) { - &setpwd if ($answer == 1); - &addall($answer) if ($answer =~ /^[2345]$/); - if ($answer == 0) { - print "Sorry, hope we can help you next time \n\n"; + if ($answer =~ /^[12345678]$/) { + if ($answer == 1) { + setpwd(); + } elsif ($answer =~ /^[2345678]$/) { + addall($answer); + } else { + print "Sorry, something went wrong. With such option number you should not get here.\n\n"; $end = 1; } + } elsif ($answer == 0) { + print "We hope we can help you next time \n\n"; + $end = 1; } else { print "Your answer was $answer\n"; print "and that's wrong .... Try again\n"; @@ -121,7 +143,7 @@ sub q1 { # first question ... ### sub setpwd { - my ($user,$pass,$host); + my ($user,$pass,$host) = ""; print "\n\nSetting a (new) password for a user.\n"; $user = user(); @@ -168,22 +190,18 @@ sub setpwd ### # all things which will be added are done here ### -sub addall -{ +sub addall { my ($todo) = @_; my ($answer,$good,$db,$user,$pass,$host,$priv); - if ($todo == 2) - { + if ($todo == 2) { $db = newdatabase(); - } - else - { + } else { $db = database(); } $user = newuser(); - $pass = newpass(); + $pass = newpass("$user"); $host = newhosts(); print "#"x70; @@ -198,104 +216,80 @@ sub addall print "Are you pretty sure you would like to implement this [yes/no]: "; my $no = <STDIN>; chomp($no); - if ($no =~ /n/i) - { + if ($no =~ /n/i) { print "Okay .. that was it then ... See ya\n\n"; return(0); - } - else - { + } else { print "Okay ... let's go then ...\n\n"; } - if ($todo == 2) - { + if ($todo == 2) { # create the database - my $sth = $dbh->do("create database $db") || $dbh->errstr; - } - - # select the privilege .... - if (($todo == 2) || ($todo == 3)) - { - $priv = "'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y'"; + if ($db) { + my $sth = $dbh->do("CREATE DATABASE $db") || $dbh->errstr; + } else { + print STDERR "What do you want? You wanted to create new database and add new user, right?\n"; + die "But then specify databasename, please\n"; } - elsif ($todo == 4) - { - $priv = "'Y','Y','Y','Y','N','N','N','Y','Y','Y'"; } - elsif ($todo == 5) - { - $priv = "'Y','N','N','N','N','N','N','N','N','N'"; - } - else - { - print "Sorry, choice number $todo isn't known inside the program .. See ya\n"; + + if ( ( !$todo ) or not ( $todo =~ m/^[2-8]$/ ) ) { + print STDERR "Sorry, select option $todo isn't known inside the program .. See ya\n"; quit(); } my @hosts = split(/,/,$host); - $user = $dbh->quote($user); - $db = $dbh->quote($db); - if ($pass eq '') - { - $pass = "''"; + if (!$user) { + die "username not specified: $user\n"; } - else - { - $pass = "PASSWORD(". $dbh->quote($pass) . ")"; + if (!$db) { + die "databasename is not specified nor *\n"; } - foreach my $key (@hosts) - { - my $key1 = $dbh->quote($key); - my $sth = $dbh->prepare("select Host,User from user where Host = $key1 and User = $user") || die $dbh->errstr; - $sth->execute || die $dbh->errstr; - my @r = $sth->fetchrow_array; - if ($r[0]) - { - print "WARNING WARNING SKIPPING CREATE FOR USER $user AND HOST $key\n"; - print "Reason: entry already exists in the user table.\n"; + foreach $host (@hosts) { + # user privileges: SELECT + if (($todo == 2) || ($todo == 3)) { + $sth = $dbh->do("GRANT SELECT ON $db.* TO $user@\"$host\" IDENTIFIED BY \'$pass\'") || die $dbh->errstr; + } elsif ($todo == 4) { + # user privileges: SELECT,INSERT,UPDATE,DELETE + $sth = $dbh->do("GRANT SELECT,INSERT,UPDATE,DELETE ON $db.* TO $user@\"$host\" IDENTIFIED BY \'$pass\'") || die $dbh->errstr; + } elsif ($todo == 5) { + # user privileges: SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,LOCK TABLES,CREATE TEMPORARY TABLES + $sth = $dbh->do("GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,LOCK TABLES,CREATE TEMPORARY TABLES ON $db.* TO $user@\"$host\" IDENTIFIED BY \'$pass\'") || die $dbh->errstr; + } elsif ($todo == 6) { + # admin privileges: GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,LOCK TABLES,CREATE TEMPORARY TABLES,SHOW DATABASES,PROCESS + $sth = $dbh->do("GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,LOCK TABLES,CREATE TEMPORARY TABLES,SHOW DATABASES,PROCESS ON $db.* TO $user@\"$host\" IDENTIFIED BY \'$pass\'") || die $dbh->errstr; + } elsif ($todo == 7) { + # all privileges + $sth = $dbh->do("GRANT ALL ON $db.* TO \'$user\'\@\'$host\' IDENTIFIED BY \'$pass\'") || die $dbh->errstr; + } elsif ($todo == 8) { + # all privileges set to N + $sth = $dbh->do("REVOKE ALL ON *.* FROM \'$user\'\@\'$host\'") || die $dbh->errstr; } - else - { - $sth = $dbh->prepare("insert into user (Host,User,Password) values($key1,$user,$pass)") || die $dbh->errstr; - $sth->execute || die $dbh->errstr; - $sth->finish; } - $sth = $dbh->prepare("INSERT INTO db (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Grant_priv,References_priv,Index_priv,Alter_priv) VALUES ($key1,$db,$user,$priv)") || die $dbh->errstr; - $sth->execute || die $dbh->errstr; - $sth->finish; - } - $dbh->do("flush privileges") || print "Can't load privileges\n"; + $dbh->do("FLUSH PRIVILEGES") || print STDERR "Can't flush privileges\n"; print "Everything is inserted and mysql privileges have been reloaded.\n\n"; } ### # ask for a new database name ### -sub newdatabase -{ +sub newdatabase { my ($answer,$good,$db); print "\n\nWhich database would you like to add: "; - while (<STDIN>) - { + while (<STDIN>) { $answer = $_; $good = 0; chomp($answer); - if ($answer) - { - my $sth = $dbh->prepare("show databases") || die $dbh->errstr; + if ($answer) { + my $sth = $dbh->prepare("SHOW DATABASES") || die $dbh->errstr; $sth->execute || die $dbh->errstr; - while (my @r = $sth->fetchrow_array) - { - if ($r[0] eq $answer) - { + while (my @r = $sth->fetchrow_array) { + if ($r[0] eq $answer) { print "\n\nSorry, this database name is already in use; try something else: "; $good = 1; } } - } - else - { + } else { print "You must type something ...\nTry again: "; next; } @@ -309,48 +303,44 @@ sub newdatabase ### # select a database ### -sub database -{ +sub database { my ($answer,$good,$db); - print "\n\nWhich database would you like to select: \n"; + print "\n\nWhich database from existing databases would you like to select: \n"; print "You can choose from: \n"; my $sth = $dbh->prepare("show databases") || die $dbh->errstr; $sth->execute || die $dbh->errstr; - while (my @r = $sth->fetchrow_array) - { + while (my @r = $sth->fetchrow_array) { print " - $r[0] \n"; } - print "Which database will it be (case sensitive): "; - while (<STDIN>) - { + print "Which database will it be (case sensitive). Type * for any: \n"; + while (<STDIN>) { $answer = $_; $good = 0; chomp($answer); - if ($answer) - { + if ($answer) { + if ($answer eq "*") { + print "OK, the user entry will NOT be limited to any database"; + return("*"); + } my $sth = $dbh->prepare("show databases") || die $dbh->errstr; $sth->execute || die $dbh->errstr; - while (my @r = $sth->fetchrow_array) - { - if ($r[0] eq $answer) - { + while (my @r = $sth->fetchrow_array) { + if ($r[0] eq $answer) { $good = 1; $db = $r[0]; last; } } - } - else - { - print "You must type something ...\nTry again: "; + } else { + print "Type either database name or * meaning any databasename. That means"; + print " any of those above but also any which will be created in future!"; + print " This option gives a user chance to operate on databse mysql, which"; + print " contains privilege settings. That is really risky!\n"; next; } - if ($good == 1) - { + if ($good == 1) { last; - } - else - { + } else { print "You must select one from the list.\nTry again: "; next; } @@ -364,7 +354,8 @@ sub database ### sub newuser { - my ($answer,$user); + my $user = ""; + my $answer = ""; print "\nWhat username is to be created: "; while(<STDIN>) @@ -430,7 +421,7 @@ sub user sub newpass { my ($user) = @_; - my ($answer,$good,$pass,$yes); + my ($pass,$answer,$good,$yes); print "Would you like to set a password for $user [y/n]: "; $yes = <STDIN>; @@ -487,7 +478,7 @@ sub newpass ### sub newhosts { - my ($answer,$good,$host); + my ($host,$answer,$good); print "We now need to know from what host(s) the user will connect.\n"; print "Keep in mind that % means 'from any host' ...\n"; diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 094b1fbfcd3..e400c27b84c 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -224,7 +224,7 @@ then if test -n "$open_files" then ulimit -n $open_files - args="open-files-limit=$open_files $args" + args="--open-files-limit=$open_files $args" fi if test -n "$core_file_size" then diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index ec76aa479f3..a89a8919752 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -55,7 +55,8 @@ Usage: $0 db_name[./table_regex/] [new_db_name | directory] -P, --port=# port to use when connecting to local server with TCP/IP -S, --socket=# socket to use when connecting to local server - --allowold don\'t abort if target already exists (rename it _old) + --allowold don\'t abort if target dir already exists (rename it _old) + --addtodest don\'t rename target dir if it exists, just add files to it --keepold don\'t delete previous (now renamed) target when done --noindices don\'t include full index files in copy --method=# method for copy (only "cp" currently supported) @@ -98,6 +99,7 @@ GetOptions( \%opt, "socket|S=s", "allowold!", "keepold!", + "addtodest!", "noindices!", "method=s", "debug", @@ -380,14 +382,14 @@ if ($opt{method} =~ /^cp\b/) push @existing, $rdb->{target} if ( -d $rdb->{target} ); } - if ( @existing && !$opt{allowold} ) + if ( @existing && !($opt{allowold} || $opt{addtodest}) ) { $dbh->disconnect(); - die "Can't hotcopy to '", join( "','", @existing ), "' because directory\nalready exist and the --allowold option was not given.\n" + die "Can't hotcopy to '", join( "','", @existing ), "' because directory\nalready exist and the --allowold or --addtodest options were not given.\n" } } -retire_directory( @existing ) if ( @existing ); +retire_directory( @existing ) if @existing && !$opt{addtodest}; foreach my $rdb ( @db_desc ) { foreach my $td ( '', @{$rdb->{raid_dirs}} ) { @@ -403,8 +405,8 @@ foreach my $rdb ( @db_desc ) { ## ... } else { - mkdir($tgt_dirpath, 0750) - or die "Can't create '$tgt_dirpath': $!\n"; + mkdir($tgt_dirpath, 0750) or die "Can't create '$tgt_dirpath': $!\n" + unless -d $tgt_dirpath; } } } @@ -861,6 +863,22 @@ Any existing versions of the backup directory are deleted. Behaves as for the --allowold, with the additional feature of keeping the backup directory after the copy successfully completes. +=item --addtodest + +Don't rename target directory if it already exists, just add the +copied files into it. + +This is most useful when backing up a database with many large +tables and you don't want to have all the tables locked for the +whole duration. + +In this situation, I<if> you are happy for groups of tables to be +backed up separately (and thus possibly not be logically consistant +with one another) then you can run mysqlhotcopy several times on +the same database each with different db_name./table_regex/. +All but the first should use the --addtodest option so the tables +all end up in the same directory. + =item --flushlog Rotate the log files by executing "FLUSH LOGS" after all tables are @@ -869,13 +887,13 @@ locked, and before they are copied. =item --resetmaster Reset the bin-log by executing "RESET MASTER" after all tables are -locked, and before they are copied. Usefull if you are recovering a +locked, and before they are copied. Useful if you are recovering a slave in a replication setup. =item --resetslave Reset the master.info by executing "RESET SLAVE" after all tables are -locked, and before they are copied. Usefull if you are recovering a +locked, and before they are copied. Useful if you are recovering a server in a mutual replication setup. =item --regexp pattern @@ -941,7 +959,7 @@ will vary with your ability to understand how scp works. 'man scp' and 'man ssh' are your friends. The destination directory _must exist_ on the target machine using the -scp method. --keepold and --allowold are meeningless with scp. +scp method. --keepold and --allowold are meaningless with scp. Liberal use of the --debug option will help you figure out what\'s really going on when you do an scp. diff --git a/sql-bench/Makefile.am b/sql-bench/Makefile.am index ab6be7269e3..579a2a9f7fe 100644 --- a/sql-bench/Makefile.am +++ b/sql-bench/Makefile.am @@ -41,12 +41,9 @@ EXTRA_DIST = $(EXTRA_SCRIPTS) dist-hook: mkdir -p $(distdir)/Data/ATIS $(distdir)/Data/Wisconsin \ - $(distdir)/Results $(distdir)/Results-win32 \ $(distdir)/limits $(distdir)/Comments for i in $(srcdir)/Data/ATIS/*.* ; do $(INSTALL_DATA) $$i $(distdir)/Data/ATIS ; done for i in $(srcdir)/Data/Wisconsin/*.* ; do $(INSTALL_DATA) $$i $(distdir)/Data/Wisconsin ; done - for i in $(srcdir)/Results/*-* ; do $(INSTALL_DATA) $$i $(distdir)/Results; done - for i in $(srcdir)/Results-win32/*-* ; do $(INSTALL_DATA) $$i $(distdir)/Results-win32; done for i in $(srcdir)/limits/*.* ; do $(INSTALL_DATA) $$i $(distdir)/limits; done for i in $(srcdir)/Comments/*.* ; do $(INSTALL_DATA) $$i $(distdir)/Comments; done @@ -55,15 +52,11 @@ install-data-local: $(DESTDIR)$(benchdir)/Data \ $(DESTDIR)$(benchdir)/Data/ATIS \ $(DESTDIR)$(benchdir)/Data/Wisconsin \ - $(DESTDIR)$(benchdir)/Results \ - $(DESTDIR)$(benchdir)/Results-win32 \ $(DESTDIR)$(benchdir)/limits \ $(DESTDIR)$(benchdir)/Comments $(INSTALL_DATA) $(srcdir)/README $(DESTDIR)$(benchdir) for i in $(srcdir)/Data/ATIS/*.* ; do $(INSTALL_DATA) $$i $(DESTDIR)$(benchdir)/Data/ATIS ; done for i in $(srcdir)/Data/Wisconsin/*.* ; do $(INSTALL_DATA) $$i $(DESTDIR)$(benchdir)/Data/Wisconsin ; done - for i in $(srcdir)/Results/*-* ; do $(INSTALL_DATA) $$i $(DESTDIR)$(benchdir)/Results; done - for i in $(srcdir)/Results-win32/*-* ; do $(INSTALL_DATA) $$i $(DESTDIR)$(benchdir)/Results-win32; done for i in $(srcdir)/limits/*.* ; do $(INSTALL_DATA) $$i $(DESTDIR)$(benchdir)/limits; done for i in $(srcdir)/Comments/*.* ; do $(INSTALL_DATA) $$i $(DESTDIR)$(benchdir)/Comments; done diff --git a/sql-bench/crash-me.sh b/sql-bench/crash-me.sh index 61468d69fb1..ff649acdae4 100644 --- a/sql-bench/crash-me.sh +++ b/sql-bench/crash-me.sh @@ -2734,6 +2734,51 @@ assert("drop table crash_me_n $drop_attr"); +$key = 'sorted_group_by'; +$prompt = 'Group by always sorted'; +if (!defined($limits{$key})) +{ + save_incomplete($key,$prompt); + print "$prompt="; + safe_query_l($key,[ + "create table crash_me_t1 (a int not null, b int not null)", + "insert into crash_me_t1 values (1,1)", + "insert into crash_me_t1 values (1,2)", + "insert into crash_me_t1 values (3,1)", + "insert into crash_me_t1 values (3,2)", + "insert into crash_me_t1 values (2,2)", + "insert into crash_me_t1 values (2,1)", + "create table crash_me_t2 (a int not null, b int not null)", + "create index crash_me_t2_ind on crash_me_t2 (a)", + "insert into crash_me_t2 values (1,3)", + "insert into crash_me_t2 values (3,1)", + "insert into crash_me_t2 values (2,2)", + "insert into crash_me_t2 values (1,1)"]); + + my $bigqry = "select crash_me_t1.a,crash_me_t2.b from ". + "crash_me_t1,crash_me_t2 where crash_me_t1.a=crash_me_t2.a ". + "group by crash_me_t1.a,crash_me_t2.b"; + + my $limit='no'; + my $rs = get_recordset($key,$bigqry); + print_recordset($key,$rs); + if ( defined ($rs)) { + if (compare_recordset($key,$rs,[[1,1],[1,3],[2,2],[3,1]]) eq 0) + { + $limit='yes' + } + } else { + add_log($key,"error: ".$DBI::errstr); + } + + print "$limit\n"; + safe_query_l($key,["drop table crash_me_t1", + "drop table crash_me_t2"]); + save_config_data($key,$limit,$prompt); + +} else { + print "$prompt=$limits{$key} (cashed)\n"; +} # diff --git a/sql/convert.cc b/sql/convert.cc index bfdf49bf42d..880c462f4aa 100644 --- a/sql/convert.cc +++ b/sql/convert.cc @@ -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 */ -#if 0 +#ifdef NOT_USED /* ** Convert tables between different character sets @@ -462,4 +462,4 @@ bool CONVERT::store(String *packet,const char *from,uint length) return 0; } -#endif +#endif /* NOT_USED */ diff --git a/sql/field.cc b/sql/field.cc index 3b358446da1..5c3961a949e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -161,6 +161,14 @@ static bool test_if_real(const char *str,int length, CHARSET_INFO *cs) } +static inline uint field_length_without_space(const char *ptr, uint length) +{ + const char *end= ptr+length; + while (end > ptr && end[-1] == ' ') + end--; + return (uint) (end-ptr); +} + /**************************************************************************** ** Functions for the base classes ** This is an unpacked number. @@ -3616,11 +3624,11 @@ bool Field_newdate::get_date(TIME *ltime,bool fuzzydate) if (is_null()) return 1; uint32 tmp=(uint32) uint3korr(ptr); - bzero((char*) ltime,sizeof(*ltime)); ltime->day= tmp & 31; ltime->month= (tmp >> 5) & 15; ltime->year= (tmp >> 9); ltime->time_type=TIMESTAMP_DATE; + ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; return (!fuzzydate && (!ltime->month || !ltime->day)) ? 1 : 0; } @@ -3983,9 +3991,19 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)), int Field_string::cmp(const char *a_ptr, const char *b_ptr) { - return my_strnncoll(field_charset, - (const uchar*)a_ptr,field_length, - (const uchar*)b_ptr,field_length); + if (field_charset->strxfrm_multiply > 1) + { + /* + We have to remove end space to be able to compare multi-byte-characters + like in latin_de 'ae' and 0xe4 + */ + return field_charset->strnncollsp(field_charset, + (const uchar*) a_ptr, field_length, + (const uchar*) b_ptr, field_length); + } + return field_charset->strnncoll(field_charset, + (const uchar*) a_ptr, field_length, + (const uchar*) b_ptr, field_length); } void Field_string::sort_string(char *to,uint length) diff --git a/sql/field.h b/sql/field.h index 8e395b7cace..cf08b1a9717 100644 --- a/sql/field.h +++ b/sql/field.h @@ -134,6 +134,8 @@ public: Field *tmp= (Field*) memdup_root(root,(char*) this,size_of()); if (tmp) { + if (tmp->table->maybe_null) + tmp->flags&= ~NOT_NULL_FLAG; tmp->table= new_table; tmp->key_start= tmp->part_of_key= tmp->part_of_sortkey= 0; tmp->unireg_check=Field::NONE; diff --git a/sql/filesort.cc b/sql/filesort.cc index a3d24cd9242..2130bdaeb93 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -76,7 +76,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, ulong memavl, min_sort_memory; uint maxbuffer; BUFFPEK *buffpek; - ha_rows records; + ha_rows records= HA_POS_ERROR; uchar **sort_keys; IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile; SORTPARAM param; @@ -494,6 +494,7 @@ static void make_sortkey(register SORTPARAM *param, sort_field != param->end ; sort_field++) { + bool maybe_null=0; if ((field=sort_field->field)) { // Field if (field->maybe_null()) @@ -519,7 +520,7 @@ static void make_sortkey(register SORTPARAM *param, case STRING_RESULT: { CHARSET_INFO *cs=item->charset(); - if (item->maybe_null) + if ((maybe_null=item->maybe_null)) *to++=1; /* All item->str() to use some extra byte for end null.. */ String tmp((char*) to,sort_field->length+4,cs); @@ -567,7 +568,7 @@ static void make_sortkey(register SORTPARAM *param, case INT_RESULT: { longlong value=item->val_int(); - if (item->maybe_null) + if ((maybe_null=item->maybe_null)) *to++=1; /* purecov: inspected */ if (item->null_value) { @@ -601,13 +602,13 @@ static void make_sortkey(register SORTPARAM *param, case REAL_RESULT: { double value=item->val(); - if (item->null_value) + if ((maybe_null=item->null_value)) { bzero((char*) to,sort_field->length+1); to++; break; } - if (item->maybe_null) + if ((maybe_null=item->maybe_null)) *to++=1; change_double_for_sort(value,(byte*) to); break; @@ -621,6 +622,8 @@ static void make_sortkey(register SORTPARAM *param, } if (sort_field->reverse) { /* Revers key */ + if (maybe_null) + to[-1]= ~to[-1]; length=sort_field->length; while (length--) { diff --git a/sql/ha_heap.h b/sql/ha_heap.h index fe874dab3f2..c369c7029b4 100644 --- a/sql/ha_heap.h +++ b/sql/ha_heap.h @@ -53,8 +53,9 @@ class ha_heap: public handler uint max_keys() const { return MAX_KEY; } uint max_key_parts() const { return MAX_REF_PARTS; } uint max_key_length() const { return HA_MAX_REC_LENGTH; } - virtual double scan_time() { return (double) (records+deleted) / 20.0+10; } - virtual double read_time(ha_rows rows) { return (double) rows / 20.0+1; } + double scan_time() { return (double) (records+deleted) / 20.0+10; } + double read_time(uint index, uint ranges, ha_rows rows) + { return (double) rows / 20.0+1; } virtual bool fast_key_read() { return 1;} int open(const char *name, int mode, uint test_if_locked); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 4f955d8f79e..a426dc5a9a9 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -100,7 +100,7 @@ char* innobase_unix_file_flush_method = NULL; /* Below we have boolean-valued start-up parameters, and their default values */ -uint innobase_flush_log_at_trx_commit = 0; +uint innobase_flush_log_at_trx_commit = 1; my_bool innobase_log_archive = FALSE; my_bool innobase_use_native_aio = FALSE; my_bool innobase_fast_shutdown = TRUE; @@ -242,6 +242,10 @@ convert_error_code_to_mysql( return(HA_ERR_CANNOT_ADD_FOREIGN); + } else if (error == (int) DB_CANNOT_DROP_CONSTRAINT) { + + return(HA_WRONG_CREATE_OPTION); + } else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) { return(HA_ERR_CRASHED); @@ -597,7 +601,7 @@ innobase_invalidate_query_cache( Call this when you have opened a new table handle in HANDLER, before you call index_read_idx() etc. Actually, we can let the cursor stay open even over a transaction commit! Then you should call this before every operation, -fecth next etc. This function inits the necessary things even after a +fetch next etc. This function inits the necessary things even after a transaction commit. */ void @@ -644,6 +648,8 @@ ha_innobase::init_table_handle_for_HANDLER(void) we???? */ prebuilt->read_just_key = FALSE; + + prebuilt->used_in_HANDLER = TRUE; } /************************************************************************* @@ -883,7 +889,7 @@ innobase_flush_logs(void) DBUG_ENTER("innobase_flush_logs"); - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); DBUG_RETURN(result); } @@ -932,7 +938,7 @@ Commits a transaction in an InnoDB database. */ int innobase_commit( /*============*/ - /* out: 0 or error number */ + /* out: 0 */ THD* thd, /* in: MySQL thread handle of the user for whom the transaction should be committed */ void* trx_handle)/* in: InnoDB trx handle or @@ -940,7 +946,6 @@ innobase_commit( that the current SQL statement ended, and we should mark the start of a new statement with a savepoint */ { - int error = 0; trx_t* trx; DBUG_ENTER("innobase_commit"); @@ -967,29 +972,27 @@ innobase_commit( innobase_release_stat_resources(trx); trx_mark_sql_stat_end(trx); -#ifndef DBUG_OFF - if (error) { - DBUG_PRINT("error", ("error: %d", error)); - } -#endif /* Tell InnoDB server that there might be work for utility threads: */ srv_active_wake_master_thread(); - DBUG_RETURN(error); + DBUG_RETURN(0); } /********************************************************************* This is called when MySQL writes the binlog entry for the current transaction. Writes to the InnoDB tablespace info which tells where the MySQL binlog entry for the current transaction ended. Also commits the -transaction inside InnoDB. */ +transaction inside InnoDB but does NOT flush InnoDB log files to disk. +To flush you have to call innobase_flush_log_to_disk. We have separated +flushing to eliminate the bottleneck of LOCK_log in log.cc which disabled +InnoDB's group commit capability. */ int innobase_report_binlog_offset_and_commit( /*=====================================*/ - /* out: 0 or error code */ + /* out: 0 */ THD* thd, /* in: user thread */ void* trx_handle, /* in: InnoDB trx handle */ char* log_file_name, /* in: latest binlog file name */ @@ -1005,7 +1008,39 @@ innobase_report_binlog_offset_and_commit( trx->mysql_log_file_name = log_file_name; trx->mysql_log_offset = (ib_longlong)end_offset; - return(innobase_commit(thd, trx_handle)); + trx->flush_log_later = TRUE; + + innobase_commit(thd, trx_handle); + + trx->flush_log_later = FALSE; + + return(0); +} + +/********************************************************************* +This is called after MySQL has written the binlog entry for the current +transaction. Flushes the InnoDB log files to disk if required. */ + +int +innobase_commit_complete( +/*=====================*/ + /* out: 0 */ + void* trx_handle) /* in: InnoDB trx handle */ +{ + trx_t* trx; + + if (srv_flush_log_at_trx_commit == 0) { + + return(0); + } + + trx = (trx_t*)trx_handle; + + ut_a(trx != NULL); + + trx_commit_complete_for_mysql(trx); + + return(0); } /********************************************************************* @@ -1195,6 +1230,9 @@ ha_innobase::open( last_query_id = (ulong)-1; + active_index = 0; + active_index_before_scan = (uint)-1; /* undefined value */ + if (!(share=get_share(name))) DBUG_RETURN(1); @@ -1938,13 +1976,6 @@ ha_innobase::write_row( build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW); } - if (user_thd->lex.sql_command == SQLCOM_INSERT - && user_thd->lex.duplicates == DUP_IGNORE) { - prebuilt->trx->ignore_duplicates_in_insert = TRUE; - } else { - prebuilt->trx->ignore_duplicates_in_insert = FALSE; - } - srv_conc_enter_innodb(prebuilt->trx); error = row_insert_for_mysql((byte*) record, prebuilt); @@ -1985,8 +2016,6 @@ ha_innobase::write_row( } } - prebuilt->trx->ignore_duplicates_in_insert = FALSE; - error = convert_error_code_to_mysql(error, user_thd); /* Tell InnoDB server that there might be work for @@ -2057,7 +2086,8 @@ calc_row_difference( upd_t* uvect, /* in/out: update vector */ mysql_byte* old_row, /* in: old row in MySQL format */ mysql_byte* new_row, /* in: new row in MySQL format */ - struct st_table* table, /* in: table in MySQL data dictionary */ + struct st_table* table, /* in: table in MySQL data + dictionary */ mysql_byte* upd_buff, /* in: buffer to use */ row_prebuilt_t* prebuilt, /* in: InnoDB prebuilt struct */ THD* thd) /* in: user thread */ @@ -2107,8 +2137,10 @@ calc_row_difference( case DATA_VARCHAR: case DATA_BINARY: case DATA_VARMYSQL: - o_ptr = row_mysql_read_var_ref_noninline(&o_len, o_ptr); - n_ptr = row_mysql_read_var_ref_noninline(&n_len, n_ptr); + o_ptr = row_mysql_read_var_ref_noninline(&o_len, + o_ptr); + n_ptr = row_mysql_read_var_ref_noninline(&n_len, + n_ptr); default: ; } @@ -2556,7 +2588,7 @@ ha_innobase::change_active_index( /* MySQL changes the active index for a handle also during some queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX() - and then calculates te sum. Previously we played safe and used + and then calculates the sum. Previously we played safe and used the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary copying. Starting from MySQL-4.1 we use a more efficient flag here. */ @@ -2755,6 +2787,11 @@ ha_innobase::rnd_init( row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; + /* Store the active index value so that we can restore the original + value after a scan */ + + active_index_before_scan = active_index; + if (prebuilt->clust_index_was_generated) { err = change_active_index(MAX_KEY); } else { @@ -2767,13 +2804,25 @@ ha_innobase::rnd_init( } /********************************************************************* -Ends a table scan ???????????????? */ +Ends a table scan. */ int ha_innobase::rnd_end(void) /*======================*/ /* out: 0 or error number */ { + /* Restore the old active_index back; MySQL may assume that a table + scan does not change active_index. We only restore the value if + MySQL has called rnd_init before: sometimes MySQL seems to call + rnd_end WITHOUT calling rnd_init. */ + + if (active_index_before_scan != (uint)-1) { + + change_active_index(active_index_before_scan); + + active_index_before_scan = (uint)-1; + } + return(index_end()); } @@ -3088,6 +3137,9 @@ ha_innobase::create( trx_search_latch_release_if_reserved(parent_trx); trx = trx_allocate_for_mysql(); + + trx->mysql_thd = thd; + trx->mysql_query_str = &((*thd).query); if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { trx->check_foreigns = FALSE; @@ -3216,7 +3268,7 @@ ha_innobase::create( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); innobase_table = dict_table_get(norm_name, NULL); @@ -3271,6 +3323,9 @@ ha_innobase::delete_table( trx = trx_allocate_for_mysql(); + trx->mysql_thd = current_thd; + trx->mysql_query_str = &((*current_thd).query); + name_len = strlen(name); assert(name_len < 1000); @@ -3288,7 +3343,7 @@ ha_innobase::delete_table( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); /* Tell the InnoDB server that there might be work for utility threads: */ @@ -3349,6 +3404,8 @@ innobase_drop_database( my_casedn_str(system_charset_info, namebuf); #endif trx = trx_allocate_for_mysql(); + trx->mysql_thd = current_thd; + trx->mysql_query_str = &((*current_thd).query); error = row_drop_database_for_mysql(namebuf, trx); @@ -3356,7 +3413,7 @@ innobase_drop_database( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); /* Tell the InnoDB server that there might be work for utility threads: */ @@ -3408,6 +3465,8 @@ ha_innobase::rename_table( } trx = trx_allocate_for_mysql(); + trx->mysql_thd = current_thd; + trx->mysql_query_str = &((*current_thd).query); name_len1 = strlen(from); name_len2 = strlen(to); @@ -3426,7 +3485,7 @@ ha_innobase::rename_table( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); /* Tell the InnoDB server that there might be work for utility threads: */ @@ -3541,10 +3600,8 @@ ha_innobase::records_in_range( /************************************************************************* Gives an UPPER BOUND to the number of rows in a table. This is used in -filesort.cc and the upper bound must hold. TODO: Since the number of -rows in a table may change after this function is called, we still may -get a 'Sort aborted' error in filesort.cc of MySQL. The ultimate fix is to -improve the algorithm of filesort.cc. */ +filesort.cc and its better if the upper bound hold. +*/ ha_rows ha_innobase::estimate_number_of_rows(void) @@ -3610,6 +3667,29 @@ ha_innobase::scan_time() return((double) (prebuilt->table->stat_clustered_index_size)); } +/* + Calculate the time it takes to read a set of ranges through and index + This enables us to optimise reads for clustered indexes. +*/ + +double ha_innobase::read_time(uint index, uint ranges, ha_rows rows) +{ + ha_rows total_rows; + double time_for_scan; + if (index != table->primary_key) + return handler::read_time(index, ranges, rows); // Not clustered + if (rows <= 2) + return (double) rows; + /* + Assume that the read is proportional to scan time for all rows + one + seek per range. + */ + time_for_scan= scan_time(); + if ((total_rows= estimate_number_of_rows()) < rows) + return time_for_scan; + return (ranges + (double) rows / (double) total_rows * time_for_scan); +} + /************************************************************************* Returns statistics information of the table to the MySQL interpreter, in various fields of the handle object. */ @@ -3734,6 +3814,23 @@ ha_innobase::info( DBUG_VOID_RETURN; } +/************************************************************************** +Updates index cardinalities of the table, based on 10 random dives into +each index tree. This does NOT calculate exact statistics of the table. */ + +int +ha_innobase::analyze( +/*=================*/ + /* out: returns always 0 (success) */ + THD* thd, /* in: connection thread handle */ + HA_CHECK_OPT* check_opt) /* in: currently ignored */ +{ + /* Simply call ::info() with all the flags */ + info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE); + + return(0); +} + /*********************************************************************** Tries to check that an InnoDB table is not corrupted. If corruption is noticed, prints to stderr information about it. In case of corruption @@ -3915,7 +4012,7 @@ ha_innobase::extra( break; case HA_EXTRA_RESET_STATE: prebuilt->read_just_key = 0; - break; + break; case HA_EXTRA_NO_KEYREAD: prebuilt->read_just_key = 0; break; @@ -4084,6 +4181,8 @@ ha_innobase::external_lock( trx->mysql_n_tables_locked = 0; + prebuilt->used_in_HANDLER = FALSE; + /* Here we release the search latch and InnoDB thread FIFO ticket if they were reserved. */ diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index be1174added..9ca8475e75e 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -58,7 +58,15 @@ class ha_innobase: public handler ulong start_of_scan; /* this is set to 1 when we are starting a table scan but have not yet fetched any row, else 0 */ - + uint active_index_before_scan; + /* since a table scan in InnoDB is + always done through an index, a table + scan may change active_index; but + MySQL may assume that active_index + after a table scan is the same as + before; we store the value here so + that we can restore the value after + a scan */ uint last_match_mode;/* match mode of the latest search: ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX, or undefined */ @@ -118,6 +126,7 @@ class ha_innobase: public handler void initialize(void); int close(void); double scan_time(); + double read_time(uint index, uint ranges, ha_rows rows); int write_row(byte * buf); int update_row(const byte * old_data, byte * new_data); @@ -143,6 +152,7 @@ class ha_innobase: public handler void position(const byte *record); void info(uint); + int analyze(THD* thd,HA_CHECK_OPT* check_opt); int extra(enum ha_extra_function operation); int reset(void); int external_lock(THD *thd, int lock_type); @@ -189,6 +199,9 @@ extern char *innobase_unix_file_flush_method; /* The following variables have to be my_bool for SHOW VARIABLES to work */ extern my_bool innobase_log_archive, innobase_use_native_aio, innobase_fast_shutdown; +extern "C" { +extern ulong srv_max_buf_pool_modified_pct; +} extern TYPELIB innobase_lock_typelib; @@ -203,6 +216,8 @@ int innobase_report_binlog_offset_and_commit( void* trx_handle, char* log_file_name, my_off_t end_offset); +int innobase_commit_complete( + void* trx_handle); int innobase_rollback(THD *thd, void* trx_handle); int innobase_close_connection(THD *thd); int innobase_drop_database(char *path); diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 213f5baf388..a9c3ddaef60 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -499,7 +499,7 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt) param.thd = thd; param.op_name = (char*) "repair"; param.testflag = ((check_opt->flags & ~(T_EXTEND)) | - T_SILENT | T_FORCE_CREATE | + T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM | (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT)); param.sort_buffer_length= check_opt->sort_buffer_size; start_records=file->state->records; @@ -592,10 +592,24 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) { local_testflag|= T_STATISTICS; param.testflag|= T_STATISTICS; // We get this for free - thd->proc_info="Repair by sorting"; statistics_done=1; - error = mi_repair_by_sort(¶m, file, fixed_name, - param.testflag & T_QUICK); + if (current_thd->variables.myisam_repair_threads>1) + { + char buf[40]; + /* TODO: respect myisam_repair_threads variable */ + my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map)); + thd->proc_info=buf; + error = mi_repair_parallel(¶m, file, fixed_name, + param.testflag & T_QUICK); + thd->proc_info="Repair done"; // to reset proc_info, as + // it was pointing to local buffer + } + else + { + thd->proc_info="Repair by sorting"; + error = mi_repair_by_sort(¶m, file, fixed_name, + param.testflag & T_QUICK); + } } else { diff --git a/sql/handler.cc b/sql/handler.cc index f2b7dbdf531..db1857e938c 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -253,6 +253,9 @@ int ha_autocommit_or_rollback(THD *thd, int error) replication. This function also calls the commit of the table handler, because the order of transactions in the log of the table handler must be the same as in the binlog. + NOTE that to eliminate the bottleneck of the group commit, we do not + flush the handler log files here, but only later in a call of + ha_commit_complete(). arguments: thd: the thread handle of the current connection @@ -279,13 +282,38 @@ int ha_report_binlog_offset_and_commit(THD *thd, my_error(ER_ERROR_DURING_COMMIT, MYF(0), error); error=1; } - trans->innodb_active_trans=0; } #endif return error; } /* + Flushes the handler log files (if my.cnf settings do not free us from it) + after we have called ha_report_binlog_offset_and_commit(). To eliminate + the bottleneck from the group commit, this should be called when + LOCK_log has been released in log.cc. + + arguments: + thd: the thread handle of the current connection + return value: always 0 +*/ + +int ha_commit_complete(THD *thd) +{ +#ifdef HAVE_INNOBASE_DB + THD_TRANS *trans; + trans = &thd->transaction.all; + if (trans->innobase_tid) + { + innobase_commit_complete(trans->innobase_tid); + + trans->innodb_active_trans=0; + } +#endif + return 0; +} + +/* This function should be called when MySQL sends rows of a SELECT result set or the EOF mark to the client. It releases a possible adaptive hash index S-latch held by thd in InnoDB and also releases a possible InnoDB query @@ -812,7 +840,8 @@ void handler::print_error(int error, myf errflag) DBUG_VOID_RETURN; } - /* Return key if error because of duplicated keys */ + +/* Return key if error because of duplicated keys */ uint handler::get_dup_key(int error) { @@ -823,6 +852,7 @@ uint handler::get_dup_key(int error) DBUG_RETURN(table->file->errkey); } + int handler::delete_table(const char *name) { int error=0; @@ -849,9 +879,10 @@ int handler::rename_table(const char * from, const char * to) DBUG_RETURN(0); } -/* Tell the handler to turn on or off logging to the handler's - recovery log +/* + Tell the handler to turn on or off logging to the handler's recovery log */ + int ha_recovery_logging(THD *thd, bool on) { int error=0; @@ -906,7 +937,6 @@ bool handler::caching_allowed(THD* thd, char* table_key, int ha_create_table(const char *name, HA_CREATE_INFO *create_info, bool update_create_info) - { int error; TABLE table; diff --git a/sql/handler.h b/sql/handler.h index 8c23a3625e0..97ce295d520 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -235,7 +235,8 @@ public: void change_table_ptr(TABLE *table_arg) { table=table_arg; } virtual double scan_time() { return ulonglong2double(data_file_length) / IO_SIZE + 1; } - virtual double read_time(ha_rows rows) { return rows2double(rows); } + virtual double read_time(uint index, uint ranges, ha_rows rows) + { return rows2double(ranges+rows); } virtual bool fast_key_read() { return 0;} virtual key_map keys_to_use_for_scanning() { return 0; } virtual bool has_transactions(){ return 0;} @@ -389,6 +390,7 @@ void ha_resize_key_cache(void); int ha_start_stmt(THD *thd); int ha_report_binlog_offset_and_commit(THD *thd, char *log_file_name, my_off_t end_offset); +int ha_commit_complete(THD *thd); int ha_release_temporary_latches(THD *thd); int ha_commit_trans(THD *thd, THD_TRANS *trans); int ha_rollback_trans(THD *thd, THD_TRANS *trans); diff --git a/sql/init.cc b/sql/init.cc index 8834fd3a89c..50d504068a0 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -38,13 +38,11 @@ void unireg_init(ulong options) init_my_atof(); /* use our atof */ #endif my_abort_hook=unireg_abort; /* Abort with close of databases */ - f_fyllchar=' '; /* Input fill char */ VOID(strmov(reg_ext,".frm")); for (i=0 ; i < 6 ; i++) // YYMMDDHHMMSS dayord.pos[i]=i; specialflag=SPECIAL_SAME_DB_NAME; - blob_newline='^'; /* Convert newline in blobs to this */ /* Make a tab of powers of 10 */ for (i=0,nr=1.0; i < array_elements(log_10) ; i++) { /* It's used by filesort... */ diff --git a/sql/item.cc b/sql/item.cc index 053a94cb695..636cefb511b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -90,28 +90,32 @@ bool Item::check_cols(uint c) return 0; } -void Item::set_name(const char *str,uint length, CHARSET_INFO *cs) + +void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) { if (!length) - name= (char*) str; // Empty string, used by AS - else { - while (length && !my_isgraph(cs,*str)) - { // Fix problem with yacc - length--; - str++; - } - if (length && !my_charset_same(cs, system_charset_info)) - { - String tmp; - tmp.copy(str, length, cs, system_charset_info); - name=sql_strmake(tmp.ptr(),min(tmp.length(),MAX_FIELD_WIDTH)); - } - else - name=sql_strmake(str,min(length,MAX_FIELD_WIDTH)); + /* Empty string, used by AS or internal function like last_insert_id() */ + name= (char*) str; + return; } + while (length && !my_isgraph(cs,*str)) + { // Fix problem with yacc + length--; + str++; + } + if (!my_charset_same(cs, system_charset_info)) + { + uint32 res_length; + name= sql_strmake_with_convert(str, length, cs, + MAX_ALIAS_NAME, system_charset_info, + &res_length); + } + else + name=sql_strmake(str, min(length,MAX_ALIAS_NAME)); } + /* This function is only called when comparing items in the WHERE clause */ @@ -1048,6 +1052,7 @@ inline uint char_val(char X) X-'a'+10); } + Item_varbinary::Item_varbinary(const char *str, uint str_length) { name=(char*) str-2; // Lex makes this start with 0x diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index e2885c8764a..dfc46793ee7 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -90,7 +90,7 @@ static bool convert_constant_item(Field *field, Item **item) bool Item_bool_func2::set_cmp_charset(CHARSET_INFO *cs1, enum coercion co1, CHARSET_INFO *cs2, enum coercion co2) { - if((cs1 == &my_charset_bin) || (cs2 == &my_charset_bin)) + if ((cs1 == &my_charset_bin) || (cs2 == &my_charset_bin)) { cmp_charset= &my_charset_bin; return 0; @@ -114,29 +114,45 @@ bool Item_bool_func2::set_cmp_charset(CHARSET_INFO *cs1, enum coercion co1, { if (co1 == COER_COERCIBLE) { - CHARSET_INFO *c= get_charset_by_csname(cs1->csname,MY_CS_PRIMARY,MYF(0)); - if (c) + CHARSET_INFO *c; + if ((c= get_charset_by_csname(cs1->csname, MY_CS_PRIMARY, MYF(0)))) { cmp_charset= c; return 0; } - else - return 1; } - else - return 1; + return 1; } } return 0; } + +bool Item_bool_func2::fix_fields(THD *thd, struct st_table_list *tables, + Item ** ref) +{ + if (Item_int_func::fix_fields(thd, tables, ref)) + return 1; + if (!cmp_charset) + { + /* set_cmp_charset() failed */ + my_error(ER_CANT_AGGREGATE_COLLATIONS,MYF(0), + args[0]->charset()->name,coercion_name(args[0]->coercibility), + args[1]->charset()->name,coercion_name(args[1]->coercibility), + func_name()); + return 1; + } + return 0; +} + + void Item_bool_func2::fix_length_and_dec() { max_length= 1; // Function returns 0 or 1 /* As some compare functions are generated after sql_yacc, - we have to check for out of memory conditons here + we have to check for out of memory conditions here */ if (!args[0] || !args[1]) return; @@ -149,7 +165,8 @@ void Item_bool_func2::fix_length_and_dec() if (convert_constant_item(field,&args[1])) { cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, - INT_RESULT); // Works for all types. + INT_RESULT); // Works for all types. + cmp_charset= &my_charset_bin; // For test in fix_fields return; } } @@ -163,20 +180,19 @@ void Item_bool_func2::fix_length_and_dec() { cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, INT_RESULT); // Works for all types. + cmp_charset= &my_charset_bin; // For test in fix_fields return; } } } - if (set_cmp_charset(args[0]->charset(), args[0]->coercibility, - args[1]->charset(), args[1]->coercibility)) - { - my_error(ER_CANT_AGGREGATE_COLLATIONS,MYF(0), - args[0]->charset()->name,coercion_name(args[0]->coercibility), - args[1]->charset()->name,coercion_name(args[1]->coercibility), - func_name()); - return; - } set_cmp_func(); + /* + We must set cmp_charset here as we may be called from for an automatic + generated item, like in natural join + */ +end: + set_cmp_charset(args[0]->charset(), args[0]->coercibility, + args[1]->charset(), args[1]->coercibility); } @@ -194,22 +210,22 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) comparators= 0; return 1; } - if ((comparators= (Arg_comparator *) sql_alloc(sizeof(Arg_comparator)*n))) - for (uint i=0; i < n; i++) + if (!(comparators= (Arg_comparator *) sql_alloc(sizeof(Arg_comparator)*n))) + return 1; + for (uint i=0; i < n; i++) + { + if ((*a)->el(i)->cols() != (*b)->el(i)->cols()) { - if ((*a)->el(i)->cols() != (*b)->el(i)->cols()) - { - my_error(ER_CARDINALITY_COL, MYF(0), (*a)->el(i)->cols()); - return 1; - } - comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); + my_error(ER_CARDINALITY_COL, MYF(0), (*a)->el(i)->cols()); + return 1; } - else - return 1; + comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); + } } return 0; } + int Arg_comparator::compare_string() { String *res1,*res2; @@ -1884,16 +1900,6 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) if (Item_bool_func2::fix_fields(thd, tlist, ref)) return 1; - if (set_cmp_charset(args[0]->charset(), args[0]->coercibility, - args[1]->charset(), args[1]->coercibility)) - { - my_error(ER_CANT_AGGREGATE_COLLATIONS,MYF(0), - args[0]->charset()->name,coercion_name(args[0]->coercibility), - args[1]->charset()->name,coercion_name(args[1]->coercibility), - func_name()); - return 1; - } - /* We could also do boyer-more for non-const items, but as we would have to recompute the tables for each row it's not worth it. diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 5e246e3e285..ff469deab30 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -116,7 +116,8 @@ protected: public: Item_bool_func2(Item *a,Item *b): - Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {} + Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1), cmp_charset(0) {} + bool fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref); void fix_length_and_dec(); void set_cmp_func() { diff --git a/sql/item_create.cc b/sql/item_create.cc index 1e547a9c76e..b027b156641 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -321,7 +321,7 @@ Item *create_func_current_user() char buff[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; uint length; - length= (uint) (strxmov(buff, thd->priv_user, "@", thd->host_or_ip, NullS) - + length= (uint) (strxmov(buff, thd->priv_user, "@", thd->priv_host, NullS) - buff); return new Item_string(NullS, thd->memdup(buff, length), length, default_charset_info); diff --git a/sql/item_func.cc b/sql/item_func.cc index 6af65ece692..7ed9e5c85f6 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -40,8 +40,8 @@ eval_const_cond(COND *cond) } -Item_func::Item_func(List<Item> &list): - allowed_arg_cols(1) +Item_func::Item_func(List<Item> &list) + :allowed_arg_cols(1) { arg_count=list.elements; if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count))) @@ -109,15 +109,18 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { // Print purify happy for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++) { + Item *item; + /* We can't yet set item to *arg as fix_fields may change *arg */ if ((*arg)->fix_fields(thd, tables, arg) || (*arg)->check_cols(allowed_arg_cols)) return 1; /* purecov: inspected */ - if ((*arg)->maybe_null) + item= *arg; + if (item->maybe_null) maybe_null=1; - with_sum_func= with_sum_func || (*arg)->with_sum_func; - used_tables_cache|=(*arg)->used_tables(); - const_item_cache&= (*arg)->const_item(); + with_sum_func= with_sum_func || item->with_sum_func; + used_tables_cache|=item->used_tables(); + const_item_cache&= item->const_item(); } } fix_length_and_dec(); @@ -140,14 +143,15 @@ void Item_func::split_sum_func(Item **ref_pointer_array, List<Item> &fields) Item **arg, **arg_end; for (arg= args, arg_end= args+arg_count; arg != arg_end ; arg++) { - if ((*arg)->with_sum_func && (*arg)->type() != SUM_FUNC_ITEM) - (*arg)->split_sum_func(ref_pointer_array, fields); - else if ((*arg)->used_tables() || (*arg)->type() == SUM_FUNC_ITEM) + Item *item=* arg; + if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) + item->split_sum_func(ref_pointer_array, fields); + else if (item->used_tables() || item->type() == SUM_FUNC_ITEM) { uint el= fields.elements; - fields.push_front(*arg); - ref_pointer_array[el]= *arg; - *arg= new Item_ref(ref_pointer_array + el, 0, (*arg)->name); + fields.push_front(item); + ref_pointer_array[el]= item; + *arg= new Item_ref(ref_pointer_array + el, 0, item->name); } } } @@ -1250,47 +1254,6 @@ longlong Item_func_find_in_set::val_int() return 0; } -static char nbits[256] = { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, -}; - -uint count_bits(ulonglong v) -{ -#if SIZEOF_LONG_LONG > 4 - /* The following code is a bit faster on 16 bit machines than if we would - only shift v */ - ulong v2=(ulong) (v >> 32); - return (uint) (uchar) (nbits[(uchar) v] + - nbits[(uchar) (v >> 8)] + - nbits[(uchar) (v >> 16)] + - nbits[(uchar) (v >> 24)] + - nbits[(uchar) (v2)] + - nbits[(uchar) (v2 >> 8)] + - nbits[(uchar) (v2 >> 16)] + - nbits[(uchar) (v2 >> 24)]); -#else - return (uint) (uchar) (nbits[(uchar) v] + - nbits[(uchar) (v >> 8)] + - nbits[(uchar) (v >> 16)] + - nbits[(uchar) (v >> 24)]); -#endif -} - longlong Item_func_bit_count::val_int() { ulonglong value= (ulonglong) args[0]->val_int(); @@ -1299,7 +1262,7 @@ longlong Item_func_bit_count::val_int() null_value=1; /* purecov: inspected */ return 0; /* purecov: inspected */ } - return (longlong) count_bits(value); + return (longlong) my_count_bits(value); } @@ -1373,16 +1336,17 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, arg != arg_end ; arg++,i++) { - if ((*arg)->fix_fields(thd, tables, arg) || (*arg)->check_cols(1)) + Item *item= *arg; + if (item->fix_fields(thd, tables, arg) || item->check_cols(1)) return 1; - if ((*arg)->binary()) + if (item->binary()) func->set_charset(&my_charset_bin); - if ((*arg)->maybe_null) + if (item->maybe_null) func->maybe_null=1; - func->with_sum_func= func->with_sum_func || (*arg)->with_sum_func; - used_tables_cache|=(*arg)->used_tables(); - const_item_cache&=(*arg)->const_item(); - f_args.arg_type[i]=(*arg)->result_type(); + func->with_sum_func= func->with_sum_func || item->with_sum_func; + used_tables_cache|=item->used_tables(); + const_item_cache&=item->const_item(); + f_args.arg_type[i]=item->result_type(); } if (!(buffers=new String[arg_count]) || !(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) || @@ -2452,7 +2416,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) used_tables_cache|=item->used_tables(); } /* check that all columns come from the same table */ - if (count_bits(used_tables_cache) != 1) + if (my_count_bits(used_tables_cache) != 1) key=NO_SUCH_KEY; const_item_cache=0; table=((Item_field *)fields.head())->field->table; @@ -2626,10 +2590,7 @@ Item *get_system_var(enum_var_type var_type, LEX_STRING name) char buff[MAX_SYS_VAR_LENGTH+3+8], *pos; if (!(var= find_sys_var(name.str, name.length))) - { - net_printf(thd, ER_UNKNOWN_SYSTEM_VARIABLE, name.str); return 0; - } if (!(item=var->item(thd, var_type))) return 0; // Impossible thd->lex.uncacheable(); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 8aaf9f944e8..dd48314596b 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -27,9 +27,6 @@ #include "mysql_priv.h" #include "sql_acl.h" #include <m_ctype.h> -#ifdef HAVE_CRYPT_H -#include <crypt.h> -#endif #ifdef HAVE_OPENSSL #include <openssl/des.h> #endif /* HAVE_OPENSSL */ @@ -931,7 +928,7 @@ void Item_str_func::left_right_max_length() max_length=args[0]->max_length; if (args[1]->const_item()) { - int length=(int) args[1]->val_int(); + int length=(int) args[1]->val_int()*default_charset_info->mbmaxlen; if (length <= 0) max_length=0; else @@ -1012,7 +1009,7 @@ void Item_func_substr::fix_length_and_dec() } if (arg_count == 3 && args[2]->const_item()) { - int32 length= (int32) args[2]->val_int(); + int32 length= (int32) args[2]->val_int() * default_charset_info->mbmaxlen; if (length <= 0) max_length=0; /* purecov: inspected */ else @@ -1591,15 +1588,17 @@ String *Item_func_format::val_str(String *str) str_length=str->length(); if (nr < 0) str_length--; // Don't count sign - length=str->length()+(diff=(str_length- dec-1)/3); - if (diff) + + /* We need this test to handle 'nan' values */ + if (str_length >= dec+4) { char *tmp,*pos; - str=copy_if_not_alloced(&tmp_str,str,length); + length= str->length()+(diff=(str_length- dec-1)/3); + str= copy_if_not_alloced(&tmp_str,str,length); str->length(length); - tmp=(char*) str->ptr()+length - dec-1; - for (pos=(char*) str->ptr()+length ; pos != tmp; pos--) - pos[0]=pos[- (int) diff]; + tmp= (char*) str->ptr()+length - dec-1; + for (pos= (char*) str->ptr()+length ; pos != tmp; pos--) + pos[0]= pos[-(int) diff]; while (diff) { pos[0]=pos[-(int) diff]; pos--; @@ -2184,7 +2183,7 @@ void Item_func_set_collation::fix_length_and_dec() const char *colname; String tmp, *str= args[1]->val_str(&tmp); colname= str->c_ptr(); - if (!strncmp(colname,"BINARY",6)) + if (colname == binary_keyword) set_collation= get_charset_by_csname(args[0]->charset()->csname, MY_CS_BINSORT,MYF(0)); else diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 11c850f9d5f..fa8bf7e6e0f 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -219,12 +219,14 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) void Item_sum_sum::reset() { - null_value=0; sum=0.0; Item_sum_sum::add(); + null_value=1; sum=0.0; Item_sum_sum::add(); } bool Item_sum_sum::add() { sum+=args[0]->val(); + if (!args[0]->null_value) + null_value= 0; return 0; } @@ -641,8 +643,10 @@ void Item_sum_sum::reset_field() { double nr=args[0]->val(); // Nulls also return 0 float8store(result_field->ptr,nr); - null_value=0; - result_field->set_notnull(); + if (args[0]->null_value) + result_field->set_null(); + else + result_field->set_notnull(); } @@ -698,7 +702,10 @@ void Item_sum_sum::update_field(int offset) float8get(old_nr,res+offset); nr=args[0]->val(); if (!args[0]->null_value) + { old_nr+=nr; + result_field->set_notnull(); + } float8store(res,old_nr); } diff --git a/sql/item_sum.h b/sql/item_sum.h index 37d7e7f79d0..f996f980fff 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -99,9 +99,6 @@ public: class Item_sum_int :public Item_sum_num { - void fix_length_and_dec() - { decimals=0; max_length=21; maybe_null=null_value=0; } - public: Item_sum_int(Item *item_par) :Item_sum_num(item_par) {} Item_sum_int(List<Item> &list) :Item_sum_num(list) {} @@ -109,6 +106,8 @@ public: double val() { return (double) val_int(); } String *val_str(String*str); enum Item_result result_type () const { return INT_RESULT; } + void fix_length_and_dec() + { decimals=0; max_length=21; maybe_null=null_value=0; } }; @@ -127,6 +126,7 @@ class Item_sum_sum :public Item_sum_num double val(); void reset_field(); void update_field(int offset); + void no_rows_in_result() {} const char *func_name() const { return "sum"; } Item *copy_or_same(THD* thd) { return new Item_sum_sum(thd, *this); } }; @@ -449,6 +449,8 @@ class Item_sum_bit :public Item_sum_int void reset(); longlong val_int(); void reset_field(); + void fix_length_and_dec() + { decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; } }; diff --git a/sql/log.cc b/sql/log.cc index c9e20bc0cc9..c05d52bdc5d 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -317,7 +317,10 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, DBUG_RETURN(0); err: - sql_print_error("Could not use %s for logging (error %d)", log_name, errno); + sql_print_error("Could not use %s for logging (error %d). \ +Turning logging off for the whole duration of the MySQL server process. \ +To turn it on again: fix the cause, \ +shutdown the MySQL server and restart it.", log_name, errno); if (file >= 0) my_close(file,MYF(0)); if (index_file_nr >= 0) @@ -1157,6 +1160,8 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, bool MYSQL_LOG::write(Log_event* event_info) { + THD *thd=event_info->thd; + bool called_handler_commit=0; bool error=0; bool should_rotate = 0; DBUG_ENTER("MYSQL_LOG::write(event)"); @@ -1171,7 +1176,6 @@ bool MYSQL_LOG::write(Log_event* event_info) /* In most cases this is only called if 'is_open()' is true */ if (is_open()) { - THD *thd=event_info->thd; const char *local_db = event_info->get_db(); #ifdef USING_TRANSACTIONS IO_CACHE *file = ((event_info->get_cache_stmt()) ? @@ -1268,24 +1272,35 @@ bool MYSQL_LOG::write(Log_event* event_info) the table handler commit here, protected by the LOCK_log mutex, because otherwise the transactions may end up in a different order in the table handler log! + + Note that we will NOT call ha_report_binlog_offset_and_commit() if + there are binlog events cached in the transaction cache. That is + because then the log event which we write to the binlog here is + not a transactional event. In versions < 4.0.13 before this fix this + caused an InnoDB transaction to be committed if in the middle there + was a MyISAM event! */ - if (file == &log_file) + if (file == &log_file) // we are writing to the real log (disk) { - /* - LOAD DATA INFILE in AUTOCOMMIT=1 mode writes to the binlog - chunks also before it is successfully completed. We only report - the binlog write and do the commit inside the transactional table - handler if the log event type is appropriate. - */ - - if (event_info->get_type_code() == QUERY_EVENT - || event_info->get_type_code() == EXEC_LOAD_EVENT) + if (opt_using_transactions && !my_b_tell(&thd->transaction.trans_log)) { - error = ha_report_binlog_offset_and_commit(thd, log_file_name, - file->pos_in_file); + /* + LOAD DATA INFILE in AUTOCOMMIT=1 mode writes to the binlog + chunks also before it is successfully completed. We only report + the binlog write and do the commit inside the transactional table + handler if the log event type is appropriate. + */ + + if (event_info->get_type_code() == QUERY_EVENT + || event_info->get_type_code() == EXEC_LOAD_EVENT) + { + error = ha_report_binlog_offset_and_commit(thd, log_file_name, + file->pos_in_file); + called_handler_commit=1; + } } - + /* we wrote to the real log, check automatic rotation */ should_rotate= (my_b_tell(file) >= (my_off_t) max_binlog_size); } @@ -1309,6 +1324,16 @@ err: } pthread_mutex_unlock(&LOCK_log); + + /* + Flush the transactional handler log file now that we have released + LOCK_log; the flush is placed here to eliminate the bottleneck on the + group commit + */ + + if (called_handler_commit) + ha_commit_complete(thd); + #ifdef HAVE_REPLICATION if (should_rotate && expire_logs_days) { @@ -1316,7 +1341,6 @@ err: if (purge_time >= 0) error= purge_logs_before_date(purge_time); } - #endif DBUG_RETURN(error); } @@ -1423,6 +1447,13 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache) } VOID(pthread_mutex_unlock(&LOCK_log)); + + /* Flush the transactional handler log file now that we have released + LOCK_log; the flush is placed here to eliminate the bottleneck on the + group commit */ + + ha_commit_complete(thd); + DBUG_RETURN(0); err: diff --git a/sql/log_event.cc b/sql/log_event.cc index 530e878b458..fb690efc364 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -26,11 +26,10 @@ #define log_cs &my_charset_latin1 -/***************************************************************************** - +/* my_b_safe_write() +*/ - ****************************************************************************/ inline int my_b_safe_write(IO_CACHE* file, const byte *buf, int len) { @@ -45,11 +44,11 @@ inline int my_b_safe_write(IO_CACHE* file, const byte *buf, return my_b_write(file, buf,len); } -/***************************************************************************** +/* pretty_print_str() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT static void pretty_print_str(FILE* file, char* str, int len) { @@ -75,11 +74,11 @@ static void pretty_print_str(FILE* file, char* str, int len) } #endif // MYSQL_CLIENT -/***************************************************************************** +/* ignored_error_code() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) inline int ignored_error_code(int err_code) { @@ -87,11 +86,10 @@ inline int ignored_error_code(int err_code) } #endif -/***************************************************************************** - +/* pretty_print_str() +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT static char* pretty_print_str(char* packet, char* str, int len) { @@ -117,13 +115,13 @@ static char* pretty_print_str(char* packet, char* str, int len) *pos++= '\''; return pos; } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ -/***************************************************************************** +/* slave_load_file_stem() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) static inline char* slave_load_file_stem(char*buf, uint file_id, int event_server_id) @@ -138,8 +136,7 @@ static inline char* slave_load_file_stem(char*buf, uint file_id, } #endif -/***************************************************************************** - +/* cleanup_load_tmpdir() Delete all temporary files used for SQL_LOAD. @@ -148,8 +145,8 @@ static inline char* slave_load_file_stem(char*buf, uint file_id, - When we get a 'server start' event, we should only remove the files associated with the server id that just started. Easily fixable by adding server_id as a prefix to the log files. +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) static void cleanup_load_tmpdir() { @@ -170,22 +167,22 @@ static void cleanup_load_tmpdir() } #endif -/***************************************************************************** +/* write_str() +*/ - ****************************************************************************/ static bool write_str(IO_CACHE *file, char *str, byte length) { return (my_b_safe_write(file, &length, 1) || my_b_safe_write(file, (byte*) str, (int) length)); } -/***************************************************************************** +/* read_str() +*/ - ****************************************************************************/ static inline int read_str(char * &buf, char *buf_end, char * &str, uint8 &len) { @@ -198,19 +195,14 @@ static inline int read_str(char * &buf, char *buf_end, char * &str, } -/***************************************************************************** - ***************************************************************************** - - Log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Log_event methods +**************************************************************************/ +/* Log_event::get_type_str() +*/ - ****************************************************************************/ const char* Log_event::get_type_str() { switch(get_type_code()) { @@ -232,11 +224,11 @@ const char* Log_event::get_type_str() } } -/***************************************************************************** +/* Log_event::Log_event() +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans) :temp_buf(0), exec_time(0), cached_event_len(0), flags(flags_arg), @@ -258,13 +250,13 @@ Log_event::Log_event() when= time(NULL); log_pos= 0; } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ -/***************************************************************************** +/* Log_event::Log_event() +*/ - ****************************************************************************/ Log_event::Log_event(const char* buf, bool old_format) :temp_buf(0), cached_event_len(0), cache_stmt(0) { @@ -285,15 +277,13 @@ Log_event::Log_event(const char* buf, bool old_format) #endif } - #ifndef MYSQL_CLIENT #ifdef HAVE_REPLICATION -/***************************************************************************** - +/* Log_event::exec_event() +*/ - ****************************************************************************/ int Log_event::exec_event(struct st_relay_log_info* rli) { /* @@ -324,15 +314,15 @@ int Log_event::exec_event(struct st_relay_log_info* rli) - then it will be MyISAM on the slave - but as opt_using_transactions is true, the slave will believe he is transactional with the MyISAM table. And problems will come when one - does START SLAVE; STOP SLAVE; START SLAVE; (the slave will resume at BEGIN - whereas there has not been any rollback). This is the problem of + does START SLAVE; STOP SLAVE; START SLAVE; (the slave will resume at + BEGIN whereas there has not been any rollback). This is the problem of using opt_using_transactions instead of a finer "does the slave support _the_transactional_handler_used_on_the_master_". More generally, we'll have problems when a query mixes a transactional handler and MyISAM and STOP SLAVE is issued in the middle of the - "transaction". START SLAVE will resume at BEGIN while the MyISAM table has - already been updated. + "transaction". START SLAVE will resume at BEGIN while the MyISAM table + has already been updated. */ if ((thd->options & OPTION_BEGIN) && opt_using_transactions) @@ -346,24 +336,22 @@ int Log_event::exec_event(struct st_relay_log_info* rli) return 0; } -/***************************************************************************** +/* Log_event::pack_info() +*/ - ****************************************************************************/ void Log_event::pack_info(Protocol *protocol) { protocol->store("", &my_charset_bin); } -/***************************************************************************** - +/* Log_event::net_send() Only called by SHOW BINLOG EVENTS - - ****************************************************************************/ +*/ int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos) { @@ -384,11 +372,11 @@ int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos) } #endif /* HAVE_REPLICATION */ -/***************************************************************************** +/* Log_event::init_show_field_list() +*/ - ****************************************************************************/ void Log_event::init_show_field_list(List<Item>* field_list) { field_list->push_back(new Item_empty_string("Log_name", 20)); @@ -404,21 +392,20 @@ void Log_event::init_show_field_list(List<Item>* field_list) #endif // !MYSQL_CLIENT -/***************************************************************************** - +/* Log_event::write() +*/ - ****************************************************************************/ int Log_event::write(IO_CACHE* file) { return (write_header(file) || write_data(file)) ? -1 : 0; } -/***************************************************************************** +/* Log_event::write_header() +*/ - ****************************************************************************/ int Log_event::write_header(IO_CACHE* file) { char buf[LOG_EVENT_HEADER_LEN]; @@ -439,11 +426,10 @@ int Log_event::write_header(IO_CACHE* file) } -/***************************************************************************** - +/* Log_event::read_log_event() +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT int Log_event::read_log_event(IO_CACHE* file, String* packet, pthread_mutex_t* log_lock) @@ -510,13 +496,13 @@ end: #define LOCK_MUTEX #endif -/***************************************************************************** - +/* Log_event::read_log_event() - Allocates memory--the caller is responsible for clean-up + NOTE: + Allocates memory; The caller is responsible for clean-up +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT Log_event* Log_event::read_log_event(IO_CACHE* file, pthread_mutex_t* log_lock, @@ -588,11 +574,11 @@ data_len=%d,event_type=%d",error,data_len,head[EVENT_TYPE_OFFSET]); return res; } -/***************************************************************************** +/* Log_event::read_log_event() +*/ - ****************************************************************************/ Log_event* Log_event::read_log_event(const char* buf, int event_len, const char **error, bool old_format) { @@ -657,9 +643,18 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, } if (!ev || !ev->is_valid()) { - *error= "Found invalid event in binary log"; delete ev; +#ifdef MYSQL_CLIENT + if (!force_opt) + { + *error= "Found invalid event in binary log"; + return 0; + } + ev= new Unknown_log_event(buf, old_format); +#else + *error= "Found invalid event in binary log"; return 0; +#endif } ev->cached_event_len = event_len; return ev; @@ -667,11 +662,10 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, #ifdef MYSQL_CLIENT -/***************************************************************************** - +/* Log_event::print_header() +*/ - ****************************************************************************/ void Log_event::print_header(FILE* file) { char llbuff[22]; @@ -681,11 +675,10 @@ void Log_event::print_header(FILE* file) llstr(log_pos,llbuff)); } -/***************************************************************************** - +/* Log_event::print_timestamp() +*/ - ****************************************************************************/ void Log_event::print_timestamp(FILE* file, time_t* ts) { struct tm *res; @@ -709,11 +702,10 @@ void Log_event::print_timestamp(FILE* file, time_t* ts) #endif // MYSQL_CLIENT -/***************************************************************************** - +/* Log_event::set_log_pos() +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT void Log_event::set_log_pos(MYSQL_LOG* log) { @@ -723,21 +715,16 @@ void Log_event::set_log_pos(MYSQL_LOG* log) #endif // !MYSQL_CLIENT - -/***************************************************************************** - ***************************************************************************** - - Query_log_event methods - - ***************************************************************************** - ****************************************************************************/ +/************************************************************************** + Query_log_event methods +**************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -/***************************************************************************** +/* Query_log_event::pack_info() +*/ - ****************************************************************************/ void Query_log_event::pack_info(Protocol *protocol) { char *buf, *pos; @@ -761,21 +748,21 @@ void Query_log_event::pack_info(Protocol *protocol) } #endif -/***************************************************************************** +/* Query_log_event::write() +*/ - ****************************************************************************/ int Query_log_event::write(IO_CACHE* file) { return query ? Log_event::write(file) : -1; } -/***************************************************************************** +/* Query_log_event::write_data() +*/ - ****************************************************************************/ int Query_log_event::write_data(IO_CACHE* file) { if (!query) @@ -792,11 +779,11 @@ int Query_log_event::write_data(IO_CACHE* file) my_b_safe_write(file, (byte*) query, q_len)) ? -1 : 0; } -/***************************************************************************** +/* Query_log_event::Query_log_event() +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans) @@ -812,13 +799,12 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, exec_time = (ulong) (end_time - thd->start_time); db_len = (db) ? (uint32) strlen(db) : 0; } -#endif // MYSQL_CLIENT - -/***************************************************************************** +#endif /* MYSQL_CLIENT */ +/* Query_log_event::Query_log_event() +*/ - ****************************************************************************/ Query_log_event::Query_log_event(const char* buf, int event_len, bool old_format) :Log_event(buf, old_format),data_buf(0), query(NULL), db(NULL) @@ -854,11 +840,11 @@ Query_log_event::Query_log_event(const char* buf, int event_len, *((char*)query+q_len) = 0; } -/***************************************************************************** +/* Query_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Query_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -889,13 +875,13 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db) my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME)); fprintf(file, ";\n"); } -#endif // MYSQL_CLIENT +#endif /* MYSQL_CLIENT */ -/***************************************************************************** +/* Query_log_event::exec_event() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Query_log_event::exec_event(struct st_relay_log_info* rli) { @@ -996,19 +982,14 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) #endif -/***************************************************************************** - ***************************************************************************** - - Start_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Start_log_event methods +**************************************************************************/ +/* Start_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Start_log_event::pack_info(Protocol *protocol) { @@ -1021,11 +1002,11 @@ void Start_log_event::pack_info(Protocol *protocol) } #endif -/***************************************************************************** +/* Start_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Start_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -1035,17 +1016,16 @@ void Start_log_event::print(FILE* file, bool short_form, char* last_db) print_header(file); fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version, server_version); - print_timestamp(file, (time_t*)&created); + print_timestamp(file, &created); fputc('\n', file); fflush(file); } -#endif // MYSQL_CLIENT - -/***************************************************************************** +#endif /* MYSQL_CLIENT */ +/* Start_log_event::Start_log_event() +*/ - ****************************************************************************/ Start_log_event::Start_log_event(const char* buf, bool old_format) :Log_event(buf, old_format) @@ -1057,11 +1037,11 @@ Start_log_event::Start_log_event(const char* buf, created = uint4korr(buf+ST_CREATED_OFFSET); } -/***************************************************************************** +/* Start_log_event::write_data() +*/ - ****************************************************************************/ int Start_log_event::write_data(IO_CACHE* file) { char buff[START_HEADER_LEN]; @@ -1071,8 +1051,7 @@ int Start_log_event::write_data(IO_CACHE* file) return (my_b_safe_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0); } -/***************************************************************************** - +/* Start_log_event::exec_event() The master started @@ -1080,6 +1059,10 @@ int Start_log_event::write_data(IO_CACHE* file) IMPLEMENTATION - To handle the case where the master died without a stop event, we clean up all temporary tables + locks that we got. + However, we don't clean temporary tables if the master was 3.23 + (this is because a 3.23 master writes a Start_log_event at every + binlog rotation; if we were not careful we would remove temp tables + on the slave when FLUSH LOGS is issued on the master). TODO - Remove all active user locks @@ -1087,36 +1070,37 @@ int Start_log_event::write_data(IO_CACHE* file) in the middle while writing the transaction to the binary log. In this case we should stop the slave. - ****************************************************************************/ +*/ + #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Start_log_event::exec_event(struct st_relay_log_info* rli) { DBUG_ENTER("Start_log_event::exec_event"); - /* All temporary tables was deleted on the master */ - close_temporary_tables(thd); - /* - If we have old format, load_tmpdir is cleaned up by the I/O thread - */ + if (!rli->mi->old_format) + { + /* + If 4.0 master, all temporary tables have been deleted on the master; + if 3.23 master, this is far from sure. + */ + close_temporary_tables(thd); + /* + If we have old format, load_tmpdir is cleaned up by the I/O thread + */ cleanup_load_tmpdir(); + } DBUG_RETURN(Log_event::exec_event(rli)); } -#endif - - -/***************************************************************************** - ***************************************************************************** - - Load_log_event methods - - ***************************************************************************** - ****************************************************************************/ +#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ -/***************************************************************************** +/************************************************************************** + Load_log_event methods +**************************************************************************/ +/* Load_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Load_log_event::pack_info(Protocol *protocol) { @@ -1224,13 +1208,13 @@ void Load_log_event::pack_info(Protocol *protocol) protocol->store(buf, pos-buf, &my_charset_bin); my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); } -#endif +#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ -/***************************************************************************** +/* Load_log_event::write_data_header() +*/ - ****************************************************************************/ int Load_log_event::write_data_header(IO_CACHE* file) { char buf[LOAD_HEADER_LEN]; @@ -1243,11 +1227,11 @@ int Load_log_event::write_data_header(IO_CACHE* file) return my_b_safe_write(file, (byte*)buf, LOAD_HEADER_LEN); } -/***************************************************************************** +/* Load_log_event::write_data_body() +*/ - ****************************************************************************/ int Load_log_event::write_data_body(IO_CACHE* file) { if (sql_ex.write_data(file)) @@ -1263,11 +1247,11 @@ int Load_log_event::write_data_body(IO_CACHE* file) my_b_safe_write(file, (byte*)fname, fname_len)); } -/***************************************************************************** +/* Load_log_event::Load_log_event() +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex, const char *db_arg, const char *table_name_arg, @@ -1347,16 +1331,16 @@ Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex, field_lens = (const uchar*)field_lens_buf.ptr(); fields = fields_buf.ptr(); } -#endif // !MYSQL_CLIENT - -/***************************************************************************** +#endif /* !MYSQL_CLIENT */ +/* Load_log_event::Load_log_event() - The caller must do buf[event_len] = 0 before he starts using the - constructed event. + NOTE + The caller must do buf[event_len] = 0 before he starts using the + constructed event. +*/ - ****************************************************************************/ Load_log_event::Load_log_event(const char *buf, int event_len, bool old_format) :Log_event(buf, old_format),num_fields(0),fields(0), @@ -1368,11 +1352,11 @@ Load_log_event::Load_log_event(const char *buf, int event_len, copy_log_event(buf, event_len, old_format); } -/***************************************************************************** +/* Load_log_event::copy_log_event() +*/ - ****************************************************************************/ int Load_log_event::copy_log_event(const char *buf, ulong event_len, bool old_format) { @@ -1417,11 +1401,11 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len, return 0; } -/***************************************************************************** +/* Load_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Load_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -1510,13 +1494,13 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) fprintf(file, ";\n"); } -#endif /* #ifdef MYSQL_CLIENT */ +#endif /* MYSQL_CLIENT */ -/***************************************************************************** +/* Load_log_event::set_fields() +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT void Load_log_event::set_fields(List<Item> &field_list) { @@ -1653,12 +1637,11 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, close_thread_tables(thd); if (thd->query_error) { - int sql_error = thd->net.last_errno; + int sql_error= thd->net.last_errno; if (!sql_error) - sql_error = ER_UNKNOWN_ERROR; - + sql_error= ER_UNKNOWN_ERROR; slave_print_error(rli,sql_error, - "Slave: Error '%s' running load data infile ", + "Error '%s' running LOAD DATA INFILE", ER_SAFE(sql_error)); free_root(&thd->mem_root,0); return 1; @@ -1667,7 +1650,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, if (thd->is_fatal_error) { - sql_print_error("Slave: Fatal error running LOAD DATA INFILE "); + sql_print_error("Fatal error running LOAD DATA INFILE"); return 1; } @@ -1676,19 +1659,14 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, #endif -/***************************************************************************** - ***************************************************************************** - - Rotate_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Rotate_log_event methods +**************************************************************************/ +/* Rotate_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Rotate_log_event::pack_info(Protocol *protocol) { @@ -1707,11 +1685,11 @@ void Rotate_log_event::pack_info(Protocol *protocol) } #endif -/***************************************************************************** +/* Rotate_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Rotate_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -1732,11 +1710,11 @@ void Rotate_log_event::print(FILE* file, bool short_form, char* last_db) } #endif // MYSQL_CLIENT -/***************************************************************************** +/* Rotate_log_event::Rotate_log_event() +*/ - ****************************************************************************/ Rotate_log_event::Rotate_log_event(const char* buf, int event_len, bool old_format) :Log_event(buf, old_format),new_log_ident(NULL),alloced(0) @@ -1768,11 +1746,11 @@ Rotate_log_event::Rotate_log_event(const char* buf, int event_len, alloced = 1; } -/***************************************************************************** +/* Rotate_log_event::write_data() +*/ - ****************************************************************************/ int Rotate_log_event::write_data(IO_CACHE* file) { char buf[ROTATE_HEADER_LEN]; @@ -1781,8 +1759,8 @@ int Rotate_log_event::write_data(IO_CACHE* file) my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len)); } -/***************************************************************************** +/* Rotate_log_event::exec_event() Got a rotate log even from the master @@ -1796,8 +1774,8 @@ int Rotate_log_event::write_data(IO_CACHE* file) RETURN VALUES 0 ok +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Rotate_log_event::exec_event(struct st_relay_log_info* rli) { @@ -1818,19 +1796,14 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) #endif -/***************************************************************************** - ***************************************************************************** - - Intvar_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Intvar_log_event methods +**************************************************************************/ +/* Intvar_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Intvar_log_event::pack_info(Protocol *protocol) { @@ -1842,11 +1815,11 @@ void Intvar_log_event::pack_info(Protocol *protocol) } #endif -/***************************************************************************** +/* Intvar_log_event::Intvar_log_event() +*/ - ****************************************************************************/ Intvar_log_event::Intvar_log_event(const char* buf, bool old_format) :Log_event(buf, old_format) { @@ -1855,11 +1828,11 @@ Intvar_log_event::Intvar_log_event(const char* buf, bool old_format) val = uint8korr(buf+I_VAL_OFFSET); } -/***************************************************************************** +/* Intvar_log_event::get_var_type_name() +*/ - ****************************************************************************/ const char* Intvar_log_event::get_var_type_name() { switch(type) { @@ -1869,11 +1842,11 @@ const char* Intvar_log_event::get_var_type_name() } } -/***************************************************************************** +/* Intvar_log_event::write_data() +*/ - ****************************************************************************/ int Intvar_log_event::write_data(IO_CACHE* file) { char buf[9]; @@ -1882,11 +1855,11 @@ int Intvar_log_event::write_data(IO_CACHE* file) return my_b_safe_write(file, (byte*) buf, sizeof(buf)); } -/***************************************************************************** +/* Intvar_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Intvar_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -1912,13 +1885,13 @@ void Intvar_log_event::print(FILE* file, bool short_form, char* last_db) fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff)); fflush(file); } -#endif // MYSQL_CLIENT +#endif -/***************************************************************************** +/* Intvar_log_event::exec_event() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT) int Intvar_log_event::exec_event(struct st_relay_log_info* rli) { @@ -1937,9 +1910,9 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli) #endif -/**************************************************************************** +/************************************************************************** Rand_log_event methods -****************************************************************************/ +**************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Rand_log_event::pack_info(Protocol *protocol) @@ -1999,9 +1972,9 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli) #endif // !MYSQL_CLIENT -/*************************************************************************** +/************************************************************************** User_var_log_event methods -***************************************************************************/ +**************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void User_var_log_event::pack_info(Protocol* protocol) @@ -2129,11 +2102,10 @@ int User_var_log_event::write_data(IO_CACHE* file) } -/***************************************************************************** - +/* User_var_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void User_var_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -2176,11 +2148,11 @@ void User_var_log_event::print(FILE* file, bool short_form, char* last_db) } #endif -/***************************************************************************** +/* User_var_log_event::exec_event() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int User_var_log_event::exec_event(struct st_relay_log_info* rli) { @@ -2231,10 +2203,21 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) #endif // !MYSQL_CLIENT -/**************************************************************************** +/************************************************************************** Slave_log_event methods -****************************************************************************/ +**************************************************************************/ + #ifdef HAVE_REPLICATION +#ifdef MYSQL_CLIENT +void Unknown_log_event::print(FILE* file, bool short_form, char* last_db) +{ + if (short_form) + return; + print_header(file); + fputc('\n', file); + fprintf(file, "# %s", "Unknown event\n"); +} +#endif #ifndef MYSQL_CLIENT void Slave_log_event::pack_info(Protocol *protocol) @@ -2367,19 +2350,14 @@ int Slave_log_event::exec_event(struct st_relay_log_info* rli) #endif // !MYSQL_CLIENT -/***************************************************************************** - ***************************************************************************** - - Stop_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Stop_log_event methods +**************************************************************************/ +/* Stop_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Stop_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -2392,8 +2370,8 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db) } #endif // MYSQL_CLIENT -/***************************************************************************** +/* Stop_log_event::exec_event() The master stopped. Clean up all temporary tables + locks that the @@ -2401,12 +2379,18 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db) TODO - Remove all active user locks +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT int Stop_log_event::exec_event(struct st_relay_log_info* rli) { - // do not clean up immediately after rotate event + /* + do not clean up immediately after rotate event; + QQ: this should be a useless test: the only case when it is false is when + shutdown occurred just after FLUSH LOGS. It has nothing to do with Rotate? + By the way, immediately after a Rotate the I/O thread does not write + the Stop to the relay log, so we won't come here in that case. + */ if (rli->group_master_log_pos > BIN_LOG_HEADER_SIZE) { close_temporary_tables(thd); @@ -2423,23 +2407,18 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli) flush_relay_log_info(rli); return 0; } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ #endif /* HAVE_REPLICATION */ -/***************************************************************************** - ***************************************************************************** - - Create_file_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Create_file_log_event methods +**************************************************************************/ +/* Create_file_log_event ctor +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT Create_file_log_event:: Create_file_log_event(THD* thd_arg, sql_exchange* ex, @@ -2455,11 +2434,11 @@ Create_file_log_event(THD* thd_arg, sql_exchange* ex, } #endif // !MYSQL_CLIENT -/***************************************************************************** +/* Create_file_log_event::write_data_body() +*/ - ****************************************************************************/ int Create_file_log_event::write_data_body(IO_CACHE* file) { int res; @@ -2469,11 +2448,11 @@ int Create_file_log_event::write_data_body(IO_CACHE* file) my_b_safe_write(file, (byte*) block, block_len)); } -/***************************************************************************** +/* Create_file_log_event::write_data_header() +*/ - ****************************************************************************/ int Create_file_log_event::write_data_header(IO_CACHE* file) { int res; @@ -2484,11 +2463,11 @@ int Create_file_log_event::write_data_header(IO_CACHE* file) return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN); } -/***************************************************************************** +/* Create_file_log_event::write_base() +*/ - ****************************************************************************/ int Create_file_log_event::write_base(IO_CACHE* file) { int res; @@ -2498,11 +2477,11 @@ int Create_file_log_event::write_base(IO_CACHE* file) return res; } -/***************************************************************************** +/* Create_file_log_event ctor +*/ - ****************************************************************************/ Create_file_log_event::Create_file_log_event(const char* buf, int len, bool old_format) :Load_log_event(buf,0,old_format),fake_base(0),block(0),inited_from_old(0) @@ -2529,11 +2508,11 @@ Create_file_log_event::Create_file_log_event(const char* buf, int len, } } -/***************************************************************************** +/* Create_file_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Create_file_log_event::print(FILE* file, bool short_form, char* last_db, bool enable_local) @@ -2563,11 +2542,11 @@ void Create_file_log_event::print(FILE* file, bool short_form, } #endif // MYSQL_CLIENT -/***************************************************************************** +/* Create_file_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Create_file_log_event::pack_info(Protocol *protocol) { @@ -2586,11 +2565,11 @@ void Create_file_log_event::pack_info(Protocol *protocol) } #endif -/***************************************************************************** +/* Create_file_log_event::exec_event() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Create_file_log_event::exec_event(struct st_relay_log_info* rli) { @@ -2651,19 +2630,14 @@ err: #endif -/***************************************************************************** - ***************************************************************************** - - Append_block_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Append_block_log_event methods +**************************************************************************/ +/* Append_block_log_event ctor +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg, uint block_len_arg, @@ -2672,13 +2646,13 @@ Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg, block_len(block_len_arg), file_id(thd_arg->file_id) { } -#endif // !MYSQL_CLIENT +#endif -/***************************************************************************** +/* Append_block_log_event ctor +*/ - ****************************************************************************/ Append_block_log_event::Append_block_log_event(const char* buf, int len) :Log_event(buf, 0),block(0) { @@ -2689,11 +2663,11 @@ Append_block_log_event::Append_block_log_event(const char* buf, int len) block_len = len - APPEND_BLOCK_EVENT_OVERHEAD; } -/***************************************************************************** +/* Append_block_log_event::write_data() +*/ - ****************************************************************************/ int Append_block_log_event::write_data(IO_CACHE* file) { byte buf[APPEND_BLOCK_HEADER_LEN]; @@ -2702,11 +2676,11 @@ int Append_block_log_event::write_data(IO_CACHE* file) my_b_safe_write(file, (byte*) block, block_len)); } -/***************************************************************************** +/* Append_block_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Append_block_log_event::print(FILE* file, bool short_form, char* last_db) @@ -2720,11 +2694,11 @@ void Append_block_log_event::print(FILE* file, bool short_form, } #endif // MYSQL_CLIENT -/***************************************************************************** +/* Append_block_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Append_block_log_event::pack_info(Protocol *protocol) { @@ -2737,11 +2711,11 @@ void Append_block_log_event::pack_info(Protocol *protocol) } #endif -/***************************************************************************** +/* Append_block_log_event::exec_event() +*/ - ****************************************************************************/ #if defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Append_block_log_event::exec_event(struct st_relay_log_info* rli) { @@ -2773,31 +2747,25 @@ err: #endif -/***************************************************************************** - ***************************************************************************** - - Delete_file_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Delete_file_log_event methods +**************************************************************************/ +/* Delete_file_log_event ctor +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT Delete_file_log_event::Delete_file_log_event(THD *thd_arg, bool using_trans) :Log_event(thd_arg, 0, using_trans),file_id(thd_arg->file_id) { } -#endif // !MYSQL_CLIENT - -/***************************************************************************** +#endif +/* Delete_file_log_event ctor +*/ - ****************************************************************************/ Delete_file_log_event::Delete_file_log_event(const char* buf, int len) :Log_event(buf, 0),file_id(0) { @@ -2806,11 +2774,11 @@ Delete_file_log_event::Delete_file_log_event(const char* buf, int len) file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET); } -/***************************************************************************** +/* Delete_file_log_event::write_data() +*/ - ****************************************************************************/ int Delete_file_log_event::write_data(IO_CACHE* file) { byte buf[DELETE_FILE_HEADER_LEN]; @@ -2818,11 +2786,11 @@ int Delete_file_log_event::write_data(IO_CACHE* file) return my_b_safe_write(file, buf, DELETE_FILE_HEADER_LEN); } -/***************************************************************************** +/* Delete_file_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Delete_file_log_event::print(FILE* file, bool short_form, char* last_db) @@ -2835,11 +2803,10 @@ void Delete_file_log_event::print(FILE* file, bool short_form, } #endif // MYSQL_CLIENT -/***************************************************************************** - +/* Delete_file_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Delete_file_log_event::pack_info(Protocol *protocol) { @@ -2850,11 +2817,10 @@ void Delete_file_log_event::pack_info(Protocol *protocol) } #endif -/***************************************************************************** - +/* Delete_file_log_event::exec_event() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Delete_file_log_event::exec_event(struct st_relay_log_info* rli) { @@ -2871,31 +2837,26 @@ int Delete_file_log_event::exec_event(struct st_relay_log_info* rli) #endif -/***************************************************************************** - ***************************************************************************** - - Execute_load_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Execute_load_log_event methods +**************************************************************************/ +/* Execute_load_log_event ctor +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT Execute_load_log_event::Execute_load_log_event(THD *thd_arg, bool using_trans) :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id) { } -#endif // !MYSQL_CLIENT +#endif -/***************************************************************************** +/* Execute_load_log_event ctor +*/ - ****************************************************************************/ Execute_load_log_event::Execute_load_log_event(const char* buf, int len) :Log_event(buf, 0), file_id(0) { @@ -2904,11 +2865,11 @@ Execute_load_log_event::Execute_load_log_event(const char* buf, int len) file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + EL_FILE_ID_OFFSET); } -/***************************************************************************** +/* Execute_load_log_event::write_data() +*/ - ****************************************************************************/ int Execute_load_log_event::write_data(IO_CACHE* file) { byte buf[EXEC_LOAD_HEADER_LEN]; @@ -2916,11 +2877,11 @@ int Execute_load_log_event::write_data(IO_CACHE* file) return my_b_safe_write(file, buf, EXEC_LOAD_HEADER_LEN); } -/***************************************************************************** +/* Execute_load_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Execute_load_log_event::print(FILE* file, bool short_form, char* last_db) @@ -2932,13 +2893,12 @@ void Execute_load_log_event::print(FILE* file, bool short_form, fprintf(file, "#Exec_load: file_id=%d\n", file_id); } -#endif // MYSQL_CLIENT - -/***************************************************************************** +#endif +/* Execute_load_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Execute_load_log_event::pack_info(Protocol *protocol) { @@ -2948,11 +2908,10 @@ void Execute_load_log_event::pack_info(Protocol *protocol) protocol->store(buf, (int32) length, &my_charset_bin); } -/***************************************************************************** +/* Execute_load_log_event::exec_event() - - ****************************************************************************/ +*/ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) { @@ -3017,22 +2976,17 @@ err: return error ? error : Log_event::exec_event(rli); } -#endif - - -/***************************************************************************** - ***************************************************************************** - - sql_ex_info methods +#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ - ***************************************************************************** - ****************************************************************************/ -/***************************************************************************** +/************************************************************************** + sql_ex_info methods +**************************************************************************/ +/* sql_ex_info::write_data() +*/ - ****************************************************************************/ int sql_ex_info::write_data(IO_CACHE* file) { if (new_format()) @@ -3058,11 +3012,11 @@ int sql_ex_info::write_data(IO_CACHE* file) } } -/***************************************************************************** +/* sql_ex_info::init() +*/ - ****************************************************************************/ char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format) { cached_new_format = use_new_format; diff --git a/sql/log_event.h b/sql/log_event.h index 62b5873fabb..1d2fc741fa8 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -227,10 +227,11 @@ struct sql_ex_info enum Log_event_type { - START_EVENT = 1, QUERY_EVENT =2, STOP_EVENT=3, ROTATE_EVENT = 4, - INTVAR_EVENT=5, LOAD_EVENT=6, SLAVE_EVENT=7, CREATE_FILE_EVENT=8, - APPEND_BLOCK_EVENT=9, EXEC_LOAD_EVENT=10, DELETE_FILE_EVENT=11, - NEW_LOAD_EVENT=12, RAND_EVENT=13, USER_VAR_EVENT=14 + UNKNOWN_EVENT= 0, START_EVENT= 1, QUERY_EVENT= 2, STOP_EVENT= 3, + ROTATE_EVENT= 4, INTVAR_EVENT= 5, LOAD_EVENT=6, SLAVE_EVENT= 7, + CREATE_FILE_EVENT= 8, APPEND_BLOCK_EVENT= 9, EXEC_LOAD_EVENT= 10, + DELETE_FILE_EVENT= 11, NEW_LOAD_EVENT= 12, RAND_EVENT= 13, + USER_VAR_EVENT= 14 }; enum Int_event_type @@ -524,14 +525,14 @@ extern char server_version[SERVER_VERSION_LENGTH]; class Start_log_event: public Log_event { public: - uint32 created; + time_t created; uint16 binlog_version; char server_version[ST_SERVER_VER_LEN]; #ifndef MYSQL_CLIENT Start_log_event() :Log_event(), binlog_version(BINLOG_VERSION) { - created = (uint32) when; + created = (time_t) when; memcpy(server_version, ::server_version, ST_SERVER_VER_LEN); } #ifdef HAVE_REPLICATION @@ -887,4 +888,18 @@ public: int write_data(IO_CACHE* file); }; +#ifdef MYSQL_CLIENT +class Unknown_log_event: public Log_event +{ +public: + Unknown_log_event(const char* buf, bool old_format): + Log_event(buf, old_format) + {} + ~Unknown_log_event() {} + void print(FILE* file, bool short_form= 0, char* last_db= 0); + Log_event_type get_type_code() { return UNKNOWN_EVENT;} + bool is_valid() { return 1; } +}; +#endif + #endif /* _log_event_h */ diff --git a/sql/mini_client.cc b/sql/mini_client.cc index afcee5fbb02..9bfaa95d9d9 100644 --- a/sql/mini_client.cc +++ b/sql/mini_client.cc @@ -247,7 +247,7 @@ static void mc_free_old_query(MYSQL *mysql) static int mc_sock_connect(my_socket s, const struct sockaddr *name, uint namelen, uint to) { -#if defined(__WIN__) || defined(OS2) +#if defined(__WIN__) || defined(OS2) || defined(__NETWARE__) return connect(s, (struct sockaddr*) name, namelen); #else int flags, res, s_err; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 632007d1415..c618b6bacd3 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -45,6 +45,10 @@ char *sql_strdup(const char *str); char *sql_strmake(const char *str,uint len); gptr sql_memdup(const void * ptr,unsigned size); void sql_element_free(void *ptr); +char *sql_strmake_with_convert(const char *str, uint32 arg_length, + CHARSET_INFO *from_cs, + uint32 max_res_length, + CHARSET_INFO *to_cs, uint32 *result_length); void kill_one_thread(THD *thd, ulong id); bool net_request_file(NET* net, const char* fname); char* query_table_status(THD *thd,const char *db,const char *table_name); @@ -368,7 +372,12 @@ void mysql_execute_command(THD *thd); bool do_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); +#ifndef EMBEDDED_LIBRARY bool check_stack_overrun(THD *thd,char *dummy); +#else +#define check_stack_overrun(A, B) 0 +#endif + bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, bool *write_to_binlog); void table_cache_init(void); @@ -624,8 +633,8 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table, bool return_if_owned_by_thd=0); bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables); void copy_field_from_tmp_record(Field *field,int offset); -int fill_record(List<Item> &fields,List<Item> &values); -int fill_record(Field **field,List<Item> &values); +int fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors); +int fill_record(Field **field,List<Item> &values, bool ignore_errors); OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild); /* sql_calc.cc */ @@ -682,7 +691,7 @@ extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], #define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list)) extern MY_TMPDIR mysql_tmpdir_list; extern const char *command_name[]; -extern const char *first_keyword, *localhost, *delayed_user; +extern const char *first_keyword, *localhost, *delayed_user, *binary_keyword; extern const char **errmesg; /* Error messages */ extern const char *myisam_recover_options_str; extern uchar *days_in_month; @@ -690,7 +699,6 @@ extern char language[LIBLEN],reg_ext[FN_EXTLEN]; extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN]; extern char pidfile_name[FN_REFLEN], time_zone[30], *opt_init_file; extern char log_error_file[FN_REFLEN]; -extern char blob_newline; extern double log_10[32]; extern ulonglong keybuff_size; extern ulong refresh_version,flush_version, thread_id,query_id,opened_tables; @@ -736,11 +744,11 @@ extern uint volatile thread_count, thread_running, global_read_lock; extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; extern my_bool opt_safe_show_db, opt_local_infile, lower_case_table_names; extern my_bool opt_slave_compressed_protocol, use_temp_pool; +extern my_bool opt_readonly; extern my_bool opt_enable_named_pipe; extern my_bool opt_old_passwords, use_old_passwords; extern char *shared_memory_base_name; extern bool opt_enable_shared_memory; -extern char f_fyllchar; extern MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log; extern FILE *bootstrap_file; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1036e4d2835..8037da06c33 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -46,7 +46,7 @@ #define MAIN_THD #define SIGNAL_THD -#ifdef PURIFY +#ifdef HAVE_purify #define IF_PURIFY(A,B) (A) #else #define IF_PURIFY(A,B) (B) @@ -116,7 +116,7 @@ int deny_severity = LOG_WARNING; #define my_fromhost(A) fromhost() #define my_hosts_access(A) hosts_access() #define my_eval_client(A) eval_client() -#endif +#endif /* __STDC__ */ #endif /* HAVE_LIBWRAP */ #ifdef HAVE_SYS_MMAN_H @@ -128,8 +128,8 @@ int deny_severity = LOG_WARNING; #include <library.h> #include <monitor.h> -event_handle_t eh; -Report_t ref; +static event_handle_t eh; +static Report_t ref; #endif /* __NETWARE__ */ #ifdef _AIX41 @@ -169,6 +169,7 @@ inline void reset_floating_point_exceptions() #else #define THR_KILL_SIGNAL SIGUSR2 // Can't use this with LinuxThreads #endif +#define MYSQL_KILL_SIGNAL SIGTERM #ifdef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R #include <sys/types.h> @@ -183,229 +184,95 @@ inline void reset_floating_point_exceptions() extern "C" int gethostname(char *name, int namelen); #endif -#define MYSQL_KILL_SIGNAL SIGTERM - -#ifndef DBUG_OFF -static const char* default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace", - "d:t:i:o,/tmp/mysqld.trace"); -#endif - -#ifdef __NT__ -static char szPipeName [ 257 ]; -static SECURITY_ATTRIBUTES saPipeSecurity; -static SECURITY_DESCRIPTOR sdPipeDescriptor; -static HANDLE hPipe = INVALID_HANDLE_VALUE; -#endif -#ifdef __WIN__ -static pthread_cond_t COND_handler_count; -static uint handler_count; -static bool start_mode=0, use_opt_args; -static int opt_argc; -static char **opt_argv; -#endif /* Set prefix for windows binary */ #ifdef __WIN__ #undef MYSQL_SERVER_SUFFIX #ifdef __NT__ -#if defined(HAVE_INNOBASE_DB) || defined(HAVE_BERKELEY_DB) +#if defined(HAVE_BERKELEY_DB) #define MYSQL_SERVER_SUFFIX "-max-nt" #else #define MYSQL_SERVER_SUFFIX "-nt" #endif /* ...DB */ -#elif defined(HAVE_INNOBASE_DB) || defined(HAVE_BERKELEY_DB) +#elif defined(HAVE_BERKELEY_DB) #define MYSQL_SERVER_SUFFIX "-max" #else #define MYSQL_SERVER_SUFFIX "" #endif /* __NT__ */ #endif /* __WIN__ */ -#ifdef HAVE_BERKELEY_DB -SHOW_COMP_OPTION have_berkeley_db=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_berkeley_db=SHOW_OPTION_NO; -#endif -#ifdef HAVE_INNOBASE_DB -SHOW_COMP_OPTION have_innodb=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_innodb=SHOW_OPTION_NO; -#endif -#ifdef HAVE_ISAM -SHOW_COMP_OPTION have_isam=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_isam=SHOW_OPTION_NO; -#endif -#ifdef USE_RAID -SHOW_COMP_OPTION have_raid=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_raid=SHOW_OPTION_NO; -#endif -#ifdef HAVE_OPENSSL -SHOW_COMP_OPTION have_openssl=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_openssl=SHOW_OPTION_NO; -#endif -#ifdef HAVE_BROKEN_REALPATH -SHOW_COMP_OPTION have_symlink=SHOW_OPTION_NO; -#else -SHOW_COMP_OPTION have_symlink=SHOW_OPTION_YES; -#endif -#ifdef HAVE_QUERY_CACHE -SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_NO; -#endif -#ifdef HAVE_CRYPT -SHOW_COMP_OPTION have_crypt=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_crypt=SHOW_OPTION_NO; -#endif -#ifdef HAVE_COMPRESS -SHOW_COMP_OPTION have_compress= SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_compress= SHOW_OPTION_NO; -#endif -const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"}; +/* Constants */ -bool opt_large_files= sizeof(my_off_t) > 4; +const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"}; +const char *sql_mode_names[] = +{ + "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE", + "SERIALIZE", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION", + "POSTGRESQL", "ORACLE", "MSSQL", "DB2", "SAPDB", "NO_KEY_OPTIONS", + "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", + NullS +}; +TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"", + sql_mode_names }; +const char *first_keyword= "first", *binary_keyword= "BINARY"; +const char *localhost= "localhost", *delayed_user= "DELAYED"; #if SIZEOF_OFF_T > 4 && defined(BIG_TABLES) #define GET_HA_ROWS GET_ULL #else #define GET_HA_ROWS GET_ULONG #endif -#ifdef HAVE_LIBWRAP -char *libwrapName= NULL; -#endif +bool opt_large_files= sizeof(my_off_t) > 4; +arg_cmp_func Arg_comparator::comparator_matrix[4][2] = +{{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string}, + {&Arg_comparator::compare_real, &Arg_comparator::compare_e_real}, + {&Arg_comparator::compare_int, &Arg_comparator::compare_e_int}, + {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}}; -/* - Variables to store startup options -*/ -my_bool opt_skip_slave_start = 0; // If set, slave is not autostarted -/* - If set, some standard measures to enforce slave data integrity will not - be performed -*/ -my_bool opt_reckless_slave = 0; +/* Global variables */ -ulong back_log, connect_timeout, concurrency; -char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], time_zone[30]; -char log_error_file[FN_REFLEN]; bool opt_log, opt_update_log, opt_bin_log, opt_slow_log; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; +bool server_id_supplied = 0; +bool opt_endinfo,using_udf_functions, locked_in_memory; +bool opt_using_transactions, using_update_log; +bool volatile abort_loop, select_thread_in_use, signal_thread_in_use; +bool volatile ready_to_exit, shutdown_in_progress, grant_option; + +my_bool opt_skip_slave_start = 0; // If set, slave is not autostarted +my_bool opt_reckless_slave = 0; my_bool opt_enable_named_pipe= 0; my_bool opt_local_infile, opt_external_locking, opt_slave_compressed_protocol; -uint delay_key_write_options= (uint) DELAY_KEY_WRITE_ON; - -static bool opt_do_pstack = 0; -static ulong opt_specialflag=SPECIAL_ENGLISH; - -static ulong opt_myisam_block_size; -static my_socket unix_sock= INVALID_SOCKET,ip_sock= INVALID_SOCKET; -static my_string opt_logname=0,opt_update_logname=0, - opt_binlog_index_name = 0,opt_slow_logname=0; - -static char* mysql_home_ptr= mysql_home; -static char* pidfile_name_ptr= pidfile_name; -char* log_error_file_ptr= log_error_file; -static pthread_t select_thread; -static my_bool opt_noacl=0, opt_bootstrap=0, opt_myisam_log=0; my_bool opt_safe_user_create = 0, opt_no_mix_types = 0; my_bool lower_case_table_names, opt_old_rpl_compat; my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0; my_bool opt_log_slave_updates= 0, opt_old_passwords=0, use_old_passwords=0; my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam; +my_bool opt_readonly, use_temp_pool, relay_log_purge; +volatile bool mqh_used = 0; -volatile bool mqh_used = 0; -FILE *bootstrap_file=0; - -static bool kill_in_progress=0, segfaulted= 0; -struct rand_struct sql_rand; // used by sql_class.cc:THD::THD() -static int cleanup_done; -static char **defaults_argv; -char glob_hostname[FN_REFLEN]; +uint mysql_port, test_flags, select_errors, dropping_tables, ha_open_options; +uint delay_key_write_options, protocol_version; +uint volatile thread_count, thread_running, kill_cached_threads, wake_thread; -#include "sslopt-vars.h" -#ifdef HAVE_OPENSSL -char *des_key_file = 0; -struct st_VioSSLAcceptorFd *ssl_acceptor_fd= 0; -#endif /* HAVE_OPENSSL */ - -I_List <i_string_pair> replicate_rewrite_db; -I_List<i_string> replicate_do_db, replicate_ignore_db; -// allow the user to tell us which db to replicate and which to ignore -I_List<i_string> binlog_do_db, binlog_ignore_db; - -/* if we guessed server_id , we need to know about it */ -ulong server_id= 0; // Must be long becasue of set_var.cc -bool server_id_supplied = 0; - -uint mysql_port; -uint test_flags = 0, select_errors=0, dropping_tables=0,ha_open_options=0; -uint volatile thread_count=0, thread_running=0, kill_cached_threads=0, - wake_thread=0; -ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL | - OPTION_BIN_LOG | OPTION_QUOTE_SHOW_CREATE ); -uint protocol_version=PROTOCOL_VERSION; -struct system_variables global_system_variables; -struct system_variables max_system_variables; -ulonglong keybuff_size; -ulong table_cache_size, - thread_stack, - thread_stack_min,what_to_log= ~ (1L << (uint) COM_TIME), - query_buff_size, - slow_launch_time = 2L, - slave_open_temp_tables=0, - open_files_limit=0, max_binlog_size; -ulong com_stat[(uint) SQLCOM_END], com_other; +ulong back_log, connect_timeout, concurrency; +ulong server_id, thd_startup_options; +ulong table_cache_size, thread_stack, thread_stack_min, what_to_log; +ulong query_buff_size, slow_launch_time, slave_open_temp_tables; +ulong open_files_limit, max_binlog_size; ulong slave_net_timeout; ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0; ulong query_cache_size=0; -#ifdef HAVE_QUERY_CACHE -ulong query_cache_limit= 0; -ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE; -Query_cache query_cache; -#endif -arg_cmp_func Arg_comparator::comparator_matrix[4][2] = -{{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string}, - {&Arg_comparator::compare_real, &Arg_comparator::compare_e_real}, - {&Arg_comparator::compare_int, &Arg_comparator::compare_e_int}, - {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}}; -#ifdef HAVE_SMEM -char *shared_memory_base_name=default_shared_memory_base_name; -my_bool opt_enable_shared_memory = 0; -#endif - -volatile ulong cached_thread_count=0; - -// replication parameters, if master_host is not NULL, we are a slave -my_string master_user = (char*) "test", master_password = 0, master_host=0, - master_info_file = (char*) "master.info", - relay_log_info_file = (char*) "relay-log.info", - master_ssl_key=0, master_ssl_cert=0, master_ssl_capath=0, master_ssl_cipher=0; -my_string report_user = 0, report_password = 0, report_host=0; - -const char *localhost=LOCAL_HOST; -const char *delayed_user="DELAYED"; -uint master_port = MYSQL_PORT, master_connect_retry = 60; -uint report_port = MYSQL_PORT; -bool master_ssl = 0; - -ulong master_retry_count=0; -ulong bytes_sent = 0L, bytes_received = 0L; - -bool opt_endinfo,using_udf_functions, locked_in_memory; -bool opt_using_transactions, using_update_log; -bool volatile abort_loop, select_thread_in_use, signal_thread_in_use; -bool volatile ready_to_exit, shutdown_in_progress, grant_option; +ulong com_stat[(uint) SQLCOM_END], com_other; +ulong bytes_sent, bytes_received; ulong refresh_version=1L,flush_version=1L; /* Increments on each reload */ -ulong query_id=1L,long_query_count,aborted_threads, - aborted_connects,delayed_insert_timeout,delayed_insert_limit, - delayed_queue_size,delayed_insert_threads,delayed_insert_writes, - delayed_rows_in_use,delayed_insert_errors,flush_time, thread_created; +ulong query_id, long_query_count, aborted_threads, aborted_connects; +ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; +ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use; +ulong delayed_insert_errors,flush_time, thread_created; ulong filesort_rows, filesort_range_count, filesort_scan_count; ulong filesort_merge_passes; ulong select_range_check_count, select_range_count, select_scan_count; @@ -417,53 +284,51 @@ ulong max_connections,max_insert_delayed_threads,max_used_connections, ulong thread_id=1L,current_pid; ulong slow_launch_threads = 0; ulong expire_logs_days = 0; +ulong rpl_recovery_rank=0; +ulong my_bind_addr; /* the address we bind to */ +volatile ulong cached_thread_count= 0; + +ulonglong keybuff_size; + +double log_10[32]; /* 10 potences */ +time_t start_time; + +char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], time_zone[30]; +char log_error_file[FN_REFLEN], glob_hostname[FN_REFLEN]; +char* log_error_file_ptr= log_error_file; char mysql_real_data_home[FN_REFLEN], - language[LIBLEN],reg_ext[FN_EXTLEN], - mysql_charsets_dir[FN_REFLEN], - blob_newline,f_fyllchar,max_sort_char,*mysqld_user,*mysqld_chroot, - *opt_init_file; + language[LIBLEN],reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN], + max_sort_char,*mysqld_user,*mysqld_chroot, *opt_init_file; char *language_ptr= language; char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home; -char *default_collation_name= (char*) default_charset_info->name; -#ifndef EMBEDDED_LIBRARY -bool mysql_embedded=0; -#else -bool mysql_embedded=1; -#endif - -static char *opt_bin_logname = 0; -char *opt_relay_logname = 0, *opt_relaylog_index_name=0; char server_version[SERVER_VERSION_LENGTH]=MYSQL_SERVER_VERSION; -const char *first_keyword="first"; +char *mysql_unix_port, *opt_mysql_tmpdir; +char *my_bind_addr_str; const char **errmesg; /* Error messages */ const char *myisam_recover_options_str="OFF"; const char *sql_mode_str="OFF"; -ulong rpl_recovery_rank=0; -my_bool relay_log_purge=1; -my_string mysql_unix_port=NULL, opt_mysql_tmpdir=NULL; -MY_TMPDIR mysql_tmpdir_list; -ulong my_bind_addr; /* the address we bind to */ -char *my_bind_addr_str; -DATE_FORMAT dayord; -double log_10[32]; /* 10 potences */ +FILE *bootstrap_file; + +I_List <i_string_pair> replicate_rewrite_db; +I_List<i_string> replicate_do_db, replicate_ignore_db; +// allow the user to tell us which db to replicate and which to ignore +I_List<i_string> binlog_do_db, binlog_ignore_db; I_List<THD> threads,thread_cache; -time_t start_time; -const char *sql_mode_names[] = -{ - "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE", - "SERIALIZE", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION", - "POSTGRESQL", "ORACLE", "MSSQL", "DB2", "SAPDB", "NO_KEY_OPTIONS", - "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", - NullS -}; -TYPELIB sql_mode_typelib= {array_elements(sql_mode_names)-1,"", - sql_mode_names}; +struct system_variables global_system_variables; +struct system_variables max_system_variables; +MY_TMPDIR mysql_tmpdir_list; +DATE_FORMAT dayord; MY_BITMAP temp_pool; -my_bool use_temp_pool=0; + +SHOW_COMP_OPTION have_berkeley_db, have_innodb, have_isam; +SHOW_COMP_OPTION have_raid, have_openssl, have_symlink, have_query_cache; +SHOW_COMP_OPTION have_crypt, have_compress; + +/* Thread specific variables */ pthread_key(MEM_ROOT*,THR_MALLOC); pthread_key(THD*, THR_THD); @@ -481,24 +346,98 @@ pthread_cond_t COND_thread_cache,COND_flush_thread_cache; pthread_t signal_thread; pthread_attr_t connection_attrib; +/* replication parameters, if master_host is not NULL, we are a slave */ +my_bool master_ssl; +uint master_port= MYSQL_PORT, master_connect_retry = 60; +uint report_port= MYSQL_PORT; +ulong master_retry_count=0; +char *master_user, *master_password, *master_host, *master_info_file; +char *relay_log_info_file, *master_ssl_key, *master_ssl_cert; +char *master_ssl_capath, *master_ssl_cipher, *report_user; +char *report_password, *report_host; +char *opt_relay_logname = 0, *opt_relaylog_index_name=0; + +/* Static variables */ + +static bool kill_in_progress, segfaulted; +static my_bool opt_do_pstack, opt_noacl, opt_bootstrap, opt_myisam_log; +static int cleanup_done; +static ulong opt_specialflag, opt_myisam_block_size; +static char *opt_logname, *opt_update_logname, *opt_binlog_index_name; +static char *opt_slow_logname; +static char *mysql_home_ptr, *pidfile_name_ptr; +static char **defaults_argv; +static char *opt_bin_logname; + +static my_socket unix_sock,ip_sock; +static pthread_t select_thread; +struct rand_struct sql_rand; // used by sql_class.cc:THD::THD() + +/* OS specific variables */ + #ifdef __WIN__ #undef getpid #include <process.h> + +static pthread_cond_t COND_handler_count; +static uint handler_count; +static bool start_mode=0, use_opt_args; +static int opt_argc; +static char **opt_argv; + #if !defined(EMBEDDED_LIBRARY) -HANDLE hEventShutdown; +static HANDLE hEventShutdown; static char shutdown_event_name[40]; #include "nt_servc.h" static NTService Service; // Service object for WinNT -#endif +#endif /* EMBEDDED_LIBRARY */ +#endif /* __WIN__ */ + +#ifdef __NT__ +static char szPipeName [ 257 ]; +static SECURITY_ATTRIBUTES saPipeSecurity; +static SECURITY_DESCRIPTOR sdPipeDescriptor; +static HANDLE hPipe = INVALID_HANDLE_VALUE; #endif #ifdef OS2 pthread_cond_t eventShutdown; #endif +#ifndef EMBEDDED_LIBRARY +bool mysql_embedded=0; +#else +bool mysql_embedded=1; +#endif + +#ifndef DBUG_OFF +static const char* default_dbug_option; +#endif +#ifdef HAVE_LIBWRAP +char *libwrapName= NULL; +#endif +#ifdef HAVE_QUERY_CACHE +ulong query_cache_limit= 0; +ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE; +Query_cache query_cache; +#endif +#ifdef HAVE_SMEM +char *shared_memory_base_name= default_shared_memory_base_name; +my_bool opt_enable_shared_memory; +#endif + +#include "sslopt-vars.h" +#ifdef HAVE_OPENSSL +char *des_key_file; +struct st_VioSSLAcceptorFd *ssl_acceptor_fd; +#endif /* HAVE_OPENSSL */ + + +/* Function declarations */ + static void start_signal_handler(void); extern "C" pthread_handler_decl(signal_hand, arg); -static void set_options(void); +static void mysql_init_variables(void); static void get_options(int argc,char **argv); static int init_thread_environment(); static char *get_relative_path(const char *path); @@ -824,9 +763,9 @@ static void __cdecl kill_server(int sig_ptr) unireg_end(); #ifdef __NETWARE__ pthread_join(select_thread, NULL); // wait for main thread -#else - pthread_exit(0); /* purecov: deadcode */ #endif /* __NETWARE__ */ + + pthread_exit(0); /* purecov: deadcode */ #endif /* EMBEDDED_LIBRARY */ RETURN_FROM_KILL_SERVER; @@ -884,13 +823,11 @@ void unireg_end(void) { clean_up(1); my_thread_end(); -#ifndef __NETWARE__ -#ifdef SIGNALS_DONT_BREAK_READ +#if defined(SIGNALS_DONT_BREAK_READ) && !defined(__NETWARE__) exit(0); #else pthread_exit(0); // Exit is in main thread #endif -#endif /* __NETWARE__ */ } @@ -954,6 +891,8 @@ void clean_up(bool print_message) end_slave_list(); #endif #ifdef HAVE_OPENSSL + if (ssl_acceptor_fd) + my_free((gptr) ssl_acceptor_fd, MYF(MY_ALLOW_ZERO_PTR)); free_des_key_file(); #endif /* HAVE_OPENSSL */ #ifdef USE_REGEX @@ -1647,6 +1586,7 @@ static void init_signals(void) sa.sa_handler=handle_segfault; #endif sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGABRT, &sa, NULL); #ifdef SIGBUS sigaction(SIGBUS, &sa, NULL); #endif @@ -1732,9 +1672,10 @@ extern "C" void *signal_hand(void *arg __attribute__((unused))) /* Setup alarm handler - The two extra handlers are for slave threads + This should actually be '+ max_number_of_slaves' instead of +10, + but the +10 should be quite safe. */ - init_thr_alarm(max_connections+max_insert_delayed_threads+2); + init_thr_alarm(max_connections+max_insert_delayed_threads+10); #if SIGINT != THR_KILL_SIGNAL (void) sigemptyset(&set); // Setup up SIGINT for debug (void) sigaddset(&set,SIGINT); // For debugging @@ -1997,6 +1938,7 @@ static int init_common_variables(const char *conf_file_name, int argc, max_system_variables.pseudo_thread_id= (ulong)~0; start_time=time((time_t*) 0); + mysql_init_variables(); #ifdef OS2 { @@ -2035,7 +1977,6 @@ static int init_common_variables(const char *conf_file_name, int argc, load_defaults(conf_file_name, groups, &argc, &argv); defaults_argv=argv; - set_options(); get_options(argc,argv); if (init_thread_environment()) return 1; @@ -3482,10 +3423,11 @@ enum options OPT_QUERY_CACHE_TYPE, OPT_RECORD_BUFFER, OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE, OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME, + OPT_READONLY, OPT_SORT_BUFFER, OPT_TABLE_CACHE, OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE, OPT_TMP_TABLE_SIZE, OPT_THREAD_STACK, - OPT_WAIT_TIMEOUT, + OPT_WAIT_TIMEOUT, OPT_MYISAM_REPAIR_THREADS, OPT_INNODB_MIRRORED_LOG_GROUPS, OPT_INNODB_LOG_FILES_IN_GROUP, OPT_INNODB_LOG_FILE_SIZE, @@ -3497,6 +3439,7 @@ enum options OPT_INNODB_LOCK_WAIT_TIMEOUT, OPT_INNODB_THREAD_CONCURRENCY, OPT_INNODB_FORCE_RECOVERY, + OPT_INNODB_MAX_DIRTY_PAGES_PCT, OPT_BDB_CACHE_SIZE, OPT_BDB_LOG_BUFFER_SIZE, OPT_BDB_MAX_LOCK, @@ -3667,6 +3610,10 @@ Disable with --skip-bdb (will save memory)", {"innodb_fast_shutdown", OPT_INNODB_FAST_SHUTDOWN, "Speeds up server shutdown process", (gptr*) &innobase_fast_shutdown, (gptr*) &innobase_fast_shutdown, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"innodb_max_dirty_pages_pct", OPT_INNODB_MAX_DIRTY_PAGES_PCT, + "Percentage of dirty pages allowed in bufferpool", (gptr*) &srv_max_buf_pool_modified_pct, + (gptr*) &srv_max_buf_pool_modified_pct, 0, GET_ULONG, REQUIRED_ARG, 90, 0, 100, 0, 0, 0}, + #endif /* End HAVE_INNOBASE_DB */ {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -3685,7 +3632,7 @@ Disable with --skip-bdb (will save memory)", (gptr*) &opt_local_infile, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, {"log-bin", OPT_BIN_LOG, - "Log queries in new binary format (for replication)", + "Log update queries in binary format", (gptr*) &opt_bin_logname, (gptr*) &opt_bin_logname, 0, GET_STR_ALLOC, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-bin-index", OPT_BIN_LOG_INDEX, @@ -3739,27 +3686,32 @@ Disable with --skip-bdb (will save memory)", (gptr*) &master_retry_count, (gptr*) &master_retry_count, 0, GET_ULONG, REQUIRED_ARG, 3600*24, 0, 0, 0, 0, 0}, {"master-info-file", OPT_MASTER_INFO_FILE, - "The location of the file that remembers where we left off on the master during the replication process. The default is `master.info' in the data directory. You should not need to change this.", + "The location and name of the file that remembers the master and where the I/O replication \ +thread is in the master's binlogs.", (gptr*) &master_info_file, (gptr*) &master_info_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl", OPT_MASTER_SSL, - "Turn SSL on for replication. Be warned that is this is a relatively new feature.", + "Planned to enable the slave to connect to the master using SSL. Does nothing yet.", (gptr*) &master_ssl, (gptr*) &master_ssl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-key", OPT_MASTER_SSL_KEY, - "Master SSL keyfile name. Only applies if you have enabled master-ssl.", + "Master SSL keyfile name. Only applies if you have enabled master-ssl. Does \ +nothing yet.", (gptr*) &master_ssl_key, (gptr*) &master_ssl_key, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-cert", OPT_MASTER_SSL_CERT, - "Master SSL certificate file name. Only applies if you have enabled master-ssl.", + "Master SSL certificate file name. Only applies if you have enabled \ +master-ssl. Does nothing yet.", (gptr*) &master_ssl_cert, (gptr*) &master_ssl_cert, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-capath", OPT_MASTER_SSL_CAPATH, - "Master SSL CA path. Only applies if you have enabled master-ssl.", + "Master SSL CA path. Only applies if you have enabled master-ssl. \ +Does nothing yet.", (gptr*) &master_ssl_capath, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-cipher", OPT_MASTER_SSL_CIPHER, - "Master SSL cipher. Only applies if you have enabled master-ssl.", + "Master SSL cipher. Only applies if you have enabled master-ssl. \ +Does nothing yet.", (gptr*) &master_ssl_cipher, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"myisam-recover", OPT_MYISAM_RECOVER, @@ -3860,10 +3812,13 @@ Disable with --skip-bdb (will save memory)", {"rpl-recovery-rank", OPT_RPL_RECOVERY_RANK, "Undocumented", (gptr*) &rpl_recovery_rank, (gptr*) &rpl_recovery_rank, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"relay-log", OPT_RELAY_LOG, "Undocumented", + {"relay-log", OPT_RELAY_LOG, + "The location and name to use for relay logs", (gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"relay-log-index", OPT_RELAY_LOG_INDEX, "Undocumented", + {"relay-log-index", OPT_RELAY_LOG_INDEX, + "The location and name to use for the file that keeps a list of the last \ +relay logs", (gptr*) &opt_relaylog_index_name, (gptr*) &opt_relaylog_index_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).", @@ -3933,16 +3888,20 @@ Disable with --skip-isam", {"skip-stack-trace", OPT_SKIP_STACK_TRACE, "Don't print a stack trace on failure", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables", + {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. Depricated option. Use --skip-symbolic-links instead", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-thread-priority", OPT_SKIP_PRIOR, "Don't give threads different priorities.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"relay-log-info-file", OPT_RELAY_LOG_INFO_FILE, "Undocumented", + {"relay-log-info-file", OPT_RELAY_LOG_INFO_FILE, + "The location and name of the file that remembers where the SQL replication \ +thread is in the relay logs", (gptr*) &relay_log_info_file, (gptr*) &relay_log_info_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_REPLICATION - {"slave-load-tmpdir", OPT_SLAVE_LOAD_TMPDIR, "Undocumented", + {"slave-load-tmpdir", OPT_SLAVE_LOAD_TMPDIR, + "The location where the slave should put its temporary files when \ +replicating a LOAD DATA INFILE command", (gptr*) &slave_load_tmpdir, (gptr*) &slave_load_tmpdir, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"slave-skip-errors", OPT_SLAVE_SKIP_ERRORS, @@ -3983,11 +3942,12 @@ Disable with --skip-isam", {"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running", (gptr*) &opt_external_locking, (gptr*) &opt_external_locking, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef USE_SYMDIR - {"use-symbolic-links", 's', "Enable symbolic link support", + {"use-symbolic-links", 's', "Enable symbolic link support. Depricated option; Use --symbolic-links instead", + (gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG, + IF_PURIFY(0,1), 0, 0, 0, 0, 0}, + {"--symbolic-links", 's', "Enable symbolic link support", (gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG, IF_PURIFY(0,1), 0, 0, 0, 0, 0}, -#endif {"user", 'u', "Run mysqld daemon as user", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit", 0, 0, 0, GET_NO_ARG, @@ -4165,7 +4125,7 @@ Disable with --skip-isam", (gptr*) &max_connect_errors, (gptr*) &max_connect_errors, 0, GET_ULONG, REQUIRED_ARG, MAX_CONNECT_ERRORS, 1, ~0L, 0, 1, 0}, {"max_delayed_threads", OPT_MAX_DELAYED_THREADS, - "Don't start more than this number of threads to handle INSERT DELAYED statements. This option does not yet have effect (on TODO), unless it is set to zero, which means INSERT DELAYED is not used.", + "Don't start more than this number of threads to handle INSERT DELAYED statements. If set to zero, which means INSERT DELAYED is not used.", (gptr*) &max_insert_delayed_threads, (gptr*) &max_insert_delayed_threads, 0, GET_ULONG, REQUIRED_ARG, 20, 0, 16384, 0, 1, 0}, {"max_error_count", OPT_MAX_ERROR_COUNT, @@ -4227,12 +4187,18 @@ Disable with --skip-isam", (gptr*) &global_system_variables.myisam_max_extra_sort_file_size, (gptr*) &max_system_variables.myisam_max_extra_sort_file_size, 0, GET_ULL, REQUIRED_ARG, (ulonglong) MI_MAX_TEMP_LENGTH, - 0, ~0L, 0, 1, 0}, + 0, (ulonglong) MAX_FILE_SIZE, 0, 1, 0}, {"myisam_max_sort_file_size", OPT_MYISAM_MAX_SORT_FILE_SIZE, "Don't use the fast sort index method to created index if the temporary file would get bigger than this!", (gptr*) &global_system_variables.myisam_max_sort_file_size, (gptr*) &max_system_variables.myisam_max_sort_file_size, 0, - GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, ~0L, 0, 1024*1024, 0}, + GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, (ulonglong) MAX_FILE_SIZE, + 0, 1024*1024, 0}, + {"myisam_repair_threads", OPT_MYISAM_REPAIR_THREADS, + "Number of threads to use when repairing MyISAM tables. The value of 1 disables parallel repair.", + (gptr*) &global_system_variables.myisam_repair_threads, + (gptr*) &max_system_variables.myisam_repair_threads, 0, + GET_ULONG, REQUIRED_ARG, 1, 1, ~0L, 0, 1, 0}, {"myisam_sort_buffer_size", OPT_MYISAM_SORT_BUFFER_SIZE, "The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE.", (gptr*) &global_system_variables.myisam_sort_buff_size, @@ -4307,7 +4273,7 @@ Disable with --skip-isam", (gptr*) &relay_log_purge, 0, GET_BOOL, NO_ARG, 1, 0, 1, 0, 1, 0}, {"relay_log_space_limit", OPT_RELAY_LOG_SPACE_LIMIT, - "Max space to use for all relay logs", + "Maximum space to use for all relay logs", (gptr*) &relay_log_space_limit, (gptr*) &relay_log_space_limit, 0, GET_ULL, REQUIRED_ARG, 0L, 0L, (longlong) ULONG_MAX, 0, 1, 0}, @@ -4321,6 +4287,11 @@ Disable with --skip-isam", (gptr*) &slave_net_timeout, (gptr*) &slave_net_timeout, 0, GET_ULONG, REQUIRED_ARG, SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, #endif /* HAVE_REPLICATION */ + {"read-only", OPT_READONLY, + "Make all tables readonly, with the expections for replications (slave) threads and users with the SUPER privilege", + (gptr*) &opt_readonly, + (gptr*) &opt_readonly, + 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, {"slow_launch_time", OPT_SLOW_LAUNCH_TIME, "If creating the thread takes longer than this value (in seconds), the Slow_launch_threads counter will be incremented.", (gptr*) &slow_launch_time, (gptr*) &slow_launch_time, 0, GET_ULONG, @@ -4597,19 +4568,111 @@ To see what values a running MySQL server is using, type\n\ } -static void set_options(void) -{ -#if !defined( my_pthread_setprio ) && !defined( HAVE_PTHREAD_SETSCHEDPARAM ) - opt_specialflag |= SPECIAL_NO_PRIOR; -#endif +/* + Initialize all MySQL global variables to default values + + SYNOPSIS + mysql_init_variables() + + NOTES + The reason to set a lot of global variables to zero is to allow one to + restart the embedded server with a clean environment + It's also needed on some exotic platforms where global variables are + not set to 0 when a program starts. + + We don't need to set numeric variables refered to in my_long_options + as these are initialized by my_getopt. +*/ +static void mysql_init_variables(void) +{ + /* Things reset to zero */ + opt_skip_slave_start= opt_reckless_slave = 0; + mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0; + opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0; + opt_disable_networking= opt_skip_show_db=0; + opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname=0; + opt_bootstrap= opt_myisam_log= use_old_passwords= 0; + mqh_used= 0; + segfaulted= kill_in_progress= 0; + cleanup_done= 0; + defaults_argv= 0; + server_id_supplied= 0; + test_flags= select_errors= dropping_tables= ha_open_options=0; + thread_count= thread_running= kill_cached_threads= wake_thread=0; + slave_open_temp_tables= 0; + com_other= 0; + cached_thread_count= 0; + bytes_sent= bytes_received= 0; + opt_endinfo= using_udf_functions= 0; + opt_using_transactions= using_update_log= 0; + abort_loop= select_thread_in_use= signal_thread_in_use= 0; + ready_to_exit= shutdown_in_progress= grant_option= 0; + long_query_count= aborted_threads= aborted_connects= 0; + delayed_insert_threads= delayed_insert_writes= delayed_rows_in_use= 0; + delayed_insert_errors= thread_created= 0; + filesort_rows= filesort_range_count= filesort_scan_count= 0; + filesort_merge_passes= select_range_check_count= select_range_count= 0; + select_scan_count= select_full_range_join_count= select_full_join_count= 0; + specialflag= opened_tables= created_tmp_tables= created_tmp_disk_tables= 0; + max_used_connections= slow_launch_threads = 0; + max_sort_char= 0; + mysqld_user= mysqld_chroot= opt_init_file= opt_bin_logname = 0; + errmesg= 0; + mysql_unix_port= opt_mysql_tmpdir= my_bind_addr_str= NullS; + bzero((gptr) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list)); + bzero((gptr) &com_stat, sizeof(com_stat)); + + /* Things with default values that are not zero */ + delay_key_write_options= (uint) DELAY_KEY_WRITE_ON; + opt_specialflag= SPECIAL_ENGLISH; + unix_sock= ip_sock= INVALID_SOCKET; + mysql_home_ptr= mysql_home; + pidfile_name_ptr= pidfile_name; + log_error_file_ptr= log_error_file; + language_ptr= language; + mysql_data_home= mysql_real_data_home; + thd_startup_options= (OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL | + OPTION_BIN_LOG | OPTION_QUOTE_SHOW_CREATE); + protocol_version= PROTOCOL_VERSION; + what_to_log= ~ (1L << (uint) COM_TIME); + refresh_version= flush_version= 1L; /* Increments on each reload */ + thread_id= 1L; + strmov(server_version, MYSQL_SERVER_VERSION); + myisam_recover_options_str= sql_mode_str= "OFF"; + my_bind_addr = htonl(INADDR_ANY); + threads.empty(); + thread_cache.empty(); + + /* Initialize structures that is used when processing options */ + replicate_rewrite_db.empty(); + replicate_do_db.empty(); + replicate_ignore_db.empty(); + binlog_do_db.empty(); + binlog_ignore_db.empty(); + + /* Set directory paths */ + strmake(language, LANGUAGE, sizeof(language)-1); + strmake(mysql_real_data_home, get_relative_path(DATADIR), + sizeof(mysql_real_data_home)-1); + mysql_data_home_buff[0]=FN_CURLIB; // all paths are relative from here + mysql_data_home_buff[1]=0; + + /* Replication parameters */ + master_user= (char*) "test"; + master_password= master_host= 0; + master_info_file= (char*) "master.info", + relay_log_info_file= (char*) "relay-log.info", + master_ssl_key= master_ssl_cert= master_ssl_capath= master_ssl_cipher= 0; + report_user= report_password = report_host= 0; /* TO BE DELETED */ + opt_relay_logname= opt_relaylog_index_name= 0; + + /* Variables in libraries */ + charsets_dir= 0; sys_charset.value= (char*) MYSQL_CHARSET; sys_charset_system.value= (char*) system_charset_info->csname; - (void) strmake(language, LANGUAGE, sizeof(language)-1); - (void) strmake(mysql_real_data_home, get_relative_path(DATADIR), - sizeof(mysql_real_data_home)-1); - /* Set default values for some variables */ + /* Set default values for some option variables */ global_system_variables.character_set_results= NULL; global_system_variables.character_set_client= default_charset_info; global_system_variables.collation_connection= default_charset_info; @@ -4620,6 +4683,71 @@ static void set_options(void) global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; + /* Variables that depends on compile options */ +#ifndef DBUG_OFF + default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace", + "d:t:i:o,/tmp/mysqld.trace"); +#endif + opt_error_log= IF_WIN(1,0); +#ifdef HAVE_BERKELEY_DB + have_berkeley_db= SHOW_OPTION_YES; +#else + have_berkeley_db= SHOW_OPTION_NO; +#endif +#ifdef HAVE_INNOBASE_DB + have_innodb=SHOW_OPTION_YES; +#else + have_innodb=SHOW_OPTION_NO; +#endif +#ifdef HAVE_ISAM + have_isam=SHOW_OPTION_YES; +#else + have_isam=SHOW_OPTION_NO; +#endif +#ifdef USE_RAID + have_raid=SHOW_OPTION_YES; +#else + have_raid=SHOW_OPTION_NO; +#endif +#ifdef HAVE_OPENSSL + have_openssl=SHOW_OPTION_YES; +#else + have_openssl=SHOW_OPTION_NO; +#endif +#ifdef HAVE_BROKEN_REALPATH + have_symlink=SHOW_OPTION_NO; +#else + have_symlink=SHOW_OPTION_YES; +#endif +#ifdef HAVE_QUERY_CACHE + have_query_cache=SHOW_OPTION_YES; +#else + have_query_cache=SHOW_OPTION_NO; +#endif +#ifdef HAVE_CRYPT + have_crypt=SHOW_OPTION_YES; +#else + have_crypt=SHOW_OPTION_NO; +#endif +#ifdef HAVE_COMPRESS + SHOW_COMP_OPTION have_compress= SHOW_OPTION_YES; +#else + SHOW_COMP_OPTION have_compress= SHOW_OPTION_NO; +#endif +#ifdef HAVE_LIBWRAP + libwrapName= NullS; +#endif +#ifdef HAVE_OPENSSL + des_key_file = 0; + ssl_acceptor_fd= 0; +#endif +#ifdef HAVE_SMEM + shared_memory_base_name= default_shared_memory_base_name; +#endif +#if !defined(my_pthread_setprio) && !defined(HAVE_PTHREAD_SETSCHEDPARAM) + opt_specialflag |= SPECIAL_NO_PRIOR; +#endif + #if defined(__WIN__) || defined(__NETWARE__) /* Allow Win32 and NetWare users to move MySQL anywhere */ { @@ -4634,10 +4762,6 @@ static void set_options(void) tmpenv = DEFAULT_MYSQL_HOME; (void) strmake(mysql_home, tmpenv, sizeof(mysql_home)-1); #endif - - my_disable_locking=myisam_single_user= 1; - opt_external_locking=0; - my_bind_addr = htonl( INADDR_ANY ); } @@ -4866,9 +4990,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE; myisam_concurrent_insert=0; myisam_recover_options= HA_RECOVER_NONE; - my_disable_symlinks=1; my_use_symdir=0; - have_symlink=SHOW_OPTION_DISABLED; ha_open_options&= ~(HA_OPEN_ABORT_IF_CRASHED | HA_OPEN_DELAY_KEY_WRITE); #ifdef HAVE_QUERY_CACHE query_cache_size=0; @@ -4915,9 +5037,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), test_flags|=TEST_NO_STACKTRACE; break; case (int) OPT_SKIP_SYMLINKS: - my_disable_symlinks=1; my_use_symdir=0; - have_symlink=SHOW_OPTION_DISABLED; break; case (int) OPT_BIND_ADDRESS: if (argument && my_isdigit(mysqld_charset, argument[0])) @@ -5189,11 +5309,9 @@ static void get_options(int argc,char **argv) my_disable_locking= myisam_single_user= test(opt_external_locking == 0); my_default_record_cache_size=global_system_variables.read_buff_size; myisam_max_temp_length= - (my_off_t) min(global_system_variables.myisam_max_sort_file_size, - (ulonglong) MAX_FILE_SIZE); + (my_off_t) global_system_variables.myisam_max_sort_file_size; myisam_max_extra_temp_length= - (my_off_t) min(global_system_variables.myisam_max_extra_sort_file_size, - (ulonglong) MAX_FILE_SIZE); + (my_off_t) global_system_variables.myisam_max_extra_sort_file_size; /* Set global variables based on startup options */ myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size); diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 550fb772fce..8271d971782 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -48,13 +48,6 @@ can't normally do this the client should have a bigger max_allowed_packet. */ -#ifdef MYSQL_SERVER -#define USE_QUERY_CACHE -extern uint test_flags; -extern void query_cache_insert(NET *net, const char *packet, ulong length); -#else -#endif - #if defined(__WIN__) || !defined(MYSQL_SERVER) /* The following is because alarms doesn't work on windows. */ #define NO_ALARM @@ -63,16 +56,23 @@ extern void query_cache_insert(NET *net, const char *packet, ulong length); #ifndef NO_ALARM #include "my_pthread.h" void sql_print_error(const char *format,...); -extern ulong bytes_sent, bytes_received; -extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; #else -#undef statistic_add -#define statistic_add(A,B,C) #define DONT_USE_THR_ALARM #endif /* NO_ALARM */ #include "thr_alarm.h" +#ifdef MYSQL_SERVER +#define USE_QUERY_CACHE +extern uint test_flags; +extern void query_cache_insert(NET *net, const char *packet, ulong length); +extern ulong bytes_sent, bytes_received; +extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; +#else +#undef statistic_add +#define statistic_add(A,B,C) +#endif + #define TEST_BLOCKING 8 #define MAX_PACKET_LENGTH (256L*256L*256L-1) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7526772cd09..d40f2e22ea2 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -283,7 +283,7 @@ typedef struct st_qsel_param { KEY_PART *key_parts,*key_parts_end,*key[MAX_KEY]; MEM_ROOT *mem_root; table_map prev_tables,read_tables,current_table; - uint baseflag,keys,max_key_part; + uint baseflag, keys, max_key_part, range_count; uint real_keynr[MAX_KEY]; char min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH], max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; @@ -709,8 +709,10 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, (double) keys_per_block); } else - found_read_time= head->file->read_time(found_records)+ - (double) found_records / TIME_FOR_COMPARE; + found_read_time= (head->file->read_time(keynr, + param.range_count, + found_records)+ + (double) found_records / TIME_FOR_COMPARE); if (read_time > found_read_time) { read_time=found_read_time; @@ -2074,11 +2076,12 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree) if (!tree) DBUG_RETURN(HA_POS_ERROR); // Can't use it + param->max_key_part=0; + param->range_count=0; if (tree->type == SEL_ARG::IMPOSSIBLE) DBUG_RETURN(0L); // Impossible select. return if (tree->type != SEL_ARG::KEY_RANGE || tree->part != 0) DBUG_RETURN(HA_POS_ERROR); // Don't use tree - param->max_key_part=0; records=check_quick_keys(param,idx,tree,param->min_key,0,param->max_key,0); if (records != HA_POS_ERROR) { @@ -2146,6 +2149,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, } keynr=param->real_keynr[idx]; + param->range_count++; if (!tmp_min_flag && ! tmp_max_flag && (uint) key_tree->part+1 == param->table->key_info[keynr].key_parts && (param->table->key_info[keynr].flags & HA_NOSAME) && diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 1e116518da0..34cce98d087 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -69,8 +69,10 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond); RETURN VALUES 0 No errors - 1 if all items was resolved - -1 on impossible conditions + 1 if all items were resolved + -1 on impossible conditions + OR an error number from my_base.h HA_ERR_... if a deadlock or a lock + wait timeout happens, for example */ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) @@ -82,6 +84,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) table_map where_tables= 0; Item *item; COND *org_conds= conds; + int error; if (conds) where_tables= conds->used_tables(); @@ -131,7 +134,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) if (outer_tables || (table->table->file->table_flags() & HA_NOT_EXACT_COUNT)) { - const_result= 0; // Can't optimize left join + const_result= 0; // Can't optimize left join break; } tables->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -164,6 +167,11 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) Item_field *item_field= ((Item_field*) expr); TABLE *table= item_field->field->table; + if ((table->file->table_flags() & HA_NOT_READ_AFTER_KEY)) + { + const_result=0; + break; + } /* Look for a partial key that can be used for optimization. If we succeed, ref.key_length will contain the length of @@ -179,18 +187,21 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) const_result= 0; break; } - bool error= table->file->index_init((uint) ref.key); + error= table->file->index_init((uint) ref.key); if (!ref.key_length) - error= table->file->index_first(table->record[0]) != 0; + error= table->file->index_first(table->record[0]); else - error= table->file->index_read(table->record[0],key_buff, - ref.key_length, - range_fl & NEAR_MIN ? - HA_READ_AFTER_KEY : - HA_READ_KEY_OR_NEXT) || - reckey_in_range(0, &ref, item_field->field, - conds, range_fl, prefix_len); + { + error= table->file->index_read(table->record[0],key_buff, + ref.key_length, + range_fl & NEAR_MIN ? + HA_READ_AFTER_KEY : + HA_READ_KEY_OR_NEXT); + if (!error && reckey_in_range(0, &ref, item_field->field, + conds, range_fl, prefix_len)) + error= HA_ERR_KEY_NOT_FOUND; + } if (table->key_read) { table->key_read= 0; @@ -198,10 +209,16 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } table->file->index_end(); if (error) - return -1; // No rows matching where + { + if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE) + return -1; // No rows matching WHERE + /* HA_ERR_LOCK_DEADLOCK or some other error */ + table->file->print_error(error, MYF(0)); + return(error); + } removed_tables|= table->map; } - else if (!expr->const_item()) // This is VERY seldom false + else if (!expr->const_item()) // This is VERY seldom false { const_result= 0; break; @@ -249,18 +266,21 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) const_result= 0; break; } - bool error= table->file->index_init((uint) ref.key); + error= table->file->index_init((uint) ref.key); if (!ref.key_length) - error=table->file->index_last(table->record[0]) != 0; + error= table->file->index_last(table->record[0]); else - error= table->file->index_read(table->record[0], key_buff, - ref.key_length, - range_fl & NEAR_MAX ? - HA_READ_BEFORE_KEY : - HA_READ_PREFIX_LAST_OR_PREV) || - reckey_in_range(1, &ref, item_field->field, - conds, range_fl, prefix_len); + { + error= table->file->index_read(table->record[0], key_buff, + ref.key_length, + range_fl & NEAR_MAX ? + HA_READ_BEFORE_KEY : + HA_READ_PREFIX_LAST_OR_PREV); + if (!error && reckey_in_range(1, &ref, item_field->field, + conds, range_fl, prefix_len)) + error= HA_ERR_KEY_NOT_FOUND; + } if (table->key_read) { table->key_read=0; @@ -268,10 +288,16 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } table->file->index_end(); if (error) - return -1; // Impossible query + { + if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE) + return -1; // No rows matching WHERE + /* HA_ERR_LOCK_DEADLOCK or some other error */ + table->file->print_error(error, MYF(0)); + return(error); + } removed_tables|= table->map; } - else if (!expr->const_item()) // This is VERY seldom false + else if (!expr->const_item()) // This is VERY seldom false { const_result= 0; break; @@ -597,6 +623,10 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, (if we have a condition field = const, prefix_len contains the length of the whole search key) + NOTE + This function may set table->key_read to 1, which must be reset after + index is used! (This can only happen when function returns 1) + RETURN 0 Index can not be used to optimize MIN(field)/MAX(field) 1 Can use key to optimize MIN()/MAX() diff --git a/sql/records.cc b/sql/records.cc index 9d8627bc1fc..783ca663dfe 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -16,7 +16,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Functions to read, write and lock records */ +/* Functions for easy reading of records, possible through a cache */ #include "mysql_priv.h" diff --git a/sql/set_var.cc b/sql/set_var.cc index a102991a0f2..fe6ee46068c 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -87,6 +87,8 @@ static void fix_max_join_size(THD *thd, enum_var_type type); static void fix_query_cache_size(THD *thd, enum_var_type type); static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type); static void fix_key_buffer_size(THD *thd, enum_var_type type); +static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type); +static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type); static byte *get_error_count(THD *thd); static byte *get_warning_count(THD *thd); @@ -188,8 +190,9 @@ sys_var_thd_ulong sys_max_tmp_tables("max_tmp_tables", &SV::max_tmp_tables); sys_var_long_ptr sys_max_write_lock_count("max_write_lock_count", &max_write_lock_count); -sys_var_thd_ulonglong sys_myisam_max_extra_sort_file_size("myisam_max_extra_sort_file_size", &SV::myisam_max_extra_sort_file_size); -sys_var_thd_ulonglong sys_myisam_max_sort_file_size("myisam_max_sort_file_size", &SV::myisam_max_sort_file_size); +sys_var_thd_ulonglong sys_myisam_max_extra_sort_file_size("myisam_max_extra_sort_file_size", &SV::myisam_max_extra_sort_file_size, fix_myisam_max_extra_sort_file_size, 1); +sys_var_thd_ulonglong sys_myisam_max_sort_file_size("myisam_max_sort_file_size", &SV::myisam_max_sort_file_size, fix_myisam_max_sort_file_size, 1); +sys_var_thd_ulong sys_myisam_repair_threads("myisam_repair_threads", &SV::myisam_repair_threads); sys_var_thd_ulong sys_myisam_sort_buffer_size("myisam_sort_buffer_size", &SV::myisam_sort_buff_size); sys_var_thd_ulong sys_net_buffer_length("net_buffer_length", &SV::net_buffer_length); @@ -233,6 +236,7 @@ sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol", sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout", &slave_net_timeout); #endif +sys_var_bool_ptr sys_readonly("read_only", &opt_readonly); sys_var_long_ptr sys_slow_launch_time("slow_launch_time", &slow_launch_time); sys_var_thd_ulong sys_sort_buffer("sort_buffer_size", @@ -253,6 +257,11 @@ sys_var_thd_ulong sys_tmp_table_size("tmp_table_size", &SV::tmp_table_size); sys_var_thd_ulong sys_net_wait_timeout("wait_timeout", &SV::net_wait_timeout); + +#ifdef HAVE_INNOBASE_DB +sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct", + &srv_max_buf_pool_modified_pct); +#endif /* Variables that are bits in THD */ @@ -271,7 +280,7 @@ static sys_var_thd_bit sys_sql_big_tables("sql_big_tables", #endif static sys_var_thd_bit sys_big_selects("sql_big_selects", set_option_bit, - OPTION_BIG_TABLES); + OPTION_BIG_SELECTS); static sys_var_thd_bit sys_log_off("sql_log_off", set_option_bit, OPTION_LOG_OFF); @@ -399,6 +408,7 @@ sys_var *sys_variables[]= &sys_max_write_lock_count, &sys_myisam_max_extra_sort_file_size, &sys_myisam_max_sort_file_size, + &sys_myisam_repair_threads, &sys_myisam_sort_buffer_size, &sys_net_buffer_length, &sys_net_read_timeout, @@ -430,6 +440,7 @@ sys_var *sys_variables[]= &sys_slave_net_timeout, &sys_slave_skip_counter, #endif + &sys_readonly, &sys_slow_launch_time, &sys_sort_buffer, &sys_sql_big_tables, @@ -443,6 +454,9 @@ sys_var *sys_variables[]= &sys_timestamp, &sys_tmp_table_size, &sys_tx_isolation, +#ifdef HAVE_INNOBASE_DB + &sys_innodb_max_dirty_pages_pct, +#endif &sys_unique_checks, &sys_warning_count }; @@ -518,6 +532,7 @@ struct show_var_st init_vars[]= { {"innodb_log_files_in_group", (char*) &innobase_log_files_in_group, SHOW_LONG}, {"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR}, {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG}, + {sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS}, #endif {sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS}, {sys_join_buffer_size.name, (char*) &sys_join_buffer_size, SHOW_SYS}, @@ -554,13 +569,14 @@ struct show_var_st init_vars[]= { {sys_max_prep_stmt_count.name,(char*) &sys_max_prep_stmt_count, SHOW_SYS}, {sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS}, {sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS}, - {sys_max_tmp_tables.name, (char*) &sys_max_tmp_tables, SHOW_SYS}, + {sys_max_tmp_tables.name, (char*) &sys_max_tmp_tables, SHOW_SYS}, {sys_max_write_lock_count.name, (char*) &sys_max_write_lock_count,SHOW_SYS}, {sys_myisam_max_extra_sort_file_size.name, (char*) &sys_myisam_max_extra_sort_file_size, SHOW_SYS}, - {sys_myisam_max_sort_file_size.name, - (char*) &sys_myisam_max_sort_file_size, + {sys_myisam_max_sort_file_size.name, (char*) &sys_myisam_max_sort_file_size, + SHOW_SYS}, + {sys_myisam_repair_threads.name, (char*) &sys_myisam_repair_threads, SHOW_SYS}, {"myisam_recover_options", (char*) &myisam_recover_options_str, SHOW_CHAR_PTR}, {sys_myisam_sort_buffer_size.name, (char*) &sys_myisam_sort_buffer_size, SHOW_SYS}, @@ -599,6 +615,7 @@ struct show_var_st init_vars[]= { #ifdef HAVE_REPLICATION {sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS}, #endif + {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS}, {"skip_external_locking", (char*) &my_disable_locking, SHOW_MY_BOOL}, {"skip_networking", (char*) &opt_disable_networking, SHOW_BOOL}, {"skip_show_database", (char*) &opt_skip_show_db, SHOW_BOOL}, @@ -665,6 +682,21 @@ static void fix_low_priority_updates(THD *thd, enum_var_type type) } +static void +fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type) +{ + myisam_max_extra_temp_length= + (my_off_t) global_system_variables.myisam_max_extra_sort_file_size; +} + + +static void +fix_myisam_max_sort_file_size(THD *thd, enum_var_type type) +{ + myisam_max_temp_length= + (my_off_t) global_system_variables.myisam_max_sort_file_size; +} + /* Set the OPTION_BIG_SELECTS flag if max_join_size == HA_POS_ERROR */ @@ -915,15 +947,22 @@ byte *sys_var_thd_ha_rows::value_ptr(THD *thd, enum_var_type type) bool sys_var_thd_ulonglong::update(THD *thd, set_var *var) { + ulonglong tmp= var->value->val_int(); + + if ((ulonglong) tmp > max_system_variables.*offset) + tmp= max_system_variables.*offset; + + if (option_limits) + tmp= (ulong) getopt_ull_limit_value(tmp, option_limits); if (var->type == OPT_GLOBAL) { /* Lock is needed to make things safe on 32 bit systems */ pthread_mutex_lock(&LOCK_global_system_variables); - global_system_variables.*offset= var->value->val_int(); + global_system_variables.*offset= (ulonglong) tmp; pthread_mutex_unlock(&LOCK_global_system_variables); } else - thd->variables.*offset= var->value->val_int(); + thd->variables.*offset= (ulonglong) tmp; return 0; } diff --git a/sql/set_var.h b/sql/set_var.h index d381843df0d..f501426e553 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -235,17 +235,27 @@ class sys_var_thd_ulonglong :public sys_var_thd { public: ulonglong SV::*offset; + bool only_global; sys_var_thd_ulonglong(const char *name_arg, ulonglong SV::*offset_arg) :sys_var_thd(name_arg), offset(offset_arg) {} sys_var_thd_ulonglong(const char *name_arg, ulonglong SV::*offset_arg, - sys_after_update_func func) - :sys_var_thd(name_arg,func), offset(offset_arg) + sys_after_update_func func, bool only_global_arg) + :sys_var_thd(name_arg, func), offset(offset_arg), + only_global(only_global_arg) {} bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE type() { return SHOW_LONGLONG; } byte *value_ptr(THD *thd, enum_var_type type); + bool check_default(enum_var_type type) + { + return type == OPT_GLOBAL && !option_limits; + } + bool check_type(enum_var_type type) + { + return (only_global && type != OPT_GLOBAL); + } }; diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index e04d4494a93..e277c19e26f 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -114,7 +114,7 @@ v/* "Blob polo-B¾ka '%-.64s' nemù¾e mít defaultní hodnotu", "Nep-Bøípustné jméno databáze '%-.64s'", "Nep-Bøípustné jméno tabulky '%-.64s'", -"Zadan-Bý SELECT by procházel pøíli¹ mnoho záznamù a trval velmi dlouho. Zkontrolujte tvar WHERE a je-li SELECT v poøádku, pou¾ijte SET OPTION SQL_BIG_SELECTS=1", +"Zadan-Bý SELECT by procházel pøíli¹ mnoho záznamù a trval velmi dlouho. Zkontrolujte tvar WHERE a je-li SELECT v poøádku, pou¾ijte SET SQL_BIG_SELECTS=1", "Nezn-Bámá chyba", "Nezn-Bámá procedura %s", "Chybn-Bý poèet parametrù procedury %s", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index ff89dbb6bcf..01856ffed01 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -108,7 +108,7 @@ "BLOB feltet '%-.64s' kan ikke have en standard værdi", "Ugyldigt database navn '%-.64s'", "Ugyldigt tabel navn '%-.64s'", -"SELECT ville undersøge for mange poster og ville sandsynligvis tage meget lang tid. Undersøg WHERE delen og brug SET OPTION SQL_BIG_SELECTS=1 hvis udtrykket er korrekt", +"SELECT ville undersøge for mange poster og ville sandsynligvis tage meget lang tid. Undersøg WHERE delen og brug SET SQL_BIG_SELECTS=1 hvis udtrykket er korrekt", "Ukendt fejl", "Ukendt procedure %s", "Forkert antal parametre til proceduren %s", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 98ca6a834e4..4b9b0b9f710 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -116,7 +116,7 @@ "Blob veld '%-.64s' can geen standaardwaarde bevatten", "Databasenaam '%-.64s' is niet getoegestaan", "Niet toegestane tabelnaam '%-.64s'", -"Het SELECT-statement zou te veel records analyseren en dus veel tijd in beslagnemen. Kijk het WHERE-gedeelte van de query na en kies SET OPTION SQL_BIG_SELECTS=1 als het stament in orde is.", +"Het SELECT-statement zou te veel records analyseren en dus veel tijd in beslagnemen. Kijk het WHERE-gedeelte van de query na en kies SET SQL_BIG_SELECTS=1 als het stament in orde is.", "Onbekende Fout", "Onbekende procedure %s", "Foutief aantal parameters doorgegeven aan procedure %s", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index c964447a306..89045b13985 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -105,7 +105,7 @@ "BLOB column '%-.64s' can't have a default value", "Incorrect database name '%-.100s'", "Incorrect table name '%-.100s'", -"The SELECT would examine too many records and probably take a very long time. Check your WHERE and use SET OPTION SQL_BIG_SELECTS=1 if the SELECT is ok", +"The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok", "Unknown error", "Unknown procedure '%-.64s'", "Incorrect parameter count to procedure '%-.64s'", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index f9d5a2b6324..d5064b53790 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -110,7 +110,7 @@ "BLOB-tüüpi tulp '%-.64s' ei saa omada vaikeväärtust", "Vigane andmebaasi nimi '%-.100s'", "Vigane tabeli nimi '%-.100s'", -"SELECT lause peab läbi vaatama suure hulga kirjeid ja võtaks tõenäoliselt liiga kaua aega. Tasub kontrollida WHERE klauslit ja vajadusel kasutada käsku SET OPTION SQL_BIG_SELECTS=1", +"SELECT lause peab läbi vaatama suure hulga kirjeid ja võtaks tõenäoliselt liiga kaua aega. Tasub kontrollida WHERE klauslit ja vajadusel kasutada käsku SET SQL_BIG_SELECTS=1", "Tundmatu viga", "Tundmatu protseduur '%-.64s'", "Vale parameetrite hulk protseduurile '%-.64s'", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 1c4efab7e53..eb936243332 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -105,7 +105,7 @@ "BLOB '%-.64s' ne peut avoir de valeur par défaut", "Nom de base de donnée illégal: '%-.64s'", "Nom de table illégal: '%-.64s'", -"SELECT va devoir examiner beaucoup d'enregistrements ce qui va prendre du temps. Vérifiez la clause WHERE et utilisez SET OPTION SQL_BIG_SELECTS=1 si SELECT se passe bien", +"SELECT va devoir examiner beaucoup d'enregistrements ce qui va prendre du temps. Vérifiez la clause WHERE et utilisez SET SQL_BIG_SELECTS=1 si SELECT se passe bien", "Erreur inconnue", "Procédure %s inconnue", "Mauvais nombre de paramètres pour la procedure %s", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 00d6e784dcb..2ac25216b8e 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -114,7 +114,7 @@ "BLOB-Feld '%-.64s' kann keinen Vorgabewert (Default-Value) besitzen.", "Unerlaubter Datenbankname '%-.64s'.", "Unerlaubter Tabellenname '%-.64s'.", -"Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange daueren. Bitte WHERE überprüfen oder gegebenenfalls SET OPTION SQL_BIG_SELECTS=1 verwenden.", +"Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange daueren. Bitte WHERE überprüfen oder gegebenenfalls SET SQL_BIG_SELECTS=1 verwenden.", "Unbekannter Fehler.", "Unbekannte Procedure %-.64s.", "Falsche Parameterzahl für Procedure %-.64s.", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index fdeb787859c..8e82559db5c 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -105,7 +105,7 @@ "Ôá Blob ðåäßá '%-.64s' äåí ìðïñïýí íá Ý÷ïõí ðñïêáèïñéóìÝíåò ôéìÝò (default value)", "ËÜèïò üíïìá âÜóçò äåäïìÝíùí '%-.100s'", "ËÜèïò üíïìá ðßíáêá '%-.100s'", -"Ôï SELECT èá åîåôÜóåé ìåãÜëï áñéèìü åããñáöþí êáé ðéèáíþò èá êáèõóôåñÞóåé. Ðáñáêáëþ åîåôÜóôå ôéò ðáñáìÝôñïõò ôïõ WHERE êáé ÷ñçóéìïðïéåßóôå SET OPTION SQL_BIG_SELECTS=1 áí ôï SELECT åßíáé óùóôü", +"Ôï SELECT èá åîåôÜóåé ìåãÜëï áñéèìü åããñáöþí êáé ðéèáíþò èá êáèõóôåñÞóåé. Ðáñáêáëþ åîåôÜóôå ôéò ðáñáìÝôñïõò ôïõ WHERE êáé ÷ñçóéìïðïéåßóôå SET SQL_BIG_SELECTS=1 áí ôï SELECT åßíáé óùóôü", "ÐñïÝêõøå Üãíùóôï ëÜèïò", "Áãíùóôç äéáäéêáóßá '%-.64s'", "ËÜèïò áñéèìüò ðáñáìÝôñùí óôç äéáäéêáóßá '%-.64s'", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 708bad26391..de0e7da614e 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -107,7 +107,7 @@ "A(z) '%-.64s' blob objektumnak nem lehet alapertelmezett erteke", "Hibas adatbazisnev: '%-.100s'", "Hibas tablanev: '%-.100s'", -"A SELECT tul sok rekordot fog megvizsgalni es nagyon sokaig fog tartani. Ellenorizze a WHERE-t es hasznalja a SET OPTION SQL_BIG_SELECTS=1 beallitast, ha a SELECT ok", +"A SELECT tul sok rekordot fog megvizsgalni es nagyon sokaig fog tartani. Ellenorizze a WHERE-t es hasznalja a SET SQL_BIG_SELECTS=1 beallitast, ha a SELECT ok", "Ismeretlen hiba", "Ismeretlen eljaras: '%-.64s'", "Rossz parameter a(z) '%-.64s'eljaras szamitasanal", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 23d157ce628..d9308faf8a6 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -105,7 +105,7 @@ "Il campo BLOB '%-.64s' non puo` avere un valore di default", "Nome database errato '%-.100s'", "Nome tabella errato '%-.100s'", -"La SELECT dovrebbe esaminare troppi record e usare troppo tempo. Controllare la WHERE e usa SET OPTION SQL_BIG_SELECTS=1 se e` tutto a posto.", +"La SELECT dovrebbe esaminare troppi record e usare troppo tempo. Controllare la WHERE e usa SET SQL_BIG_SELECTS=1 se e` tutto a posto.", "Errore sconosciuto", "Procedura '%-.64s' sconosciuta", "Numero di parametri errato per la procedura '%-.64s'", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 82a8c23ab67..45e78941906 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -107,7 +107,7 @@ "BLOB column '%-.64s' can't have a default value", "»ØÄꤷ¤¿ database ̾ '%-.100s' ¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹", "»ØÄꤷ¤¿ table ̾ '%-.100s' ¤Ï¤Þ¤Á¤¬¤Ã¤Æ¤¤¤Þ¤¹", -"The SELECT would examine too many records and probably take a very long time. Check your WHERE and use SET OPTION SQL_BIG_SELECTS=1 if the SELECT is ok", +"The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok", "Unknown error", "Unknown procedure '%-.64s'", "Incorrect parameter count to procedure '%-.64s'", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index a96805c1dc5..43d291ae3a5 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -105,7 +105,7 @@ "BLOB Ä®·³ '%-.64s' ´Â µðÆúÆ® °ªÀ» °¡Áú ¼ö ¾ø½À´Ï´Ù.", "'%-.100s' µ¥ÀÌŸº£À̽ºÀÇ À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù.", "'%-.100s' Å×À̺í À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù.", -"SELECT ¸í·É¿¡¼ ³Ê¹« ¸¹Àº ·¹Äڵ带 ã±â ¶§¹®¿¡ ¸¹Àº ½Ã°£ÀÌ ¼Ò¿äµË´Ï´Ù. µû¶ó¼ WHERE ¹®À» Á¡°ËÇϰųª, ¸¸¾à SELECT°¡ okµÇ¸é SET OPTION SQL_BIG_SELECTS=1 ¿É¼ÇÀ» »ç¿ëÇϼ¼¿ä.", +"SELECT ¸í·É¿¡¼ ³Ê¹« ¸¹Àº ·¹Äڵ带 ã±â ¶§¹®¿¡ ¸¹Àº ½Ã°£ÀÌ ¼Ò¿äµË´Ï´Ù. µû¶ó¼ WHERE ¹®À» Á¡°ËÇϰųª, ¸¸¾à SELECT°¡ okµÇ¸é SET SQL_BIG_SELECTS=1 ¿É¼ÇÀ» »ç¿ëÇϼ¼¿ä.", "¾Ë¼ö ¾ø´Â ¿¡·¯ÀÔ´Ï´Ù.", "¾Ë¼ö ¾ø´Â ¼öÇ๮ : '%-.64s'", "'%-.64s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆĶó¸ÞÅÍ", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 31e2afa0cc9..c0c045438ec 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -107,7 +107,7 @@ "Blob feltet '%-.64s' kan ikkje ha ein standard verdi", "Ugyldig database namn '%-.64s'", "Ugyldig tabell namn '%-.64s'", -"SELECT ville undersøkje for mange postar og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET OPTION SQL_BIG_SELECTS=1 om SELECTen er korrekt", +"SELECT ville undersøkje for mange postar og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET SQL_BIG_SELECTS=1 om SELECTen er korrekt", "Ukjend feil", "Ukjend prosedyre %s", "Feil parameter tal til prosedyra %s", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 2e1468bc815..03430ae546b 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -107,7 +107,7 @@ "Blob feltet '%-.64s' kan ikke ha en standard verdi", "Ugyldig database navn '%-.64s'", "Ugyldig tabell navn '%-.64s'", -"SELECT ville undersøke for mange poster og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET OPTION SQL_BIG_SELECTS=1 om SELECTen er korrekt", +"SELECT ville undersøke for mange poster og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET SQL_BIG_SELECTS=1 om SELECTen er korrekt", "Ukjent feil", "Ukjent prosedyre %s", "Feil parameter antall til prosedyren %s", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 284334cbfbd..99eb13aa856 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -105,7 +105,7 @@ "Coluna BLOB '%-.64s' não pode ter um valor padrão (default)", "Nome de banco de dados '%-.100s' incorreto", "Nome de tabela '%-.100s' incorreto", -"O SELECT examinaria registros demais e provavelmente levaria muito tempo. Cheque sua cláusula WHERE e use SET OPTION SQL_BIG_SELECTS=1, se o SELECT estiver correto", +"O SELECT examinaria registros demais e provavelmente levaria muito tempo. Cheque sua cláusula WHERE e use SET SQL_BIG_SELECTS=1, se o SELECT estiver correto", "Erro desconhecido", "'Procedure' '%-.64s' desconhecida", "Número de parâmetros incorreto para a 'procedure' '%-.64s'", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 1966b37bc72..89c00b4bf15 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -109,7 +109,7 @@ "Coloana BLOB '%-.64s' nu poate avea o valoare default", "Numele bazei de date este incorect '%-.100s'", "Numele tabelei este incorect '%-.100s'", -"SELECT-ul ar examina prea multe cimpuri si probabil ar lua prea mult timp. Verifica clauza WHERE si foloseste SET OPTION SQL_BIG_SELECTS=1 daca SELECT-ul e ok", +"SELECT-ul ar examina prea multe cimpuri si probabil ar lua prea mult timp. Verifica clauza WHERE si foloseste SET SQL_BIG_SELECTS=1 daca SELECT-ul e ok", "Eroare unknown", "Procedura unknown '%-.64s'", "Procedura '%-.64s' are un numar incorect de parametri", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 3935aef82e3..fac4dedb3ee 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -107,7 +107,7 @@ "îÅ×ÏÚÍÏÖÎÏ ÕËÁÚÙ×ÁÔØ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ ÓÔÏÌÂÃÁ BLOB '%-.64s'", "îÅËÏÒÒÅËÔÎÏÅ ÉÍÑ ÂÁÚÙ ÄÁÎÎÙÈ '%-.100s'", "îÅËÏÒÒÅËÔÎÏÅ ÉÍÑ ÔÁÂÌÉÃÙ '%-.100s'", -"äÌÑ ÔÁËÏÊ ×ÙÂÏÒËÉ SELECT ÄÏÌÖÅÎ ÂÕÄÅÔ ÐÒÏÓÍÏÔÒÅÔØ ÓÌÉÛËÏÍ ÍÎÏÇÏ ÚÁÐÉÓÅÊ É, ×ÉÄÉÍÏ, ÜÔÏ ÚÁÊÍÅÔ ÏÞÅÎØ ÍÎÏÇÏ ×ÒÅÍÅÎÉ. ðÒÏ×ÅÒØÔÅ ×ÁÛÅ ÕËÁÚÁÎÉÅ WHERE, É, ÅÓÌÉ × ÎÅÍ ×ÓÅ × ÐÏÒÑÄËÅ, ÕËÁÖÉÔÅ SET OPTION SQL_BIG_SELECTS=1", +"äÌÑ ÔÁËÏÊ ×ÙÂÏÒËÉ SELECT ÄÏÌÖÅÎ ÂÕÄÅÔ ÐÒÏÓÍÏÔÒÅÔØ ÓÌÉÛËÏÍ ÍÎÏÇÏ ÚÁÐÉÓÅÊ É, ×ÉÄÉÍÏ, ÜÔÏ ÚÁÊÍÅÔ ÏÞÅÎØ ÍÎÏÇÏ ×ÒÅÍÅÎÉ. ðÒÏ×ÅÒØÔÅ ×ÁÛÅ ÕËÁÚÁÎÉÅ WHERE, É, ÅÓÌÉ × ÎÅÍ ×ÓÅ × ÐÏÒÑÄËÅ, ÕËÁÖÉÔÅ SET SQL_BIG_SELECTS=1", "îÅÉÚ×ÅÓÔÎÁÑ ÏÛÉÂËÁ", "îÅÉÚ×ÅÓÔÎÁÑ ÐÒÏÃÅÄÕÒÁ '%-.64s'", "îÅËÏÒÒÅËÔÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÐÁÒÁÍÅÔÒÏ× ÄÌÑ ÐÒÏÃÅÄÕÒÙ '%-.64s'", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index db25f12ed13..8f7747c6bf6 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -113,7 +113,7 @@ "Pole BLOB '%-.64s' nemô¾e ma» implicitnú hodnotu", "Neprípustné meno databázy '%-.100s'", "Neprípustné meno tabuµky '%-.100s'", -"Zadaná po¾iadavka SELECT by prechádzala príli¹ mnoho záznamov a trvala by príli¹ dlho. Skontrolujte tvar WHERE a ak je v poriadku, pou¾ite SET OPTION SQL_BIG_SELECTS=1", +"Zadaná po¾iadavka SELECT by prechádzala príli¹ mnoho záznamov a trvala by príli¹ dlho. Skontrolujte tvar WHERE a ak je v poriadku, pou¾ite SET SQL_BIG_SELECTS=1", "Neznámá chyba", "Neznámá procedúra '%-.64s'", "Chybný poèet parametrov procedúry '%-.64s'", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 44fb0a19640..4a7989ce7be 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -106,7 +106,7 @@ "Campo Blob '%-.64s' no puede tener valores patron", "Nombre de base de datos ilegal '%-.64s'", "Nombre de tabla ilegal '%-.64s'", -"El SELECT puede examinar muchos registros y probablemente con mucho tiempo. Verifique tu WHERE y usa SET OPTION SQL_BIG_SELECTS=1 si el SELECT esta correcto", +"El SELECT puede examinar muchos registros y probablemente con mucho tiempo. Verifique tu WHERE y usa SET SQL_BIG_SELECTS=1 si el SELECT esta correcto", "Error desconocido", "Procedimiento desconocido %s", "Equivocado parametro count para procedimiento %s", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index e40a44957f1..6734369d3ac 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -105,7 +105,7 @@ "BLOB fält '%-.64s' kan inte ha ett DEFAULT-värde", "Felaktigt databasnamn '%-.64s'", "Felaktigt tabellnamn '%-.64s'", -"Den angivna frågan skulle troligen ta mycket lång tid! Kontrollera din WHERE och använd SET OPTION SQL_BIG_SELECTS=1 ifall du vill hantera stora joins", +"Den angivna frågan skulle läsa mer än MAX_JOIN_SIZE rader. Kontrollera din WHERE och använd SET SQL_BIG_SELECTS=1 eller SET MAX_JOIN_SIZE=# ifall du vill hantera stora joins", "Oidentifierat fel", "Okänd procedur: %s", "Felaktigt antal parametrar till procedur %s", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 968327a1024..67c52dc8fee 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -110,7 +110,7 @@ "óÔÏ×ÂÅÃØ BLOB '%-.64s' ÎÅ ÍÏÖÅ ÍÁÔÉ ÚÎÁÞÅÎÎÑ ÐÏ ÚÁÍÏ×ÞÕ×ÁÎÎÀ", "îÅצÒÎÅ ¦Í'Ñ ÂÁÚÉ ÄÁÎÎÉÈ '%-.100s'", "îÅצÒÎÅ ¦Í'Ñ ÔÁÂÌÉæ '%-.100s'", -"úÁÐÉÔÕ SELECT ÐÏÔÒ¦ÂÎÏ ÏÂÒÏÂÉÔÉ ÂÁÇÁÔÏ ÚÁÐÉÓ¦×, ÝÏ, ÐÅ×ÎÅ, ÚÁÊÍÅ ÄÕÖÅ ÂÁÇÁÔÏ ÞÁÓÕ. ðÅÒÅצÒÔÅ ×ÁÛÅ WHERE ÔÁ ×ÉËÏÒÉÓÔÏ×ÕÊÔÅ SET OPTION SQL_BIG_SELECTS=1, ÑËÝÏ ÃÅÊ ÚÁÐÉÔ SELECT ¤ צÒÎÉÍ", +"úÁÐÉÔÕ SELECT ÐÏÔÒ¦ÂÎÏ ÏÂÒÏÂÉÔÉ ÂÁÇÁÔÏ ÚÁÐÉÓ¦×, ÝÏ, ÐÅ×ÎÅ, ÚÁÊÍÅ ÄÕÖÅ ÂÁÇÁÔÏ ÞÁÓÕ. ðÅÒÅצÒÔÅ ×ÁÛÅ WHERE ÔÁ ×ÉËÏÒÉÓÔÏ×ÕÊÔÅ SET SQL_BIG_SELECTS=1, ÑËÝÏ ÃÅÊ ÚÁÐÉÔ SELECT ¤ צÒÎÉÍ", "îÅצÄÏÍÁ ÐÏÍÉÌËÁ", "îÅצÄÏÍÁ ÐÒÏÃÅÄÕÒÁ '%-.64s'", "èÉÂÎÁ ˦ÌØ˦ÓÔØ ÐÁÒÁÍÅÔÒ¦× ÐÒÏÃÅÄÕÒÉ '%-.64s'", diff --git a/sql/slave.cc b/sql/slave.cc index eae795ae760..be95cc16d90 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2429,9 +2429,7 @@ err: goto slave_begin; #endif my_thread_end(); -#ifndef __NETWARE__ pthread_exit(0); -#endif /* __NETWARE__ */ DBUG_RETURN(0); // Can't return anything here } @@ -2573,9 +2571,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ goto slave_begin; #endif my_thread_end(); -#ifndef __NETWARE__ pthread_exit(0); -#endif /* __NETWARE__ */ DBUG_RETURN(0); // Can't return anything here } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b6191b2061e..ec6db64ea73 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -70,7 +70,7 @@ static ACL_USER *find_acl_user(const char *host, const char *user); static bool update_user_table(THD *thd, const char *host, const char *user, const char *new_password); static void update_hostname(acl_host_and_ip *host, const char *hostname); -static bool compare_hostname(const acl_host_and_ip *host, const char *hostname, +static bool compare_hostname(const acl_host_and_ip *host,const char *hostname, const char *ip); /* @@ -496,8 +496,9 @@ void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble) ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, const char *password,const char *message,char **priv_user, - bool old_ver, USER_RESOURCES *mqh, char *prepared_scramble, - uint *cur_priv_version, ACL_USER **cached_user) + char *priv_host, bool old_ver, USER_RESOURCES *mqh, + char *prepared_scramble, uint *cur_priv_version, + ACL_USER **cached_user) { ulong user_access=NO_ACCESS; *priv_user= (char*) user; @@ -593,7 +594,7 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, { Vio *vio=thd->net.vio; /* - In this point we know that user is allowed to connect + At this point we know that user is allowed to connect from given host by given username/password pair. Now we check if SSL is required, if user is using SSL and if X509 certificate attributes are OK @@ -611,8 +612,11 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, /* Connections with non-valid certificates are dropped already in sslaccept() anyway, so we do not check validity here. + + We need to check for absence of SSL because without SSL + we should reject connection. */ - if (SSL_get_peer_certificate(vio->ssl_)) + if (vio_type(vio) == VIO_TYPE_SSL && SSL_get_peer_certificate(vio->ssl_)) user_access=acl_user->access; break; case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */ @@ -622,6 +626,8 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, If cipher name is specified, we compare it to actual cipher in use. */ + if (vio_type(vio) != VIO_TYPE_SSL) + break; if (acl_user->ssl_cipher) { DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'", @@ -630,6 +636,10 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, user_access=acl_user->access; else { + if (global_system_variables.log_warnings) + sql_print_error("X509 ciphers mismatch: should be '%s' but is '%s'", + acl_user->ssl_cipher, + SSL_get_cipher(vio->ssl_)); user_access=NO_ACCESS; break; } @@ -647,6 +657,9 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, acl_user->x509_issuer, ptr)); if (strcmp(acl_user->x509_issuer, ptr)) { + if (global_system_variables.log_warnings) + sql_print_error("X509 issuer mismatch: should be '%s' but is '%s'", + acl_user->x509_issuer, ptr); user_access=NO_ACCESS; free(ptr); break; @@ -662,7 +675,12 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, DBUG_PRINT("info",("comparing subjects: '%s' and '%s'", acl_user->x509_subject, ptr)); if (strcmp(acl_user->x509_subject,ptr)) + { + if (global_system_variables.log_warnings) + sql_print_error("X509 subject mismatch: '%s' vs '%s'", + acl_user->x509_subject, ptr); user_access=NO_ACCESS; + } else user_access=acl_user->access; free(ptr); @@ -677,6 +695,11 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, if (!acl_user->user) *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */ + if (acl_user->host.hostname) + strmake(priv_host, acl_user->host.hostname, MAX_HOSTNAME); + else + *priv_host= 0; + unlock_and_exit: VOID(pthread_mutex_unlock(&acl_cache->lock)); DBUG_RETURN(user_access); @@ -780,7 +803,7 @@ static void acl_insert_user(const char *user, const char *host, VOID(push_dynamic(&acl_users,(gptr) &acl_user)); if (!acl_user.host.hostname || acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1]) - allow_all_hosts=1; // Anyone can connect /* purecov: tested */ + allow_all_hosts=1; // Anyone can connect /* purecov: tested */ qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, sizeof(ACL_USER),(qsort_cmp) acl_compare); @@ -1126,8 +1149,7 @@ bool change_password(THD *thd, const char *host, const char *user, Simple hack to avoid cracking */ length=(uint) strlen(new_password); - - if (length!=45) + if (length != 45) new_password[length & 16]=0; VOID(pthread_mutex_lock(&acl_cache->lock)); @@ -2060,10 +2082,10 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, } -int mysql_table_grant (THD *thd, TABLE_LIST *table_list, - List <LEX_USER> &user_list, - List <LEX_COLUMN> &columns, ulong rights, - bool revoke_grant) +int mysql_table_grant(THD *thd, TABLE_LIST *table_list, + List <LEX_USER> &user_list, + List <LEX_COLUMN> &columns, ulong rights, + bool revoke_grant) { ulong column_priv = 0; List_iterator <LEX_USER> str_list (user_list); @@ -2437,7 +2459,7 @@ my_bool grant_init(THD *org_thd) mem_check->ok() && hash_insert(&column_priv_hash,(byte*) mem_check)) { /* This could only happen if we are out memory */ - grant_option = FALSE; /* purecov: deadcode */ + grant_option= FALSE; /* purecov: deadcode */ goto end_unlock; } } @@ -2477,16 +2499,16 @@ void grant_reload(THD *thd) rw_wrlock(&LOCK_grant); grant_version++; old_column_priv_hash= column_priv_hash; - old_grant_option = grant_option; - old_mem = memex; + old_grant_option= grant_option; + old_mem= memex; if (grant_init(thd)) { // Error. Revert to old hash DBUG_PRINT("error",("Reverting to old privileges")); grant_free(); /* purecov: deadcode */ column_priv_hash= old_column_priv_hash; /* purecov: deadcode */ - grant_option = old_grant_option; /* purecov: deadcode */ - memex = old_mem; /* purecov: deadcode */ + grant_option= old_grant_option; /* purecov: deadcode */ + memex= old_mem; /* purecov: deadcode */ } else { @@ -2583,8 +2605,8 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, } -bool check_grant_column (THD *thd,TABLE *table, const char *name, - uint length, uint show_tables) +bool check_grant_column(THD *thd,TABLE *table, const char *name, + uint length, uint show_tables) { GRANT_TABLE *grant_table; GRANT_COLUMN *grant_column; @@ -2650,7 +2672,12 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) want_access &= ~table->grant.privilege; if (!want_access) - return 0; // Already checked + return 0; // Already checked + if (!grant_option) + { + field= table->field[0]; // To give a meaningful error message + goto err2; + } rw_rdlock(&LOCK_grant); @@ -2679,9 +2706,9 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) return 0; /* We must use my_printf_error() here! */ - err: +err: rw_unlock(&LOCK_grant); - +err2: const char *command=""; if (want_access & SELECT_ACL) command ="select"; @@ -3108,11 +3135,11 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) } } } - global.append(" ON ",4); + global.append(" ON `",5); global.append(grant_table->db); - global.append(".",1); + global.append("`.`",3); global.append(grant_table->tname); - global.append(" TO '",5); + global.append("` TO '",6); global.append(lex_user->user.str,lex_user->user.length); global.append("'@'",3); global.append(lex_user->host.str,lex_user->host.length); diff --git a/sql/sql_acl.h b/sql/sql_acl.h index ceb866d809f..d85a281cbb5 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -136,7 +136,8 @@ void acl_free(bool end=0); ulong acl_get(const char *host, const char *ip, const char *bin_ip, const char *user, const char *db); ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, - const char *password,const char *scramble,char **priv_user, + const char *password,const char *scramble, + char **priv_user, char *priv_host, bool old_ver, USER_RESOURCES *max,char* prepared_scramble, uint *cur_priv_version, ACL_USER **cached_user); bool acl_check_host(const char *host, const char *ip); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index fc95f5deb40..eeaf560693e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -423,8 +423,9 @@ bool close_thread_table(THD *thd, TABLE **table_ptr) { DBUG_ENTER("close_thread_table"); - bool found_old_table=0; - TABLE *table=*table_ptr; + bool found_old_table= 0; + TABLE *table= *table_ptr; + DBUG_ASSERT(table->key_read == 0); *table_ptr=table->next; if (table->version != refresh_version || @@ -1693,7 +1694,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, else thd->dupp_field=field; } - if (check_grants && check_grant_column(thd,table,name,length)) + if (check_grants && check_grant_column(thd,table,name,length)) return WRONG_GRANT; return field; } @@ -1743,8 +1744,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, { found_table=1; Field *find=find_field_in_table(thd,tables->table,name,length, - grant_option && - tables->table->grant.want_privilege, + test(tables->table->grant. + want_privilege), 1); if (find) { @@ -1801,8 +1802,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, } Field *field=find_field_in_table(thd,tables->table,name,length, - grant_option && - tables->table->grant.want_privilege, + test(tables->table->grant.want_privilege), allow_rowid); if (field) { @@ -2098,9 +2098,10 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, (!db_name || !strcmp(tables->db,db_name)))) { /* Ensure that we have access right to all columns */ - if (grant_option && !thd->master_access && - check_grant_all_columns(thd,SELECT_ACL,table) ) + if (!(table->grant.privilege & SELECT_ACL) && + check_grant_all_columns(thd,SELECT_ACL,table)) DBUG_RETURN(-1); + Field **ptr=table->field,*field; thd->used_tables|=table->map; while ((field = *ptr++)) @@ -2227,7 +2228,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ******************************************************************************/ int -fill_record(List<Item> &fields,List<Item> &values) +fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors) { List_iterator_fast<Item> f(fields),v(values); Item *value; @@ -2237,7 +2238,7 @@ fill_record(List<Item> &fields,List<Item> &values) while ((field=(Item_field*) f++)) { value=v++; - if (value->save_in_field(field->field, 0) > 0) + if (value->save_in_field(field->field, 0) > 0 && !ignore_errors) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -2245,7 +2246,7 @@ fill_record(List<Item> &fields,List<Item> &values) int -fill_record(Field **ptr,List<Item> &values) +fill_record(Field **ptr,List<Item> &values, bool ignore_errors) { List_iterator_fast<Item> v(values); Item *value; @@ -2255,7 +2256,7 @@ fill_record(Field **ptr,List<Item> &values) while ((field = *ptr++)) { value=v++; - if (value->save_in_field(field, 0) == 1) + if (value->save_in_field(field, 0) == 1 && !ignore_errors) DBUG_RETURN(1); } DBUG_RETURN(0); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index d8265a1b359..adc3d177fdf 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -761,11 +761,11 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) uint8 tables_type= 0; if ((local_tables = is_cacheable(thd, thd->query_length, - thd->query, &thd->lex, tables_used, - &tables_type))) + thd->query, &thd->lex, tables_used, + &tables_type))) { NET *net= &thd->net; - byte flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0); + byte flags= (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0); STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size == 0) @@ -790,8 +790,10 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) */ flags|= (byte) thd->charset()->number; DBUG_ASSERT(thd->charset()->number < 128); - tot_length=thd->query_length+thd->db_length+2; - thd->query[tot_length-1] = (char) flags; + tot_length= thd->query_length+thd->db_length+2+sizeof(ha_rows); + thd->query[tot_length-1]= (char) flags; + memcpy((void *)(thd->query + (tot_length-sizeof(ha_rows)-1)), + (const void *)&thd->variables.select_limit, sizeof(ha_rows)); /* Check if another thread is processing the same query? */ Query_cache_block *competitor = (Query_cache_block *) @@ -921,7 +923,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) } Query_cache_block *query_block; - tot_length=query_length+thd->db_length+2; + tot_length= query_length+thd->db_length+2+sizeof(ha_rows); if (thd->db_length) { memcpy(sql+query_length+1, thd->db, thd->db_length); @@ -937,10 +939,12 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) Most significant bit - CLIENT_LONG_FLAG, Other - charset number (0 no charset convertion) */ - flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0); - flags |= (byte) thd->charset()->number; + flags= (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0); + flags|= (byte) thd->charset()->number; DBUG_ASSERT(thd->charset()->number < 128); - sql[tot_length-1] = (char) flags; + sql[tot_length-1]= (char) flags; + memcpy((void *)(sql + (tot_length-sizeof(ha_rows)-1)), + (const void *)&thd->variables.select_limit, sizeof(ha_rows)); query_block = (Query_cache_block *) hash_search(&queries, (byte*) sql, tot_length); /* Quick abort on unlocked data */ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f579b02ee50..9f6edd629ca 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -120,6 +120,7 @@ THD::THD():user_time(0), is_fatal_error(0), net.last_error[0]=0; // If error on boot ull=0; system_thread=cleanup_done=0; + peer_port= 0; // For SHOW PROCESSLIST transaction.changed_tables = 0; #ifdef __WIN__ real_id = 0; diff --git a/sql/sql_class.h b/sql/sql_class.h index 08043e7e626..00b3b9f8444 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -358,6 +358,7 @@ struct system_variables ulong max_prep_stmt_count; ulong max_sort_length; ulong max_tmp_tables; + ulong myisam_repair_threads; ulong myisam_sort_buff_size; ulong net_buffer_length; ulong net_interactive_timeout; @@ -434,13 +435,14 @@ public: ip - client IP */ char *host,*user,*priv_user,*db,*ip; + char priv_host[MAX_HOSTNAME]; /* remote (peer) port */ uint16 peer_port; /* Points to info-string that will show in SHOW PROCESSLIST */ const char *proc_info; /* points to host if host is available, otherwise points to ip */ const char *host_or_ip; - + ulong client_capabilities; /* What the client supports */ /* Determines if which non-standard SQL behaviour should be enabled */ ulong max_client_packet_length; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index fe8a945bff8..e0a592d2450 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -401,6 +401,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, ulong found_other_files=0; char filePath[FN_REFLEN]; TABLE_LIST *tot_list=0, **tot_list_next; + List<String> raid_dirs; + DBUG_ENTER("mysql_rm_known_files"); DBUG_PRINT("enter",("path: %s", org_path)); @@ -420,6 +422,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, { char newpath[FN_REFLEN]; MY_DIR *new_dirp; + String *dir; + strxmov(newpath,org_path,"/",file->name,NullS); unpack_filename(newpath,newpath); if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT)))) @@ -430,7 +434,11 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, my_dirend(dirp); DBUG_RETURN(-1); } + raid_dirs.push_back(dir=new String(newpath, &my_charset_latin1)); + dir->copy(); + continue; } + found_other_files++; continue; } if (find_type(fn_ext(file->name),&deletable_extentions,1+2) <= 0) @@ -440,7 +448,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, continue; } strxmov(filePath,org_path,"/",file->name,NullS); - if (db && !my_strcasecmp(&my_charset_latin1, + if (db && !my_strcasecmp(&my_charset_latin1, fn_ext(file->name), reg_ext)) { /* Drop the table nicely */ @@ -470,12 +478,19 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, deleted++; } } - my_dirend(dirp); - if (thd->killed || (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0, 1))) + { + my_dirend(dirp); DBUG_RETURN(-1); - + } + List_iterator<String> it(raid_dirs); + String *dir; + while ((dir= it++)) + if (rmdir(dir->c_ptr()) < 0) + found_other_files++; + my_dirend(dirp); + /* If the directory is a symbolic link, remove the link first, then remove the directory the symbolic link pointed at @@ -573,11 +588,11 @@ bool mysql_change_db(THD *thd, const char *name) { net_printf(thd,ER_DBACCESS_DENIED_ERROR, thd->priv_user, - thd->host_or_ip, + thd->priv_host, dbname); mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), thd->priv_user, - thd->host_or_ip, + thd->priv_host, dbname); my_free(dbname,MYF(0)); DBUG_RETURN(1); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 6bb336a87a6..a12f6efb006 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -67,7 +67,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, } /* Test if the user wants to delete all rows */ - if (!using_limit && const_cond && + if (!using_limit && const_cond && (!conds || conds->val_int()) && !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE))) { deleted= table->file->records; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 7f555f37d40..2bf1a68e504 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -116,7 +116,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *first_table= (TABLE_LIST*) select_cursor->table_list.first; /* Setting up. A must if a join or IGNORE, USE or similar are utilised */ if (setup_tables(first_table) || - setup_wild(thd, first_table, select_cursor->item_list, 0, select_cursor->with_wild)) + setup_wild(thd, first_table, select_cursor->item_list, 0, + select_cursor->with_wild)) { res= -1; goto exit; @@ -128,16 +129,18 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, (item_list.elements + select_cursor->with_sum_func + select_cursor->order_list.elements + select_cursor->group_list.elements)) || - setup_fields(thd, select_cursor->ref_pointer_array, first_table, item_list, - 0, 0, 1)) + setup_fields(thd, select_cursor->ref_pointer_array, first_table, + item_list, 0, 0, 1)) { res= -1; goto exit; } bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); tmp_table_param.field_count= item_list.elements; - /* temp table is created so that it hounours if UNION without ALL is to be - processed */ + /* + Temp table is created so that it hounours if UNION without ALL is to be + processed + */ if (!(table= create_tmp_table(thd, &tmp_table_param, item_list, (ORDER*) 0, is_union && !unit->union_option, 1, @@ -190,6 +193,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, org_table_list->table=table; table->derived_select_number= select_cursor->select_number; table->tmp_table= TMP_TABLE; + org_table_list->grant.privilege= SELECT_ACL; if (lex->describe) { // to fix a problem in EXPLAIN @@ -206,7 +210,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, /* Try to catch errors if this is accessed */ org_table_list->derived=(SELECT_LEX_UNIT *) 1; #endif -// This line is required to force read of table stats in the optimizer + // Force read of table stats in the optimizer table->file->info(HA_STATUS_VARIABLE); } } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index a3e11d9d1c6..9be0270947a 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -258,7 +258,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, if (fields.elements || !value_count) { restore_record(table,default_values); // Get empty record - if (fill_record(fields,*values)|| thd->net.report_error || + if (fill_record(fields, *values, 0)|| thd->net.report_error || check_null_fields(thd,table)) { if (values_list.elements != 1 && !thd->net.report_error) @@ -276,7 +276,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, restore_record(table,default_values); // Get empty record else table->record[0][0]=table->default_values[0]; // Fix delete marker - if (fill_record(table->field,*values) || thd->net.report_error) + if (fill_record(table->field,*values, 0) || thd->net.report_error) { if (values_list.elements != 1 && ! thd->net.report_error) { @@ -484,7 +484,8 @@ int write_record(TABLE *table,COPY_INFO *info) key_copy((byte*) key,table,key_nr,0); if ((error=(table->file->index_read_idx(table->record[1],key_nr, (byte*) key, - table->key_info[key_nr].key_length, + table->key_info[key_nr]. + key_length, HA_READ_KEY_EXACT)))) goto err; } @@ -496,7 +497,7 @@ int write_record(TABLE *table,COPY_INFO *info) */ store_record(table,insert_values); restore_record(table,record[1]); - if (fill_record(*info->update_fields,*info->update_values)) + if (fill_record(*info->update_fields, *info->update_values, 0)) goto err; if ((error=table->file->update_row(table->record[1],table->record[0]))) goto err; @@ -507,10 +508,11 @@ int write_record(TABLE *table,COPY_INFO *info) { if (last_uniq_key(table,key_nr)) { - if ((error=table->file->update_row(table->record[1],table->record[0]))) + if ((error=table->file->update_row(table->record[1], + table->record[0]))) goto err; info->deleted++; - break; /* Update logfile and count */ + break; /* Update logfile and count */ } else if ((error=table->file->delete_row(table->record[1]))) goto err; @@ -709,6 +711,9 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) /* no match; create a new thread to handle the table */ if (!(tmp=find_handler(thd,table_list))) { + /* Don't create more than max_insert_delayed_threads */ + if (delayed_insert_threads >= max_insert_delayed_threads) + DBUG_RETURN(0); thd->proc_info="Creating delayed handler"; pthread_mutex_lock(&LOCK_delayed_create); if (!(tmp=find_handler(thd,table_list))) // Was just created @@ -1087,12 +1092,12 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) while (!thd->killed) { int error; -#if (defined(HAVE_BROKEN_COND_TIMEDWAIT) || defined(HAVE_LINUXTHREADS)) +#if defined(HAVE_BROKEN_COND_TIMEDWAIT) error=pthread_cond_wait(&di->cond,&di->mutex); #else error=pthread_cond_timedwait(&di->cond,&di->mutex,&abstime); #ifdef EXTRA_DEBUG - if (error && error != EINTR) + if (error && error != EINTR && error != ETIMEDOUT) { fprintf(stderr, "Got error %d from pthread_cond_timedwait\n",error); DBUG_PRINT("error",("Got error %d from pthread_cond_timedwait", @@ -1394,9 +1399,9 @@ bool select_insert::send_data(List<Item> &values) return 0; } if (fields->elements) - fill_record(*fields,values); + fill_record(*fields, values, 1); else - fill_record(table->field,values); + fill_record(table->field, values, 1); if (thd->net.report_error || write_record(table,&info)) return 1; if (table->next_number_field) // Clear for next record @@ -1461,7 +1466,7 @@ bool select_insert::send_eof() thd->cuted_fields); if (last_insert_id) thd->insert_id(last_insert_id); // For update log - ::send_ok(thd,info.copied,last_insert_id,buff); + ::send_ok(thd,info.copied+info.deleted,last_insert_id,buff); mysql_update_log.write(thd,thd->query,thd->query_length); return 0; } @@ -1511,7 +1516,7 @@ bool select_create::send_data(List<Item> &values) unit->offset_limit_cnt--; return 0; } - fill_record(field,values); + fill_record(field, values, 1); if (thd->net.report_error ||write_record(table,&info)) return 1; if (table->next_number_field) // Clear for next record diff --git a/sql/sql_list.h b/sql/sql_list.h index f4cca627515..ff21663576a 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -368,6 +368,7 @@ template <class T> class I_List :private base_ilist { public: I_List() :base_ilist() {} + inline void empty() { base_ilist::empty(); } inline bool is_empty() { return base_ilist::is_empty(); } inline void append(T* a) { base_ilist::append(a); } inline void push_back(T* a) { base_ilist::push_back(a); } diff --git a/sql/sql_load.cc b/sql/sql_load.cc index fa2321a1e9d..7476472a79a 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -185,7 +185,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else { unpack_filename(name,ex->file_name); -#if !defined(__WIN__) && !defined(OS2) +#if !defined(__WIN__) && !defined(OS2) && ! defined(__NETWARE__) MY_STAT stat_info; if (!my_stat(name,&stat_info,MYF(MY_WME))) DBUG_RETURN(-1); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 815068ff470..e8f028e3720 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -213,7 +213,15 @@ static int check_user(THD *thd,enum_server_command command, const char *user, thd->db=0; thd->db_length=0; USER_RESOURCES ur; + char tmp_passwd[SCRAMBLE41_LENGTH]; DBUG_ENTER("check_user"); + + /* + Move password to temporary buffer as it may be stored in communication + buffer + */ + strmake(tmp_passwd, passwd, sizeof(tmp_passwd)); + passwd= tmp_passwd; // Use local copy /* We shall avoid dupplicate user allocations here */ if (!thd->user && !(thd->user = my_strdup(user, MYF(0)))) @@ -222,7 +230,8 @@ static int check_user(THD *thd,enum_server_command command, const char *user, DBUG_RETURN(1); } thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user, - passwd, thd->scramble, &thd->priv_user, + passwd, thd->scramble, + &thd->priv_user, thd->priv_host, (protocol_version == 9 || !(thd->client_capabilities & CLIENT_LONG_PASSWORD)), @@ -230,9 +239,9 @@ static int check_user(THD *thd,enum_server_command command, const char *user, cur_priv_version,hint_user); DBUG_PRINT("info", - ("Capabilities: %d packet_length: %ld Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'", + ("Capabilities: %d packet_length: %ld Host: '%s' Login user: '%s' Priv_user: '%s' Using password: %s Access: %u db: '%s'", thd->client_capabilities, thd->max_client_packet_length, - thd->host_or_ip, thd->priv_user, + thd->host_or_ip, thd->user, thd->priv_user, had_password ? "yes": "no", thd->master_access, thd->db ? thd->db : "*none*")); @@ -307,6 +316,7 @@ static int check_user(THD *thd,enum_server_command command, const char *user, DBUG_RETURN(error); } send_ok(thd); // Ready to handle questions + thd->password= test(passwd[0]); // Remember for error messages DBUG_RETURN(0); // ok } @@ -582,7 +592,6 @@ check_connections(THD *thd) DBUG_PRINT("info",("Host: %s",thd->host)); thd->host_or_ip= thd->host; thd->ip= 0; - thd->peer_port= 0; bzero((char*) &thd->remote,sizeof(struct sockaddr)); } /* Ensure that wrong hostnames doesn't cause buffer overflows */ @@ -751,7 +760,6 @@ check_connections(THD *thd) } else if (res) return -1; // Error sent from check_user() - thd->password=using_password; return 0; } @@ -1551,7 +1559,8 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length) /* We must allocate some extra memory for query cache */ if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet), packet_length, - thd->db_length+2))) + thd->db_length+2+ + sizeof(ha_rows)))) return 1; thd->query[packet_length]=0; thd->query_length= packet_length; @@ -1648,6 +1657,18 @@ mysql_execute_command(THD *thd) #endif ) DBUG_VOID_RETURN; + + /* + When option readonly is set deny operations which change tables. + Except for the replication thread and the 'super' users. + */ + if (opt_readonly && + !(thd->slave_thread || (thd->master_access & SUPER_ACL)) && + (uc_update_queries[lex->sql_command] > 0)) + { + send_error(thd, ER_CANT_UPDATE_WITH_READLOCK); + DBUG_VOID_RETURN; + } statistic_increment(com_stat[lex->sql_command],&LOCK_status); switch (lex->sql_command) { @@ -1832,7 +1853,8 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_SLAVE_STAT: { - if (check_global_access(thd, SUPER_ACL)) + /* Accept one of two privileges */ + if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error; LOCK_ACTIVE_MI; res = show_master_info(thd,active_mi); @@ -1841,7 +1863,8 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_MASTER_STAT: { - if (check_global_access(thd, SUPER_ACL)) + /* Accept one of two privileges */ + if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error; res = show_binlog_info(thd); break; @@ -3058,12 +3081,21 @@ error: /**************************************************************************** Get the user (global) and database privileges for all used tables - Returns true (error) if we can't get the privileges and we don't use - table/column grants. - The idea of EXTRA_ACL is that one will be granted access to the table if - one has the asked privilege on any column combination of the table; For - example to be able to check a table one needs to have SELECT privilege on - any column of the table. + + NOTES + The idea of EXTRA_ACL is that one will be granted access to the table if + one has the asked privilege on any column combination of the table; For + example to be able to check a table one needs to have SELECT privilege on + any column of the table. + + RETURN + 0 ok + 1 If we can't get the privileges and we don't use table/column grants. + + save_priv In this we store global and db level grants for the table + Note that we don't store db level grants if the global grants + is enough to satisfy the request and the global grants contains + a SELECT grant. ****************************************************************************/ bool @@ -3088,7 +3120,17 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if ((thd->master_access & want_access) == want_access) { - *save_priv=thd->master_access; + /* + If we don't have a global SELECT privilege, we have to get the database + specific access rights to be able to handle queries of type + UPDATE t1 SET a=1 WHERE b > 0 + */ + db_access= thd->db_access; + if (!(thd->master_access & SELECT_ACL) && + (db && (!thd->db || strcmp(db,thd->db)))) + db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr, + thd->priv_user, db); /* purecov: inspected */ + *save_priv=thd->master_access | db_access; DBUG_RETURN(FALSE); } if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) || @@ -3097,7 +3139,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if (!no_errors) net_printf(thd,ER_ACCESS_DENIED_ERROR, thd->priv_user, - thd->host_or_ip, + thd->priv_host, thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */ DBUG_RETURN(TRUE); /* purecov: tested */ } @@ -3122,18 +3164,35 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if (!no_errors) net_printf(thd,ER_DBACCESS_DENIED_ERROR, thd->priv_user, - thd->host_or_ip, + thd->priv_host, db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */ DBUG_RETURN(TRUE); /* purecov: tested */ } -/* check for global access and give descriptive error message if it fails */ +/* + check for global access and give descriptive error message if it fails + + SYNOPSIS + check_global_access() + thd Thread handler + want_access Use should have any of these global rights + + WARNING + One gets access rigth if one has ANY of the rights in want_access + This is useful as one in most cases only need one global right, + but in some case we want to check if the user has SUPER or + REPL_CLIENT_ACL rights. + + RETURN + 0 ok + 1 Access denied. In this case an error is sent to the client +*/ bool check_global_access(THD *thd, ulong want_access) { char command[128]; - if ((thd->master_access & want_access) == want_access) + if ((thd->master_access & want_access)) return 0; get_privilege_desc(command, sizeof(command), want_access); net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR, @@ -3237,6 +3296,7 @@ static bool check_merge_table_access(THD *thd, char *db, #define used_stack(A,B) (long) (B - A) #endif +#ifndef EMBEDDED_LIBRARY bool check_stack_overrun(THD *thd,char *buf __attribute__((unused))) { long stack_used; @@ -3250,6 +3310,7 @@ bool check_stack_overrun(THD *thd,char *buf __attribute__((unused))) } return 0; } +#endif /* EMBEDDED_LIBRARY */ #define MY_YACC_INIT 1000 // Start with big alloc #define MY_YACC_MAX 32000 // Because of 'short' @@ -3548,9 +3609,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, new_field->comment.str= (char*) comment->str_value.ptr(); new_field->comment.length=comment->str_value.length(); } - if (length) - if (!(new_field->length= (uint) atoi(length))) - length=0; /* purecov: inspected */ + if (length && !(new_field->length= (uint) atoi(length))) + length=0; /* purecov: inspected */ uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1; if (new_field->length && new_field->decimals && @@ -3583,10 +3643,13 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, break; case FIELD_TYPE_DECIMAL: if (!length) - new_field->length = 10; // Default length for DECIMAL - new_field->length+=sign_len; - if (new_field->decimals) - new_field->length++; + new_field->length= 10; // Default length for DECIMAL + if (new_field->length < MAX_FIELD_WIDTH) // Skip wrong argument + { + new_field->length+=sign_len; + if (new_field->decimals) + new_field->length++; + } break; case FIELD_TYPE_STRING: case FIELD_TYPE_VAR_STRING: @@ -4012,6 +4075,24 @@ void add_join_on(TABLE_LIST *b,Item *expr) } +/* + Mark that we have a NATURAL JOIN between two tables + + SYNOPSIS + add_join_natural() + a Table to do normal join with + b Do normal join with this table + + IMPLEMENTATION + This function just marks that table b should be joined with a. + The function setup_cond() will create in b->on_expr a list + of equal condition between all fields of the same name. + + SELECT * FROM t1 NATURAL LEFT JOIN t2 + <=> + SELECT * FROM t1 LEFT JOIN t2 ON (t1.i=t2.i and t1.j=t2.j ... ) +*/ + void add_join_natural(TABLE_LIST *a,TABLE_LIST *b) { b->natural_join=a; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index a39541b0fc5..b8f6de30840 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1079,6 +1079,9 @@ err: } send_eof(thd); + pthread_mutex_lock(&LOCK_thread_count); + thd->current_linfo = 0; + pthread_mutex_unlock(&LOCK_thread_count); DBUG_RETURN(0); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bc58fc534a2..832058ff935 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -466,8 +466,17 @@ JOIN::optimize() if (tables_list && tmp_table_param.sum_func_count && ! group_list) { int res; + /* + opt_sum_query() returns -1 if no rows match to the WHERE conditions, + or 1 if all items were resolved, or 0, or an error number HA_ERR_... + */ if ((res=opt_sum_query(tables_list, all_fields, conds))) { + if (res > 1) + { + delete procedure; + DBUG_RETURN(-1); + } if (res < 0) { zero_result_cause= "No matching min/max row"; @@ -610,7 +619,17 @@ JOIN::optimize() select_distinct= 0; no_order= !order; if (all_order_fields_used) + { + if (order && skip_sort_order) + { + /* + Force MySQL to read the table in sorted order to get result in + ORDER BY order. + */ + tmp_table_param.quick_group=0; + } order=0; + } group=1; // For end_write_group } else @@ -2379,7 +2398,10 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, if (table->quick_keys & ((key_map) 1 << key)) records= (double) table->quick_rows[key]; else - records= (double) s->records/rec; // quick_range couldn't use key! + { + /* quick_range couldn't use key! */ + records= (double) s->records/rec; + } } else { @@ -3037,6 +3059,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) join->unit->select_limit_cnt)) < 0) DBUG_RETURN(1); // Impossible range sel->cond=orig_cond; + /* Fix for EXPLAIN */ + if (sel->quick) + join->best_positions[i].records_read= sel->quick->records; } else { @@ -4239,7 +4264,6 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, table->blob_ptr_size=mi_portable_sizeof_char_ptr; table->map=1; table->tmp_table= TMP_TABLE; - table->derived_select_number= 0; table->db_low_byte_first=1; // True for HEAP and MyISAM table->temp_pool_slot = temp_pool_slot; table->copy_blobs= 1; @@ -7251,7 +7275,8 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, while ((item=li++)) { - if (item->type() != Item::SUM_FUNC_ITEM && !item->marker) + if (item->type() != Item::SUM_FUNC_ITEM && !item->marker && + !item->const_item()) { my_printf_error(ER_WRONG_FIELD_WITH_GROUP, ER(ER_WRONG_FIELD_WITH_GROUP), @@ -7959,6 +7984,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, TABLE *table=tab->table; char buff[512],*buff_ptr=buff; char buff1[512], buff2[512]; + char derived_name[64]; String tmp1(buff1,sizeof(buff1),cs); String tmp2(buff2,sizeof(buff2),cs); tmp1.length(0); @@ -7972,13 +7998,13 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, cs)); if (tab->type == JT_ALL && tab->select && tab->select->quick) tab->type= JT_RANGE; - if (table->tmp_table == TMP_TABLE && table->derived_select_number != 0) + if (table->derived_select_number) { - // Derived table name generation - char buff[512]; - int len= my_snprintf(buff, 512, "<derived%u>", + /* Derived table name generation */ + int len= my_snprintf(derived_name, sizeof(derived_name)-1, + "<derived%u>", table->derived_select_number); - item_list.push_back(new Item_string(buff, len, cs)); + item_list.push_back(new Item_string(derived_name, len, cs)); } else item_list.push_back(new Item_string(table->table_name, @@ -8172,5 +8198,3 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) unit= unit->next_unit()) unit->cleanup(); } - - diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2b8982f2484..25bbd4851ba 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -923,7 +923,10 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) protocol->store((const char*) pos, system_charset_info); protocol->store(table->file->index_type(i), system_charset_info); /* Comment */ - protocol->store("", system_charset_info); + if (!(table->keys_in_use & ((key_map) 1 << i))) + protocol->store("disabled",8, system_charset_info); + else + protocol->store("", 0, system_charset_info); if (protocol->write()) DBUG_RETURN(1); /* purecov: inspected */ } @@ -1587,7 +1590,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, case SHOW_QUESTION: end= int10_to_str((long) thd->query_id, buff, 10); break; -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION case SHOW_RPL_STATUS: end= strmov(buff, rpl_status_type[(int)rpl_status]); break; @@ -1599,7 +1602,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, UNLOCK_ACTIVE_MI; break; } -#endif /* EMBEDDED_LIBRARY */ +#endif /* HAVE_REPLICATION */ case SHOW_OPENTABLES: end= int10_to_str((long) cached_tables(), buff, 10); break; diff --git a/sql/sql_string.cc b/sql/sql_string.cc index ca38651b3b6..bd101944160 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -34,9 +34,6 @@ CHARSET_INFO *national_charset_info= &my_charset_utf8; extern gptr sql_alloc(unsigned size); extern void sql_element_free(void *ptr); -static uint32 -copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, - const char *from, uint32 from_length, CHARSET_INFO *from_cs); #include "sql_string.h" @@ -630,7 +627,7 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length) */ -static uint32 +uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, const char *from, uint32 from_length, CHARSET_INFO *from_cs) { diff --git a/sql/sql_string.h b/sql/sql_string.h index 9c494600058..8212bd0a2bd 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -27,6 +27,9 @@ class String; int sortcmp(const String *a,const String *b, CHARSET_INFO *cs); String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); +uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, + const char *from, uint32 from_length, + CHARSET_INFO *from_cs); class String { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index cbd09d83a72..ea3b30d24e8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -23,6 +23,7 @@ #endif #include <hash.h> #include <myisam.h> +#include <my_dir.h> #ifdef __WIN__ #include <io.h> @@ -716,6 +717,14 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, column->field_name); DBUG_RETURN(-1); } + /* for fulltext keys keyseg length is 1 for blobs (it's ignored in + ft code anyway, and 0 (set to column width later) for char's. + it has to be correct col width for char's, as char data are not + prefixed with length (unlike blobs, where ft code takes data length + from a data prefix, ignoring column->length). + */ + if (key->type == Key::FULLTEXT) + column->length=test(f_is_blob(sql_field->pack_flag)); if (f_is_blob(sql_field->pack_flag)) { if (!(file->table_flags() & HA_BLOB_KEY)) @@ -726,15 +735,10 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, } if (!column->length) { - if (key->type == Key::FULLTEXT) - column->length=1; /* ft-code ignores it anyway :-) */ - else - { - my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH, - ER(ER_BLOB_KEY_WITHOUT_LENGTH),MYF(0), - column->field_name); - DBUG_RETURN(-1); - } + my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH, + ER(ER_BLOB_KEY_WITHOUT_LENGTH),MYF(0), + column->field_name); + DBUG_RETURN(-1); } } if (key->type == Key::SPATIAL) @@ -752,8 +756,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, { if (key->type == Key::PRIMARY) { - my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0)); - DBUG_RETURN(-1); + /* Implicitly set primary key fields to NOT NULL for ISO conf. */ + sql_field->flags|= NOT_NULL_FLAG; + sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL; } if (!(file->table_flags() & HA_NULL_KEY)) { @@ -1081,12 +1086,9 @@ mysql_rename_table(enum db_type base, Win32 clients must also have a WRITE LOCK on the table ! */ -bool close_cached_table(THD *thd,TABLE *table) +static void safe_remove_from_cache(THD *thd,TABLE *table) { - bool result=0; - DBUG_ENTER("close_cached_table"); - safe_mutex_assert_owner(&LOCK_open); - + DBUG_ENTER("safe_remove_from_cache"); if (table) { DBUG_PRINT("enter",("table: %s", table->real_name)); @@ -1109,16 +1111,29 @@ bool close_cached_table(THD *thd,TABLE *table) #endif /* When lock on LOCK_open is freed other threads can continue */ pthread_cond_broadcast(&COND_refresh); + } + DBUG_VOID_RETURN; +} + +bool close_cached_table(THD *thd,TABLE *table) +{ + DBUG_ENTER("close_cached_table"); + safe_mutex_assert_owner(&LOCK_open); + + if (table) + { + safe_remove_from_cache(thd,table); /* Close lock if this is not got with LOCK TABLES */ if (thd->lock) { - mysql_unlock_tables(thd, thd->lock); thd->lock=0; // Start locked threads + mysql_unlock_tables(thd, thd->lock); + thd->lock=0; // Start locked threads } /* Close all copies of 'table'. This also frees all LOCK TABLES lock */ thd->open_tables=unlink_open_table(thd,thd->open_tables,table); } - DBUG_RETURN(result); + DBUG_RETURN(0); } static int send_check_errmsg(THD *thd, TABLE_LIST* table, @@ -1199,69 +1214,105 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table, } -static int prepare_for_repair(THD* thd, TABLE_LIST* table, +static int prepare_for_repair(THD* thd, TABLE_LIST *table_list, HA_CHECK_OPT *check_opt) { + int error= 0; + TABLE tmp_table, *table; DBUG_ENTER("prepare_for_repair"); if (!(check_opt->sql_flags & TT_USEFRM)) - { DBUG_RETURN(0); - } - else + + if (!(table= table_list->table)) /* if open_ltable failed */ { + char name[FN_REFLEN]; + strxmov(name, mysql_data_home, "/", table_list->db, "/", + table_list->real_name, NullS); + if (openfrm(name, "", 0, 0, 0, &tmp_table)) + DBUG_RETURN(0); // Can't open frm file + table= &tmp_table; + } - char from[FN_REFLEN],tmp[FN_REFLEN]; - char* db = thd->db ? thd->db : table->db; + /* + User gave us USE_FRM which means that the header in the index file is + trashed. + In this case we will try to fix the table the following way: + - Rename the data file to a temporary name + - Truncate the table + - Replace the new data file with the old one + - Run a normal repair using the new index file and the old data file + */ - sprintf(from, "%s/%s/%s", mysql_real_data_home, db, table->real_name); - fn_format(from, from, "", MI_NAME_DEXT, 4); - sprintf(tmp,"%s-%lx_%lx", from, current_pid, thd->thread_id); + char from[FN_REFLEN],tmp[FN_REFLEN+32]; + const char **ext= table->file->bas_ext(); + MY_STAT stat_info; - pthread_mutex_lock(&LOCK_open); - close_cached_table(thd,table->table); - pthread_mutex_unlock(&LOCK_open); + /* + Check if this is a table type that stores index and data separately, + like ISAM or MyISAM + */ + if (!ext[0] || !ext[1]) + goto end; // No data file - if (lock_and_wait_for_table_name(thd,table)) - DBUG_RETURN(-1); + strxmov(from, table->path, ext[1], NullS); // Name of data file + if (!my_stat(from, &stat_info, MYF(0))) + goto end; // Can't use USE_FRM flag - if (my_rename(from, tmp, MYF(MY_WME))) - { - pthread_mutex_lock(&LOCK_open); - unlock_table_name(thd, table); - pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(send_check_errmsg(thd, table, "repair", - "Failed renaming .MYD file")); - } - if (mysql_truncate(thd, table, 1)) - { - pthread_mutex_lock(&LOCK_open); - unlock_table_name(thd, table); - pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(send_check_errmsg(thd, table, "repair", - "Failed generating table from .frm file")); - } - if (my_rename(tmp, from, MYF(MY_WME))) - { - pthread_mutex_lock(&LOCK_open); - unlock_table_name(thd, table); - pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(send_check_errmsg(thd, table, "repair", - "Failed restoring .MYD file")); - } + sprintf(tmp,"%s-%lx_%lx", from, current_pid, thd->thread_id); + + pthread_mutex_lock(&LOCK_open); + close_cached_table(thd,table_list->table); + pthread_mutex_unlock(&LOCK_open); + + if (lock_and_wait_for_table_name(thd,table_list)) + { + error= -1; + goto end; + } + if (my_rename(from, tmp, MYF(MY_WME))) + { + pthread_mutex_lock(&LOCK_open); + unlock_table_name(thd, table_list); + pthread_mutex_unlock(&LOCK_open); + error= send_check_errmsg(thd, table_list, "repair", + "Failed renaming data file"); + goto end; + } + if (mysql_truncate(thd, table_list, 1)) + { + pthread_mutex_lock(&LOCK_open); + unlock_table_name(thd, table_list); + pthread_mutex_unlock(&LOCK_open); + error= send_check_errmsg(thd, table_list, "repair", + "Failed generating table from .frm file"); + goto end; + } + if (my_rename(tmp, from, MYF(MY_WME))) + { + pthread_mutex_lock(&LOCK_open); + unlock_table_name(thd, table_list); + pthread_mutex_unlock(&LOCK_open); + error= send_check_errmsg(thd, table_list, "repair", + "Failed restoring .MYD file"); + goto end; } /* Now we should be able to open the partially repaired table to finish the repair in the handler later on. */ - if (!(table->table = reopen_name_locked_table(thd, table))) + if (!(table_list->table = reopen_name_locked_table(thd, table_list))) { pthread_mutex_lock(&LOCK_open); - unlock_table_name(thd, table); + unlock_table_name(thd, table_list); pthread_mutex_unlock(&LOCK_open); } - DBUG_RETURN(0); + +end: + if (table == &tmp_table) + closefrm(table); // Free allocated memory + DBUG_RETURN(error); } @@ -1759,9 +1810,11 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, case LEAVE_AS_IS: break; case ENABLE: - error=table->file->activate_all_index(thd); + safe_remove_from_cache(thd,table); + error= table->file->activate_all_index(thd); break; case DISABLE: + safe_remove_from_cache(thd,table); table->file->deactivate_non_unique_index(HA_POS_ERROR); break; } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index fe4ca49da14..1d0f37f0042 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -76,7 +76,7 @@ bool select_union::send_data(List<Item> &values) unit->offset_limit_cnt--; return 0; } - fill_record(table->field,values); + fill_record(table->field, values, 1); if (thd->net.report_error || write_record(table,&info)) { if (thd->net.last_errno == ER_RECORD_FILE_FULL) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index a1464aa509f..9d4d7ccbbab 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -62,33 +62,46 @@ int mysql_update(THD *thd, int error=0; uint used_index, want_privilege; ulong query_id=thd->query_id, timestamp_query_id; + ha_rows updated, found; key_map old_used_keys; TABLE *table; SQL_SELECT *select; READ_RECORD info; - TABLE_LIST *update_table_list= (TABLE_LIST*) - thd->lex.select_lex.table_list.first; + TABLE_LIST *update_table_list= ((TABLE_LIST*) + thd->lex.select_lex.table_list.first); + TABLE_LIST tables; + List<Item> all_fields; DBUG_ENTER("mysql_update"); + LINT_INIT(used_index); LINT_INIT(timestamp_query_id); if ((open_and_lock_tables(thd, table_list))) DBUG_RETURN(-1); + thd->proc_info="init"; fix_tables_pointers(thd->lex.all_selects_list); table= table_list->table; - table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); - thd->proc_info="init"; /* Calculate "table->used_keys" based on the WHERE */ table->used_keys=table->keys_in_use; table->quick_keys=0; want_privilege=table->grant.want_privilege; table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege); - if (setup_tables(update_table_list) || - setup_conds(thd,update_table_list,&conds) - || setup_ftfuncs(&thd->lex.select_lex)) + + bzero((char*) &tables,sizeof(tables)); // For ORDER BY + tables.table= table; + + if (setup_tables(update_table_list) || + setup_conds(thd,update_table_list,&conds) || + setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array, + order_num) || + setup_order(thd, thd->lex.select_lex.ref_pointer_array, + &tables, all_fields, all_fields, order) || + setup_ftfuncs(&thd->lex.select_lex)) DBUG_RETURN(-1); /* purecov: inspected */ + + /* Check that we are not using table that we are updating in a sub select */ if (find_real_table_in_list(table_list->next, table_list->db, table_list->real_name)) { @@ -96,8 +109,7 @@ int mysql_update(THD *thd, DBUG_RETURN(-1); } - old_used_keys=table->used_keys; // Keys used in WHERE - + old_used_keys= table->used_keys; // Keys used in WHERE /* Change the query_id for the timestamp column so that we can check if this is modified directly @@ -151,10 +163,9 @@ int mysql_update(THD *thd, thd->lex.select_lex.options|=QUERY_NO_INDEX_USED; if (safe_update && !using_limit) { - delete select; - free_underlaid_joins(thd, &thd->lex.select_lex); - send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); - DBUG_RETURN(1); + my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, + ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0)); + goto err; } } init_ftfuncs(thd, &thd->lex.select_lex, 1); @@ -175,14 +186,6 @@ int mysql_update(THD *thd, matching rows before updating the table! */ table->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE); - IO_CACHE tempfile; - if (open_cached_file(&tempfile, mysql_tmpdir,TEMP_PREFIX, - DISK_BUFFER_SIZE, MYF(MY_WME))) - { - delete select; /* purecov: inspected */ - free_underlaid_joins(thd, &thd->lex.select_lex); - DBUG_RETURN(-1); - } if (old_used_keys & ((key_map) 1 << used_index)) { table->key_read=1; @@ -191,94 +194,102 @@ int mysql_update(THD *thd, if (order) { + /* + Doing an ORDER BY; Let filesort find and sort the rows we are going + to update + */ uint length; SORT_FIELD *sortorder; - TABLE_LIST tables; List<Item> fields; - List<Item> all_fields; ha_rows examined_rows; - bzero((char*) &tables,sizeof(tables)); - tables.table = table; - table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE), - MYF(MY_FAE | MY_ZEROFILL)); - if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array, - order_num)|| - setup_order(thd, thd->lex.select_lex.ref_pointer_array, - &tables, fields, all_fields, order) || - !(sortorder=make_unireg_sortorder(order, &length)) || + MYF(MY_FAE | MY_ZEROFILL)); + if (!(sortorder=make_unireg_sortorder(order, &length)) || (table->sort.found_records = filesort(thd, table, sortorder, length, - (SQL_SELECT *) 0, - HA_POS_ERROR, &examined_rows)) + select, limit, + &examined_rows)) == HA_POS_ERROR) { - delete select; - free_underlaid_joins(thd, &thd->lex.select_lex); - DBUG_RETURN(-1); + free_io_cache(table); + goto err; } + /* + Filesort has already found and selected the rows we want to update, + so we don't need the where clause + */ + delete select; + select= 0; } + else + { + /* + We are doing a search on a key that is updated. In this case + we go trough the matching rows, save a pointer to them and + update these in a separate loop based on the pointer. + */ + + IO_CACHE tempfile; + if (open_cached_file(&tempfile, mysql_tmpdir,TEMP_PREFIX, + DISK_BUFFER_SIZE, MYF(MY_WME))) + goto err; - init_read_record(&info,thd,table,select,0,1); - thd->proc_info="Searching rows for update"; + init_read_record(&info,thd,table,select,0,1); + thd->proc_info="Searching rows for update"; + uint tmp_limit= limit; - while (!(error=info.read_record(&info)) && !thd->killed) - { - if (!(select && select->skipp_record())) + while (!(error=info.read_record(&info)) && !thd->killed) { - table->file->position(table->record[0]); - if (my_b_write(&tempfile,table->file->ref, - table->file->ref_length)) + if (!(select && select->skipp_record())) { - error=1; /* purecov: inspected */ - break; /* purecov: inspected */ + table->file->position(table->record[0]); + if (my_b_write(&tempfile,table->file->ref, + table->file->ref_length)) + { + error=1; /* purecov: inspected */ + break; /* purecov: inspected */ + } + if (!--limit && using_limit) + { + error= -1; + break; + } } } + limit= tmp_limit; + end_read_record(&info); + /* Change select to use tempfile */ + if (select) + { + delete select->quick; + if (select->free_cond) + delete select->cond; + select->quick=0; + select->cond=0; + } else { - if (!(test_flags & 512)) /* For debugging */ - { - DBUG_DUMP("record",(char*) table->record[0],table->reclength); - } + select= new SQL_SELECT; + select->head=table; } + if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0)) + error=1; /* purecov: inspected */ + select->file=tempfile; // Read row ptrs from this file + if (error >= 0) + goto err; } - end_read_record(&info); - if (table->key_read) { table->key_read=0; table->file->extra(HA_EXTRA_NO_KEYREAD); } - /* Change select to use tempfile */ - if (select) - { - delete select->quick; - if (select->free_cond) - delete select->cond; - select->quick=0; - select->cond=0; - } - else - { - select= new SQL_SELECT; - select->head=table; - } - if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0)) - error=1; /* purecov: inspected */ - select->file=tempfile; // Read row ptrs from this file - if (error >= 0) - { - delete select; - free_underlaid_joins(thd, &thd->lex.select_lex); - DBUG_RETURN(-1); - } } if (handle_duplicates == DUP_IGNORE) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); init_read_record(&info,thd,table,select,0,1); - ha_rows updated=0L,found=0L; + updated= found= 0; thd->count_cuted_fields=1; /* calc cuted fields */ thd->cuted_fields=0L; thd->proc_info="Updating"; @@ -289,7 +300,7 @@ int mysql_update(THD *thd, if (!(select && select->skipp_record())) { store_record(table,record[1]); - if (fill_record(fields,values) || thd->net.report_error) + if (fill_record(fields,values, 0) || thd->net.report_error) break; /* purecov: inspected */ found++; if (compare_record(table, query_id)) @@ -298,11 +309,6 @@ int mysql_update(THD *thd, (byte*) table->record[0]))) { updated++; - if (!--limit && using_limit) - { - error= -1; - break; - } } else if (handle_duplicates != DUP_IGNORE || error != HA_ERR_FOUND_DUPP_KEY) @@ -312,12 +318,18 @@ int mysql_update(THD *thd, break; } } + if (!--limit && using_limit) + { + error= -1; // Simulate end of file + break; + } } else table->file->unlock_row(); thd->row_count++; } end_read_record(&info); + free_io_cache(table); // If ORDER BY thd->proc_info="end"; VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY)); transactional_table= table->file->has_transactions(); @@ -371,8 +383,17 @@ int mysql_update(THD *thd, } thd->count_cuted_fields=0; /* calc cuted fields */ free_io_cache(table); - DBUG_RETURN(0); + +err: + delete select; + free_underlaid_joins(thd, &thd->lex.select_lex); + if (table->key_read) + { + table->key_read=0; + table->file->extra(HA_EXTRA_NO_KEYREAD); + } + DBUG_RETURN(-1); } @@ -509,6 +530,8 @@ int multi_update::prepare(List<Item> ¬_used_values, SELECT_LEX_UNIT *unit) table->pos_in_table_list= tl; } } + + table_count= update.elements; update_tables= (TABLE_LIST*) update.first; @@ -733,7 +756,7 @@ bool multi_update::send_data(List<Item> ¬_used_values) { table->status|= STATUS_UPDATED; store_record(table,record[1]); - if (fill_record(*fields_for_table[offset], *values_for_table[offset])) + if (fill_record(*fields_for_table[offset], *values_for_table[offset], 0)) DBUG_RETURN(1); found++; if (compare_record(table, thd->query_id)) @@ -761,7 +784,7 @@ bool multi_update::send_data(List<Item> ¬_used_values) { int error; TABLE *tmp_table= tmp_tables[offset]; - fill_record(tmp_table->field+1, *values_for_table[offset]); + fill_record(tmp_table->field+1, *values_for_table[offset], 1); found++; /* Store pointer to row */ memcpy((char*) tmp_table->field[0]->ptr, @@ -771,7 +794,7 @@ bool multi_update::send_data(List<Item> ¬_used_values) (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE)) { - if (create_myisam_from_heap(thd, table, tmp_table_param + offset, + if (create_myisam_from_heap(thd, tmp_table, tmp_table_param + offset, error, 1)) { do_update=0; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4de0e2f8c13..1d735730801 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -555,11 +555,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %left '^' %right NOT %right BINARY COLLATE_SYM -/* These don't actually affect the way the query is really evaluated, but - they silence a few warnings for shift/reduce conflicts. */ -%left ',' -%left STRAIGHT_JOIN JOIN_SYM -%nonassoc CROSS INNER_SYM NATURAL LEFT RIGHT %type <lex_str> IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME @@ -1933,7 +1928,10 @@ select_option: Select->options|= OPTION_FOUND_ROWS; } | SQL_NO_CACHE_SYM { Lex->uncacheable(); } - | SQL_CACHE_SYM { Select->options|= OPTION_TO_QUERY_CACHE; } + | SQL_CACHE_SYM + { + Lex->select_lex.options|= OPTION_TO_QUERY_CACHE; + } | ALL {} ; @@ -2182,8 +2180,10 @@ simple_expr: simple_ident | simple_expr COLLATE_SYM ident_or_text %prec NEG { - $$= new Item_func_set_collation($1,new Item_string($3.str,$3.length, - YYTHD->charset())); + $$= new Item_func_set_collation($1, + new Item_string($3.str, + $3.length, + YYTHD->charset())); } | literal | param_marker @@ -2230,8 +2230,8 @@ simple_expr: | ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); } | BINARY expr %prec NEG { - $$= new Item_func_set_collation($2,new Item_string("BINARY",6, - &my_charset_latin1)); + $$= new Item_func_set_collation($2,new Item_string(binary_keyword, + 6, &my_charset_latin1)); } | CAST_SYM '(' expr AS cast_type ')' { $$= create_func_cast($3, $5); } | CASE_SYM opt_expr WHEN_SYM when_list opt_else END @@ -2581,8 +2581,12 @@ sum_expr: { $$=new Item_sum_count(new Item_int((int32) 0L,1)); } | COUNT_SYM '(' in_sum_expr ')' { $$=new Item_sum_count($3); } - | COUNT_SYM '(' DISTINCT expr_list ')' - { $$=new Item_sum_count_distinct(* $4); } + | COUNT_SYM '(' DISTINCT + { Select->select_lex()->in_sum_expr++; } + expr_list + { Select->select_lex()->in_sum_expr--; } + ')' + { $$=new Item_sum_count_distinct(* $5); } | GROUP_UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' in_sum_expr ')' { $$= new Item_sum_unique_users($3,atoi($5.str),atoi($7.str),$9); } | MIN_SYM '(' in_sum_expr ')' @@ -2711,7 +2715,7 @@ join_table_list: | join_table_list ',' join_table_list { $$=$3; } | join_table_list normal_join join_table_list { $$=$3; } | join_table_list STRAIGHT_JOIN join_table_list - { $$=$3 ; $$->straight=1; } + { $$=$3 ; $1->next->straight=1; } | join_table_list normal_join join_table_list ON expr { add_join_on($3,$5); $$=$3; } | join_table_list normal_join join_table_list @@ -2735,9 +2739,13 @@ join_table_list: USING '(' using_list ')' { add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } | join_table_list NATURAL LEFT opt_outer JOIN_SYM join_table_list - { add_join_natural($1,$6); $6->outer_join|=JOIN_TYPE_LEFT; $$=$6; } + { + add_join_natural($1,$1->next); + $1->next->outer_join|=JOIN_TYPE_LEFT; + $$=$6; + } | join_table_list RIGHT opt_outer JOIN_SYM join_table_list ON expr - { add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; } + { add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$5; } | join_table_list RIGHT opt_outer JOIN_SYM join_table_list { SELECT_LEX *sel= Select->select_lex(); @@ -2745,11 +2753,15 @@ join_table_list: sel->db2=$5->db; sel->table2=$5->alias; } USING '(' using_list ')' - { add_join_on($1,$9); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; } + { add_join_on($1,$9); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$5; } | join_table_list NATURAL RIGHT opt_outer JOIN_SYM join_table_list - { add_join_natural($6,$1); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; } + { + add_join_natural($1->next,$1); + $1->outer_join|=JOIN_TYPE_RIGHT; + $$=$6; + } | join_table_list NATURAL JOIN_SYM join_table_list - { add_join_natural($1,$4); $$=$4; }; + { add_join_natural($1,$1->next); $$=$4; }; normal_join: JOIN_SYM {} @@ -3076,7 +3088,7 @@ delete_limit_clause: ULONG_NUM: NUM { $$= strtoul($1.str,NULL,10); } - | LONG_NUM { $$= (ulonglong) strtoll($1.str,NULL,10); } + | LONG_NUM { $$= (ulong) strtoll($1.str,NULL,10); } | ULONGLONG_NUM { $$= (ulong) strtoull($1.str,NULL,10); } | REAL_NUM { $$= strtoul($1.str,NULL,10); } | FLOAT_NUM { $$= strtoul($1.str,NULL,10); }; diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc index 57560715fbe..fa678ec7de2 100644 --- a/sql/thr_malloc.cc +++ b/sql/thr_malloc.cc @@ -85,3 +85,33 @@ gptr sql_memdup(const void *ptr,uint len) void sql_element_free(void *ptr __attribute__((unused))) {} /* purecov: deadcode */ + + + +char *sql_strmake_with_convert(const char *str, uint32 arg_length, + CHARSET_INFO *from_cs, + uint32 max_res_length, + CHARSET_INFO *to_cs, uint32 *result_length) +{ + char *pos; + uint32 new_length= to_cs->mbmaxlen*arg_length; + max_res_length--; // Reserve place for end null + + set_if_smaller(new_length, max_res_length); + if (!(pos= sql_alloc(new_length+1))) + return pos; // Error + + if ((from_cs == &my_charset_bin) || (to_cs == &my_charset_bin)) + { + // Safety if to_cs->mbmaxlen > 0 + new_length= min(arg_length, max_res_length); + memcpy(pos, str, new_length); + } + else + new_length= copy_and_convert((char*) pos, new_length, to_cs, str, + arg_length, from_cs); + pos[new_length]= 0; + *result_length= new_length; + return pos; +} + diff --git a/sql/time.cc b/sql/time.cc index 94f9cb2e5e8..eba664a690d 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -251,145 +251,6 @@ void get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month, DBUG_VOID_RETURN; } -/* find date from string and put it in vektor - Input: pos = "YYMMDD" OR "YYYYMMDD" in any order or - "xxxxx YYxxxMMxxxDD xxxx" where xxx is anything exept - a number. Month or day mustn't exeed 2 digits, year may be 4 digits. -*/ - - -#ifdef NOT_NEEDED - -void find_date(string pos,uint *vek,uint flag) -{ - uint length,value; - string start; - DBUG_ENTER("find_date"); - DBUG_PRINT("enter",("pos: '%s' flag: %d",pos,flag)); - - bzero((char*) vek,sizeof(int)*4); - while (*pos && !my_isdigit(my_charset_latin1,*pos)) - pos++; - length=(uint) strlen(pos); - for (uint i=0 ; i< 3; i++) - { - start=pos; value=0; - while (my_isdigit(my_charset_latin1,pos[0]) && - ((pos-start) < 2 || ((pos-start) < 4 && length >= 8 && - !(flag & 3)))) - { - value=value*10 + (uint) (uchar) (*pos - '0'); - pos++; - } - vek[flag & 3]=value; flag>>=2; - while (*pos && (my_ispunct(my_charset_latin1,*pos) || - my_isspace(my_charset_latin1,*pos))) - pos++; - } - DBUG_PRINT("exit",("year: %d month: %d day: %d",vek[0],vek[1],vek[2])); - DBUG_VOID_RETURN; -} /* find_date */ - - - /* Outputs YYMMDD if input year < 100 or YYYYMMDD else */ - -static long calc_daynr_from_week(uint year,uint week,uint day) -{ - long daynr; - int weekday; - - daynr=calc_daynr(year,1,1); - if ((weekday= calc_weekday(daynr,0)) >= 3) - daynr+= (7-weekday); - else - daynr-=weekday; - - return (daynr+week*7+day-8); -} - -void convert_week_to_date(string date,uint flag,uint *res_length) -{ - string format; - uint year,vek[4]; - - find_date(date,vek,(uint) (1*4+2*16)); /* YY-WW-DD */ - year=vek[0]; - - get_date_from_daynr(calc_daynr_from_week(vek[0],vek[1],vek[2]), - &vek[0],&vek[1],&vek[2]); - *res_length=8; - format="%04d%02d%02d"; - if (year < 100) - { - vek[0]= vek[0]%100; - *res_length=6; - format="%02d%02d%02d"; - } - sprintf(date,format,vek[flag & 3],vek[(flag >> 2) & 3], - vek[(flag >> 4) & 3]); - return; -} - - /* returns YYWWDD or YYYYWWDD according to input year */ - /* flag only reflects format of input date */ - -void convert_date_to_week(string date,uint flag,uint *res_length) -{ - uint vek[4],weekday,days,year,week,day; - long daynr,first_daynr; - char buff[256],*format; - - if (! date[0]) - { - get_date(buff,0,0L); /* Use current date */ - find_date(buff+2,vek,(uint) (1*4+2*16)); /* YY-MM-DD */ - } - else - find_date(date,vek,flag); - - year= vek[0]; - daynr= calc_daynr(year,vek[1],vek[2]); - first_daynr=calc_daynr(year,1,1); - - /* Caculate year and first daynr of year */ - if (vek[1] == 1 && (weekday=calc_weekday(first_daynr,0)) >= 3 && - vek[2] <= 7-weekday) - { - if (!year--) - year=99; - first_daynr=first_daynr-calc_days_in_year(year); - } - else if (vek[1] == 12 && - (weekday=calc_weekday(first_daynr+calc_days_in_year(year)),0) < 3 && - vek[2] > 31-weekday) - { - first_daynr=first_daynr+calc_days_in_year(year); - if (year++ == 99) - year=0; - } - - /* Calulate daynr of first day of week 1 */ - if ((weekday= calc_weekday(first_daynr,0)) >= 3) - first_daynr+= (7-weekday); - else - first_daynr-=weekday; - - days=(int) (daynr-first_daynr); - week=days/7+1 ; day=calc_weekday(daynr,0)+1; - - *res_length=8; - format="%04d%02d%02d"; - if (year < 100) - { - *res_length=6; - format="%02d%02d%02d"; - } - sprintf(date,format,year,week,day); - return; -} - -#endif - /* Functions to handle periods */ ulong convert_period_to_month(ulong period) @@ -516,14 +377,14 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) else date[6]=0; - if (year_length == 2) + if (year_length == 2 && i >=2 && (date[1] || date[2])) date[0]+= (date[0] < YY_PART_YEAR ? 2000 : 1900); number_of_fields=i; while (i < 6) date[i++]=0; if (number_of_fields < 3 || date[1] > 12 || date[2] > 31 || date[3] > 23 || date[4] > 59 || date[5] > 59 || - !fuzzy_date && (date[1] == 0 || date[2] == 0)) + (!fuzzy_date && (date[1] == 0 || date[2] == 0))) { /* Only give warning for a zero date if there is some garbage after */ if (!not_zero_date) // If zero date diff --git a/sql/unireg.h b/sql/unireg.h index ff942f6748a..6ddd9856724 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -45,6 +45,7 @@ #define LIBLEN FN_REFLEN-FN_LEN /* Max l{ngd p} dev */ #define MAX_DBKEY_LENGTH (FN_LEN*2+6) /* extra 4 bytes for slave tmp * tables */ +#define MAX_ALIAS_NAME 256 #define MAX_FIELD_NAME 34 /* Max colum name length +2 */ #define MAX_SYS_VAR_LENGTH 32 #define MAX_KEY 32 /* Max used keys */ @@ -55,6 +56,7 @@ #else #define MAX_REFLENGTH 4 /* Max length for record ref */ #endif +#define MAX_HOSTNAME 61 /* len+1 in mysql.user */ #define MAX_FIELD_WIDTH 256 /* Max column width +1 */ #define MAX_TABLES (sizeof(table_map)*8-2) /* Max tables in join */ diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c index 21722f317a1..e108ffac6af 100644 --- a/strings/ctype-tis620.c +++ b/strings/ctype-tis620.c @@ -455,82 +455,78 @@ uchar NEAR sort_order_tis620[]= Arg: const source string and length of converted string Ret: Sortable string */ - +/* + NOTE: isn't it faster to alloc buffer in calling function? + */ static uchar* thai2sortable(const uchar * tstr,uint len) { /* We use only 3 levels (neglect capitalization). */ - const uchar* p = tstr; + const uchar* p= tstr; uchar *outBuf; -/* uchar *pRight1, *pRight2, *pRight3, *pRight4; */ -/* uchar *pLeft1, *pLeft2, *pLeft3, *pLeft4; */ uchar *pRight1, *pRight2, *pRight3; uchar *pLeft1, *pLeft2, *pLeft3; uint bufSize; - - len = (uint) strnlen((char*) tstr,len); - bufSize = (uint) buffsize((char*) tstr); - if(!(pRight1 = (uchar *)malloc(sizeof(uchar) * bufSize))) { - return( (uchar*) tstr); - } - pLeft1 = pRight1; - outBuf = pRight1; - if(!(pRight2 = (uchar *)malloc(sizeof(uchar) * (len + 1)))) { - free(pRight1); - return((uchar*) tstr); - } - pLeft2 = pRight2; - if(!(pRight3 = (uchar *)malloc(sizeof(uchar) * (len + 1)))) { - free(pRight1); - free(pRight2); - return((uchar*) tstr); - } - pLeft3 = pRight3; -/* if(!(pRight4 = (uchar *)malloc(sizeof(uchar) * (len + 1)))) { - free(pRight1); - free(pRight2); - free(pRight3); - return((uchar*) tstr); - } - pLeft4 = pRight4;*/ - while(len--) { - if(isldvowel(*p) && isconsnt(p[1])) { - *pRight1++ = t_ctype[p[1]][0]; - *pRight2++ = t_ctype[p[1]][1]; - *pRight3++ = t_ctype[p[1]][2]; -/* *pRight4++ = t_ctype[p[1]][3]; */ - *pRight1++ = t_ctype[*p][0]; - *pRight2++ = t_ctype[*p][1]; - *pRight3++ = t_ctype[*p][2]; -/* *pRight4++ = t_ctype[*p][3]; */ + uint RightSize; + + len= (uint) strnlen((char*) tstr,len); + bufSize= (uint) buffsize((char*) tstr); + RightSize= sizeof(uchar) * (len + 1); + if (!(outBuf= pLeft1= pRight1= + (uchar *)malloc(sizeof(uchar) * bufSize + RightSize*2))) + return (uchar*) tstr; + pLeft2= pRight2= pRight1 + sizeof(uchar) * bufSize; + pLeft3= pRight3= pRight2 + RightSize; + + while (--len) + { + int *t_ctype0= t_ctype[p[0]]; + if (isldvowel(*p) && isconsnt(p[1])) + { + int *t_ctype1= t_ctype[p[1]]; + *pRight1++= t_ctype1[0]; + *pRight2++= t_ctype1[1]; + *pRight3++= t_ctype1[2]; + *pRight1++= t_ctype0[0]; + *pRight2++= t_ctype0[1]; + *pRight3++= t_ctype0[2]; + p+= 2; len--; - p += 2; - } else { - *pRight1 = t_ctype[*p][0]; - if(*pRight1 != IGNORE) pRight1++; - *pRight2 = t_ctype[*p][1]; - if(*pRight2 != IGNORE) pRight2++; - *pRight3 = t_ctype[*p][2]; - if(*pRight3 != IGNORE) pRight3++; -/* *pRight4 = t_ctype[*p][3]; - if(*pRight4 != IGNORE) pRight4++;*/ + } + else + { + *pRight1= t_ctype0[0]; + if(*pRight1 != IGNORE) + pRight1++; + *pRight2= t_ctype0[1]; + if (*pRight2 != IGNORE) + pRight2++; + *pRight3= t_ctype0[2]; + if(*pRight3 != IGNORE) + pRight3++; p++; } } - *pRight1++ = L2_BLANK; - *pRight2++ = L3_BLANK; -/* *pRight3++ = L4_BLANK; */ - *pRight3++ = '\0'; -/* *pRight4++ = '\0'; */ + if (!len) + { + int *t_ctype0= t_ctype[p[0]]; + *pRight1= t_ctype0[0]; + if (*pRight1 != IGNORE) + pRight1++; + *pRight2= t_ctype0[1]; + if (*pRight2 != IGNORE) + pRight2++; + *pRight3= t_ctype0[2]; + if (*pRight3 != IGNORE) + pRight3++; + } + *pRight1++= L2_BLANK; + *pRight2++= L3_BLANK; + *pRight3++= '\0'; memcpy(pRight1, pLeft2, pRight2 - pLeft2); - pRight1 += pRight2 - pLeft2; + pRight1+= pRight2 - pLeft2; memcpy(pRight1, pLeft3, pRight3 - pLeft3); -/* pRight1 += pRight3 - pLeft3; */ -/* memcpy(pRight1, pLeft4, pRight4 - pLeft4); */ - free(pLeft2); - free(pLeft3); -/* free(pLeft4); */ - return(outBuf); + return outBuf; } /* strncoll() replacement, compare 2 string, both are conveted to sortable string @@ -543,12 +539,12 @@ int my_strnncoll_tis620(CHARSET_INFO *cs __attribute__((unused)), { uchar *tc1, *tc2; int i; - tc1 = thai2sortable(s1, len1); - tc2 = thai2sortable(s2, len2); - i = strcmp((char*)tc1, (char*)tc2); + tc1= thai2sortable(s1, len1); + tc2= thai2sortable(s2, len2); + i= strcmp((char*)tc1, (char*)tc2); free(tc1); free(tc2); - return(i); + return i; } static @@ -572,12 +568,12 @@ int my_strnxfrm_tis620(CHARSET_INFO *cs __attribute__((unused)), { uint bufSize; uchar *tmp; - bufSize = (uint) buffsize((char*)src); - tmp = thai2sortable(src,srclen); + bufSize= (uint) buffsize((char*)src); + tmp= thai2sortable(src,srclen); set_if_smaller(bufSize,(uint) len); memcpy((uchar *)dest, tmp, bufSize); free(tmp); - return (int) bufSize; + return (int)bufSize; } /* strcoll replacment, compare 2 strings @@ -588,12 +584,12 @@ int my_strcoll_tis620(const uchar * s1, const uchar * s2) { uchar *tc1, *tc2; int i; - tc1 = thai2sortable(s1, (uint) strlen((char*)s1)); - tc2 = thai2sortable(s2, (uint) strlen((char*)s2)); - i = strcmp((char*)tc1, (char*)tc2); + tc1= thai2sortable(s1, (uint) strlen((char*)s1)); + tc2= thai2sortable(s2, (uint) strlen((char*)s2)); + i= strcmp((char*)tc1, (char*)tc2); free(tc1); free(tc2); - return(i); + return i; } /* strxfrm replacment, convert Thai string to sortable string @@ -605,9 +601,9 @@ int my_strxfrm_tis620(uchar * dest, const uchar * src, int len) uint bufSize; uchar *tmp; - bufSize = (uint) buffsize((char*) src); - tmp = thai2sortable(src, len); - memcpy((uchar *) dest, tmp, bufSize); + bufSize= (uint)buffsize((char*) src); + tmp= thai2sortable(src, len); + memcpy((uchar *)dest, tmp, bufSize); free(tmp); return bufSize; } @@ -637,7 +633,7 @@ my_bool my_like_range_tis620(CHARSET_INFO *cs __attribute__((unused)), if (*ptr == escape && ptr+1 != end) { ptr++; /* Skipp escape */ - *min_str++= *max_str++ = *ptr; + *min_str++ = *max_str++ = *ptr; continue; } if (*ptr == w_one) /* '_' in SQL */ @@ -671,28 +667,24 @@ my_bool my_like_range_tis620(CHARSET_INFO *cs __attribute__((unused)), */ void ThNormalize(uchar* ptr, uint field_length, const uchar* from, uint length) { - const uchar* fr = from; - uchar* p = ptr; + const uchar* fr= from; + uchar* p= ptr; + + if (length > field_length) + length= field_length; - if(length > field_length) { - length = field_length; - } while (length--) - { - if((istone(*fr) || isdiacrt1(*fr)) && + if ((istone(*fr) || isdiacrt1(*fr)) && (islwrvowel(fr[1]) || isuprvowel(fr[1]))) { - *p = fr[1]; - p[1] = *fr; - fr += 2; - p += 2; + *p= fr[1]; + p[1]= *fr; + fr+= 2; + p+= 2; length--; } else - { *p++ = *fr++; - } - } } diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c index 92214868018..8a9863f7940 100644 --- a/strings/ctype-ujis.c +++ b/strings/ctype-ujis.c @@ -8257,7 +8257,7 @@ my_mb_wc_euc_jp(CHARSET_INFO *cs,my_wc_t *pwc, const uchar *s, const uchar *e) { int c1,c2,c3; - if (s>e) + if (s >= e) return MY_CS_TOOFEW(0); c1=s[0]; diff --git a/support-files/MacOSX/Makefile.am b/support-files/MacOSX/Makefile.am index d030ff39d84..b8047942190 100644 --- a/support-files/MacOSX/Makefile.am +++ b/support-files/MacOSX/Makefile.am @@ -34,7 +34,8 @@ CLEANFILES = Info.plist \ Description.plist \ StartupParameters.plist \ postinstall \ - preinstall + preinstall \ + ReadMe.txt SUFFIXES = .sh diff --git a/support-files/MacOSX/ReadMe.txt b/support-files/MacOSX/ReadMe.txt deleted file mode 100644 index a18c5f3aa41..00000000000 --- a/support-files/MacOSX/ReadMe.txt +++ /dev/null @@ -1,80 +0,0 @@ -Installation notes for MySQL on Mac OS X - -PLEASE READ! - -For more details about installing and running -MySQL on Mac OS X, also refer to the manual, -which is available online: - -http://www.mysql.com/doc/en/Mac_OS_X_installation.html - -NOTE: Before proceeding with the installation, please -make sure that no other MySQL server is running! - -Please shut down all running MySQL instances before -continuing by either using the MySQL Manager -Application (on Mac OS X Server) or via "mysqladmin -shutdown" on the command line. - -This MySQL package will be installed into -"/usr/local/mysql-<version>" and will also create a -symbolic link "/usr/local/mysql", pointing to the new -location. - -A previously existing /usr/local/mysql directory will -be renamed to /usr/local/mysql.bak before proceeding -with the installation. - -Additionally, it will install the mysql grant tables by -executing "mysql_install_db" after the installation. - -If you are running Mac OS X Server, you already have a -version MySQL installed. Make sure to read Apple's help -about installing MySQL (Run the "Help View" application, -select "Mac OS X Server help", and do a search for MySQL -and read the item entitled "Installing MySQL"). - -If you previously used Marc Liyanage's MySQL packages -for MacOS X from http://www.entropy.ch, you can simply -follow the update instructions given on his pages. - -After the installation (and restoring the old database -files, if necessary), you can start up MySQL by running -the following commands in a terminal window: - - cd /usr/local/mysql - sudo ./bin/mysqld_safe - (Enter your password) - (Press CTRL+Z) - bg - (Press CTRL+D to exit the shell) - -You should now be able to connect to the MySQL server, -e.g. by running /usr/local/mysql/bin/mysql - -If you installed MySQL for the first time, -PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER! -This is done with the following two commands: - -/usr/local/mysql/bin/mysqladmin -u root password 'new-password' - -/usr/local/mysql/bin/mysqladmin -u root -h $hostname password 'new-password' - -Please note, that after upgrading from MySQL 3.23 to -MySQL 4.0 it is recommended to convert the MySQL -privilege tables using the mysql_fix_privilege_tables -script, since some new security privileges have been -added. - -Please see -http://www.mysql.com/doc/en/Upgrading-from-3.23.html -for more information on how to upgrade from MySQL 3.23. - -If you do not want to have to type the full path -"/usr/local/mysql/bin" in front of every command, you -can to add this directory to your PATH environment -variable in your login script. For the default shell -"tcsh", you can do this by running this command once: - -echo 'setenv PATH $PATH:/usr/local/mysql/bin' >> ~/.tcshrc - diff --git a/support-files/MacOSX/postinstall.sh b/support-files/MacOSX/postinstall.sh index daaf10bda8f..f46f4480e3e 100644 --- a/support-files/MacOSX/postinstall.sh +++ b/support-files/MacOSX/postinstall.sh @@ -10,7 +10,7 @@ if cd @prefix@ ; then if [ ! -f data/mysql/db.frm ] ; then - ./scripts/mysql_install_db + ./scripts/mysql_install_db -IN-RPM fi if [ -d data ] ; then diff --git a/support-files/Makefile.am b/support-files/Makefile.am index ec88972c821..58808b5e255 100644 --- a/support-files/Makefile.am +++ b/support-files/Makefile.am @@ -25,7 +25,8 @@ EXTRA_DIST = mysql.spec.sh \ mysql-log-rotate.sh \ mysql.server.sh \ binary-configure.sh \ - magic + magic \ + MySQL-shared-compat.spec.sh SUBDIRS = MacOSX @@ -34,7 +35,7 @@ pkgdata_DATA = my-small.cnf \ my-large.cnf \ my-huge.cnf \ mysql-log-rotate \ - mysql-@VERSION@.spec + MySQL-shared-compat.spec pkgdata_SCRIPTS = mysql.server @@ -46,7 +47,8 @@ CLEANFILES = my-small.cnf \ mysql-@VERSION@.spec \ mysql-log-rotate \ mysql.server \ - binary-configure + binary-configure \ + MySQL-shared-compat.spec mysql-@VERSION@.spec: mysql.spec rm -f $@ diff --git a/support-files/MySQL-shared-compat.spec.sh b/support-files/MySQL-shared-compat.spec.sh new file mode 100644 index 00000000000..f569dc20f42 --- /dev/null +++ b/support-files/MySQL-shared-compat.spec.sh @@ -0,0 +1,72 @@ +# +# MySQL-shared-compat.spec +# +# RPM build instructions to create a "meta" package that includes two +# versions of the MySQL shared libraries (for compatibility with +# distributions that ship older versions of MySQL and do not provide a +# separate "MySQL-shared" package. This spec file simply repackages two +# already existing MySQL-shared RPMs into a single package. +# +# Copyright (C) 2003 MySQL AB +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., 59 +# Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# +# Change this to match the version of the shared libs you want to include +# +%define version4 @VERSION@ +%define version3 3.23.56 + +Name: MySQL-shared-compat +Packager: Lenz Grimmer <build@mysql.com> +Vendor: MySQL AB +License: GPL +Group: Applications/Databases +URL: http://www.mysql.com/ +Autoreqprov: on +Version: %{version4} +Release: 0 +BuildRoot: %{_tmppath}/%{name}-%{version}-build +Obsoletes: MySQL-shared, mysql-shared +Provides: MySQL-shared +Summary: MySQL shared libraries for MySQL %{version4} and %{version3} +Source0: MySQL-shared-%{version4}-0.i386.rpm +Source1: MySQL-shared-%{version3}-1.i386.rpm +# No need to include the RPMs once more - they can be downloaded seperately +# if you want to rebuild this package +NoSource: 0 +NoSource: 1 +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +%description +This package includes the shared libraries for both MySQL %{version3} and +MySQL %{version4}. Install this package instead of "MySQL-shared", if you +have applications installed that are dynamically linked against MySQL +3.23.xx but you want to upgrade to MySQL 4.0.xx without breaking the library +dependencies. + +%install +[ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT; +mkdir -p $RPM_BUILD_ROOT +cd $RPM_BUILD_ROOT +rpm2cpio %{SOURCE0} | cpio -iv --make-directories +rpm2cpio %{SOURCE1} | cpio -iv --make-directories + +%clean +[ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT; + +%files +%defattr(-, root, root) +/usr/lib/libmysqlclient* diff --git a/support-files/my-huge.cnf.sh b/support-files/my-huge.cnf.sh index 50a14b0fc96..18e926b1400 100644 --- a/support-files/my-huge.cnf.sh +++ b/support-files/my-huge.cnf.sh @@ -26,40 +26,96 @@ socket = @MYSQL_UNIX_ADDR@ port = @MYSQL_TCP_PORT@ socket = @MYSQL_UNIX_ADDR@ skip-locking -set-variable = key_buffer=384M -set-variable = max_allowed_packet=1M -set-variable = table_cache=512 -set-variable = sort_buffer=2M -set-variable = record_buffer=2M -set-variable = thread_cache=8 +key_buffer = 384M +max_allowed_packet = 1M +table_cache = 512 +sort_buffer_size = 2M +read_buffer_size = 2M +myisam_sort_buffer_size = 64M +thread_cache = 8 +query_cache_size = 32M # Try number of CPU's*2 for thread_concurrency -set-variable = thread_concurrency=8 -set-variable = myisam_sort_buffer_size=64M +thread_concurrency = 8 + +# Don't listen on a TCP/IP port at all. This can be a security enhancement, +# if all processes that need to connect to mysqld run on the same host. +# All interaction with mysqld must be made via Unix sockets or named pipes. +# Note that using this option without enabling named pipes on Windows +# (via the "enable-named-pipe" option) will render mysqld useless! +# +#skip-networking # Replication Master Server (default) -log-bin # required for replication -server-id = 1 # required unique id between 1 and 2^32 - 1 - # defaults to 1 if master-host is not set - # but will not function as a master if omitted +# binary logging is required for replication +log-bin + +# required unique id between 1 and 2^32 - 1 +# defaults to 1 if master-host is not set +# but will not function as a master if omitted +server-id = 1 -# Replication Slave Server (comment out master section to use this) -#master-host = # MUST BE SET -#master-user = # MUST BE SET -#master-password = # MUST BE SET -#master-port = # optional--defaults to 3306 -#log-bin # not required for slaves, but recommended -#server-id = 2 # required unique id between 2 and 2^32 - 1 - # (and different from the master) - # defaults to 2 if master-host is set - # but will not function as a slave if omitted +# Replication Slave (comment out master section to use this) +# +# To configure this host as a replication slave, you can choose between +# two methods : +# +# 1) Use the CHANGE MASTER TO command (fully described in our manual) - +# the syntax is: +# +# CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>, +# MASTER_USER=<user>, MASTER_PASSWORD=<password> ; +# +# where you replace <host>, <user>, <password> by quoted strings and +# <port> by the master's port number (3306 by default). +# +# Example: +# +# CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306, +# MASTER_USER='joe', MASTER_PASSWORD='secret'; +# +# OR +# +# 2) Set the variables below. However, in case you choose this method, then +# start replication for the first time (even unsuccessfully, for example +# if you mistyped the password in master-password and the slave fails to +# connect), the slave will create a master.info file, and any later +# change in this file to the variables' values below will be ignored and +# overridden by the content of the master.info file, unless you shutdown +# the slave server, delete master.info and restart the slaver server. +# For that reason, you may want to leave the lines below untouched +# (commented) and instead use CHANGE MASTER TO (see above) +# +# required unique id between 2 and 2^32 - 1 +# (and different from the master) +# defaults to 2 if master-host is set +# but will not function as a slave if omitted +#server-id = 2 +# +# The replication master for this slave - required +#master-host = <hostname> +# +# The username the slave will use for authentication when connecting +# to the master - required +#master-user = <username> +# +# The password the slave will authenticate with when connecting to +# the master - required +#master-password = <password> +# +# The port the master is listening on. +# optional - defaults to 3306 +#master-port = <port> +# +# binary logging - not required for slaves, but recommended +#log-bin # Point the following paths to different dedicated disks #tmpdir = /tmp/ #log-update = /path-to-dedicated-directory/hostname # Uncomment the following if you are using BDB tables -#set-variable = bdb_cache_size=384M -#set-variable = bdb_max_lock=100000 +#bdb_cache_size = 384M +#bdb_max_lock = 100000 # Uncomment the following if you are using InnoDB tables #innodb_data_home_dir = @localstatedir@/ @@ -68,17 +124,17 @@ server-id = 1 # required unique id between 1 and 2^32 - 1 #innodb_log_arch_dir = @localstatedir@/ # You can set .._buffer_pool_size up to 50 - 80 % # of RAM but beware of setting memory usage too high -#set-variable = innodb_buffer_pool_size=384M -#set-variable = innodb_additional_mem_pool_size=20M +#innodb_buffer_pool_size = 384M +#innodb_additional_mem_pool_size = 20M # Set .._log_file_size to 25 % of buffer pool size -#set-variable = innodb_log_file_size=100M -#set-variable = innodb_log_buffer_size=8M -#innodb_flush_log_at_trx_commit=1 -#set-variable = innodb_lock_wait_timeout=50 +#innodb_log_file_size = 100M +#innodb_log_buffer_size = 8M +#innodb_flush_log_at_trx_commit = 1 +#innodb_lock_wait_timeout = 50 [mysqldump] quick -set-variable = max_allowed_packet=16M +max_allowed_packet = 16M [mysql] no-auto-rehash @@ -86,16 +142,16 @@ no-auto-rehash #safe-updates [isamchk] -set-variable = key_buffer=256M -set-variable = sort_buffer=256M -set-variable = read_buffer=2M -set-variable = write_buffer=2M +key_buffer = 256M +sort_buffer_size = 256M +read_buffer = 2M +write_buffer = 2M [myisamchk] -set-variable = key_buffer=256M -set-variable = sort_buffer=256M -set-variable = read_buffer=2M -set-variable = write_buffer=2M +key_buffer = 256M +sort_buffer_size = 256M +read_buffer = 2M +write_buffer = 2M [mysqlhotcopy] interactive-timeout diff --git a/support-files/my-large.cnf.sh b/support-files/my-large.cnf.sh index 3c388d611d8..2b92dc61053 100644 --- a/support-files/my-large.cnf.sh +++ b/support-files/my-large.cnf.sh @@ -26,21 +26,96 @@ socket = @MYSQL_UNIX_ADDR@ port = @MYSQL_TCP_PORT@ socket = @MYSQL_UNIX_ADDR@ skip-locking -set-variable = key_buffer=256M -set-variable = max_allowed_packet=1M -set-variable = table_cache=256 -set-variable = sort_buffer=1M -set-variable = record_buffer=1M -set-variable = myisam_sort_buffer_size=64M -set-variable = thread_cache=8 +key_buffer = 256M +max_allowed_packet = 1M +table_cache = 256 +sort_buffer_size = 1M +read_buffer_size = 1M +myisam_sort_buffer_size = 64M +thread_cache = 8 +query_cache_size= 16M # Try number of CPU's*2 for thread_concurrency -set-variable = thread_concurrency=8 +thread_concurrency = 8 + +# Don't listen on a TCP/IP port at all. This can be a security enhancement, +# if all processes that need to connect to mysqld run on the same host. +# All interaction with mysqld must be made via Unix sockets or named pipes. +# Note that using this option without enabling named pipes on Windows +# (via the "enable-named-pipe" option) will render mysqld useless! +# +#skip-networking + +# Replication Master Server (default) +# binary logging is required for replication log-bin + +# required unique id between 1 and 2^32 - 1 +# defaults to 1 if master-host is not set +# but will not function as a master if omitted server-id = 1 +# Replication Slave (comment out master section to use this) +# +# To configure this host as a replication slave, you can choose between +# two methods : +# +# 1) Use the CHANGE MASTER TO command (fully described in our manual) - +# the syntax is: +# +# CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>, +# MASTER_USER=<user>, MASTER_PASSWORD=<password> ; +# +# where you replace <host>, <user>, <password> by quoted strings and +# <port> by the master's port number (3306 by default). +# +# Example: +# +# CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306, +# MASTER_USER='joe', MASTER_PASSWORD='secret'; +# +# OR +# +# 2) Set the variables below. However, in case you choose this method, then +# start replication for the first time (even unsuccessfully, for example +# if you mistyped the password in master-password and the slave fails to +# connect), the slave will create a master.info file, and any later +# change in this file to the variables' values below will be ignored and +# overridden by the content of the master.info file, unless you shutdown +# the slave server, delete master.info and restart the slaver server. +# For that reason, you may want to leave the lines below untouched +# (commented) and instead use CHANGE MASTER TO (see above) +# +# required unique id between 2 and 2^32 - 1 +# (and different from the master) +# defaults to 2 if master-host is set +# but will not function as a slave if omitted +#server-id = 2 +# +# The replication master for this slave - required +#master-host = <hostname> +# +# The username the slave will use for authentication when connecting +# to the master - required +#master-user = <username> +# +# The password the slave will authenticate with when connecting to +# the master - required +#master-password = <password> +# +# The port the master is listening on. +# optional - defaults to 3306 +#master-port = <port> +# +# binary logging - not required for slaves, but recommended +#log-bin + +# Point the following paths to different dedicated disks +#tmpdir = /tmp/ +#log-update = /path-to-dedicated-directory/hostname + # Uncomment the following if you are using BDB tables -#set-variable = bdb_cache_size=64M -#set-variable = bdb_max_lock=100000 +#bdb_cache_size = 64M +#bdb_max_lock = 100000 # Uncomment the following if you are using InnoDB tables #innodb_data_home_dir = @localstatedir@/ @@ -49,21 +124,17 @@ server-id = 1 #innodb_log_arch_dir = @localstatedir@/ # You can set .._buffer_pool_size up to 50 - 80 % # of RAM but beware of setting memory usage too high -#set-variable = innodb_buffer_pool_size=256M -#set-variable = innodb_additional_mem_pool_size=20M +#innodb_buffer_pool_size = 256M +#innodb_additional_mem_pool_size = 20M # Set .._log_file_size to 25 % of buffer pool size -#set-variable = innodb_log_file_size=64M -#set-variable = innodb_log_buffer_size=8M -#innodb_flush_log_at_trx_commit=1 -#set-variable = innodb_lock_wait_timeout=50 - -# Point the following paths to different dedicated disks -#tmpdir = /tmp/ -#log-update = /path-to-dedicated-directory/hostname +#innodb_log_file_size = 64M +#innodb_log_buffer_size = 8M +#innodb_flush_log_at_trx_commit = 1 +#innodb_lock_wait_timeout = 50 [mysqldump] quick -set-variable = max_allowed_packet=16M +max_allowed_packet = 16M [mysql] no-auto-rehash @@ -71,16 +142,16 @@ no-auto-rehash #safe-updates [isamchk] -set-variable = key_buffer=128M -set-variable = sort_buffer=128M -set-variable = read_buffer=2M -set-variable = write_buffer=2M +key_buffer = 128M +sort_buffer_size = 128M +read_buffer = 2M +write_buffer = 2M [myisamchk] -set-variable = key_buffer=128M -set-variable = sort_buffer=128M -set-variable = read_buffer=2M -set-variable = write_buffer=2M +key_buffer = 128M +sort_buffer_size = 128M +read_buffer = 2M +write_buffer = 2M [mysqlhotcopy] interactive-timeout diff --git a/support-files/my-medium.cnf.sh b/support-files/my-medium.cnf.sh index a92494358cb..601ffc503c0 100644 --- a/support-files/my-medium.cnf.sh +++ b/support-files/my-medium.cnf.sh @@ -27,22 +27,92 @@ socket = @MYSQL_UNIX_ADDR@ port = @MYSQL_TCP_PORT@ socket = @MYSQL_UNIX_ADDR@ skip-locking -set-variable = key_buffer=16M -set-variable = max_allowed_packet=1M -set-variable = table_cache=64 -set-variable = sort_buffer=512K -set-variable = net_buffer_length=8K -set-variable = myisam_sort_buffer_size=8M +key_buffer = 16M +max_allowed_packet = 1M +table_cache = 64 +sort_buffer_size = 512K +net_buffer_length = 8K +myisam_sort_buffer_size = 8M + +# Don't listen on a TCP/IP port at all. This can be a security enhancement, +# if all processes that need to connect to mysqld run on the same host. +# All interaction with mysqld must be made via Unix sockets or named pipes. +# Note that using this option without enabling named pipes on Windows +# (via the "enable-named-pipe" option) will render mysqld useless! +# +#skip-networking + +# Replication Master Server (default) +# binary logging is required for replication log-bin + +# required unique id between 1 and 2^32 - 1 +# defaults to 1 if master-host is not set +# but will not function as a master if omitted server-id = 1 +# Replication Slave (comment out master section to use this) +# +# To configure this host as a replication slave, you can choose between +# two methods : +# +# 1) Use the CHANGE MASTER TO command (fully described in our manual) - +# the syntax is: +# +# CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>, +# MASTER_USER=<user>, MASTER_PASSWORD=<password> ; +# +# where you replace <host>, <user>, <password> by quoted strings and +# <port> by the master's port number (3306 by default). +# +# Example: +# +# CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306, +# MASTER_USER='joe', MASTER_PASSWORD='secret'; +# +# OR +# +# 2) Set the variables below. However, in case you choose this method, then +# start replication for the first time (even unsuccessfully, for example +# if you mistyped the password in master-password and the slave fails to +# connect), the slave will create a master.info file, and any later +# change in this file to the variables' values below will be ignored and +# overridden by the content of the master.info file, unless you shutdown +# the slave server, delete master.info and restart the slaver server. +# For that reason, you may want to leave the lines below untouched +# (commented) and instead use CHANGE MASTER TO (see above) +# +# required unique id between 2 and 2^32 - 1 +# (and different from the master) +# defaults to 2 if master-host is set +# but will not function as a slave if omitted +#server-id = 2 +# +# The replication master for this slave - required +#master-host = <hostname> +# +# The username the slave will use for authentication when connecting +# to the master - required +#master-user = <username> +# +# The password the slave will authenticate with when connecting to +# the master - required +#master-password = <password> +# +# The port the master is listening on. +# optional - defaults to 3306 +#master-port = <port> +# +# binary logging - not required for slaves, but recommended +#log-bin + # Point the following paths to different dedicated disks #tmpdir = /tmp/ #log-update = /path-to-dedicated-directory/hostname # Uncomment the following if you are using BDB tables -#set-variable = bdb_cache_size=4M -#set-variable = bdb_max_lock=10000 +#bdb_cache_size = 4M +#bdb_max_lock = 10000 # Uncomment the following if you are using InnoDB tables #innodb_data_home_dir = @localstatedir@/ @@ -51,17 +121,17 @@ server-id = 1 #innodb_log_arch_dir = @localstatedir@/ # You can set .._buffer_pool_size up to 50 - 80 % # of RAM but beware of setting memory usage too high -#set-variable = innodb_buffer_pool_size=16M -#set-variable = innodb_additional_mem_pool_size=2M +#innodb_buffer_pool_size = 16M +#innodb_additional_mem_pool_size = 2M # Set .._log_file_size to 25 % of buffer pool size -#set-variable = innodb_log_file_size=5M -#set-variable = innodb_log_buffer_size=8M -#innodb_flush_log_at_trx_commit=1 -#set-variable = innodb_lock_wait_timeout=50 +#innodb_log_file_size = 5M +#innodb_log_buffer_size = 8M +#innodb_flush_log_at_trx_commit = 1 +#innodb_lock_wait_timeout = 50 [mysqldump] quick -set-variable = max_allowed_packet=16M +max_allowed_packet = 16M [mysql] no-auto-rehash @@ -69,16 +139,16 @@ no-auto-rehash #safe-updates [isamchk] -set-variable = key_buffer=20M -set-variable = sort_buffer=20M -set-variable = read_buffer=2M -set-variable = write_buffer=2M +key_buffer = 20M +sort_buffer_size = 20M +read_buffer = 2M +write_buffer = 2M [myisamchk] -set-variable = key_buffer=20M -set-variable = sort_buffer=20M -set-variable = read_buffer=2M -set-variable = write_buffer=2M +key_buffer = 20M +sort_buffer_size = 20M +read_buffer = 2M +write_buffer = 2M [mysqlhotcopy] interactive-timeout diff --git a/support-files/my-small.cnf.sh b/support-files/my-small.cnf.sh index b8941184fe0..f9e30da78ac 100644 --- a/support-files/my-small.cnf.sh +++ b/support-files/my-small.cnf.sh @@ -27,12 +27,20 @@ socket = @MYSQL_UNIX_ADDR@ port = @MYSQL_TCP_PORT@ socket = @MYSQL_UNIX_ADDR@ skip-locking -set-variable = key_buffer=16K -set-variable = max_allowed_packet=1M -set-variable = thread_stack=64K -set-variable = table_cache=4 -set-variable = sort_buffer=64K -set-variable = net_buffer_length=2K +key_buffer = 16K +max_allowed_packet = 1M +table_cache = 4 +sort_buffer_size = 64K +net_buffer_length = 2K +thread_stack = 64K + +# Don't listen on a TCP/IP port at all. This can be a security enhancement, +# if all processes that need to connect to mysqld run on the same host. +# All interaction with mysqld must be made via Unix sockets or named pipes. +# Note that using this option without enabling named pipes on Windows +# (using the "enable-named-pipe" option) will render mysqld useless! +# +#skip-networking server-id = 1 # Uncomment the following if you want to log updates @@ -48,17 +56,17 @@ server-id = 1 #innodb_log_arch_dir = @localstatedir@/ # You can set .._buffer_pool_size up to 50 - 80 % # of RAM but beware of setting memory usage too high -#set-variable = innodb_buffer_pool_size=16M -#set-variable = innodb_additional_mem_pool_size=2M +#innodb_buffer_pool_size = 16M +#innodb_additional_mem_pool_size = 2M # Set .._log_file_size to 25 % of buffer pool size -#set-variable = innodb_log_file_size=5M -#set-variable = innodb_log_buffer_size=8M -#innodb_flush_log_at_trx_commit=1 -#set-variable = innodb_lock_wait_timeout=50 +#innodb_log_file_size = 5M +#innodb_log_buffer_size = 8M +#innodb_flush_log_at_trx_commit = 1 +#innodb_lock_wait_timeout = 50 [mysqldump] quick -set-variable = max_allowed_packet=16M +max_allowed_packet = 16M [mysql] no-auto-rehash @@ -66,12 +74,12 @@ no-auto-rehash #safe-updates [isamchk] -set-variable = key_buffer=8M -set-variable = sort_buffer=8M +key_buffer = 8M +sort_buffer_size = 8M [myisamchk] -set-variable = key_buffer=8M -set-variable = sort_buffer=8M +key_buffer = 8M +sort_buffer_size = 8M [mysqlhotcopy] interactive-timeout diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index 7340cff9cad..de01142beac 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -10,7 +10,7 @@ # started and shut down when the systems goes down. # Comments to support chkconfig on RedHat Linux -# chkconfig: 2345 90 90 +# chkconfig: 2345 90 20 # description: A very fast and reliable SQL database engine. # Comments to support LSB init script conventions @@ -18,8 +18,8 @@ # Provides: mysql # Required-Start: $local_fs $network $remote_fs # Required-Stop: $local_fs $network $remote_fs -# Default-Start: 3 5 -# Default-Stop: 3 5 +# Default-Start: 2 3 4 5 +# Default-Stop: 2 3 4 5 # Short-Description: start and stop MySQL # Description: MySQL is a very fast and reliable SQL database engine. ### END INIT INFO @@ -118,7 +118,18 @@ else test -z "$print_defaults" && print_defaults="my_print_defaults" fi -parse_arguments `$print_defaults mysqld mysql_server mysql.server` +# +# Test if someone changed datadir; In this case we should also read the +# default arguments from this directory +# + +extra_args="" +if test "$datadir" != "@localstatedir@" +then + extra_args="-e $datadir/my.cnf" +fi + +parse_arguments `$print_defaults $extra_args mysqld mysql_server mysql.server` # Safeguard (relative paths, core dumps..) cd $basedir diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 42d9ef5391c..11e850206c3 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -16,7 +16,7 @@ Copyright: GPL Source: http://www.mysql.com/Downloads/MySQL-@MYSQL_BASE_VERSION@/mysql-%{mysql_version}.tar.gz Icon: mysql.gif URL: http://www.mysql.com/ -Packager: Lenz Grimmer <lenz@mysql.com> +Packager: Lenz Grimmer <build@mysql.com> Vendor: MySQL AB Requires: fileutils sh-utils Provides: msqlormysql MySQL-server mysql @@ -154,7 +154,7 @@ Requires: MySQL >= 4.0 %description Max Optional MySQL server binary that supports additional features like -Berkeley DB, OpenSSL, RAID and User Defined Functions (UDF). +Berkeley DB, OpenSSL, RAID and User Defined Functions (UDFs). To activate this binary, just install this package in addition to the standard MySQL package. @@ -536,6 +536,14 @@ fi %attr(644, root, root) /usr/lib/mysql/libmysqld.a %changelog +* Fri May 16 2003 Lenz Grimmer <lenz@mysql.com> + +- re-enabled RAID again + +* Wed Apr 30 2003 Lenz Grimmer <lenz@mysql.com> + +- disabled MyISAM RAID (--with-raid) - it throws an assertion which + needs to be investigated first. * Mon Mar 10 2003 Lenz Grimmer <lenz@mysql.com> diff --git a/tests/big_record.pl b/tests/big_record.pl index 08547b50823..fbe94e3540f 100755 --- a/tests/big_record.pl +++ b/tests/big_record.pl @@ -11,12 +11,13 @@ use Getopt::Long; $opt_host=""; $opt_user=$opt_password=""; $opt_db="test"; -$opt_rows=200; # Test of blobs up to ($rows-1)*100000+1 bytes +$opt_rows=20; # Test of blobs up to ($rows-1)*100000+1 bytes $opt_compress=0; $opt_table="test_big_record"; +$opt_loop_count=100000; # Change this to make test harder/easier GetOptions("host=s","db=s","user=s", "password=s", "table=s", "rows=i", - "compress") || die "Aborted"; + "compress", "loop-count=i") || die "Aborted"; print "Connection to database $test_db\n"; @@ -42,12 +43,12 @@ $|=1; # Flush output to stdout to be able to monitor process for ($i=0 ; $i < $opt_rows ; $i++) { $tmp= chr(65+($i % 16)) x ($i*100000+1); - print $i," ",length($tmp),"\n"; $tmp= $dbh->quote($tmp); $dbh->do("insert into $opt_table (test) values ($tmp)") or die $DBI::errstr; + print "."; } -print "Reading records\n"; +print "\nReading records\n"; $sth=$dbh->prepare("select * from $opt_table", { "mysql_use_result" => 1}) or die $dbh->errstr; @@ -56,14 +57,40 @@ $sth->execute() or die $sth->errstr; $i=0; while (($row = $sth->fetchrow_arrayref)) { - print $row->[0]," ",length($row->[1]),"\n"; die "Record $i had wrong data in blob" if ($row->[1] ne (chr(65+($i % 16)) x ($i*100000+1))); $i++; } die "Didn't get all rows from server" if ($i != $opt_rows); -$dbh->do("drop table $opt_table") or die $DBI::errstr; +# +# Test by insert/updating/deleting random rows for a while +# -print "Test ok\n"; +print "Testing insert/update/delete\n"; + +$max_row_id= $rows; +for ($i= 0 ; $i < $opt_loop_count ; $i++) +{ + $length= int(rand 65535); + $tmp= chr(65+($i % 16)) x $length; + $tmp= $dbh->quote($tmp); + $dbh->do("insert into $opt_table (test) values ($tmp)") or die $DBI::errstr; + $max_row_id++; + $length=int(rand 65535); + $tmp= chr(65+($i % 16)) x $length; + $tmp= $dbh->quote($tmp); + $id= int(rand $max_row_id); + $dbh->do("update $opt_table set test= $tmp where auto= $id") or die $DBI::errstr; + if (($i % 2) == 1) + { + $id= int(rand $max_row_id); + $dbh->do("delete from $opt_table where auto= $id") or die $DBI::errstr; + } + print "." if ($i % ($opt_loop_count/100) == 1); +} + +# $dbh->do("drop table $opt_table") or die $DBI::errstr; + +print "\nTest ok\n"; exit 0; diff --git a/tests/grant.pl b/tests/grant.pl index 5a24127d79d..3146b7b6c25 100644 --- a/tests/grant.pl +++ b/tests/grant.pl @@ -63,6 +63,12 @@ user_connect(1); #goto test; # +# Enable column grant code +# +safe_query("grant select(user) on mysql.user to $user"); +safe_query("revoke select(user) on mysql.user from $user"); + +# # Test grants on user level # @@ -76,6 +82,7 @@ user_query("select * from mysql.user where user = '$opt_user'"); user_query("select * from mysql.db where user = '$opt_user'"); safe_query("grant select on *.* to $user,$user"); safe_query("show grants for $user"); +user_connect(0); # The following should fail user_query("insert into mysql.user (host,user) values ('error','$opt_user')",1); @@ -89,16 +96,21 @@ safe_query("grant select on $opt_database.not_exists to $opt_user",1); safe_query("grant FILE on $opt_database.test to $opt_user",1); safe_query("grant select on *.* to wrong___________user_name",1); safe_query("grant select on $opt_database.* to wrong___________user_name",1); +user_connect(0); user_query("grant select on $opt_database.test to $opt_user with grant option",1); safe_query("set password FOR ''\@''=''",1); user_query("set password FOR root\@$opt_host = password('test')",1); # Change privileges for user safe_query("revoke select on *.* from $user"); -safe_query("grant create on *.* to $user"); +safe_query("grant create,update on *.* to $user"); user_connect(0); +safe_query("flush privileges"); user_query("create table $opt_database.test (a int,b int)"); - +user_query("update $opt_database.test set b=b+1 where a > 0",1); +safe_query("show grants for $user"); +safe_query("revoke update on *.* from $user"); +user_connect(0); safe_query("grant select(c) on $opt_database.test to $user",1); safe_query("revoke select(c) on $opt_database.test from $user",1); safe_query("grant select on $opt_database.test to wrong___________user_name",1); @@ -217,8 +229,21 @@ user_query("update $opt_database.test set b=b+1",1); safe_query("grant SELECT on *.* to $user"); user_connect(0); user_query("update $opt_database.test set b=b+1"); +user_query("update $opt_database.test set b=b+1 where a > 0"); safe_query("revoke SELECT on *.* from $user"); +safe_query("grant SELECT on $opt_database.* to $user"); user_connect(0); +user_query("update $opt_database.test set b=b+1"); +user_query("update $opt_database.test set b=b+1 where a > 0"); +safe_query("grant UPDATE on *.* to $user"); +user_connect(0); +user_query("update $opt_database.test set b=b+1"); +user_query("update $opt_database.test set b=b+1 where a > 0"); +safe_query("revoke UPDATE on *.* from $user"); +safe_query("revoke SELECT on $opt_database.* from $user"); +user_connect(0); +user_query("update $opt_database.test set b=b+1 where a > 0",1); +user_query("update $opt_database.test set b=b+1",1); # Add one privilege at a time until the user has all privileges user_query("select * from test",1); @@ -408,21 +433,29 @@ safe_query("grant ALL PRIVILEGES on $opt_database.test to $user identified by 'd user_connect(0,"dummy"); safe_query("grant SELECT on $opt_database.* to $user identified by ''"); user_connect(0); -safe_query("revoke ALL PRIVILEGES on $opt_database.test from $user identified by ''"); +safe_query("revoke ALL PRIVILEGES on $opt_database.test from $user identified by '', ${opt_user}\@127.0.0.1 identified by 'dummy2'"); safe_query("revoke ALL PRIVILEGES on $opt_database.* from $user identified by ''"); + safe_query("show grants for $user"); # # Test bug reported in SELECT INTO OUTFILE # -safe_query("create table $opt_database.test3 (a int)"); +safe_query("create table $opt_database.test3 (a int, b int)"); safe_query("grant SELECT on $opt_database.test3 to $user"); safe_query("grant FILE on *.* to $user"); -safe_query("insert into $opt_database.test3 values (1)"); +safe_query("insert into $opt_database.test3 values (1,1)"); user_connect(0); user_query("select * into outfile '$tmp_table' from $opt_database.test3"); safe_query("revoke SELECT on $opt_database.test3 from $user"); +safe_query("grant SELECT(a) on $opt_database.test3 to $user"); +user_query("select a from $opt_database.test3"); +user_query("select * from $opt_database.test3",1); +user_query("select a,b from $opt_database.test3",1); +user_query("select b from $opt_database.test3",1); + +safe_query("revoke SELECT(a) on $opt_database.test3 from $user"); safe_query("revoke FILE on *.* from $user"); safe_query("drop table $opt_database.test3"); diff --git a/tests/grant.res b/tests/grant.res index adb4494eb28..7b244f099f8 100644 --- a/tests/grant.res +++ b/tests/grant.res @@ -10,6 +10,8 @@ Error in execute: Can't drop database 'grant_test'. Database doesn't exist create database grant_test Connecting grant_user Error on connect: Access denied for user: '@localhost' to database 'grant_test' +grant select(user) on mysql.user to grant_user@localhost +revoke select(user) on mysql.user from grant_user@localhost grant select on *.* to grant_user@localhost set password FOR grant_user2@localhost = password('test') Error in execute: Can't find any matching row in the user table @@ -26,6 +28,7 @@ grant select on *.* to grant_user@localhost,grant_user@localhost show grants for grant_user@localhost GRANT SELECT ON *.* TO 'grant_user'@'localhost' +Connecting grant_user insert into mysql.user (host,user) values ('error','grant_user') Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql' update mysql.user set host='error' WHERE user='grant_user' @@ -48,6 +51,7 @@ grant select on *.* to wrong___________user_name Error in execute: The host or user argument to GRANT is too long grant select on grant_test.* to wrong___________user_name Error in execute: The host or user argument to GRANT is too long +Connecting grant_user grant select on grant_test.test to grant_user with grant option Error in execute: grant command denied to user: 'grant_user@localhost' for table 'test' set password FOR ''@''='' @@ -55,9 +59,17 @@ Error in execute: Can't find any matching row in the user table set password FOR root@localhost = password('test') Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql' revoke select on *.* from grant_user@localhost -grant create on *.* to grant_user@localhost +grant create,update on *.* to grant_user@localhost Connecting grant_user +flush privileges create table grant_test.test (a int,b int) +update grant_test.test set b=b+1 where a > 0 +Error in execute: SELECT command denied to user: 'grant_user@localhost' for column 'a' in table 'test' +show grants for grant_user@localhost +GRANT UPDATE, CREATE ON *.* TO 'grant_user'@'localhost' + +revoke update on *.* from grant_user@localhost +Connecting grant_user grant select(c) on grant_test.test to grant_user@localhost Error in execute: Unknown column 'c' in 'test' revoke select(c) on grant_test.test from grant_user@localhost @@ -198,9 +210,24 @@ Error in execute: SELECT command denied to user: 'grant_user@localhost' for colu grant SELECT on *.* to grant_user@localhost Connecting grant_user update grant_test.test set b=b+1 +update grant_test.test set b=b+1 where a > 0 revoke SELECT on *.* from grant_user@localhost +grant SELECT on grant_test.* to grant_user@localhost +Connecting grant_user +update grant_test.test set b=b+1 +update grant_test.test set b=b+1 where a > 0 +grant UPDATE on *.* to grant_user@localhost Connecting grant_user -lect * from test +update grant_test.test set b=b+1 +update grant_test.test set b=b+1 where a > 0 +revoke UPDATE on *.* from grant_user@localhost +revoke SELECT on grant_test.* from grant_user@localhost +Connecting grant_user +update grant_test.test set b=b+1 where a > 0 +Error in execute: SELECT command denied to user: 'grant_user@localhost' for column 'a' in table 'test' +update grant_test.test set b=b+1 +Error in execute: SELECT command denied to user: 'grant_user@localhost' for column 'b' in table 'test' +select * from test Error in execute: select command denied to user: 'grant_user@localhost' for table 'test' grant select on grant_test.test to grant_user@localhost delete from grant_test.test where a=1 @@ -448,21 +475,34 @@ grant ALL PRIVILEGES on grant_test.test to grant_user@localhost identified by 'd Connecting grant_user grant SELECT on grant_test.* to grant_user@localhost identified by '' Connecting grant_user -revoke ALL PRIVILEGES on grant_test.test from grant_user@localhost identified by '' +revoke ALL PRIVILEGES on grant_test.test from grant_user@localhost identified by '', grant_user@127.0.0.1 identified by 'dummy2' revoke ALL PRIVILEGES on grant_test.* from grant_user@localhost identified by '' show grants for grant_user@localhost -create table grant_test.test3 (a int) +GRANT USAGE ON *.* TO 'grant_user'@'localhost' + +create table grant_test.test3 (a int, b int) grant SELECT on grant_test.test3 to grant_user@localhost grant FILE on *.* to grant_user@localhost -insert into grant_test.test3 values (1) +insert into grant_test.test3 values (1,1) Connecting grant_user select * into outfile '/tmp/mysql-grant.test' from grant_test.test3 revoke SELECT on grant_test.test3 from grant_user@localhost +grant SELECT(a) on grant_test.test3 to grant_user@localhost +select a from grant_test.test3 +1 + +select * from grant_test.test3 +Error in execute: select command denied to user: 'grant_user@localhost' for column 'b' in table 'test3' +select a,b from grant_test.test3 +Error in execute: SELECT command denied to user: 'grant_user@localhost' for column 'b' in table 'test3' +select b from grant_test.test3 +Error in execute: SELECT command denied to user: 'grant_user@localhost' for column 'b' in table 'test3' +revoke SELECT(a) on grant_test.test3 from grant_user@localhost revoke FILE on *.* from grant_user@localhost drop table grant_test.test3 create table grant_test.test3 (a int) Connecting grant_user -Access denied for user: 'grant_user@localhost' to database 'grant_test' +Error on connect: Access denied for user: 'grant_user@localhost' to database 'grant_test' grant INSERT on grant_test.test3 to grant_user@localhost Connecting grant_user select * into outfile '/tmp/mysql-grant.test' from grant_test.test3 @@ -474,7 +514,7 @@ Error in execute: Access denied for user: 'grant_user@localhost' to database 'gr grant LOCK TABLES on *.* to grant_user@localhost show grants for grant_user@localhost GRANT LOCK TABLES ON *.* TO 'grant_user'@'localhost' -GRANT SELECT, INSERT ON grant_test.test3 TO 'grant_user'@'localhost' +GRANT SELECT, INSERT ON `grant_test`.`test3` TO 'grant_user'@'localhost' select * from mysql.user where user='grant_user' 127.0.0.1 grant_user *042a99b3d247ae587783f647f2d69496d390aa71eab3 N N N N N N N N N N N N N N N N N N N N N 0 0 0 @@ -487,9 +527,11 @@ revoke SELECT,INSERT,UPDATE,DELETE on grant_test.test3 from grant_user@localhost Connecting grant_user revoke LOCK TABLES on *.* from grant_user@localhost Connecting grant_user -Access denied for user: 'grant_user@localhost' to database 'grant_test' +Error on connect: Access denied for user: 'grant_user@localhost' to database 'grant_test' drop table grant_test.test3 show grants for grant_user@localhost +GRANT USAGE ON *.* TO 'grant_user'@'localhost' + grant all on *.* to grant_user@localhost WITH MAX_QUERIES_PER_HOUR 1 MAX_UPDATES_PER_HOUR 2 MAX_CONNECTIONS_PER_HOUR 3 show grants for grant_user@localhost GRANT ALL PRIVILEGES ON *.* TO 'grant_user'@'localhost' WITH MAX_QUERIES_PER_HOUR 1 MAX_UPDATES_PER_HOUR 2 MAX_CONNECTIONS_PER_HOUR 3 @@ -501,6 +543,8 @@ GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, F revoke ALL PRIVILEGES on *.* from grant_user@localhost show grants for grant_user@localhost +GRANT USAGE ON *.* TO 'grant_user'@'localhost' WITH MAX_QUERIES_PER_HOUR 1 MAX_UPDATES_PER_HOUR 2 MAX_CONNECTIONS_PER_HOUR 3 + drop database grant_test delete from user where user='grant_user' delete from db where user='grant_user' diff --git a/tests/table_types.pl b/tests/table_types.pl index 8198cd9ba86..4dbcdcb975c 100755 --- a/tests/table_types.pl +++ b/tests/table_types.pl @@ -66,13 +66,6 @@ $dbh = $server->connect(); #### $table_name="bench1"; -<<<<<<< table_types.pl -||||||| 1.2 -test("n","type=isam","char"); test("m","type=myisam pack_keys=1","char"); exit(1); - -======= - ->>>>>>> /tmp/T4a17019 test($table_name,"type=isam","char"); test($table_name,"type=myisam pack_keys=0","char"); test($table_name,"type=myisam pack_keys=0","char"); @@ -91,7 +84,7 @@ exit (0); sub test { my ($name,$options,$chartype)=@_; - + print "\nTesting with options: '$options'\n"; $dbh->do("drop table $name"); do_many($dbh,$server->create("$name", @@ -102,23 +95,23 @@ sub test { ["primary key (id,id2)", "index index_id3 (id3)"], $options)); - + if ($opt_lock_tables) { $sth = $dbh->do("LOCK TABLES $name WRITE") || die $DBI::errstr; } - + if ($opt_fast && defined($server->{vacuum})) { $server->vacuum(\$dbh,1); } - + #### #### Insert $total_rows records in order, in reverse order and random. #### - + $loop_time=new Benchmark; - + if ($opt_fast_insert) { $query="insert into $name values "; @@ -127,11 +120,11 @@ sub test { { $query="insert into $name (id,id2,id3,dummy1) values "; } - + if (($opt_fast || $opt_fast_insert) && $limits->{'multi_value_insert'}) { $query_size=$server->{'limits'}->{'query_size'}; - + print "Inserting $opt_loop_count multiple-value rows in order\n"; $res=$query; for ($i=0 ; $i < $opt_loop_count ; $i++) @@ -186,7 +179,7 @@ sub test { { $sth = $dbh->do($query . "($i,$i,$i,'ABCDEFGHIJ')") or die $DBI::errstr; } - + print "Inserting $opt_loop_count rows in reverse order\n"; for ($i=0 ; $i < $opt_loop_count ; $i++) { @@ -195,25 +188,25 @@ sub test { ($total_rows-1-$i) . ",'BCDEFGHIJK')") or die $DBI::errstr; } - + print "Inserting $opt_loop_count rows in random order\n"; - + for ($i=0 ; $i < $opt_loop_count ; $i++) { $sth = $dbh->do($query . "(". $random[$i] . "," . $random[$i] . "," . $random[$i] . ",'CDEFGHIJKL')") or die $DBI::errstr; } } - + $end_time=new Benchmark; print "Time for insert (" . ($total_rows) . "): " . timestr(timediff($end_time, $loop_time),"all") . "\n\n"; - + if ($opt_fast && defined($server->{vacuum})) { $server->vacuum(\$dbh,1); } - + $sth=$dbh->prepare("show table status like '$name'"); $sth->execute || die "Show table status returned error: $DBI::errstr\n"; while (@row = $sth->fetchrow_array) diff --git a/vio/viossl.c b/vio/viossl.c index cf1c98b5382..834343a77d9 100644 --- a/vio/viossl.c +++ b/vio/viossl.c @@ -212,13 +212,14 @@ my_socket vio_ssl_fd(Vio* vio) } -my_bool vio_ssl_peer_addr(Vio * vio, char *buf) +my_bool vio_ssl_peer_addr(Vio * vio, char *buf, uint16 *port) { DBUG_ENTER("vio_ssl_peer_addr"); DBUG_PRINT("enter", ("sd=%d", vio->sd)); if (vio->localhost) { strmov(buf,"127.0.0.1"); + *port=0; } else { @@ -229,8 +230,13 @@ my_bool vio_ssl_peer_addr(Vio * vio, char *buf) DBUG_PRINT("exit", ("getpeername, error: %d", socket_errno)); DBUG_RETURN(1); } - /* FIXME */ -/* my_inet_ntoa(vio->remote.sin_addr,buf); */ +#ifdef TO_BE_FIXED + my_inet_ntoa(vio->remote.sin_addr,buf); + *port= 0; +#else + strmov(buf, "unknown"); + *port= 0; +#endif } DBUG_PRINT("exit", ("addr=%s", buf)); DBUG_RETURN(0); @@ -281,7 +287,8 @@ int sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio, long timeout) SSL_SESSION_set_timeout(SSL_get_session(vio->ssl_), timeout); SSL_set_fd(vio->ssl_,vio->sd); SSL_set_accept_state(vio->ssl_); - if (SSL_do_handshake(vio->ssl_) < 1) + if (SSL_do_handshake(vio->ssl_) < 1 || + SSL_get_verify_result(vio->ssl_) != X509_V_OK) { DBUG_PRINT("error", ("SSL_do_handshake failure")); report_errors(); @@ -354,7 +361,8 @@ int sslconnect(struct st_VioSSLConnectorFd* ptr, Vio* vio, long timeout) SSL_SESSION_set_timeout(SSL_get_session(vio->ssl_), timeout); SSL_set_fd (vio->ssl_, vio->sd); SSL_set_connect_state(vio->ssl_); - if (SSL_do_handshake(vio->ssl_) < 1) + if (SSL_do_handshake(vio->ssl_) < 1 || + SSL_get_verify_result(vio->ssl_) != X509_V_OK) { DBUG_PRINT("error", ("SSL_do_handshake failure")); report_errors(); |