Commit c6b3afe2 authored by monty@hundin.mysql.fi's avatar monty@hundin.mysql.fi

Merge work:/home/bk/mysql-4.0 into hundin.mysql.fi:/my/bk/mysql-4.0

parents 3e231a82 27d2057c
...@@ -3488,7 +3488,8 @@ select * from temporary_table, temporary_table as t2; ...@@ -3488,7 +3488,8 @@ select * from temporary_table, temporary_table as t2;
@end example @end example
@item @item
@code{RENAME} doesn't work with @code{TEMPORARY} tables. @code{RENAME} doesn't work with @code{TEMPORARY} tables or tables used in a
@code{MERGE} table.
@item @item
The optimiser may handle @code{DISTINCT} differently if you are using The optimiser may handle @code{DISTINCT} differently if you are using
...@@ -3584,6 +3585,7 @@ Minimum respective maximum possible @code{double} value. ...@@ -3584,6 +3585,7 @@ Minimum respective maximum possible @code{double} value.
@item @item
@code{LIMIT} on negative numbers are treated as big positive numbers. @code{LIMIT} on negative numbers are treated as big positive numbers.
@item @item
If you use @code{ALTER TABLE} to first add an @code{UNIQUE} index to a If you use @code{ALTER TABLE} to first add an @code{UNIQUE} index to a
table used in a @code{MERGE} table and then use @code{ALTER TABLE} to table used in a @code{MERGE} table and then use @code{ALTER TABLE} to
...@@ -3731,6 +3733,9 @@ able to choose the right index when there is many to choose from. We should ...@@ -3731,6 +3733,9 @@ able to choose the right index when there is many to choose from. We should
also extend the info interface to get the key distribution for each index, also extend the info interface to get the key distribution for each index,
of @code{analyze} is run on all sub tables. of @code{analyze} is run on all sub tables.
@item @item
@code{RENAME TABLE} on a table used in an active @code{MERGE} table may
corrupt the table.
@item
@code{SET SQL_DEFAULT_TABLE_TYPE=[MyISAM | INNODB | BDB | HEAP]}. @code{SET SQL_DEFAULT_TABLE_TYPE=[MyISAM | INNODB | BDB | HEAP]}.
@end itemize @end itemize
...@@ -3800,8 +3805,6 @@ in microseconds. ...@@ -3800,8 +3805,6 @@ in microseconds.
Add a configurable prompt to the @code{mysql} command line client, with Add a configurable prompt to the @code{mysql} command line client, with
options like database in use, time and date... options like database in use, time and date...
@item @item
Add range checking to @code{MERGE} tables.
@item
Link the @code{myisampack} code into the server. Link the @code{myisampack} code into the server.
@item @item
Port of MySQL to BeOS. Port of MySQL to BeOS.
...@@ -6986,6 +6989,10 @@ Multithreaded clients should use @code{mysql_thread_init()} and ...@@ -6986,6 +6989,10 @@ Multithreaded clients should use @code{mysql_thread_init()} and
If you want to recompile the perl DBD-MySQL module, you must get If you want to recompile the perl DBD-MySQL module, you must get
Msql-Mysql-modules version 1.2218 or newer, because the older DBD modules Msql-Mysql-modules version 1.2218 or newer, because the older DBD modules
used the deprecated @code{drop_db()} call. used the deprecated @code{drop_db()} call.
@item
@code{RAND(seed)} returns a different random number series in 4.0 than in
3.23; This was done to get @code{RAND(seed)} and @code{RAND(seed+1)} more
different.
@end itemize @end itemize
@node Upgrading-from-3.22, Upgrading-from-3.21, Upgrading-from-3.23, Upgrade @node Upgrading-from-3.22, Upgrading-from-3.21, Upgrading-from-3.23, Upgrade
...@@ -8334,12 +8341,14 @@ from usage by other threads. This has to do with the fact that on Windows, ...@@ -8334,12 +8341,14 @@ from usage by other threads. This has to do with the fact that on Windows,
you can't delete a file that is in use by another threads. (In the future, you can't delete a file that is in use by another threads. (In the future,
we may find some way to work around this problem.) we may find some way to work around this problem.)
@item @code{DROP TABLE} on a table that is in use by a @code{MERGE} table will not work @item
The @code{MERGE} handler does its table mapping hidden from MySQL. @code{DROP TABLE} on a table that is in use by a @code{MERGE} table will
Because Windows doesn't allow you to drop files that are open, you first not work on windows becasue @code{MERGE} handler does the table mapping
must flush all @code{MERGE} tables (with @code{FLUSH TABLES}) or drop the hidden from the upper layer of MySQL. Because Windows doesn't allow you
@code{MERGE} table before dropping the table. We will fix this at the same to drop files that are open, you first must flush all @code{MERGE}
time we introduce @code{VIEW}s. tables (with @code{FLUSH TABLES}) or drop the @code{MERGE} table before
dropping the table. We will fix this at the same time we introduce
@code{VIEW}s.
@item @item
@code{DATA DIRECTORY} and @code{INDEX DIRECTORY} directives in @code{DATA DIRECTORY} and @code{INDEX DIRECTORY} directives in
@code{CREATE TABLE} is ignored on windows, because windows doesn't support @code{CREATE TABLE} is ignored on windows, because windows doesn't support
...@@ -12283,7 +12292,7 @@ DROP TABLE tmp; ...@@ -12283,7 +12292,7 @@ DROP TABLE tmp;
@end example @end example
The above way to solve this query is in effect a @code{UNION} of two queries. The above way to solve this query is in effect a @code{UNION} of two queries.
@xref{UNION}.
@node Calculating days, example-AUTO_INCREMENT, Searching on two keys, Examples @node Calculating days, example-AUTO_INCREMENT, Searching on two keys, Examples
@subsection Calculating visits per day @subsection Calculating visits per day
...@@ -15085,14 +15094,19 @@ You can specify wild cards in the hostname. For example, ...@@ -15085,14 +15094,19 @@ You can specify wild cards in the hostname. For example,
for any host in the @code{144.155.166} class C subnet. for any host in the @code{144.155.166} class C subnet.
The simple form @code{user} is a synonym for @code{user@@"%"}. The simple form @code{user} is a synonym for @code{user@@"%"}.
MySQL doesn't support wildcards in user names. Anonymous users are
defined by inserting entries with @code{User=''} into the
@code{mysql.user} table or creating an user with an empty name with the
@code{GRANT} command.
@strong{Note:} If you allow anonymous users to connect to the MySQL @strong{Note:} If you allow anonymous users to connect to the MySQL
server (which is the default), you should also add all local users as server, you should also grant privileges to all local users as
@code{user@@localhost} because otherwise the anonymous user entry for the @code{user@@localhost} because otherwise the anonymous user entry for
local host in the @code{mysql.user} table will be used when the user tries to the local host in the @code{mysql.user} table will be used when the user
log into the MySQL server from the local machine! Anonymous users tries to log into the MySQL server from the local machine!
are defined by inserting entries with @code{User=''} into the
@code{mysql.user} table. You can verify if this applies to you by executing You can verify if this applies to you by executing this query:
this query:
@example @example
mysql> SELECT Host,User FROM mysql.user WHERE User=''; mysql> SELECT Host,User FROM mysql.user WHERE User='';
...@@ -24301,9 +24315,9 @@ option to @code{DELETE} may help. @xref{DELETE, , @code{DELETE}}. ...@@ -24301,9 +24315,9 @@ option to @code{DELETE} may help. @xref{DELETE, , @code{DELETE}}.
* MySQL indexes:: How MySQL Uses Indexes * MySQL indexes:: How MySQL Uses Indexes
* Indexes:: Column Indexes * Indexes:: Column Indexes
* Multiple-column indexes:: Multiple-Column Indexes * Multiple-column indexes:: Multiple-Column Indexes
* Open tables:: Why So Many Open tables?
* Table cache:: How MySQL Opens and Closes Tables * Table cache:: How MySQL Opens and Closes Tables
* Creating many tables:: Drawbacks to Creating Large Numbers of Tables in the Same Database * Creating many tables:: Drawbacks to Creating Large Numbers of Tables in the Same Database
* Open tables:: Why So Many Open tables?
@end menu @end menu
...@@ -24648,7 +24662,7 @@ created only from @code{VARCHAR} and @code{TEXT} columns. ...@@ -24648,7 +24662,7 @@ created only from @code{VARCHAR} and @code{TEXT} columns.
Indexing always happens over the entire column and partial indexing is not Indexing always happens over the entire column and partial indexing is not
supported. See @ref{Fulltext Search} for details. supported. See @ref{Fulltext Search} for details.
@node Multiple-column indexes, Table cache, Indexes, Optimising Database Structure @node Multiple-column indexes, Open tables, Indexes, Optimising Database Structure
@subsection Multiple-Column Indexes @subsection Multiple-Column Indexes
@cindex multi-column indexes @cindex multi-column indexes
...@@ -24709,8 +24723,31 @@ For more information on the manner in which MySQL uses indexes to ...@@ -24709,8 +24723,31 @@ For more information on the manner in which MySQL uses indexes to
improve query performance, see @ref{MySQL indexes, , MySQL improve query performance, see @ref{MySQL indexes, , MySQL
indexes}. indexes}.
@node Open tables, Table cache, Multiple-column indexes, Optimising Database Structure
@subsection Why So Many Open tables?
@cindex tables, open
@cindex open tables
When you run @code{mysqladmin status}, you'll see something like this:
@example
Uptime: 426 Running threads: 1 Questions: 11082 Reloads: 1 Open tables: 12
@end example
This can be somewhat perplexing if you only have 6 tables.
MySQL is multithreaded, so it may have many queries on the same table
simultaneously. To minimise the problem with two threads having
different states on the same file, the table is opened independently by
each concurrent thread. This takes some memory but will normaly increase
performance. Wth ISAM and MyISAM tables this also requires one extra file
descriptor for the data file. With these table types the index file
descriptor is shared between all threads.
You can read more about this topic in the next section. @xref{Table cache}.
@node Table cache, Creating many tables, Multiple-column indexes, Optimising Database Structure @node Table cache, Creating many tables, Open tables, Optimising Database Structure
@subsection How MySQL Opens and Closes Tables @subsection How MySQL Opens and Closes Tables
@findex table_cache @findex table_cache
...@@ -24745,11 +24782,27 @@ in increase the number of file descriptors available for MySQL with ...@@ -24745,11 +24782,27 @@ in increase the number of file descriptors available for MySQL with
the @code{--open-files-limit=#} startup option. @xref{Not enough file the @code{--open-files-limit=#} startup option. @xref{Not enough file
handles}. handles}.
The cache of open tables can grow to a maximum of @code{table_cache} The cache of open tables will be keept at a level of @code{table_cache}
(default 64; this can be changed with the @code{-O table_cache=#} entries (default 64; this can be changed with the @code{-O
option to @code{mysqld}). A table is never closed, except when the table_cache=#} option to @code{mysqld}). Note that in MySQL may
cache is full and another thread tries to open a table or if you use temporarly open even more tables to be able to execute queries.
@code{mysqladmin refresh} or @code{mysqladmin flush-tables}.
A not used table is closed and removed from the table cache under the
following circumstances:
@itemize @bullet
@item
When the cache is full and a thread tries to open a table that is not in
the cache.
@item
When the cache contains more than @code{table_cache} entires and
a thread is not anymore using a table.
@item
When someone executes @code{mysqladmin refresh} or
@code{mysqladmin flush-tables}.
@item
When someone executes 'FLUSH TABLES'
@end itemize
When the table cache fills up, the server uses the following procedure When the table cache fills up, the server uses the following procedure
to locate a cache entry to use: to locate a cache entry to use:
...@@ -24780,15 +24833,16 @@ If you are opening a table with the @code{HANDLER table_name OPEN} ...@@ -24780,15 +24833,16 @@ If you are opening a table with the @code{HANDLER table_name OPEN}
statement, a dedicated table object is allocated for the thread. statement, a dedicated table object is allocated for the thread.
This table object is not shared by other threads an will not be closed This table object is not shared by other threads an will not be closed
until the thread calls @code{HANDLER table_name CLOSE} or the thread dies. until the thread calls @code{HANDLER table_name CLOSE} or the thread dies.
@xref{HANDLER}. @xref{HANDLER}. When this happens, the table is put back in the table_cache
(if it isn't full).
You can check if your table cache is too small by checking the mysqld You can check if your table cache is too small by checking the mysqld
variable @code{opened_tables}. If this is quite big, even if you variable @code{Opened_tables}. If this is quite big, even if you
haven't done a lot of @code{FLUSH TABLES}, you should increase your table haven't done a lot of @code{FLUSH TABLES}, you should increase your table
cache. @xref{SHOW STATUS}. cache. @xref{SHOW STATUS}.
@node Creating many tables, Open tables, Table cache, Optimising Database Structure @node Creating many tables, , Table cache, Optimising Database Structure
@subsection Drawbacks to Creating Large Numbers of Tables in the Same Database @subsection Drawbacks to Creating Large Numbers of Tables in the Same Database
@cindex tables, too many @cindex tables, too many
...@@ -24800,28 +24854,6 @@ every table that has to be opened, another must be closed. You can reduce ...@@ -24800,28 +24854,6 @@ every table that has to be opened, another must be closed. You can reduce
this overhead by making the table cache larger. this overhead by making the table cache larger.
@node Open tables, , Creating many tables, Optimising Database Structure
@subsection Why So Many Open tables?
@cindex tables, open
@cindex open tables
When you run @code{mysqladmin status}, you'll see something like this:
@example
Uptime: 426 Running threads: 1 Questions: 11082 Reloads: 1 Open tables: 12
@end example
This can be somewhat perplexing if you only have 6 tables.
MySQL is multithreaded, so it may have many queries on the same
table simultaneously. To minimise the problem with two threads having
different states on the same file, the table is opened independently by
each concurrent thread. This takes some memory and one extra file
descriptor for the data file. The index file descriptor is shared
between all threads.
@node Optimising the Server, Disk issues, Optimising Database Structure, MySQL Optimisation @node Optimising the Server, Disk issues, Optimising Database Structure, MySQL Optimisation
@section Optimising the MySQL Server @section Optimising the MySQL Server
...@@ -29519,16 +29551,17 @@ Returns a random floating-point value in the range @code{0} to @code{1.0}. ...@@ -29519,16 +29551,17 @@ Returns a random floating-point value in the range @code{0} to @code{1.0}.
If an integer argument @code{N} is specified, it is used as the seed value: If an integer argument @code{N} is specified, it is used as the seed value:
@example @example
mysql> select RAND(); mysql> select RAND();
-> 0.5925 -> 0.9233482386203
mysql> select RAND(20); mysql> select RAND(20);
-> 0.1811 -> 0.15888261251047
mysql> select RAND(20); mysql> select RAND(20);
-> 0.1811 -> 0.15888261251047
mysql> select RAND(); mysql> select RAND();
-> 0.2079 -> 0.63553050033332
mysql> select RAND(); mysql> select RAND();
-> 0.7888 -> 0.70100469486881
@end example @end example
You can't use a column with @code{RAND()} values in an @code{ORDER BY} You can't use a column with @code{RAND()} values in an @code{ORDER BY}
clause, because @code{ORDER BY} would evaluate the column multiple times. clause, because @code{ORDER BY} would evaluate the column multiple times.
In MySQL Version 3.23, you can, however, do: In MySQL Version 3.23, you can, however, do:
...@@ -29540,6 +29573,10 @@ table1,table2 WHERE a=b AND c<d ORDER BY RAND() LIMIT 1000}. ...@@ -29540,6 +29573,10 @@ table1,table2 WHERE a=b AND c<d ORDER BY RAND() LIMIT 1000}.
Note that a @code{RAND()} in a @code{WHERE} clause will be re-evaluated Note that a @code{RAND()} in a @code{WHERE} clause will be re-evaluated
every time the @code{WHERE} is executed. every time the @code{WHERE} is executed.
@code{RAND()} is not meant to be a perfect random generator, but instead a
fast way to generate add-hook random numbers that will be portable between
platforms for the same MySQL version.
@findex LEAST() @findex LEAST()
@item LEAST(X,Y,...) @item LEAST(X,Y,...)
With two or more arguments, returns the smallest (minimum-valued) argument. With two or more arguments, returns the smallest (minimum-valued) argument.
...@@ -34626,17 +34663,59 @@ Change the @code{.MRG} file and issue a @code{FLUSH TABLE} on the ...@@ -34626,17 +34663,59 @@ Change the @code{.MRG} file and issue a @code{FLUSH TABLE} on the
read the new definition file. read the new definition file.
@end itemize @end itemize
@menu
* MERGE table problems::
@end menu
@node MERGE table problems, , MERGE, MERGE
@subsection MERGE table problems.
The following are the known problems with @code{MERGE} tables:
@itemize @bullet
@item
@code{DELETE FROM merge_table} used without a @code{WHERE}
will only clear the mapping for the table, not delete everything in the
mapped tables.
@item
@code{RENAME TABLE} on a table used in an active @code{MERGE} table may
corrupt the table. This will be fixed in MySQL 4.0.x.
@item
Creation of a table of type @code{MERGE} doesn't check if the underlying
tables are of compatible types. If you use @code{MERGE} tables in this
fasion you are very likely to run into strange problems.
@item
If you use @code{ALTER TABLE} to first add an @code{UNIQUE} index to a
table used in a @code{MERGE} table and then use @code{ALTER TABLE} to
add a normal index on the @code{MERGE} table, the key order will be
different for the tables if there was an old not-unique key in the
table. This is because @code{ALTER TABLE} puts @code{UNIQUE} keys before
normal keys to be able to detect duplicate keys as early as possible.
@item
The range optimizer can't yet use @code{MERGE} table efficiently and may
sometimes produce not optimal joins. This will be fixed in MySQL 4.0.x.
@item
@code{DROP TABLE} on a table that is in use by a @code{MERGE} table will
not work on windows becasue @code{MERGE} handler does the table mapping
hidden from the upper layer of MySQL. Because Windows doesn't allow you
to drop files that are open, you first must flush all @code{MERGE}
tables (with @code{FLUSH TABLES}) or drop the @code{MERGE} table before
dropping the table. We will fix this at the same time we introduce
@code{VIEW}s.
@end itemize
@node ISAM, HEAP, MERGE, Table types @node ISAM, HEAP, MERGE, Table types
@section ISAM Tables @section ISAM Tables
@cindex tables, ISAM @cindex tables, ISAM
You can also use the deprecated ISAM table type. This will disappear You can also use the deprecated ISAM table type. This will disappear
rather soon because @code{MyISAM} is a better implementation of the same rather soon (probably in MySQL 4.1) because @code{MyISAM} is a better
thing. ISAM uses a @code{B-tree} index. The index is stored in a file implementation of the same thing. ISAM uses a @code{B-tree} index. The
with the @code{.ISM} extension, and the data is stored in a file with the index is stored in a file with the @code{.ISM} extension, and the data
@code{.ISD} extension. You can check/repair ISAM tables with the is stored in a file with the @code{.ISD} extension. You can
@code{isamchk} utility. @xref{Crash recovery}. check/repair ISAM tables with the @code{isamchk} utility. @xref{Crash
recovery}.
@code{ISAM} has the following features/properties: @code{ISAM} has the following features/properties:
...@@ -34669,6 +34748,7 @@ TABLE} statement: ...@@ -34669,6 +34748,7 @@ TABLE} statement:
mysql> ALTER TABLE tbl_name TYPE = MYISAM; mysql> ALTER TABLE tbl_name TYPE = MYISAM;
@end example @end example
The embedded MySQL versions doesn't support ISAM tables.
@node HEAP, InnoDB, ISAM, Table types @node HEAP, InnoDB, ISAM, Table types
@section HEAP Tables @section HEAP Tables
...@@ -45921,6 +46001,14 @@ not yet 100% confident in this code. ...@@ -45921,6 +46001,14 @@ not yet 100% confident in this code.
@appendixsubsec Changes in release 3.23.45 @appendixsubsec Changes in release 3.23.45
@itemize @bullet @itemize @bullet
@item @item
Fix a bug which could cause InnoDB to complain if it cannot find free blocks
from the buffer cache during recovery.
@item
Fixed a bug in InnoDB insert buffer B-tree handling that could cause crashes.
@item
Fixed bug in @code{OPTIMIZE TABLE} that reset index cardinality if it
was up to date.
@item
Fixed problem with @code{t1 LEFT_JOIN t2 ... WHERE t2.date_column IS NULL} when Fixed problem with @code{t1 LEFT_JOIN t2 ... WHERE t2.date_column IS NULL} when
date_column was declared as @code{NOT NULL}. date_column was declared as @code{NOT NULL}.
@item @item
...@@ -49798,7 +49886,7 @@ Fixed bug in record caches; for some queries, you could get ...@@ -49798,7 +49886,7 @@ Fixed bug in record caches; for some queries, you could get
Added user level lock functions @code{GET_LOCK(string,timeout)}, Added user level lock functions @code{GET_LOCK(string,timeout)},
@code{RELEASE_LOCK(string)}. @code{RELEASE_LOCK(string)}.
@item @item
Added @code{opened_tables} to @code{show status}. Added @code{Opened_tables} to @code{show status}.
@item @item
Changed connect timeout to 3 seconds to make it somewhat harder Changed connect timeout to 3 seconds to make it somewhat harder
for crackers to kill @code{mysqld} through telnet + TCP/IP. for crackers to kill @code{mysqld} through telnet + TCP/IP.
...@@ -21,7 +21,7 @@ Created 6/2/1994 Heikki Tuuri ...@@ -21,7 +21,7 @@ Created 6/2/1994 Heikki Tuuri
#include "lock0lock.h" #include "lock0lock.h"
#include "ibuf0ibuf.h" #include "ibuf0ibuf.h"
/** /*
Node pointers Node pointers
------------- -------------
Leaf pages of a B-tree contain the index records stored in the Leaf pages of a B-tree contain the index records stored in the
...@@ -550,14 +550,15 @@ btr_page_get_father_for_rec( ...@@ -550,14 +550,15 @@ btr_page_get_father_for_rec(
ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree), ut_ad(mtr_memo_contains(mtr, dict_tree_get_lock(tree),
MTR_MEMO_X_LOCK)); MTR_MEMO_X_LOCK));
ut_ad(user_rec != page_get_supremum_rec(page)); ut_a(user_rec != page_get_supremum_rec(page));
ut_ad(user_rec != page_get_infimum_rec(page)); ut_a(user_rec != page_get_infimum_rec(page));
ut_ad(dict_tree_get_page(tree) != buf_frame_get_page_no(page)); ut_ad(dict_tree_get_page(tree) != buf_frame_get_page_no(page));
heap = mem_heap_create(100); heap = mem_heap_create(100);
tuple = dict_tree_build_node_ptr(tree, user_rec, 0, heap); tuple = dict_tree_build_node_ptr(tree, user_rec, 0, heap,
btr_page_get_level(page, mtr));
/* In the following, we choose just any index from the tree as the /* In the following, we choose just any index from the tree as the
first parameter for btr_cur_search_to_nth_level. */ first parameter for btr_cur_search_to_nth_level. */
...@@ -569,7 +570,7 @@ btr_page_get_father_for_rec( ...@@ -569,7 +570,7 @@ btr_page_get_father_for_rec(
node_ptr = btr_cur_get_rec(&cursor); node_ptr = btr_cur_get_rec(&cursor);
ut_ad(btr_node_ptr_get_child_page_no(node_ptr) == ut_a(btr_node_ptr_get_child_page_no(node_ptr) ==
buf_frame_get_page_no(page)); buf_frame_get_page_no(page));
mem_heap_free(heap); mem_heap_free(heap);
...@@ -949,8 +950,8 @@ btr_root_raise_and_insert( ...@@ -949,8 +950,8 @@ btr_root_raise_and_insert(
/* Build the node pointer (= node key and page address) for the /* Build the node pointer (= node key and page address) for the
child */ child */
node_ptr = dict_tree_build_node_ptr(tree, rec, new_page_no, heap); node_ptr = dict_tree_build_node_ptr(tree, rec, new_page_no, heap,
level);
/* Reorganize the root to get free space */ /* Reorganize the root to get free space */
btr_page_reorganize(root, mtr); btr_page_reorganize(root, mtr);
...@@ -1365,7 +1366,7 @@ btr_attach_half_pages( ...@@ -1365,7 +1366,7 @@ btr_attach_half_pages(
half */ half */
node_ptr_upper = dict_tree_build_node_ptr(tree, split_rec, node_ptr_upper = dict_tree_build_node_ptr(tree, split_rec,
upper_page_no, heap); upper_page_no, heap, level);
/* Insert it next to the pointer to the lower half. Note that this /* Insert it next to the pointer to the lower half. Note that this
may generate recursion leading to a split on the higher level. */ may generate recursion leading to a split on the higher level. */
...@@ -2230,7 +2231,7 @@ btr_check_node_ptr( ...@@ -2230,7 +2231,7 @@ btr_check_node_ptr(
node_ptr_tuple = dict_tree_build_node_ptr( node_ptr_tuple = dict_tree_build_node_ptr(
tree, tree,
page_rec_get_next(page_get_infimum_rec(page)), page_rec_get_next(page_get_infimum_rec(page)),
0, heap); 0, heap, btr_page_get_level(page, mtr));
ut_a(cmp_dtuple_rec(node_ptr_tuple, node_ptr) == 0); ut_a(cmp_dtuple_rec(node_ptr_tuple, node_ptr) == 0);
...@@ -2488,7 +2489,8 @@ btr_validate_level( ...@@ -2488,7 +2489,8 @@ btr_validate_level(
tree, tree,
page_rec_get_next( page_rec_get_next(
page_get_infimum_rec(page)), page_get_infimum_rec(page)),
0, heap); 0, heap,
btr_page_get_level(page, &mtr));
if (cmp_dtuple_rec(node_ptr_tuple, node_ptr) != 0) { if (cmp_dtuple_rec(node_ptr_tuple, node_ptr) != 0) {
......
...@@ -2347,7 +2347,7 @@ btr_cur_pessimistic_delete( ...@@ -2347,7 +2347,7 @@ btr_cur_pessimistic_delete(
node_ptr = dict_tree_build_node_ptr( node_ptr = dict_tree_build_node_ptr(
tree, page_rec_get_next(rec), tree, page_rec_get_next(rec),
buf_frame_get_page_no(page), buf_frame_get_page_no(page),
heap); heap, btr_page_get_level(page, mtr));
btr_insert_on_non_leaf_level(tree, btr_insert_on_non_leaf_level(tree,
btr_page_get_level(page, mtr) + 1, btr_page_get_level(page, mtr) + 1,
......
...@@ -138,15 +138,11 @@ buf_flush_ready_for_flush( ...@@ -138,15 +138,11 @@ buf_flush_ready_for_flush(
return(TRUE); return(TRUE);
} else if ((block->old || (UT_LIST_GET_LEN(buf_pool->LRU) } else if (block->buf_fix_count == 0) {
< BUF_LRU_OLD_MIN_LEN))
&& (block->buf_fix_count == 0)) {
/* If we are flushing the LRU list, to avoid deadlocks /* If we are flushing the LRU list, to avoid deadlocks
we require the block not to be bufferfixed, and hence we require the block not to be bufferfixed, and hence
not latched. Since LRU flushed blocks are soon moved not latched. */
to the free list, it is good to flush only old blocks
from the end of the LRU list. */
return(TRUE); return(TRUE);
} }
...@@ -560,6 +556,15 @@ buf_flush_try_neighbors( ...@@ -560,6 +556,15 @@ buf_flush_try_neighbors(
block = buf_page_hash_get(space, i); block = buf_page_hash_get(space, i);
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 */
continue;
}
if (block && buf_flush_ready_for_flush(block, flush_type)) { if (block && buf_flush_ready_for_flush(block, flush_type)) {
mutex_exit(&(buf_pool->mutex)); mutex_exit(&(buf_pool->mutex));
......
...@@ -2415,7 +2415,9 @@ dict_tree_build_node_ptr( ...@@ -2415,7 +2415,9 @@ dict_tree_build_node_ptr(
dict_tree_t* tree, /* in: index tree */ dict_tree_t* tree, /* in: index tree */
rec_t* rec, /* in: record for which to build node pointer */ rec_t* rec, /* in: record for which to build node pointer */
ulint page_no,/* in: page number to put in node pointer */ ulint page_no,/* in: page number to put in node pointer */
mem_heap_t* heap) /* in: memory heap where pointer created */ mem_heap_t* heap, /* in: memory heap where pointer created */
ulint level) /* in: level of rec in tree: 0 means leaf
level */
{ {
dtuple_t* tuple; dtuple_t* tuple;
dict_index_t* ind; dict_index_t* ind;
...@@ -2427,9 +2429,16 @@ dict_tree_build_node_ptr( ...@@ -2427,9 +2429,16 @@ dict_tree_build_node_ptr(
if (tree->type & DICT_UNIVERSAL) { if (tree->type & DICT_UNIVERSAL) {
/* In a universal index tree, we take the whole record as /* In a universal index tree, we take the whole record as
the node pointer */ the node pointer if the reord is on the leaf level,
on non-leaf levels we remove the last field, which
contains the page number of the child page */
n_unique = rec_get_n_fields(rec); n_unique = rec_get_n_fields(rec);
if (level > 0) {
ut_a(n_unique > 1);
n_unique--;
}
} else { } else {
n_unique = dict_index_get_n_unique_in_tree(ind); n_unique = dict_index_get_n_unique_in_tree(ind);
} }
......
...@@ -622,7 +622,9 @@ dict_tree_build_node_ptr( ...@@ -622,7 +622,9 @@ dict_tree_build_node_ptr(
dict_tree_t* tree, /* in: index tree */ dict_tree_t* tree, /* in: index tree */
rec_t* rec, /* in: record for which to build node pointer */ rec_t* rec, /* in: record for which to build node pointer */
ulint page_no,/* in: page number to put in node pointer */ ulint page_no,/* in: page number to put in node pointer */
mem_heap_t* heap); /* in: memory heap where pointer created */ mem_heap_t* heap, /* in: memory heap where pointer created */
ulint level); /* in: level of rec in tree: 0 means leaf
level */
/************************************************************************** /**************************************************************************
Copies an initial segment of a physical record, long enough to specify an Copies an initial segment of a physical record, long enough to specify an
index entry uniquely. */ index entry uniquely. */
......
...@@ -68,3 +68,12 @@ select * from t2 where b="world"; ...@@ -68,3 +68,12 @@ select * from t2 where b="world";
a B a B
3 world 3 world
drop table t1,t2; drop table t1,t2;
create table t1(x varchar(50) );
create table t2 select x from t1 where 1=2;
describe t1;
Field Type Null Key Default Extra
x varchar(50) YES NULL
describe t2;
Field Type Null Key Default Extra
x char(50) YES NULL
drop table t1,t2;
...@@ -31,3 +31,20 @@ check table t1; ...@@ -31,3 +31,20 @@ check table t1;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 check status OK test.t1 check status OK
drop table t1; drop table t1;
create table t1 (a int not null auto_increment, b int not null, primary key (a), index(b));
insert into t1 (b) values (1),(2),(2),(2),(2);
optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize status OK
show index from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
t1 0 PRIMARY 1 a A 5 NULL NULL
t1 1 b 1 b A 1 NULL NULL
optimize table t1;
Table Op Msg_type Msg_text
test.t1 optimize status Table is already up to date
show index from t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
t1 0 PRIMARY 1 a A 5 NULL NULL
t1 1 b 1 b A 1 NULL NULL
drop table t1;
...@@ -65,3 +65,13 @@ create table t2 (key (b)) select * from t1; ...@@ -65,3 +65,13 @@ create table t2 (key (b)) select * from t1;
explain select * from t2 where b="world"; explain select * from t2 where b="world";
select * from t2 where b="world"; select * from t2 where b="world";
drop table t1,t2; drop table t1,t2;
#
# Test types after CREATE ... SELECT
#
create table t1(x varchar(50) );
create table t2 select x from t1 where 1=2;
describe t1;
describe t2;
drop table t1,t2;
...@@ -38,3 +38,15 @@ check table t1; ...@@ -38,3 +38,15 @@ check table t1;
repair table t1; repair table t1;
check table t1; check table t1;
drop table t1; drop table t1;
#
# Test bug: Two optimize in a row reset index cardinality
#
create table t1 (a int not null auto_increment, b int not null, primary key (a), index(b));
insert into t1 (b) values (1),(2),(2),(2),(2);
optimize table t1;
show index from t1;
optimize table t1;
show index from t1;
drop table t1;
...@@ -541,7 +541,7 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt) ...@@ -541,7 +541,7 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize) int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
{ {
int error=0; int error=0;
uint extra_testflag=0; uint local_testflag=param.testflag;
bool optimize_done= !optimize, statistics_done=0; bool optimize_done= !optimize, statistics_done=0;
const char *old_proc_info=thd->proc_info; const char *old_proc_info=thd->proc_info;
char fixed_name[FN_REFLEN]; char fixed_name[FN_REFLEN];
...@@ -570,19 +570,18 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize) ...@@ -570,19 +570,18 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
(!param.opt_rep_quick || (!param.opt_rep_quick ||
!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS)))) !(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))))
{ {
ulonglong key_map= ((param.testflag & T_CREATE_MISSING_KEYS) ? ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
((ulonglong) 1L << share->base.keys)-1 : ((ulonglong) 1L << share->base.keys)-1 :
share->state.key_map); share->state.key_map);
uint testflag=param.testflag;
if (mi_test_if_sort_rep(file,file->state->records,key_map,0) && if (mi_test_if_sort_rep(file,file->state->records,key_map,0) &&
(param.testflag & T_REP_BY_SORT)) (local_testflag & T_REP_BY_SORT))
{ {
uint testflag=param.testflag; local_testflag|= T_STATISTICS;
extra_testflag= T_STATISTICS;
param.testflag|= T_STATISTICS; // We get this for free param.testflag|= T_STATISTICS; // We get this for free
thd->proc_info="Repair by sorting"; thd->proc_info="Repair by sorting";
statistics_done=1; statistics_done=1;
error = mi_repair_by_sort(&param, file, fixed_name, param.opt_rep_quick); error = mi_repair_by_sort(&param, file, fixed_name, param.opt_rep_quick);
param.testflag=testflag;
} }
else else
{ {
...@@ -590,23 +589,29 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize) ...@@ -590,23 +589,29 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
param.testflag &= ~T_REP_BY_SORT; param.testflag &= ~T_REP_BY_SORT;
error= mi_repair(&param, file, fixed_name, param.opt_rep_quick); error= mi_repair(&param, file, fixed_name, param.opt_rep_quick);
} }
param.testflag=testflag;
optimize_done=1;
} }
if (!error) if (!error)
{ {
if ((param.testflag & T_SORT_INDEX) && if ((local_testflag & T_SORT_INDEX) &&
(share->state.changed & STATE_NOT_SORTED_PAGES)) (share->state.changed & STATE_NOT_SORTED_PAGES))
{ {
optimize_done=1; optimize_done=1;
thd->proc_info="Sorting index"; thd->proc_info="Sorting index";
error=mi_sort_index(&param,file,fixed_name); error=mi_sort_index(&param,file,fixed_name);
} }
if (!statistics_done && (param.testflag & T_STATISTICS) && if (!statistics_done && (local_testflag & T_STATISTICS))
(share->state.changed & STATE_NOT_ANALYZED)) {
if (share->state.changed & STATE_NOT_ANALYZED)
{ {
optimize_done=1; optimize_done=1;
thd->proc_info="Analyzing"; thd->proc_info="Analyzing";
error = chk_key(&param, file); error = chk_key(&param, file);
} }
else
local_testflag&= ~T_STATISTICS; // Don't update statistics
}
} }
thd->proc_info="Saving state"; thd->proc_info="Saving state";
if (!error) if (!error)
...@@ -620,9 +625,10 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize) ...@@ -620,9 +625,10 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
file->save_state=file->s->state.state; file->save_state=file->s->state.state;
if (file->s->base.auto_key) if (file->s->base.auto_key)
update_auto_increment_key(&param, file, 1); update_auto_increment_key(&param, file, 1);
if (optimize_done)
error = update_state_info(&param, file, error = update_state_info(&param, file,
UPDATE_TIME | UPDATE_OPEN_COUNT | UPDATE_TIME | UPDATE_OPEN_COUNT |
((param.testflag | extra_testflag) & (local_testflag &
T_STATISTICS ? UPDATE_STAT : 0)); T_STATISTICS ? UPDATE_STAT : 0));
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE | info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
HA_STATUS_CONST); HA_STATUS_CONST);
......
...@@ -621,8 +621,8 @@ double Item_func_rand::val() ...@@ -621,8 +621,8 @@ double Item_func_rand::val()
{ {
if (arg_count) if (arg_count)
{ // Only use argument once in query { // Only use argument once in query
ulong tmp=((ulong) args[0]->val_int())+55555555L; ulong tmp=((ulong) args[0]->val_int());
randominit(&current_thd->rand,tmp,tmp/2); randominit(&current_thd->rand,tmp*0x10001L+55555555L,tmp*0x10000001L);
#ifdef DELETE_ITEMS #ifdef DELETE_ITEMS
delete args[0]; delete args[0];
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment