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

Fix bug in SELECT SQL_CALC_FOUND_ROWS

parent e68ebac9
...@@ -3433,6 +3433,11 @@ The following problems are known and will be fixed in due time: ...@@ -3433,6 +3433,11 @@ The following problems are known and will be fixed in due time:
When using @code{SET CHARACTER SET}, one can't use translated When using @code{SET CHARACTER SET}, one can't use translated
characters in database, table, and column names. characters in database, table, and column names.
@item
If you have a @code{DECIMAL} column with a number stored in different
formats (+01.00, 1.00, 01.00), @code{GROUP BY} may regard each value
as a different value.
@item @item
@code{DELETE FROM merge_table} used without a @code{WHERE} @code{DELETE FROM merge_table} used without a @code{WHERE}
will only clear the mapping for the table, not delete everything in the will only clear the mapping for the table, not delete everything in the
...@@ -16389,6 +16394,7 @@ to restart @code{mysqld} with @code{--skip-grant-tables} to run ...@@ -16389,6 +16394,7 @@ to restart @code{mysqld} with @code{--skip-grant-tables} to run
* Privilege changes:: When Privilege Changes Take Effect * Privilege changes:: When Privilege Changes Take Effect
* Default privileges:: Setting Up the Initial MySQL Privileges * Default privileges:: Setting Up the Initial MySQL Privileges
* Adding users:: Adding New Users to MySQL * Adding users:: Adding New Users to MySQL
* User resources::
* Passwords:: Setting Up Passwords * Passwords:: Setting Up Passwords
* Password security:: Keeping Your Password Secure * Password security:: Keeping Your Password Secure
* Secure connections:: Using Secure Connections * Secure connections:: Using Secure Connections
...@@ -16417,7 +16423,8 @@ GRANT priv_type [(column_list)] [, priv_type [(column_list)] ...] ...@@ -16417,7 +16423,8 @@ GRANT priv_type [(column_list)] [, priv_type [(column_list)] ...]
[CIPHER cipher [AND]] [CIPHER cipher [AND]]
[ISSUER issuer [AND]] [ISSUER issuer [AND]]
[SUBJECT subject]] [SUBJECT subject]]
[WITH [GRANT OPTION | MAX_QUERIES_PER_HOUR=#]] [WITH [GRANT OPTION | MAX_QUERIES_PER_HOUR=# | MAX_UPDATES_PER_HOUR=#|
MAX_CONNECTIONS_PER_HOUR=#]]
REVOKE priv_type [(column_list)] [, priv_type [(column_list)] ...] REVOKE priv_type [(column_list)] [, priv_type [(column_list)] ...]
ON @{tbl_name | * | *.* | db_name.*@} ON @{tbl_name | * | *.* | db_name.*@}
...@@ -16580,11 +16587,11 @@ to other users any privileges the user has at the specified privilege level. ...@@ -16580,11 +16587,11 @@ to other users any privileges the user has at the specified privilege level.
You should be careful to whom you give the @strong{grant} privilege, as two You should be careful to whom you give the @strong{grant} privilege, as two
users with different privileges may be able to join privileges! users with different privileges may be able to join privileges!
@code{MAX_QUERIES_PER_HOUR=#} limits the number of queries the user can @code{MAX_QUERIES_PER_HOUR=#}, @code{MAX_UPDATES_PER_HOUR=#} and
do during one hour. If @code{#} is 0, then this means that there is no @code{MAX_CONNECTIONS_PER_HOUR=#} limits the limits the number of
limit of the number of queries. This works by MySQL resetting a user queries/updates and logins the user can do during one hour.
specific query counter to 0, after it has gone more than one hour If @code{#} is 0 (default), then this means that there is no limitations
since the counter started incrementing. for the user. @xref{User resources}.
You cannot grant another user a privilege you don't have yourself; You cannot grant another user a privilege you don't have yourself;
the @strong{grant} privilege allows you to give away only those privileges the @strong{grant} privilege allows you to give away only those privileges
...@@ -16875,7 +16882,7 @@ you should copy them back from your MySQL distribution before ...@@ -16875,7 +16882,7 @@ you should copy them back from your MySQL distribution before
running @code{mysql_install_db}. running @code{mysql_install_db}.
@node Adding users, Passwords, Default privileges, User Account Management @node Adding users, User resources, Default privileges, User Account Management
@subsection Adding New Users to MySQL @subsection Adding New Users to MySQL
@findex GRANT statement @findex GRANT statement
...@@ -17068,7 +17075,72 @@ You can find these utilities in the Contrib directory of the ...@@ -17068,7 +17075,72 @@ You can find these utilities in the Contrib directory of the
MySQL web site (@uref{http://www.mysql.com/Downloads/Contrib/}). MySQL web site (@uref{http://www.mysql.com/Downloads/Contrib/}).
@node Passwords, Password security, Adding users, User Account Management @node User resources, Passwords, Adding users, User Account Management
@subsection Limiting user resources
Starting from MySQL 4.0.2 one can limit certain resources per user.
Before the only available method of limiting user usage of MySQL server
resources has been setting @code{max_user_connections} startup variable
to some non-zero value at MySQL startup. But this method is strictly a
global one and does not allow management of individual users, which
could be of paricular interest to Interent Service Providers.
Therefore, management of three resources is introduced on the
individual user level :
@itemize @bullet
@item
Number of all queries per hour
@item
Number of all updates per hour. As updates is considered any command that
changes any table or database.
@item
Number of connections made per hour
@end itemize
A user in the above context is single entry in user table, which is
uniquely identified by user and host columns.
All users are by default not limited in using the above resources,
unless the limits are GRANTed to them. These limits can be granted
ONLY by global GRANT (*.*) and with a following syntax :
@example
GRANT ... WITH MAX_QUERIES_PER_HOUR = N1 MAX_UPDATES_PER_HOUR = N2
MAX_CONNECTIONS_PER_HOUR = N3;
@end example
One can specify any combination of the above resources.
N1, N2 and N3 are integers and stands for count / hour.
If user reaches any of the above limits withing one hour, his connection
will be broken or refused and the appropriate error message shall be
issued.
Current values of particular user resources can be flushed (set to
zero) by issuing a grant statement with any of the above limiting
clauses, including a GRANT statement with current value(s) of tha
resource(s).
Also, current values for all users will be flushed if privileges are
reloaded or if the folloing new flush command is issuedd :
@example
FLUSH USER_RESOURCES
@end example
Also, current values for all users will be flushed with mysqladmin
reload command.
This new feature is enabled as soon as single user is @code{GRANT}ed with
some of the limiting @code{GRANT} clauses.
As a prerequisite for enabling this features, user table in mysql
database must have the additional columns, just as defined in table
creation scripts @code{mysql_install_db} in the @code{scripts} directory.
@node Passwords, Password security, User resources, User Account Management
@subsection Setting Up Passwords @subsection Setting Up Passwords
@findex PASSWORD() @findex PASSWORD()
...@@ -19377,6 +19449,7 @@ The status variables listed above have the following meaning: ...@@ -19377,6 +19449,7 @@ The status variables listed above have the following meaning:
@item @code{Delayed_writes} @tab Number of rows written with @code{INSERT DELAYED}. @item @code{Delayed_writes} @tab Number of rows written with @code{INSERT DELAYED}.
@item @code{Delayed_errors} @tab Number of rows written with @code{INSERT DELAYED} for which some error occurred (probably @code{duplicate key}). @item @code{Delayed_errors} @tab Number of rows written with @code{INSERT DELAYED} for which some error occurred (probably @code{duplicate key}).
@item @code{Flush_commands} @tab Number of executed @code{FLUSH} commands. @item @code{Flush_commands} @tab Number of executed @code{FLUSH} commands.
@item @code{Handler_commit} @tab Number of internal @code{COMMIT} commands.
@item @code{Handler_delete} @tab Number of times a row was deleted from a table. @item @code{Handler_delete} @tab Number of times a row was deleted from a table.
@item @code{Handler_read_first} @tab Number of times the first entry was read from an index. @item @code{Handler_read_first} @tab Number of times the first entry was read from an index.
If this is high, it suggests that the server is doing a lot of full index scans, for example, If this is high, it suggests that the server is doing a lot of full index scans, for example,
...@@ -19386,12 +19459,14 @@ is high, it is a good indication that your queries and tables are properly index ...@@ -19386,12 +19459,14 @@ is high, it is a good indication that your queries and tables are properly index
@item @code{Handler_read_next} @tab Number of requests to read next row in key order. This @item @code{Handler_read_next} @tab Number of requests to read next row in key order. This
will be incremented if you are querying an index column with a range constraint. This also will be incremented if you are querying an index column with a range constraint. This also
will be incremented if you are doing an index scan. will be incremented if you are doing an index scan.
@item @code{Handler_read_prev} @tab Number of requests to read previous row in key order. This is mainly used to optimize @code{ORDER BY ... DESC}.
@item @code{Handler_read_rnd} @tab Number of requests to read a row based on a fixed position. @item @code{Handler_read_rnd} @tab Number of requests to read a row based on a fixed position.
This will be high if you are doing a lot of queries that require sorting of the result. This will be high if you are doing a lot of queries that require sorting of the result.
@item @code{Handler_read_rnd_next} @tab Number of requests to read the next row in the datafile. @item @code{Handler_read_rnd_next} @tab Number of requests to read the next row in the datafile.
This will be high if you are doing a lot of table scans. Generally this suggests that your tables This will be high if you are doing a lot of table scans. Generally this suggests that your tables
are not properly indexed or that your queries are not written to take advantage of the indexes you are not properly indexed or that your queries are not written to take advantage of the indexes you
have. have.
@item @code{Handler_rollback} @tab Number of internal @code{ROLLBACK} commands.
@item @code{Handler_update} @tab Number of requests to update a row in a table. @item @code{Handler_update} @tab Number of requests to update a row in a table.
@item @code{Handler_write} @tab Number of requests to insert a row in a table. @item @code{Handler_write} @tab Number of requests to insert a row in a table.
@item @code{Key_blocks_used} @tab The number of used blocks in the key cache. @item @code{Key_blocks_used} @tab The number of used blocks in the key cache.
...@@ -19406,6 +19481,7 @@ have. ...@@ -19406,6 +19481,7 @@ have.
@item @code{Open_files} @tab Number of files that are open. @item @code{Open_files} @tab Number of files that are open.
@item @code{Open_streams} @tab Number of streams that are open (used mainly for logging). @item @code{Open_streams} @tab Number of streams that are open (used mainly for logging).
@item @code{Opened_tables} @tab Number of tables that have been opened. @item @code{Opened_tables} @tab Number of tables that have been opened.
@item @code{Rpl_status} @tab Status of failsafe replication. (Not yet in use).
@item @code{Select_full_join} @tab Number of joins without keys (Should be 0). @item @code{Select_full_join} @tab Number of joins without keys (Should be 0).
@item @code{Select_full_range_join} @tab Number of joins where we used a range search on reference table. @item @code{Select_full_range_join} @tab Number of joins where we used a range search on reference table.
@item @code{Select_range} @tab Number of joins where we used ranges on the first table. (It's normally not critical even if this is big.) @item @code{Select_range} @tab Number of joins where we used ranges on the first table. (It's normally not critical even if this is big.)
...@@ -19414,12 +19490,14 @@ have. ...@@ -19414,12 +19490,14 @@ have.
@item @code{Questions} @tab Number of queries sent to the server. @item @code{Questions} @tab Number of queries sent to the server.
@item @code{Slave_open_temp_tables} @tab Number of temporary tables currently @item @code{Slave_open_temp_tables} @tab Number of temporary tables currently
open by the slave thread open by the slave thread
@item @code{Slave_running} @tab Is @code{ON} if this is a slave that is connected to a master.
@item @code{Slow_launch_threads} @tab Number of threads that have taken more than @code{slow_launch_time} to connect. @item @code{Slow_launch_threads} @tab Number of threads that have taken more than @code{slow_launch_time} to connect.
@item @code{Slow_queries} @tab Number of queries that have taken more than @code{long_query_time}. @xref{Slow query log}. @item @code{Slow_queries} @tab Number of queries that have taken more than @code{long_query_time}. @xref{Slow query log}.
@item @code{Sort_merge_passes} @tab Number of merges the sort has to do. If this value is large you should consider increasing @code{sort_buffer}. @item @code{Sort_merge_passes} @tab Number of merges the sort has to do. If this value is large you should consider increasing @code{sort_buffer}.
@item @code{Sort_range} @tab Number of sorts that where done with ranges. @item @code{Sort_range} @tab Number of sorts that where done with ranges.
@item @code{Sort_rows} @tab Number of sorted rows. @item @code{Sort_rows} @tab Number of sorted rows.
@item @code{Sort_scan} @tab Number of sorts that where done by scanning the table. @item @code{Sort_scan} @tab Number of sorts that where done by scanning the table.
@item @code{ssl_xxx} @tab Variables used by SSL; Not yet implemented.
@item @code{Table_locks_immediate} @tab Number of times a table lock was @item @code{Table_locks_immediate} @tab Number of times a table lock was
acquired immediately. Available after 3.23.33. acquired immediately. Available after 3.23.33.
@item @code{Table_locks_waited} @tab Number of times a table lock could not @item @code{Table_locks_waited} @tab Number of times a table lock could not
...@@ -44293,7 +44371,7 @@ have both a normal and a thread-safe client library. ...@@ -44293,7 +44371,7 @@ have both a normal and a thread-safe client library.
To get a threaded client where you can interrupt the client from other To get a threaded client where you can interrupt the client from other
threads and set timeouts when talking with the MySQL server, you should threads and set timeouts when talking with the MySQL server, you should
use the @code{-lmysys}, @code{-lstring}, and @code{-ldbug} libraries and use the @code{-lmysys}, @code{-lmystrings}, and @code{-ldbug} libraries and
the @code{net_serv.o} code that the server uses. the @code{net_serv.o} code that the server uses.
If you don't need interrupts or timeouts, you can just compile a If you don't need interrupts or timeouts, you can just compile a
...@@ -49215,72 +49293,14 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}. ...@@ -49215,72 +49293,14 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}.
@itemize @bullet @itemize @bullet
@item @item
Fixed bug in DROP DATABASE with symlink Fixed bug in @code{DROP DATABASE} with symlink
@item @item
Fixed bug in EXPLAIN with LIMIT offset != 0 Fixed bug in @code{EXPLAIN} with @code{LIMIT offset != 0}
@item @item
Fixed bug in @code{SELECT SQL_CALC_FOUND_ROWS DISTINCT ... LIMIT #}
New feature : @item
Added limiting of user resources like queries per hour, updates per hour
Management of user resources and connections made per hour.
So far, the only available method of limiting user usage of MySQL
server resources has been setting max_user_connections startup
variable to some non-zero value at MySQL startup. But this method is
strictly a global one and does not allow management of individual
users, which could be of paricular interest to Interent Service
Providers.
Therefore, management of three resources is introduced on the
individual user level :
* number of all queries per hour
* number of all updates per hour
* number of connections made per hour
Small clarification : By the updates in the above sense is considered
any command that changes any table or database. Queries in the above
context comprehend all commands that could be run by user. User in the
above context comprehends a single entry in user table, which is
uniquely identified by user and host columns.
All users are by default not limited in using the above resources,
unless the limits are GRANTed to them. These limits can be granted
ONLY by global GRANT (*.*) and with a following syntax :
GRANT ... WITH MAX_QUERIES_PER_HOUR = N1 MAX_UPDATES_PER_HOUR = N2
MAX_CONNECTIONS_PER_HOUR = N3;
It is not required that all three resources are specified. One or two
can be specified also. N1,N2 and N3 are intergers and should limit
number of times user can execute any command, update command or can
login that many times per hour.
If user reaches any of the above limits withing one hour, his
connection will be broken or refused and the appropriate error message
shall be issued.
Current values of particular user resources can be flushed (set to
zero) by issuing a grant statement with any of the above limiting
clauses, including a GRANT statement with current value(s) of tha
resource(s).
Also, current values for all users will be flushed if privileges are
reloaded or if a new flush command is issued :
flush user_resources.
Also, current values for all users will be flushed with mysqladmin
reload command.
This new feature is enabled as soon as single user is GRANTed with
some of the limiting GRANT clauses.
As a prerequisite for enabling this features, user table in mysql
database must have the additional columns, just as defined in table
creation scripts mysql_install_db and mysql_install_db.sh in scripts/
directory.
@item @item
New configure option --without-query-cache. New configure option --without-query-cache.
@item @item
...@@ -55339,7 +55359,7 @@ New math functions: ...@@ -55339,7 +55359,7 @@ New math functions:
The @code{configure} source now compiles a thread-free client library The @code{configure} source now compiles a thread-free client library
@code{-lmysqlclient}. This is the only library that needs to be linked @code{-lmysqlclient}. This is the only library that needs to be linked
with client applications. When using the binary releases, you must with client applications. When using the binary releases, you must
link with @code{-lmysql -lmysys -ldbug -lstrings} as before. link with @code{-lmysql -lmysys -ldbug -lmystrings} as before.
@item @item
New @code{readline} library from @code{bash-2.0}. New @code{readline} library from @code{bash-2.0}.
@item @item
...@@ -122,7 +122,6 @@ MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con, ...@@ -122,7 +122,6 @@ MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con,
memcpy_fixed(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr)); memcpy_fixed(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr));
} }
else else
#if defined(HAVE_GETHOSTBYNAME_R) && defined(_REENTRANT) && defined(THREAD)
{ {
int tmp_errno; int tmp_errno;
struct hostent tmp_hostent,*hp; struct hostent tmp_hostent,*hp;
...@@ -133,22 +132,12 @@ MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con, ...@@ -133,22 +132,12 @@ MYSQL_MANAGER* STDCALL mysql_manager_connect(MYSQL_MANAGER* con,
{ {
con->last_errno=tmp_errno; con->last_errno=tmp_errno;
sprintf(con->last_error,"Could not resolve host '%s'",host); sprintf(con->last_error,"Could not resolve host '%s'",host);
my_gethostbyname_r_free();
goto err; goto err;
} }
memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length); memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
my_gethostbyname_r_free();
} }
#else
{
struct hostent *hp;
if (!(hp=gethostbyname(host)))
{
con->last_errno=socket_errno;
sprintf(con->last_error, "Could not resolve host '%s'", host);
goto err;
}
memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length);
}
#endif
sock_addr.sin_port = (ushort) htons((ushort) port); sock_addr.sin_port = (ushort) htons((ushort) port);
if (my_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr), if (my_connect(sock,(struct sockaddr *) &sock_addr, sizeof(sock_addr),
0) <0) 0) <0)
......
drop table if exists t1; drop table if exists t1,t2;
create table t1 (a int not null auto_increment, b int not null, primary key(a)); create table t1 (a int not null auto_increment, b int not null, primary key(a));
insert into t1 (b) values (2),(3),(5),(5),(5),(6),(7),(9); insert into t1 (b) values (2),(3),(5),(5),(5),(6),(7),(9);
select SQL_CALC_FOUND_ROWS * from t1; select SQL_CALC_FOUND_ROWS * from t1;
...@@ -66,5 +66,90 @@ a ...@@ -66,5 +66,90 @@ a
2 2
select FOUND_ROWS(); select FOUND_ROWS();
FOUND_ROWS() FOUND_ROWS()
3 5
drop table t1; drop table t1;
CREATE TABLE t1 (
`id` smallint(5) unsigned NOT NULL auto_increment,
`kid` smallint(5) unsigned NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `kid` (`kid`)
);
CREATE TABLE t2 (
id smallint(5) unsigned NOT NULL auto_increment,
name varchar(50) NOT NULL default '',
email varchar(50) NOT NULL default '',
PRIMARY KEY (id),
UNIQUE KEY e_n (email,name)
);
INSERT INTO t2 VALUES (1,'name1','email1'),(2,'name2','email2'),(3,'name3','email3'),(4,'name4','email4'),(5,'name5','email5'),(6,'name6','email6'),(7,'name7','email7'),(8,'name8','email8'),(9,'name9','email9'),(10,'name10','email10'),(11,'name11','email11'),(12,'name12','email12'),(13,'name13','email13'),(14,'name14','email14'),(15,'name15','email15'),(16,'name16','email16'),(17,'name17','email17'),(18,'name18','email18'),(19,'name19','email19'),(20,'name20','email20'),(21,'name21','email21'),(22,'name22','email22'),(23,'name23','email23'),(24,'name24','email24'),(25,'name25','email25'),(26,'name26','email26'),(27,'name27','email27'),(28,'name28','email28'),(29,'name29','email29'),(30,'name30','email30'),(31,'name31','email31'),(32,'name32','email32'),(33,'name33','email33'),(34,'name34','email34'),(35,'name35','email35'),(36,'name36','email36'),(37,'name37','email37'),(38,'name38','email38'),(39,'name39','email39'),(40,'name40','email40'),(41,'name41','email41'),(42,'name42','email42'),(43,'name43','email43'),(44,'name44','email44'),(45,'name45','email45'),(46,'name46','email46'),(47,'name47','email47'),(48,'name48','email48'),(49,'name49','email49'),(50,'name50','email50'),(51,'name51','email51'),(52,'name52','email52'),(53,'name53','email53'),(54,'name54','email54'),(55,'name55','email55'),(56,'name56','email56'),(57,'name57','email57'),(58,'name58','email58'),(59,'name59','email59'),(60,'name60','email60'),(61,'name61','email61'),(62,'name62','email62'),(63,'name63','email63'),(64,'name64','email64'),(65,'name65','email65'),(66,'name66','email66'),(67,'name67','email67'),(68,'name68','email68'),(69,'name69','email69'),(70,'name70','email70'),(71,'name71','email71'),(72,'name72','email72'),(73,'name73','email73'),(74,'name74','email74'),(75,'name75','email75'),(76,'name76','email76'),(77,'name77','email77'),(78,'name78','email78'),(79,'name79','email79'),(80,'name80','email80'),(81,'name81','email81'),(82,'name82','email82'),(83,'name83','email83'),(84,'name84','email84'),(85,'name85','email85'),(86,'name86','email86'),(87,'name87','email87'),(88,'name88','email88'),(89,'name89','email89'),(90,'name90','email90'),(91,'name91','email91'),(92,'name92','email92'),(93,'name93','email93'),(94,'name94','email94'),(95,'name95','email95'),(96,'name96','email96'),(97,'name97','email97'),(98,'name98','email98'),(99,'name99','email99'),(100,'name100','email100'),(101,'name101','email101'),(102,'name102','email102'),(103,'name103','email103'),(104,'name104','email104'),(105,'name105','email105'),(106,'name106','email106'),(107,'name107','email107'),(108,'name108','email108'),(109,'name109','email109'),(110,'name110','email110'),(111,'name111','email111'),(112,'name112','email112'),(113,'name113','email113'),(114,'name114','email114'),(115,'name115','email115'),(116,'name116','email116'),(117,'name117','email117'),(118,'name118','email118'),(119,'name119','email119'),(120,'name120','email120'),(121,'name121','email121'),(122,'name122','email122'),(123,'name123','email123'),(124,'name124','email124'),(125,'name125','email125'),(126,'name126','email126'),(127,'name127','email127'),(128,'name128','email128'),(129,'name129','email129'),(130,'name130','email130'),(131,'name131','email131'),(132,'name132','email132'),(133,'name133','email133'),(134,'name134','email134'),(135,'name135','email135'),(136,'name136','email136'),(137,'name137','email137'),(138,'name138','email138'),(139,'name139','email139'),(140,'name140','email140'),(141,'name141','email141'),(142,'name142','email142'),(143,'name143','email143'),(144,'name144','email144'),(145,'name145','email145'),(146,'name146','email146'),(147,'name147','email147'),(148,'name148','email148'),(149,'name149','email149'),(150,'name150','email150'),(151,'name151','email151'),(152,'name152','email152'),(153,'name153','email153'),(154,'name154','email154'),(155,'name155','email155'),(156,'name156','email156'),(157,'name157','email157'),(158,'name158','email158'),(159,'name159','email159'),(160,'name160','email160'),(161,'name161','email161'),(162,'name162','email162'),(163,'name163','email163'),(164,'name164','email164'),(165,'name165','email165'),(166,'name166','email166'),(167,'name167','email167'),(168,'name168','email168'),(169,'name169','email169'),(170,'name170','email170'),(171,'name171','email171'),(172,'name172','email172'),(173,'name173','email173'),(174,'name174','email174'),(175,'name175','email175'),(176,'name176','email176'),(177,'name177','email177'),(178,'name178','email178'),(179,'name179','email179'),(180,'name180','email180'),(181,'name181','email181'),(182,'name182','email182'),(183,'name183','email183'),(184,'name184','email184'),(185,'name185','email185'),(186,'name186','email186'),(187,'name187','email187'),(188,'name188','email188'),(189,'name189','email189'),(190,'name190','email190'),(191,'name191','email191'),(192,'name192','email192'),(193,'name193','email193'),(194,'name194','email194'),(195,'name195','email195'),(196,'name196','email196'),(197,'name197','email197'),(198,'name198','email198'),(199,'name199','email199'),(200,'name200','email200');
SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10;
email
email1
email10
email100
email101
email102
email103
email104
email105
email106
email107
SELECT FOUND_ROWS();
FOUND_ROWS()
200
SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL order by email LIMIT 10;
email
email1
email10
email100
email101
email102
email103
email104
email105
email106
email107
SELECT FOUND_ROWS();
FOUND_ROWS()
200
SELECT DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10;
email
email1
email2
email3
email4
email5
email6
email7
email8
email9
email10
SELECT DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL ORDER BY email LIMIT 10;
email
email1
email10
email100
email101
email102
email103
email104
email105
email106
email107
INSERT INTO `t1` (`id`, `kid`) VALUES ('', '150');
SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10;
email
email1
email2
email3
email4
email5
email6
email7
email8
email9
email10
SELECT FOUND_ROWS();
FOUND_ROWS()
199
drop table t1,t2;
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Testing of found_rows() # Testing of found_rows()
# #
drop table if exists t1; drop table if exists t1,t2;
create table t1 (a int not null auto_increment, b int not null, primary key(a)); create table t1 (a int not null auto_increment, b int not null, primary key(a));
insert into t1 (b) values (2),(3),(5),(5),(5),(6),(7),(9); insert into t1 (b) values (2),(3),(5),(5),(5),(6),(7),(9);
select SQL_CALC_FOUND_ROWS * from t1; select SQL_CALC_FOUND_ROWS * from t1;
...@@ -32,3 +32,39 @@ select FOUND_ROWS(); ...@@ -32,3 +32,39 @@ select FOUND_ROWS();
select sql_calc_found_rows a from t1 where a in (1,2,3) order by a+2 desc limit 0,2; select sql_calc_found_rows a from t1 where a in (1,2,3) order by a+2 desc limit 0,2;
select FOUND_ROWS(); select FOUND_ROWS();
drop table t1; drop table t1;
#
# Test of SQL_CALC_FOUND_ROWS with DISTINCT
#
CREATE TABLE t1 (
`id` smallint(5) unsigned NOT NULL auto_increment,
`kid` smallint(5) unsigned NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `kid` (`kid`)
);
CREATE TABLE t2 (
id smallint(5) unsigned NOT NULL auto_increment,
name varchar(50) NOT NULL default '',
email varchar(50) NOT NULL default '',
PRIMARY KEY (id),
UNIQUE KEY e_n (email,name)
);
INSERT INTO t2 VALUES (1,'name1','email1'),(2,'name2','email2'),(3,'name3','email3'),(4,'name4','email4'),(5,'name5','email5'),(6,'name6','email6'),(7,'name7','email7'),(8,'name8','email8'),(9,'name9','email9'),(10,'name10','email10'),(11,'name11','email11'),(12,'name12','email12'),(13,'name13','email13'),(14,'name14','email14'),(15,'name15','email15'),(16,'name16','email16'),(17,'name17','email17'),(18,'name18','email18'),(19,'name19','email19'),(20,'name20','email20'),(21,'name21','email21'),(22,'name22','email22'),(23,'name23','email23'),(24,'name24','email24'),(25,'name25','email25'),(26,'name26','email26'),(27,'name27','email27'),(28,'name28','email28'),(29,'name29','email29'),(30,'name30','email30'),(31,'name31','email31'),(32,'name32','email32'),(33,'name33','email33'),(34,'name34','email34'),(35,'name35','email35'),(36,'name36','email36'),(37,'name37','email37'),(38,'name38','email38'),(39,'name39','email39'),(40,'name40','email40'),(41,'name41','email41'),(42,'name42','email42'),(43,'name43','email43'),(44,'name44','email44'),(45,'name45','email45'),(46,'name46','email46'),(47,'name47','email47'),(48,'name48','email48'),(49,'name49','email49'),(50,'name50','email50'),(51,'name51','email51'),(52,'name52','email52'),(53,'name53','email53'),(54,'name54','email54'),(55,'name55','email55'),(56,'name56','email56'),(57,'name57','email57'),(58,'name58','email58'),(59,'name59','email59'),(60,'name60','email60'),(61,'name61','email61'),(62,'name62','email62'),(63,'name63','email63'),(64,'name64','email64'),(65,'name65','email65'),(66,'name66','email66'),(67,'name67','email67'),(68,'name68','email68'),(69,'name69','email69'),(70,'name70','email70'),(71,'name71','email71'),(72,'name72','email72'),(73,'name73','email73'),(74,'name74','email74'),(75,'name75','email75'),(76,'name76','email76'),(77,'name77','email77'),(78,'name78','email78'),(79,'name79','email79'),(80,'name80','email80'),(81,'name81','email81'),(82,'name82','email82'),(83,'name83','email83'),(84,'name84','email84'),(85,'name85','email85'),(86,'name86','email86'),(87,'name87','email87'),(88,'name88','email88'),(89,'name89','email89'),(90,'name90','email90'),(91,'name91','email91'),(92,'name92','email92'),(93,'name93','email93'),(94,'name94','email94'),(95,'name95','email95'),(96,'name96','email96'),(97,'name97','email97'),(98,'name98','email98'),(99,'name99','email99'),(100,'name100','email100'),(101,'name101','email101'),(102,'name102','email102'),(103,'name103','email103'),(104,'name104','email104'),(105,'name105','email105'),(106,'name106','email106'),(107,'name107','email107'),(108,'name108','email108'),(109,'name109','email109'),(110,'name110','email110'),(111,'name111','email111'),(112,'name112','email112'),(113,'name113','email113'),(114,'name114','email114'),(115,'name115','email115'),(116,'name116','email116'),(117,'name117','email117'),(118,'name118','email118'),(119,'name119','email119'),(120,'name120','email120'),(121,'name121','email121'),(122,'name122','email122'),(123,'name123','email123'),(124,'name124','email124'),(125,'name125','email125'),(126,'name126','email126'),(127,'name127','email127'),(128,'name128','email128'),(129,'name129','email129'),(130,'name130','email130'),(131,'name131','email131'),(132,'name132','email132'),(133,'name133','email133'),(134,'name134','email134'),(135,'name135','email135'),(136,'name136','email136'),(137,'name137','email137'),(138,'name138','email138'),(139,'name139','email139'),(140,'name140','email140'),(141,'name141','email141'),(142,'name142','email142'),(143,'name143','email143'),(144,'name144','email144'),(145,'name145','email145'),(146,'name146','email146'),(147,'name147','email147'),(148,'name148','email148'),(149,'name149','email149'),(150,'name150','email150'),(151,'name151','email151'),(152,'name152','email152'),(153,'name153','email153'),(154,'name154','email154'),(155,'name155','email155'),(156,'name156','email156'),(157,'name157','email157'),(158,'name158','email158'),(159,'name159','email159'),(160,'name160','email160'),(161,'name161','email161'),(162,'name162','email162'),(163,'name163','email163'),(164,'name164','email164'),(165,'name165','email165'),(166,'name166','email166'),(167,'name167','email167'),(168,'name168','email168'),(169,'name169','email169'),(170,'name170','email170'),(171,'name171','email171'),(172,'name172','email172'),(173,'name173','email173'),(174,'name174','email174'),(175,'name175','email175'),(176,'name176','email176'),(177,'name177','email177'),(178,'name178','email178'),(179,'name179','email179'),(180,'name180','email180'),(181,'name181','email181'),(182,'name182','email182'),(183,'name183','email183'),(184,'name184','email184'),(185,'name185','email185'),(186,'name186','email186'),(187,'name187','email187'),(188,'name188','email188'),(189,'name189','email189'),(190,'name190','email190'),(191,'name191','email191'),(192,'name192','email192'),(193,'name193','email193'),(194,'name194','email194'),(195,'name195','email195'),(196,'name196','email196'),(197,'name197','email197'),(198,'name198','email198'),(199,'name199','email199'),(200,'name200','email200');
SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10;
SELECT FOUND_ROWS();
SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL order by email LIMIT 10;
SELECT FOUND_ROWS();
SELECT DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10;
SELECT DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL ORDER BY email LIMIT 10;
INSERT INTO `t1` (`id`, `kid`) VALUES ('', '150');
SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10;
SELECT FOUND_ROWS();
drop table t1,t2;
...@@ -3734,12 +3734,12 @@ struct show_var_st status_vars[]= { ...@@ -3734,12 +3734,12 @@ struct show_var_st status_vars[]= {
{"Com_show_grants", (char*) (com_stat+(uint) SQLCOM_SHOW_GRANTS),SHOW_LONG}, {"Com_show_grants", (char*) (com_stat+(uint) SQLCOM_SHOW_GRANTS),SHOW_LONG},
{"Com_show_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG}, {"Com_show_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG},
{"Com_show_logs", (char*) (com_stat+(uint) SQLCOM_SHOW_LOGS),SHOW_LONG}, {"Com_show_logs", (char*) (com_stat+(uint) SQLCOM_SHOW_LOGS),SHOW_LONG},
{"Com_show_master_stat", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG}, {"Com_show_master_status", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG},
{"Com_show_new_master", (char*) (com_stat+(uint) SQLCOM_SHOW_NEW_MASTER),SHOW_LONG}, {"Com_show_new_master", (char*) (com_stat+(uint) SQLCOM_SHOW_NEW_MASTER),SHOW_LONG},
{"Com_show_open_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_OPEN_TABLES),SHOW_LONG}, {"Com_show_open_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_OPEN_TABLES),SHOW_LONG},
{"Com_show_processlist", (char*) (com_stat+(uint) SQLCOM_SHOW_PROCESSLIST),SHOW_LONG}, {"Com_show_processlist", (char*) (com_stat+(uint) SQLCOM_SHOW_PROCESSLIST),SHOW_LONG},
{"Com_show_slave_hosts", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_HOSTS),SHOW_LONG}, {"Com_show_slave_hosts", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_HOSTS),SHOW_LONG},
{"Com_show_slave_stat", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG}, {"Com_show_slave_status", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG},
{"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG}, {"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG},
{"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG}, {"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG},
{"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG}, {"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG},
...@@ -3807,29 +3807,29 @@ struct show_var_st status_vars[]= { ...@@ -3807,29 +3807,29 @@ struct show_var_st status_vars[]= {
{"Sort_rows", (char*) &filesort_rows, SHOW_LONG}, {"Sort_rows", (char*) &filesort_rows, SHOW_LONG},
{"Sort_scan", (char*) &filesort_scan_count, SHOW_LONG}, {"Sort_scan", (char*) &filesort_scan_count, SHOW_LONG},
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
{"ssl_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT}, {"Ssl_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT},
{"ssl_finished_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_GOOD}, {"Ssl_finished_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_GOOD},
{"ssl_finished_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_GOOD}, {"Ssl_finished_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_GOOD},
{"ssl_accept_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE}, {"Ssl_accept_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE},
{"ssl_connect_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE}, {"Ssl_connect_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE},
{"ssl_callback_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_CB_HITS}, {"Ssl_callback_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_CB_HITS},
{"ssl_session_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_HITS}, {"Ssl_session_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_HITS},
{"ssl_session_cache_misses", (char*) 0, SHOW_SSL_CTX_SESS_MISSES}, {"Ssl_session_cache_misses", (char*) 0, SHOW_SSL_CTX_SESS_MISSES},
{"ssl_session_cache_timeouts", (char*) 0, SHOW_SSL_CTX_SESS_TIMEOUTS}, {"Ssl_session_cache_timeouts", (char*) 0, SHOW_SSL_CTX_SESS_TIMEOUTS},
{"ssl_used_session_cache_entries",(char*) 0, SHOW_SSL_CTX_SESS_NUMBER}, {"Ssl_used_session_cache_entries",(char*) 0, SHOW_SSL_CTX_SESS_NUMBER},
{"ssl_client_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT}, {"Ssl_client_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT},
{"ssl_session_cache_overflows", (char*) 0, SHOW_SSL_CTX_SESS_CACHE_FULL}, {"Ssl_session_cache_overflows", (char*) 0, SHOW_SSL_CTX_SESS_CACHE_FULL},
{"ssl_session_cache_size", (char*) 0, SHOW_SSL_CTX_SESS_GET_CACHE_SIZE}, {"Ssl_session_cache_size", (char*) 0, SHOW_SSL_CTX_SESS_GET_CACHE_SIZE},
{"ssl_session_cache_mode", (char*) 0, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE}, {"Ssl_session_cache_mode", (char*) 0, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE},
{"ssl_sessions_reused", (char*) 0, SHOW_SSL_SESSION_REUSED}, {"Ssl_sessions_reused", (char*) 0, SHOW_SSL_SESSION_REUSED},
{"ssl_ctx_verify_mode", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_MODE}, {"Ssl_ctx_verify_mode", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_MODE},
{"ssl_ctx_verify_depth", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_DEPTH}, {"Ssl_ctx_verify_depth", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_DEPTH},
{"ssl_verify_mode", (char*) 0, SHOW_SSL_GET_VERIFY_MODE}, {"Ssl_verify_mode", (char*) 0, SHOW_SSL_GET_VERIFY_MODE},
{"ssl_verify_depth", (char*) 0, SHOW_SSL_GET_VERIFY_DEPTH}, {"Ssl_verify_depth", (char*) 0, SHOW_SSL_GET_VERIFY_DEPTH},
{"ssl_version", (char*) 0, SHOW_SSL_GET_VERSION}, {"Ssl_version", (char*) 0, SHOW_SSL_GET_VERSION},
{"ssl_cipher", (char*) 0, SHOW_SSL_GET_CIPHER}, {"Ssl_cipher", (char*) 0, SHOW_SSL_GET_CIPHER},
{"ssl_cipher_list", (char*) 0, SHOW_SSL_GET_CIPHER_LIST}, {"Ssl_cipher_list", (char*) 0, SHOW_SSL_GET_CIPHER_LIST},
{"ssl_default_timeout", (char*) 0, SHOW_SSL_GET_DEFAULT_TIMEOUT}, {"Ssl_default_timeout", (char*) 0, SHOW_SSL_GET_DEFAULT_TIMEOUT},
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
{"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG}, {"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG},
{"Table_locks_waited", (char*) &locks_waited, SHOW_LONG}, {"Table_locks_waited", (char*) &locks_waited, SHOW_LONG},
......
...@@ -501,8 +501,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -501,8 +501,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
select_distinct=0; select_distinct=0;
} }
else if (select_distinct && join.tables - join.const_tables == 1 && else if (select_distinct && join.tables - join.const_tables == 1 &&
((thd->select_limit == HA_POS_ERROR || (thd->select_limit == HA_POS_ERROR ||
(join.select_options & OPTION_FOUND_ROWS)) && (join.select_options & OPTION_FOUND_ROWS) ||
order && order &&
!(skip_sort_order= !(skip_sort_order=
test_if_skip_sort_order(&join.join_tab[join.const_tables], test_if_skip_sort_order(&join.join_tab[join.const_tables],
...@@ -4899,11 +4899,12 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), ...@@ -4899,11 +4899,12 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
JOIN_TAB *jt=join->join_tab; JOIN_TAB *jt=join->join_tab;
if ((join->tables == 1) && !join->tmp_table && !join->sort_and_group if ((join->tables == 1) && !join->tmp_table && !join->sort_and_group
&& !join->send_group_parts && !join->having && !jt->select_cond && && !join->send_group_parts && !join->having && !jt->select_cond &&
!(jt->table->file->table_flags() & HA_NOT_EXACT_COUNT) && (jt->records < INT_MAX32)) !(jt->table->file->table_flags() & HA_NOT_EXACT_COUNT))
{ {
/* Join over all rows in table; Return number of found rows */ /* Join over all rows in table; Return number of found rows */
join->select_options ^= OPTION_FOUND_ROWS; join->select_options ^= OPTION_FOUND_ROWS;
join->send_records = jt->records; jt->table->file->info(HA_STATUS_VARIABLE);
join->send_records = jt->table->file->records;
} }
else else
{ {
...@@ -4941,10 +4942,9 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), ...@@ -4941,10 +4942,9 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
join->procedure->end_group(); join->procedure->end_group();
if (idx < (int) join->send_group_parts) if (idx < (int) join->send_group_parts)
{ {
int error; int error=0;
if (join->procedure) if (join->procedure)
{ {
error=0;
if (join->having && join->having->val_int() == 0) if (join->having && join->having->val_int() == 0)
error= -1; // Didn't satisfy having error= -1; // Didn't satisfy having
else if (join->do_send_rows) else if (join->do_send_rows)
...@@ -4962,13 +4962,11 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), ...@@ -4962,13 +4962,11 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
} }
if (join->having && join->having->val_int() == 0) if (join->having && join->having->val_int() == 0)
error= -1; // Didn't satisfy having error= -1; // Didn't satisfy having
else else if (join->do_send_rows)
error=join->result->send_data(*join->fields) ? 1 : 0; error=join->result->send_data(*join->fields) ? 1 : 0;
} }
if (error > 0) if (error > 0)
DBUG_RETURN(-1); /* purecov: inspected */ DBUG_RETURN(-1); /* purecov: inspected */
if (end_of_records)
DBUG_RETURN(0);
if (!error && ++join->send_records >= join->thd->select_limit && if (!error && ++join->send_records >= join->thd->select_limit &&
join->do_send_rows) join->do_send_rows)
{ {
...@@ -4977,6 +4975,8 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), ...@@ -4977,6 +4975,8 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
join->do_send_rows=0; join->do_send_rows=0;
join->thd->select_limit = HA_POS_ERROR; join->thd->select_limit = HA_POS_ERROR;
} }
if (end_of_records)
DBUG_RETURN(0);
} }
} }
else else
......
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