Commit 207548a8 authored by monty@tramp.mysql.fi's avatar monty@tramp.mysql.fi

DISTINCT optimization

Fixes when using column privileges
Manual updates
parent a434c8d2
bk@work.mysql.com monty@tramp.mysql.fi
davida@work.mysql.com
jamppa@work.mysql.com
jcole@ham.spaceapes.com
jcole@jcole.burghcom.com
jcole@nslinux.bedford.progress.com
jcole@tetra.bedford.progress.com
jcole@tetra.spaceapes.com
matt@work.mysql.com
monty@donna.mysql.com
monty@work.mysql.com
mwagner@evoq.home.mwagner.org
nusphere@main.burghcom.com
paul@central.snake.net
paul@work.mysql.com
sasha@mysql.sashanet.com
sasha@work.mysql.com
serg@infomag.ape.relarn.ru
serg@work.mysql.com
sinisa@work.mysql.com
spurr@nslinux.bedford.progress.com
tim@localhost.polyesthetic.msg
tim@threads.polyesthetic.msg
tim@work.mysql.com
tonu@work.mysql.com
...@@ -305,14 +305,14 @@ Post-installation Setup and Testing ...@@ -305,14 +305,14 @@ Post-installation Setup and Testing
* Command-line options:: Command-line options * Command-line options:: Command-line options
* Option files:: Option files * Option files:: Option files
Is there anything special to do when upgrading/downgrading MySQL? Is There Anything Special to Do when Upgrading/Downgrading MySQL?
* Upgrading-from-3.22:: Upgrading from a 3.22 version to 3.23 * Upgrading-from-3.22:: Upgrading from a 3.22 version to 3.23
* Upgrading-from-3.21:: Upgrading from a 3.21 version to 3.22 * Upgrading-from-3.21:: Upgrading from a 3.21 version to 3.22
* Upgrading-from-3.20:: Upgrading from a 3.20 version to 3.21 * Upgrading-from-3.20:: Upgrading from a 3.20 version to 3.21
* Upgrading-to-arch:: Upgrading to another architecture * Upgrading-to-arch:: Upgrading to another architecture
How standards-compatible is MySQL? How Standards-compatible Is MySQL?
* Extensions to ANSI:: @strong{MySQL} extensions to ANSI SQL92 * Extensions to ANSI:: @strong{MySQL} extensions to ANSI SQL92
* Ansi mode:: Running @strong{MySQL} in ANSI mode * Ansi mode:: Running @strong{MySQL} in ANSI mode
...@@ -321,7 +321,7 @@ How standards-compatible is MySQL? ...@@ -321,7 +321,7 @@ How standards-compatible is MySQL?
* Standards:: What standards does @strong{MySQL} follow? * Standards:: What standards does @strong{MySQL} follow?
* Commit-rollback:: How to cope without @code{COMMIT}-@code{ROLLBACK} * Commit-rollback:: How to cope without @code{COMMIT}-@code{ROLLBACK}
Functionality missing from MySQL Functionality Missing from MySQL
* Missing Sub-selects:: Sub-selects * Missing Sub-selects:: Sub-selects
* Missing SELECT INTO TABLE:: @code{SELECT INTO TABLE} * Missing SELECT INTO TABLE:: @code{SELECT INTO TABLE}
...@@ -335,7 +335,7 @@ Foreign Keys ...@@ -335,7 +335,7 @@ Foreign Keys
* Broken Foreign KEY:: Reasons NOT to use foreign keys * Broken Foreign KEY:: Reasons NOT to use foreign keys
The MySQL access privilege system The MySQL Access Privilege System
* General security:: General security * General security:: General security
* Security:: How to make @strong{MySQL} secure against crackers * Security:: How to make @strong{MySQL} secure against crackers
...@@ -353,7 +353,7 @@ The MySQL access privilege system ...@@ -353,7 +353,7 @@ The MySQL access privilege system
* Passwords:: How to set up passwords * Passwords:: How to set up passwords
* Access denied:: Causes of @code{Access denied} errors * Access denied:: Causes of @code{Access denied} errors
MySQL language reference MySQL Language Reference
* Literals:: Literals: how to write strings and numbers * Literals:: Literals: how to write strings and numbers
* Variables:: User variables * Variables:: User variables
...@@ -394,7 +394,7 @@ MySQL language reference ...@@ -394,7 +394,7 @@ MySQL language reference
* CREATE FUNCTION:: @code{CREATE FUNCTION} syntax * CREATE FUNCTION:: @code{CREATE FUNCTION} syntax
* Reserved words:: Is @strong{MySQL} picky about reserved words? * Reserved words:: Is @strong{MySQL} picky about reserved words?
Literals: how to write strings and numbers Literals: How to Write Strings and Numbers
* String syntax:: Strings * String syntax:: Strings
* Number syntax:: Numbers * Number syntax:: Numbers
...@@ -402,11 +402,11 @@ Literals: how to write strings and numbers ...@@ -402,11 +402,11 @@ Literals: how to write strings and numbers
* NULL values:: @code{NULL} values * NULL values:: @code{NULL} values
* Legal names:: Database, table, index, column and alias names * Legal names:: Database, table, index, column and alias names
Database, table, index, column and alias names Database, Table, Index, Column, and Alias Names
* Name case sensitivity:: Case sensitivity in names * Name case sensitivity:: Case sensitivity in names
Column types Column Types
* Storage requirements:: Column type storage requirements * Storage requirements:: Column type storage requirements
* Numeric types:: Numeric types * Numeric types:: Numeric types
...@@ -417,21 +417,21 @@ Column types ...@@ -417,21 +417,21 @@ Column types
* Multiple-column indexes:: Multiple-column indexes * Multiple-column indexes:: Multiple-column indexes
* Other-vendor column types:: Using column types from other database engines * Other-vendor column types:: Using column types from other database engines
Date and time types Date and Time Types
* Y2K issues:: Y2K issues and date types * Y2K issues:: Y2K issues and date types
* DATETIME:: The @code{DATETIME}, @code{DATE} and @code{TIMESTAMP} types * DATETIME:: The @code{DATETIME}, @code{DATE} and @code{TIMESTAMP} types
* TIME:: The @code{TIME} type * TIME:: The @code{TIME} type
* YEAR:: The @code{YEAR} type * YEAR:: The @code{YEAR} type
String types String Types
* CHAR:: The @code{CHAR} and @code{VARCHAR} types * CHAR:: The @code{CHAR} and @code{VARCHAR} types
* BLOB:: The @code{BLOB} and @code{TEXT} types * BLOB:: The @code{BLOB} and @code{TEXT} types
* ENUM:: The @code{ENUM} type * ENUM:: The @code{ENUM} type
* SET:: The @code{SET} type * SET:: The @code{SET} type
Functions for use in @code{SELECT} and @code{WHERE} clauses Functions for Use in @code{SELECT} and @code{WHERE} Clauses
* Grouping functions:: Grouping functions * Grouping functions:: Grouping functions
* Arithmetic functions:: Normal arithmetic operations * Arithmetic functions:: Normal arithmetic operations
...@@ -447,7 +447,7 @@ Functions for use in @code{SELECT} and @code{WHERE} clauses ...@@ -447,7 +447,7 @@ Functions for use in @code{SELECT} and @code{WHERE} clauses
* Miscellaneous functions:: Miscellaneous functions * Miscellaneous functions:: Miscellaneous functions
* Group by functions:: Functions for @code{GROUP BY} clause * Group by functions:: Functions for @code{GROUP BY} clause
@code{CREATE TABLE} syntax @code{CREATE TABLE} Syntax
* Silent column changes:: Silent column changes * Silent column changes:: Silent column changes
...@@ -580,6 +580,7 @@ Speed of queries that access or update data ...@@ -580,6 +580,7 @@ Speed of queries that access or update data
* Estimating performance:: Estimating query performance * Estimating performance:: Estimating query performance
* SELECT speed:: Speed of @code{SELECT} queries * SELECT speed:: Speed of @code{SELECT} queries
* Where optimizations:: How MySQL optimizes @code{WHERE} clauses * Where optimizations:: How MySQL optimizes @code{WHERE} clauses
* DISTINCT optimization::
* LEFT JOIN optimization:: How MySQL optimizes @code{LEFT JOIN} * LEFT JOIN optimization:: How MySQL optimizes @code{LEFT JOIN}
* LIMIT optimization:: How MySQL optimizes @code{LIMIT} * LIMIT optimization:: How MySQL optimizes @code{LIMIT}
* Insert speed:: Speed of @code{INSERT} queries * Insert speed:: Speed of @code{INSERT} queries
...@@ -4393,14 +4394,47 @@ last version number is newer than yours). We have tried to fix only ...@@ -4393,14 +4394,47 @@ last version number is newer than yours). We have tried to fix only
fatal bugs and make small, relatively safe changes to that version. fatal bugs and make small, relatively safe changes to that version.
@end itemize @end itemize
The second decision to make is whether you want to use a source distribution or The second decision to make is whether you want to use a source
a binary distribution: distribution or a binary distribution. In most cases you should probably
use a binary distribution, if there exist one for your platform, as this
is generally, it will be easier to install than a source distribution.
In the following cases you will probably be better of with a source
installation:
@itemize @bullet
@item
If you want to install @strong{MySQL} at some explicit location. (The standard
binary distributions are 'ready to run' at any place, but you may want
to get even more flexibility).
@item
If you want to configure @code{mysqld} with some extra feature that is NOT in
the standard binary distributions. Here follows a list of the most common
extra options that you may want to use
@itemize @bullet @itemize @bullet
@item --with-berkeley-db
@item --with-raid
@item --with-libwrap
@item --with-named-z-lib (This is done for some of the binaries)
@item --with-debugging[=full]
@end itemize
@item
The default binary distribution is normally compiled with support
for all characters sets and should work on a variety of processors from
the same processor family.
If you want a faster @strong{MySQL} server you may want to recompile it
with support for only the character sets you need, use a better compiler
(like pgcc) or use compiler options that are better optimized for your
processor.
@item @item
If you want to run @strong{MySQL} on a platform for which a current binary If you have found a bug and reported it to the @strong{MySQL}
distribution exists, use that. Generally, it will be easier to install development team you will probably got a patch that you need to apply to
than a source distribution. the source distribution to get the bug fixed.
@item @item
If you want to read (and/or modify) the C and C++ code that makes up If you want to read (and/or modify) the C and C++ code that makes up
...@@ -9122,6 +9156,7 @@ for clients from option files. ...@@ -9122,6 +9156,7 @@ for clients from option files.
@item @strong{Filename} @tab @strong{Purpose} @item @strong{Filename} @tab @strong{Purpose}
@item @code{/etc/my.cnf} @tab Global options @item @code{/etc/my.cnf} @tab Global options
@item @code{DATADIR/my.cnf} @tab Server-specific options @item @code{DATADIR/my.cnf} @tab Server-specific options
@item @code{defaults-extra-file} @tab The file specified with --defaults-extra-file=#
@item @code{~/.my.cnf} @tab User-specific options @item @code{~/.my.cnf} @tab User-specific options
@end multitable @end multitable
...@@ -9233,15 +9268,19 @@ there are sample configuration files for small, medium, large, and very ...@@ -9233,15 +9268,19 @@ there are sample configuration files for small, medium, large, and very
large systems. You can copy @file{my-xxxx.cnf} to your home directory large systems. You can copy @file{my-xxxx.cnf} to your home directory
(rename the copy to @file{.my.cnf}) to experiment with this. (rename the copy to @file{.my.cnf}) to experiment with this.
To tell a @strong{MySQL} program not to read any option files, specify All @strong{MySQL} clients that support option files support the
@code{--no-defaults} as the first option on the command line. This following options:
@strong{MUST} be the first option or it will have no effect!
If you want to check which options are used, you can give the option
@code{--print-defaults} as the first option.
If you want to force the use of a specific config file, you can use the option @multitable @columnfractions .40 .60
@code{--defaults-file=full-path-to-default-file}. If you do this, only the @item --no-defaults @tab Don't read any option files.
specified file will be read. @item --print-defaults @tab Print the program name and all options that it will get.
@item --defaults-file=full-path-to-default-file @tab Only use the given configuration file.
@item --defaults-extra-file=full-path-to-default-file @tab Read this configuration file after the global configuration file but before the user configuration file.
@end multitable
Note that the above options must be first on the command line to work!
@code{--print-defaults} may however be used directly after the
@code{--defaults-xxx-file} commands.
Note for developers: Option file handling is implemented simply by Note for developers: Option file handling is implemented simply by
processing all matching options (that is, options in the appropriate group) processing all matching options (that is, options in the appropriate group)
...@@ -9252,6 +9291,19 @@ read option files, you need add only two lines to give it that capability. ...@@ -9252,6 +9291,19 @@ read option files, you need add only two lines to give it that capability.
Check the source code of any of the standard @strong{MySQL} clients to see Check the source code of any of the standard @strong{MySQL} clients to see
how to do this. how to do this.
In shell scripts you can use the @file{my_print_defaults} command to parse the
config files:
@example
shell> my_print_defaults client mysql
--port=3306
--socket=/tmp/mysql.sock
--no-auto-rehash
@end example
The above output contains all options for the groups 'client' and 'mysql'.
@node Upgrade, , Post-installation, Installing @node Upgrade, , Post-installation, Installing
@section Is There Anything Special to Do when Upgrading/Downgrading MySQL? @section Is There Anything Special to Do when Upgrading/Downgrading MySQL?
@cindex upgrading @cindex upgrading
...@@ -20035,6 +20087,9 @@ resolve the query. Here follows an explanation of the different text ...@@ -20035,6 +20087,9 @@ resolve the query. Here follows an explanation of the different text
strings that can be found in this column: strings that can be found in this column:
@table @code @table @code
@item Distinct
@strong{MySQL} will not continue searching for more rows for the current row
combination after it has found the first matching row.
@item Not exists @item Not exists
@strong{MySQL} was able to do a @code{LEFT JOIN} optimization on the @strong{MySQL} was able to do a @code{LEFT JOIN} optimization on the
query and will not examine more rows in this table for a row combination query and will not examine more rows in this table for a row combination
...@@ -20779,9 +20834,28 @@ The biggest differences between the ANSI SQL and @strong{MySQL} versions of ...@@ -20779,9 +20834,28 @@ The biggest differences between the ANSI SQL and @strong{MySQL} versions of
@code{GRANT} are: @code{GRANT} are:
@itemize @bullet @itemize @bullet
@item
In @strong{MySQL} privileges are given for an username + hostname combination
and not only for an username.
@item @item
ANSI SQL doesn't have global or database-level privileges and ANSI SQL ANSI SQL doesn't have global or database-level privileges and ANSI SQL
doesn't support all privilege types that @strong{MySQL} supports. doesn't support all privilege types that @strong{MySQL} supports.
@strong{MySQL} doesn't support the ANSI SQL @code{TRIGGER}, @code{EXECUTE} or
@code{UNDER} privileges.
@item
ANSI SQL privileges are structured in a hierarchal manner. If you remove
an user, all privileges the user has granted are revoked. In
@strong{MySQL} the granted privileges are not automaticly revoked, but
you have to revoke these yourself if needed.
@item
If you in @code{MySQL} have the @code{INSERT} grant on only part of the
columns in a table, you can execute @code{INSERT} statements on the
table; The columns for which you don't have the @code{INSERT} privilege
will set to their default values. ANSI SQL requires you to have the
@code{INSERT} privilege on all columns.
@item @item
When you drop a table in ANSI SQL, all privileges for the table are revoked. When you drop a table in ANSI SQL, all privileges for the table are revoked.
...@@ -26092,6 +26166,7 @@ great tool to find out if this is a problem with your query. ...@@ -26092,6 +26166,7 @@ great tool to find out if this is a problem with your query.
* Estimating performance:: Estimating query performance * Estimating performance:: Estimating query performance
* SELECT speed:: Speed of @code{SELECT} queries * SELECT speed:: Speed of @code{SELECT} queries
* Where optimizations:: How MySQL optimizes @code{WHERE} clauses * Where optimizations:: How MySQL optimizes @code{WHERE} clauses
* DISTINCT optimization::
* LEFT JOIN optimization:: How MySQL optimizes @code{LEFT JOIN} * LEFT JOIN optimization:: How MySQL optimizes @code{LEFT JOIN}
* LIMIT optimization:: How MySQL optimizes @code{LIMIT} * LIMIT optimization:: How MySQL optimizes @code{LIMIT}
* Insert speed:: Speed of @code{INSERT} queries * Insert speed:: Speed of @code{INSERT} queries
...@@ -26171,7 +26246,7 @@ time for a large table! ...@@ -26171,7 +26246,7 @@ time for a large table!
@cindex optimizations @cindex optimizations
@findex WHERE @findex WHERE
@node Where optimizations, LEFT JOIN optimization, SELECT speed, Query Speed @node Where optimizations, DISTINCT optimization, SELECT speed, Query Speed
@subsection How MySQL optimizes @code{WHERE} clauses @subsection How MySQL optimizes @code{WHERE} clauses
The @code{WHERE} optimizations are put in the @code{SELECT} part here because The @code{WHERE} optimizations are put in the @code{SELECT} part here because
...@@ -26244,18 +26319,14 @@ possibilities. If all columns in @code{ORDER BY} and in @code{GROUP ...@@ -26244,18 +26319,14 @@ possibilities. If all columns in @code{ORDER BY} and in @code{GROUP
BY} come from the same table, then this table is preferred first when BY} come from the same table, then this table is preferred first when
joining. joining.
@item @item
If there is an @code{ORDER BY} clause and a different @code{GROUP BY} clause, If there is an @code{ORDER BY} clause and a different @code{GROUP BY}
or if the @code{ORDER BY} or @code{GROUP BY} clause, or if the @code{ORDER BY} or @code{GROUP BY} contains columns
contains columns from tables other than the first table in the join from tables other than the first table in the join queue, a temporary
queue, a temporary table is created. table is created.
@item @item
If you use @code{SQL_SMALL_RESULT}, @strong{MySQL} will use an in-memory If you use @code{SQL_SMALL_RESULT}, @strong{MySQL} will use an in-memory
temporary table. temporary table.
@item @item
As @code{DISTINCT} is converted to a @code{GROUP BY} on all columns,
@code{DISTINCT} combined with @code{ORDER BY} will in many cases also need
a temporary table.
@item
Each table index is queried and the best index that spans fewer than 30% of Each table index is queried and the best index that spans fewer than 30% of
the rows is used. If no such index can be found, a quick table scan is used. the rows is used. If no such index can be found, a quick table scan is used.
@item @item
...@@ -26298,9 +26369,32 @@ mysql> SELECT ... FROM tbl_name ORDER BY key_part1,key_part2,... ...@@ -26298,9 +26369,32 @@ mysql> SELECT ... FROM tbl_name ORDER BY key_part1,key_part2,...
mysql> SELECT ... FROM tbl_name ORDER BY key_part1 DESC,key_part2 DESC,... mysql> SELECT ... FROM tbl_name ORDER BY key_part1 DESC,key_part2 DESC,...
@end example @end example
@findex DISTINCT
@cindex optimizing, DISTINCT
@node DISTINCT optimization, LEFT JOIN optimization, Where optimizations, Query Speed
@subsection How MySQL optimizes @code{DISTINCT}
@code{DISTINCT} is converted to a @code{GROUP BY} on all columns,
@code{DISTINCT} combined with @code{ORDER BY} will in many cases also
need a temporary table.
When combining @code{LIMIT #} with @code{DISTINCT}, @strong{MySQL} will stop
as soon as it finds @code{#} unique rows.
If you don't use columns from all used tables, @strong{MySQL} will stop
the scanning of the not used tables as soon as it has found the first match.
@example
SELECT DISTINCT t1.a FROM t1,t2 where t1.a=t2.a;
@end example
In the case, assuming t1 is used before t2 (check with @code{EXPLAIN}), then
@strong{MySQL} will stop reading from t2 (for that particular row in t1)
when the first row in t2 is found.
@findex LEFT JOIN @findex LEFT JOIN
@cindex optimizing, LEFT JOIN @cindex optimizing, LEFT JOIN
@node LEFT JOIN optimization, LIMIT optimization, Where optimizations, Query Speed @node LEFT JOIN optimization, LIMIT optimization, DISTINCT optimization, Query Speed
@subsection How MySQL optimizes @code{LEFT JOIN} and @code{RIGHT JOIN} @subsection How MySQL optimizes @code{LEFT JOIN} and @code{RIGHT JOIN}
@code{A LEFT JOIN B} is in @strong{MySQL} implemented as follows: @code{A LEFT JOIN B} is in @strong{MySQL} implemented as follows:
...@@ -31397,6 +31491,10 @@ Load the privilege tables with: @code{mysqladmin -h hostname ...@@ -31397,6 +31491,10 @@ Load the privilege tables with: @code{mysqladmin -h hostname
flush-privileges} or with the SQL command @code{FLUSH PRIVILEGES}. flush-privileges} or with the SQL command @code{FLUSH PRIVILEGES}.
@end enumerate @end enumerate
Note that after you started @code{mysqld} with @code{--skip-grant-tables},
any usage of @code{GRANT} commands will give you an @code{Unknown command}
error until you have executed @code{FLUSH PRIVILEGES}.
@cindex files, permissions @cindex files, permissions
@cindex error mesaages, can't find file @cindex error mesaages, can't find file
@cindex files, not found message @cindex files, not found message
...@@ -37760,6 +37858,16 @@ though, so 3.23 is not released as a stable version yet. ...@@ -37760,6 +37858,16 @@ though, so 3.23 is not released as a stable version yet.
@appendixsubsec Changes in release 3.23.26 @appendixsubsec Changes in release 3.23.26
@itemize @bullet @itemize @bullet
@item @item
Added optimization of queries where @code{DISTINCT} is only used on columns
from some of the tables.
@item
Allow floating point numbers where there are no sign after the exponent
(like 1e1).
@item
@code{SHOW GRANTS} didn't always show all column grants.
@item
Added @code{--default-extra-file=#} to all @strong{MySQL} clients.
@item
Automatic repair of @code{MyISAM} tables. Automatic repair of @code{MyISAM} tables.
@item @item
Columns referenced in @code{INSERT} are are now properly initialized. Columns referenced in @code{INSERT} are are now properly initialized.
...@@ -32,6 +32,8 @@ static struct option long_options[] = ...@@ -32,6 +32,8 @@ static struct option long_options[] =
{ {
{"config-file", required_argument, 0, 'c'}, {"config-file", required_argument, 0, 'c'},
{"defaults-file", required_argument, 0, 'c'}, {"defaults-file", required_argument, 0, 'c'},
{"defaults-extra-file", required_argument, 0, 'e'},
{"extra-file", required_argument, 0, 'e'},
{"no-defaults", no_argument, 0, 'd'}, {"no-defaults", no_argument, 0, 'd'},
{"help", no_argument, 0, '?'}, {"help", no_argument, 0, '?'},
{"version", no_argument, 0, 'V'}, {"version", no_argument, 0, 'V'},
...@@ -40,7 +42,7 @@ static struct option long_options[] = ...@@ -40,7 +42,7 @@ static struct option long_options[] =
static void usage(my_bool version) static void usage(my_bool version)
{ {
printf("%s Ver 1.1 for %s at %s\n",my_progname,SYSTEM_TYPE, printf("%s Ver 1.2 for %s at %s\n",my_progname,SYSTEM_TYPE,
MACHINE_TYPE); MACHINE_TYPE);
if (version) if (version)
return; return;
...@@ -50,6 +52,9 @@ static void usage(my_bool version) ...@@ -50,6 +52,9 @@ static void usage(my_bool version)
printf("\n\ printf("\n\
-c, --config-file=#, --defaults-file=#\n\ -c, --config-file=#, --defaults-file=#\n\
The config file to use (default '%s')\n\ The config file to use (default '%s')\n\
-e, --extra-file=#, --defaults-extra-file=#\n\
Read this file after the global /etc config file and\n\
before the config file in the users home directory.\n\
--no-defaults Return an empty string (useful for scripts)\n\ --no-defaults Return an empty string (useful for scripts)\n\
-?, --help Display this help message and exit.\n\ -?, --help Display this help message and exit.\n\
-V, --version Output version information and exit.\n", -V, --version Output version information and exit.\n",
...@@ -61,13 +66,16 @@ static int get_options(int *argc,char ***argv) ...@@ -61,13 +66,16 @@ static int get_options(int *argc,char ***argv)
{ {
int c,option_index; int c,option_index;
while ((c=getopt_long(*argc,*argv,"c:V?I", while ((c=getopt_long(*argc,*argv,"c:e:V?I",
long_options, &option_index)) != EOF) long_options, &option_index)) != EOF)
{ {
switch (c) { switch (c) {
case 'c': case 'c':
config_file=optarg; config_file=optarg;
break; break;
case 'e':
defaults_extra_file=optarg; /* Used by the load_defaults */
break;
case 'n': case 'n':
exit(0); exit(0);
case 'I': case 'I':
...@@ -102,7 +110,7 @@ int main(int argc, char **argv) ...@@ -102,7 +110,7 @@ int main(int argc, char **argv)
if (get_options(&argc,&argv)) if (get_options(&argc,&argv))
exit(1); exit(1);
if (!(load_default_groups=(char**) my_malloc((argc+2)*sizeof(char*), if (!(load_default_groups=(char**) my_malloc((argc+2)*sizeof(char*),
MYF(MY_WME)))) MYF(MY_WME))))
exit(1); exit(1);
for (count=0; *argv ; argv++,count++) for (count=0; *argv ; argv++,count++)
......
...@@ -206,6 +206,7 @@ extern my_bool NEAR my_disable_locking,NEAR my_disable_async_io, ...@@ -206,6 +206,7 @@ extern my_bool NEAR my_disable_locking,NEAR my_disable_async_io,
NEAR my_disable_flush_key_blocks; NEAR my_disable_flush_key_blocks;
extern char wild_many,wild_one,wild_prefix; extern char wild_many,wild_one,wild_prefix;
extern const char *charsets_dir; extern const char *charsets_dir;
extern char *defaults_extra_file;
typedef struct wild_file_pack /* Struct to hold info when selecting files */ typedef struct wild_file_pack /* Struct to hold info when selecting files */
{ {
......
...@@ -29,8 +29,9 @@ ...@@ -29,8 +29,9 @@
** The following arguments are handled automaticly; If used, they must be ** The following arguments are handled automaticly; If used, they must be
** first argument on the command line! ** first argument on the command line!
** --no-defaults ; no options are read. ** --no-defaults ; no options are read.
** --print-defaults ; Print the modified command line and exit
** --defaults-file=full-path-to-default-file ; Only this file will be read. ** --defaults-file=full-path-to-default-file ; Only this file will be read.
** --defaults-extra-file=full-path-to-default-file ; Read this file before ~/
** --print-defaults ; Print the modified command line and exit
****************************************************************************/ ****************************************************************************/
#undef SAFEMALLOC /* safe_malloc is not yet initailized */ #undef SAFEMALLOC /* safe_malloc is not yet initailized */
...@@ -39,6 +40,8 @@ ...@@ -39,6 +40,8 @@
#include "m_string.h" #include "m_string.h"
#include "m_ctype.h" #include "m_ctype.h"
char *defaults_extra_file=0;
/* Which directories are searched for options (and in which order) */ /* Which directories are searched for options (and in which order) */
const char *default_directories[]= { const char *default_directories[]= {
...@@ -50,6 +53,7 @@ const char *default_directories[]= { ...@@ -50,6 +53,7 @@ const char *default_directories[]= {
#ifdef DATADIR #ifdef DATADIR
DATADIR, DATADIR,
#endif #endif
"", /* Place for defaults_extra_dir */
#ifndef __WIN__ #ifndef __WIN__
"~/", "~/",
#endif #endif
...@@ -71,9 +75,10 @@ void load_defaults(const char *conf_file, const char **groups, ...@@ -71,9 +75,10 @@ void load_defaults(const char *conf_file, const char **groups,
int *argc, char ***argv) int *argc, char ***argv)
{ {
DYNAMIC_ARRAY args; DYNAMIC_ARRAY args;
const char **dirs, *extra_default_file; const char **dirs, *forced_default_file;
TYPELIB group; TYPELIB group;
my_bool found_print_defaults=0; my_bool found_print_defaults=0;
uint args_used=0;
MEM_ROOT alloc; MEM_ROOT alloc;
char *ptr,**res; char *ptr,**res;
DBUG_ENTER("load_defaults"); DBUG_ENTER("load_defaults");
...@@ -97,9 +102,20 @@ void load_defaults(const char *conf_file, const char **groups, ...@@ -97,9 +102,20 @@ void load_defaults(const char *conf_file, const char **groups,
} }
/* Check if we want to force the use a specific default file */ /* Check if we want to force the use a specific default file */
extra_default_file=0; forced_default_file=0;
if (*argc >= 2 && is_prefix(argv[0][1],"--defaults-file=")) if (*argc >= 2)
extra_default_file=strchr(argv[0][1],'=')+1; {
if (is_prefix(argv[0][1],"--defaults-file="))
{
forced_default_file=strchr(argv[0][1],'=')+1;
args_used++;
}
else if (is_prefix(argv[0][1],"--defaults-extra-file="))
{
defaults_extra_file=strchr(argv[0][1],'=')+1;
args_used++;
}
}
group.count=0; group.count=0;
group.name= "defaults"; group.name= "defaults";
...@@ -109,9 +125,9 @@ void load_defaults(const char *conf_file, const char **groups, ...@@ -109,9 +125,9 @@ void load_defaults(const char *conf_file, const char **groups,
if (init_dynamic_array(&args, sizeof(char*),*argc, 32)) if (init_dynamic_array(&args, sizeof(char*),*argc, 32))
goto err; goto err;
if (extra_default_file) if (forced_default_file)
{ {
if (search_default_file(&args, &alloc, "", extra_default_file, "", if (search_default_file(&args, &alloc, "", forced_default_file, "",
&group)) &group))
goto err; goto err;
} }
...@@ -132,8 +148,14 @@ void load_defaults(const char *conf_file, const char **groups, ...@@ -132,8 +148,14 @@ void load_defaults(const char *conf_file, const char **groups,
#endif #endif
for (dirs=default_directories ; *dirs; dirs++) for (dirs=default_directories ; *dirs; dirs++)
{ {
if (search_default_file(&args, &alloc, *dirs, conf_file, default_ext, int error;
&group)) if (**dirs)
error=search_default_file(&args, &alloc, *dirs, conf_file,
default_ext, &group);
else if (defaults_extra_file)
error=search_default_file(&args, &alloc, NullS, defaults_extra_file,
default_ext, &group);
if (error)
goto err; goto err;
} }
} }
...@@ -145,11 +167,9 @@ void load_defaults(const char *conf_file, const char **groups, ...@@ -145,11 +167,9 @@ void load_defaults(const char *conf_file, const char **groups,
/* copy name + found arguments + command line arguments to new array */ /* copy name + found arguments + command line arguments to new array */
res[0]=argv[0][0]; res[0]=argv[0][0];
memcpy((gptr) (res+1), args.buffer, args.elements*sizeof(char*)); memcpy((gptr) (res+1), args.buffer, args.elements*sizeof(char*));
if (extra_default_file) /* Skipp --defaults-file and --defaults-extra-file */
{ (*argc)-= args_used;
--*argc; /* Skipp --defaults-file */ (*argv)+= args_used;
++*argv;
}
/* Check if we wan't to see the new argument list */ /* Check if we wan't to see the new argument list */
if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults")) if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults"))
......
...@@ -2004,6 +2004,8 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables, ...@@ -2004,6 +2004,8 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables,
want_access &= ~table->grant.privilege; want_access &= ~table->grant.privilege;
goto err; // No grants goto err; // No grants
} }
if (show_table)
continue; // We have some priv on this
table->grant.grant_table=grant_table; // Remember for column test table->grant.grant_table=grant_table; // Remember for column test
table->grant.version=grant_version; table->grant.version=grant_version;
...@@ -2013,8 +2015,6 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables, ...@@ -2013,8 +2015,6 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables,
if (!(~table->grant.privilege & want_access)) if (!(~table->grant.privilege & want_access))
continue; continue;
if (show_table && table->grant.privilege)
continue; // Test from show tables
if (want_access & ~(grant_table->cols | table->grant.privilege)) if (want_access & ~(grant_table->cols | table->grant.privilege))
{ {
...@@ -2457,18 +2457,18 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -2457,18 +2457,18 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
!strcmp(lex_user->host.str,host)) !strcmp(lex_user->host.str,host))
{ {
want_access=grant_table->privs; want_access=grant_table->privs;
if (want_access) if ((want_access | grant_table->cols) != 0)
{ {
String global(buff,sizeof(buff)); String global(buff,sizeof(buff));
global.length(0); global.length(0);
global.append("GRANT ",6); global.append("GRANT ",6);
if (test_all_bits(want_access,(TABLE_ACLS & ~GRANT_ACL))) if (test_all_bits(grant_table->privs,(TABLE_ACLS & ~GRANT_ACL)))
global.append("ALL PRIVILEGES",14); global.append("ALL PRIVILEGES",14);
else else
{ {
int found=0; int found=0;
uint j,test_access= want_access & ~GRANT_ACL; uint j,test_access= (want_access | grant_table->cols) & ~GRANT_ACL;
for (counter=0, j = SELECT_ACL;j <= TABLE_ACLS; counter++,j <<= 1) for (counter=0, j = SELECT_ACL;j <= TABLE_ACLS; counter++,j <<= 1)
{ {
......
...@@ -136,7 +136,8 @@ static void copy_sum_funcs(Item_sum **func_ptr); ...@@ -136,7 +136,8 @@ static void copy_sum_funcs(Item_sum **func_ptr);
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab); static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
static void init_sum_functions(Item_sum **func); static void init_sum_functions(Item_sum **func);
static bool update_sum_func(Item_sum **func); static bool update_sum_func(Item_sum **func);
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order); static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
bool distinct);
static void describe_info(const char *info); static void describe_info(const char *info);
/***************************************************************************** /*****************************************************************************
...@@ -171,6 +172,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -171,6 +172,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
no_order=0; no_order=0;
bzero((char*) &keyuse,sizeof(keyuse)); bzero((char*) &keyuse,sizeof(keyuse));
thd->proc_info="init"; thd->proc_info="init";
thd->used_tables=0; // Updated by setup_fields
if (setup_fields(thd,tables,fields,1,&all_fields) || if (setup_fields(thd,tables,fields,1,&all_fields) ||
setup_conds(thd,tables,&conds) || setup_conds(thd,tables,&conds) ||
...@@ -261,7 +263,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -261,7 +263,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
join.join_tab=0; join.join_tab=0;
join.tmp_table_param.copy_field=0; join.tmp_table_param.copy_field=0;
join.sum_funcs=0; join.sum_funcs=0;
join.send_records=0L; join.send_records=join.found_records=0;
join.tmp_table_param.end_write_records= HA_POS_ERROR; join.tmp_table_param.end_write_records= HA_POS_ERROR;
join.first_record=join.sort_and_group=0; join.first_record=join.sort_and_group=0;
join.select_options=select_options; join.select_options=select_options;
...@@ -506,7 +508,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -506,7 +508,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
order=0; order=0;
select_describe(&join,need_tmp, select_describe(&join,need_tmp,
(order != 0 && (order != 0 &&
(!need_tmp || order != group || simple_group))); (!need_tmp || order != group || simple_group)),
select_distinct);
error=0; error=0;
goto err; goto err;
} }
...@@ -557,6 +560,26 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -557,6 +560,26 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
order=0; order=0;
} }
} }
/*
Optimize distinct when used on some of the tables
SELECT DISTINCT t1.a FROM t1,t2 WHERE t1.b=t2.b
In this case we can stop scanning t2 when we have found one t1.a
*/
if (tmp_table->distinct)
{
table_map used_tables= thd->used_tables;
JOIN_TAB *join_tab=join.join_tab+join.tables-1;
do
{
if (used_tables & join_tab->table->map)
break;
join_tab->not_used_in_distinct=1;
} while (join_tab-- != join.join_tab);
}
/* Copy data to the temporary table */
thd->proc_info="Copying to tmp table"; thd->proc_info="Copying to tmp table";
if (do_select(&join,(List<Item> *) 0,tmp_table,0)) if (do_select(&join,(List<Item> *) 0,tmp_table,0))
goto err; /* purecov: inspected */ goto err; /* purecov: inspected */
...@@ -2122,7 +2145,7 @@ make_simple_join(JOIN *join,TABLE *tmp_table) ...@@ -2122,7 +2145,7 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join->tmp_table_param.copy_field=0; join->tmp_table_param.copy_field=0;
join->first_record=join->sort_and_group=0; join->first_record=join->sort_and_group=0;
join->sum_funcs=0; join->sum_funcs=0;
join->send_records=0L; join->send_records=(ha_rows) 0;
join->group=0; join->group=0;
join_tab->cache.buff=0; /* No cacheing */ join_tab->cache.buff=0; /* No cacheing */
...@@ -2130,15 +2153,16 @@ make_simple_join(JOIN *join,TABLE *tmp_table) ...@@ -2130,15 +2153,16 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join_tab->select=0; join_tab->select=0;
join_tab->select_cond=0; join_tab->select_cond=0;
join_tab->quick=0; join_tab->quick=0;
bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record));
join_tab->type= JT_ALL; /* Map through all records */ join_tab->type= JT_ALL; /* Map through all records */
join_tab->keys= (uint) ~0; /* test everything in quick */ join_tab->keys= (uint) ~0; /* test everything in quick */
join_tab->info=0; join_tab->info=0;
join_tab->on_expr=0; join_tab->on_expr=0;
join_tab->ref.key = -1; join_tab->ref.key = -1;
join_tab->not_used_in_distinct=0;
join_tab->read_first_record= join_init_read_record;
bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record));
tmp_table->status=0; tmp_table->status=0;
tmp_table->null_row=0; tmp_table->null_row=0;
join_tab->read_first_record= join_init_read_record;
return FALSE; return FALSE;
} }
...@@ -3256,7 +3280,6 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ...@@ -3256,7 +3280,6 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (item->with_sum_func && type != Item::SUM_FUNC_ITEM || if (item->with_sum_func && type != Item::SUM_FUNC_ITEM ||
item->const_item()) item->const_item())
continue; continue;
if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields) if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields)
{ /* Can't calc group yet */ { /* Can't calc group yet */
((Item_sum*) item)->result_field=0; ((Item_sum*) item)->result_field=0;
...@@ -3913,7 +3936,9 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) ...@@ -3913,7 +3936,9 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
if (!(error=(*join_tab->read_first_record)(join_tab))) if (!(error=(*join_tab->read_first_record)(join_tab)))
{ {
bool not_exists_optimize=join_tab->table->reginfo.not_exists_optimize; bool not_exists_optimize= join_tab->table->reginfo.not_exists_optimize;
bool not_used_in_distinct=join_tab->not_used_in_distinct;
ha_rows found_records=join->found_records;
READ_RECORD *info= &join_tab->read_record; READ_RECORD *info= &join_tab->read_record;
do do
...@@ -3932,6 +3957,8 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) ...@@ -3932,6 +3957,8 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
{ {
if ((error=(*next_select)(join,join_tab+1,0)) < 0) if ((error=(*next_select)(join,join_tab+1,0)) < 0)
return error; return error;
if (not_used_in_distinct && found_records != join->found_records)
return 0;
} }
} }
} while (!(error=info->read_record(info))); } while (!(error=info->read_record(info)));
...@@ -4545,23 +4572,21 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), ...@@ -4545,23 +4572,21 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
} }
if (!join->having || join->having->val_int()) if (!join->having || join->having->val_int())
{ {
join->found_records++;
if ((error=table->file->write_row(table->record[0]))) if ((error=table->file->write_row(table->record[0])))
{ {
if (error != HA_ERR_FOUND_DUPP_KEY && if (error == HA_ERR_FOUND_DUPP_KEY ||
error != HA_ERR_FOUND_DUPP_UNIQUE) error == HA_ERR_FOUND_DUPP_UNIQUE)
{ goto end;
if (create_myisam_from_heap(table, &join->tmp_table_param, error,1)) if (create_myisam_from_heap(table, &join->tmp_table_param, error,1))
DBUG_RETURN(1); // Not a table_is_full error DBUG_RETURN(1); // Not a table_is_full error
table->uniques=0; // To ensure rows are the same table->uniques=0; // To ensure rows are the same
}
}
else
{
if (++join->send_records >= join->tmp_table_param.end_write_records) if (++join->send_records >= join->tmp_table_param.end_write_records)
DBUG_RETURN(-3); DBUG_RETURN(-3);
} }
} }
} }
end:
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -4585,6 +4610,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), ...@@ -4585,6 +4610,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_RETURN(-2); /* purecov: inspected */ DBUG_RETURN(-2); /* purecov: inspected */
} }
join->found_records++;
copy_fields(&join->tmp_table_param); // Groups are copied twice. copy_fields(&join->tmp_table_param); // Groups are copied twice.
/* Make a key of group index */ /* Make a key of group index */
for (group=table->group ; group ; group=group->next) for (group=table->group ; group ; group=group->next)
...@@ -6335,12 +6361,13 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) ...@@ -6335,12 +6361,13 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
** Send a description about what how the select will be done to stdout ** Send a description about what how the select will be done to stdout
****************************************************************************/ ****************************************************************************/
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order) static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
bool distinct)
{ {
DBUG_ENTER("select_describe");
List<Item> field_list; List<Item> field_list;
Item *item; Item *item;
THD *thd=join->thd;
DBUG_ENTER("select_describe");
field_list.push_back(new Item_empty_string("table",NAME_LEN)); field_list.push_back(new Item_empty_string("table",NAME_LEN));
field_list.push_back(new Item_empty_string("type",10)); field_list.push_back(new Item_empty_string("type",10));
...@@ -6356,11 +6383,12 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order) ...@@ -6356,11 +6383,12 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order)
item->maybe_null=1; item->maybe_null=1;
field_list.push_back(new Item_real("rows",0.0,0,10)); field_list.push_back(new Item_real("rows",0.0,0,10));
field_list.push_back(new Item_empty_string("Extra",255)); field_list.push_back(new Item_empty_string("Extra",255));
if (send_fields(join->thd,field_list,1)) if (send_fields(thd,field_list,1))
return; /* purecov: inspected */ return; /* purecov: inspected */
char buff[512],*buff_ptr; char buff[512],*buff_ptr;
String tmp(buff,sizeof(buff)),*packet= &join->thd->packet; String tmp(buff,sizeof(buff)),*packet= &thd->packet;
table_map used_tables=0;
for (uint i=0 ; i < join->tables ; i++) for (uint i=0 ; i < join->tables ; i++)
{ {
JOIN_TAB *tab=join->join_tab+i; JOIN_TAB *tab=join->join_tab+i;
...@@ -6473,11 +6501,22 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order) ...@@ -6473,11 +6501,22 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order)
} }
buff_ptr=strmov(buff_ptr,"Using filesort"); buff_ptr=strmov(buff_ptr,"Using filesort");
} }
if (distinct & test_all_bits(used_tables,thd->used_tables))
{
if (buff != buff_ptr)
{
buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
}
buff_ptr=strmov(buff_ptr,"Distinct");
}
net_store_data(packet,buff,(uint) (buff_ptr - buff)); net_store_data(packet,buff,(uint) (buff_ptr - buff));
if (my_net_write(&join->thd->net,(char*) packet->ptr(),packet->length())) if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_VOID_RETURN; /* purecov: inspected */ DBUG_VOID_RETURN; /* purecov: inspected */
// For next iteration
used_tables|=table->map;
} }
send_eof(&join->thd->net); send_eof(&thd->net);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
...@@ -79,36 +79,36 @@ class JOIN; ...@@ -79,36 +79,36 @@ class JOIN;
typedef struct st_join_table { typedef struct st_join_table {
TABLE *table; TABLE *table;
KEYUSE *keyuse; /* pointer to first used key */
SQL_SELECT *select;
COND *select_cond;
QUICK_SELECT *quick;
Item *on_expr;
const char *info;
int (*read_first_record)(struct st_join_table *tab); int (*read_first_record)(struct st_join_table *tab);
int (*next_select)(JOIN *,struct st_join_table *,bool); int (*next_select)(JOIN *,struct st_join_table *,bool);
bool cached_eq_ref_table,eq_ref_table;
READ_RECORD read_record; READ_RECORD read_record;
uint keys; /* all keys with can be used */ double worst_seeks;
key_map const_keys; /* Keys with constant part */ key_map const_keys; /* Keys with constant part */
key_map checked_keys; /* Keys checked in find_best */ key_map checked_keys; /* Keys checked in find_best */
key_map needed_reg; key_map needed_reg;
ha_rows records,found_records,read_time; ha_rows records,found_records,read_time;
table_map dependent,key_dependent; table_map dependent,key_dependent;
uint keys; /* all keys with can be used */
uint use_quick,index; uint use_quick,index;
uint status; // Save status for cache uint status; // Save status for cache
enum join_type type;
JOIN_CACHE cache;
KEYUSE *keyuse; /* pointer to first used key */
SQL_SELECT *select;
COND *select_cond;
QUICK_SELECT *quick;
Item *on_expr;
uint used_fields,used_fieldlength,used_blobs; uint used_fields,used_fieldlength,used_blobs;
const char *info; enum join_type type;
double worst_seeks; bool cached_eq_ref_table,eq_ref_table,not_used_in_distinct;
TABLE_REF ref; TABLE_REF ref;
JOIN_CACHE cache;
} JOIN_TAB; } JOIN_TAB;
typedef struct st_position { /* Used in find_best */ typedef struct st_position { /* Used in find_best */
double records_read;
JOIN_TAB *table; JOIN_TAB *table;
KEYUSE *key; KEYUSE *key;
double records_read;
} POSITION; } POSITION;
...@@ -116,16 +116,16 @@ typedef struct st_position { /* Used in find_best */ ...@@ -116,16 +116,16 @@ typedef struct st_position { /* Used in find_best */
class TMP_TABLE_PARAM { class TMP_TABLE_PARAM {
public: public:
uint copy_field_count,field_count,sum_func_count,func_count; List<Item> copy_funcs;
uint group_parts,group_length;
uint quick_group;
Copy_field *copy_field; Copy_field *copy_field;
byte *group_buff; byte *group_buff;
ha_rows end_write_records;
Item_result_field **funcs; Item_result_field **funcs;
List<Item> copy_funcs;
MI_COLUMNDEF *recinfo,*start_recinfo; MI_COLUMNDEF *recinfo,*start_recinfo;
KEY *keyinfo; KEY *keyinfo;
ha_rows end_write_records;
uint copy_field_count,field_count,sum_func_count,func_count;
uint group_parts,group_length;
uint quick_group;
TMP_TABLE_PARAM() :group_parts(0),group_length(0),copy_field(0) {} TMP_TABLE_PARAM() :group_parts(0),group_length(0),copy_field(0) {}
~TMP_TABLE_PARAM() ~TMP_TABLE_PARAM()
...@@ -148,7 +148,7 @@ class JOIN { ...@@ -148,7 +148,7 @@ class JOIN {
uint send_group_parts; uint send_group_parts;
bool sort_and_group,first_record,full_join,group, no_field_update; bool sort_and_group,first_record,full_join,group, no_field_update;
table_map const_table_map; table_map const_table_map;
ha_rows send_records; ha_rows send_records,found_records;
POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1]; POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1];
double best_read; double best_read;
List<Item> *fields; List<Item> *fields;
......
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