summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xBuild-tools/mysql-copyright8
-rw-r--r--include/myisam.h2
-rw-r--r--innobase/data/data0type.c84
-rw-r--r--innobase/include/data0type.h46
-rw-r--r--innobase/include/data0type.ic97
-rw-r--r--innobase/rem/rem0cmp.c16
-rw-r--r--libmysql/client_settings.h2
-rw-r--r--libmysql/libmysql.c15
-rw-r--r--myisam/mi_check.c8
-rw-r--r--mysql-test/r/ctype_utf8.result4
-rw-r--r--mysql-test/r/gis-rtree.result40
-rw-r--r--mysql-test/r/key.result21
-rw-r--r--mysql-test/r/myisam.result10
-rw-r--r--mysql-test/r/type_blob.result10
-rw-r--r--mysql-test/t/ctype_utf8.test2
-rw-r--r--mysql-test/t/gis-rtree.test36
-rw-r--r--mysql-test/t/key.test13
-rw-r--r--mysql-test/t/myisam.test6
-rw-r--r--mysql-test/t/type_blob.test4
-rw-r--r--mysys/my_init.c4
-rw-r--r--mysys/mysys_priv.h5
-rw-r--r--sql-common/client.c2
-rw-r--r--sql/ha_innodb.cc27
-rw-r--r--sql/ha_myisam.h1
-rw-r--r--sql/hostname.cc3
-rw-r--r--sql/item.cc4
-rw-r--r--sql/item.h25
-rw-r--r--sql/item_cmpfunc.cc22
-rw-r--r--sql/item_cmpfunc.h9
-rw-r--r--sql/item_func.h5
-rw-r--r--sql/item_subselect.cc300
-rw-r--r--sql/item_subselect.h24
-rw-r--r--sql/item_sum.cc4
-rw-r--r--sql/item_sum.h2
-rw-r--r--sql/mysql_priv.h10
-rw-r--r--sql/sql_base.cc14
-rw-r--r--sql/sql_class.cc23
-rw-r--r--sql/sql_class.h89
-rw-r--r--sql/sql_lex.cc20
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_list.h2
-rw-r--r--sql/sql_prepare.cc125
-rw-r--r--sql/sql_select.cc11
-rw-r--r--sql/sql_union.cc6
-rw-r--r--tests/client_test.c96
45 files changed, 910 insertions, 349 deletions
diff --git a/Build-tools/mysql-copyright b/Build-tools/mysql-copyright
index a798ee7ab65..004476ff92c 100755
--- a/Build-tools/mysql-copyright
+++ b/Build-tools/mysql-copyright
@@ -101,8 +101,12 @@ sub main
unlink("$destdir/PUBLIC", "$destdir/README");
copy("$WD/Docs/MySQLEULA.txt", "$destdir");
- # remove readline subdir
- `rm -rf $destdir/cmd-line-utils/readline`;
+ # remove readline subdir and update configure accordingly
+ system("rm -rf $destdir/cmd-line-utils/readline");
+ unlink ("$destdir/configure") or die "Can't delete $destdir/configure: $!\n";
+ `(cd $destdir ; sed -e 's!\ cmd-line-utils\/readline\/Makefile\ dnl!!g' < configure.in > configure.in.new)`;
+ rename ("$destdir/configure.in.new","$destdir/configure.in") or die "Can't rename $destdir/configure.in.new: $!\n";;
+ `(cd $destdir ; autoconf)`;
# fix file copyrights
&fix_usage_copyright();
diff --git a/include/myisam.h b/include/myisam.h
index f4ef4695016..ed4f4aff8fe 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -38,7 +38,7 @@ extern "C" {
/* The following defines can be increased if necessary */
#define MI_MAX_KEY 32 /* Max allowed keys */
#define MI_MAX_KEY_SEG 16 /* Max segments for key */
-#define MI_MAX_KEY_LENGTH 500
+#define MI_MAX_KEY_LENGTH 1000
#define MI_MAX_KEY_BUFF (MI_MAX_KEY_LENGTH+MI_MAX_KEY_SEG*6+8+8)
#define MI_MAX_POSSIBLE_KEY_BUFF (1024+6+6) /* For myisam_chk */
diff --git a/innobase/data/data0type.c b/innobase/data/data0type.c
index 39c80b773a2..71ce5ff3d58 100644
--- a/innobase/data/data0type.c
+++ b/innobase/data/data0type.c
@@ -18,11 +18,93 @@ column definitions, or records in the insert buffer, we use this
charset-collation code for them. */
ulint data_mysql_default_charset_coll = 99999999;
+ulint data_mysql_latin1_swedish_charset_coll = 99999999;
-dtype_t dtype_binary_val = {DATA_BINARY, 0, 0, 0, 0};
+dtype_t dtype_binary_val = {DATA_BINARY, 0, 0, 0};
dtype_t* dtype_binary = &dtype_binary_val;
/*************************************************************************
+Checks if a data main type is a string type. Also a BLOB is considered a
+string type. */
+
+ibool
+dtype_is_string_type(
+/*=================*/
+ /* out: TRUE if string type */
+ ulint mtype) /* in: InnoDB main data type code: DATA_CHAR, ... */
+{
+ if (mtype <= DATA_BLOB
+ || mtype == DATA_MYSQL
+ || mtype == DATA_VARMYSQL) {
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+/*************************************************************************
+Checks if a type is a binary string type. Note that for tables created with
+< 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column. For
+those DATA_BLOB columns this function currently returns FALSE. */
+
+ibool
+dtype_is_binary_string_type(
+/*========================*/
+ /* out: TRUE if binary string type */
+ ulint mtype, /* in: main data type */
+ ulint prtype) /* in: precise type */
+{
+ if ((mtype == DATA_FIXBINARY)
+ || (mtype == DATA_BINARY)
+ || (mtype == DATA_BLOB && (prtype & DATA_BINARY_TYPE))) {
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+/*************************************************************************
+Checks if a type is a non-binary string type. That is, dtype_is_string_type is
+TRUE and dtype_is_binary_string_type is FALSE. Note that for tables created
+with < 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column.
+For those DATA_BLOB columns this function currently returns TRUE. */
+
+ibool
+dtype_is_non_binary_string_type(
+/*============================*/
+ /* out: TRUE if non-binary string type */
+ ulint mtype, /* in: main data type */
+ ulint prtype) /* in: precise type */
+{
+ if (dtype_is_string_type(mtype) == TRUE
+ && dtype_is_binary_string_type(mtype, prtype) == FALSE) {
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+/*************************************************************************
+Forms a precise type from the < 4.1.2 format precise type plus the
+charset-collation code. */
+
+ulint
+dtype_form_prtype(
+/*==============*/
+ ulint old_prtype, /* in: the MySQL type code and the flags
+ DATA_BINARY_TYPE etc. */
+ ulint charset_coll) /* in: MySQL charset-collation code */
+{
+ ut_a(old_prtype < 256 * 256);
+ ut_a(charset_coll < 256);
+
+ return(old_prtype + (charset_coll << 16));
+}
+
+/*************************************************************************
Validates a data type structure. */
ibool
diff --git a/innobase/include/data0type.h b/innobase/include/data0type.h
index 0b8d77ee542..2b27ead5fac 100644
--- a/innobase/include/data0type.h
+++ b/innobase/include/data0type.h
@@ -12,6 +12,7 @@ Created 1/16/1996 Heikki Tuuri
#include "univ.i"
extern ulint data_mysql_default_charset_coll;
+extern ulint data_mysql_latin1_swedish_charset_coll;
/* SQL data type struct */
typedef struct dtype_struct dtype_t;
@@ -30,8 +31,8 @@ extern dtype_t* dtype_binary;
#define DATA_BINARY 4 /* binary string */
#define DATA_BLOB 5 /* binary large object, or a TEXT type;
if prtype & DATA_BINARY_TYPE == 0, then this is
- actually a TEXT column; see also below about
- the flag DATA_NONLATIN1 */
+ actually a TEXT column (or a BLOB created
+ with < 4.0.14) */
#define DATA_INT 6 /* integer: can be any size 1 - 8 bytes */
#define DATA_SYS_CHILD 7 /* address of the child page in node pointer */
#define DATA_SYS 8 /* system column */
@@ -59,7 +60,7 @@ Tables created by a MySQL user have the following convention:
code (not applicable for system columns).
- In the second least significant byte we OR flags DATA_NOT_NULL,
-DATA_UNSIGNED, DATA_BINARY_TYPE, DATA_NONLATIN1.
+DATA_UNSIGNED, DATA_BINARY_TYPE.
- In the third least significant byte of the precise type of string types we
store the MySQL charset-collation code. In DATA_BLOB columns created with
@@ -73,6 +74,23 @@ installation. If the stored charset code is 0 in the system table SYS_COLUMNS
of InnoDB, that means that the default charset of this MySQL installation
should be used.
+When loading a table definition from the system tables to the InnoDB data
+dictionary cache in main memory, InnoDB versions >= 4.1.2 and >= 5.0.1 check
+if the stored charset-collation is 0, and if that is the case and the type is
+a non-binary string, replace that 0 by the default charset-collation code of
+this MySQL installation. In short, in old tables, the charset-collation code
+in the system tables on disk can be 0, but in in-memory data structures
+(dtype_t), the charset-collation code is always != 0 for non-binary string
+types.
+
+In new tables, in binary string types, the charset-collation code is the
+MySQL code for the 'binary charset', that is, != 0.
+
+For binary string types and for DATA_CHAR, DATA_VARCHAR, and for those
+DATA_BLOB which are binary or have the charset-collation latin1_swedish_ci,
+InnoDB performs all comparisons internally, without resorting to the MySQL
+comparison functions. This is to save CPU time.
+
InnoDB's own internal system tables have different precise types for their
columns, and for them the precise type is usually not used at all.
*/
@@ -112,14 +130,10 @@ be less than 256 */
string, this is ORed to the precise type:
this only holds for tables created with
>= MySQL-4.0.14 */
-#define DATA_NONLATIN1 2048 /* If the data type is DATA_BLOB with
- the prtype & DATA_BINARY_TYPE == 0, that is,
- TEXT, then in versions 4.0.14 - 4.0.xx this
- flag is set to 1, if the charset is not
- latin1. In version 4.1.1 this was set
- to 1 for all TEXT columns. In versions >= 4.1.2
- this is set to 1 if the charset-collation of a
- TEXT column is not latin1_swedish_ci. */
+/* #define DATA_NONLATIN1 2048 This is a relic from < 4.1.2 and < 5.0.1.
+ In earlier versions this was set for some
+ BLOB columns.
+*/
/*-------------------------------------------*/
/* This many bytes we need to store the type information affecting the
@@ -133,7 +147,7 @@ store the charset-collation number; one byte is left unused, though */
/*************************************************************************
Checks if a data main type is a string type. Also a BLOB is considered a
string type. */
-UNIV_INLINE
+
ibool
dtype_is_string_type(
/*=================*/
@@ -143,7 +157,7 @@ dtype_is_string_type(
Checks if a type is a binary string type. Note that for tables created with
< 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column. For
those DATA_BLOB columns this function currently returns FALSE. */
-UNIV_INLINE
+
ibool
dtype_is_binary_string_type(
/*========================*/
@@ -154,9 +168,8 @@ dtype_is_binary_string_type(
Checks if a type is a non-binary string type. That is, dtype_is_string_type is
TRUE and dtype_is_binary_string_type is FALSE. Note that for tables created
with < 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column.
-For those DATA_BLOB columns this function currently returns FALSE. */
+For those DATA_BLOB columns this function currently returns TRUE. */
-UNIV_INLINE
ibool
dtype_is_non_binary_string_type(
/*============================*/
@@ -206,11 +219,12 @@ dtype_get_charset_coll(
/*************************************************************************
Forms a precise type from the < 4.1.2 format precise type plus the
charset-collation code. */
+
ulint
dtype_form_prtype(
/*==============*/
ulint old_prtype, /* in: the MySQL type code and the flags
- DATA_NONLATIN1 etc. */
+ DATA_BINARY_TYPE etc. */
ulint charset_coll); /* in: MySQL charset-collation code */
/*************************************************************************
Gets the type length. */
diff --git a/innobase/include/data0type.ic b/innobase/include/data0type.ic
index 51a1d593d4b..21f617c7590 100644
--- a/innobase/include/data0type.ic
+++ b/innobase/include/data0type.ic
@@ -9,70 +9,6 @@ Created 1/16/1996 Heikki Tuuri
#include "mach0data.h"
/*************************************************************************
-Checks if a data main type is a string type. Also a BLOB is considered a
-string type. */
-
-ibool
-dtype_is_string_type(
-/*=================*/
- /* out: TRUE if string type */
- ulint mtype) /* in: InnoDB main data type code: DATA_CHAR, ... */
-{
- if (mtype <= DATA_BLOB
- || mtype == DATA_MYSQL
- || mtype == DATA_VARMYSQL) {
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/*************************************************************************
-Checks if a type is a binary string type. Note that for tables created with
-< 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column. For
-those DATA_BLOB columns this function currently returns FALSE. */
-UNIV_INLINE
-ibool
-dtype_is_binary_string_type(
-/*========================*/
- /* out: TRUE if binary string type */
- ulint mtype, /* in: main data type */
- ulint prtype) /* in: precise type */
-{
- if ((mtype == DATA_FIXBINARY)
- || (mtype == DATA_BINARY)
- || (mtype == DATA_BLOB && (prtype & DATA_BINARY_TYPE))) {
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/*************************************************************************
-Checks if a type is a non-binary string type. That is, dtype_is_string_type is
-TRUE and dtype_is_binary_string_type is FALSE. Note that for tables created
-with < 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column.
-For those DATA_BLOB columns this function currently returns FALSE. */
-UNIV_INLINE
-ibool
-dtype_is_non_binary_string_type(
-/*============================*/
- /* out: TRUE if non-binary string type */
- ulint mtype, /* in: main data type */
- ulint prtype) /* in: precise type */
-{
- if (dtype_is_string_type(mtype) == TRUE
- && dtype_is_binary_string_type(mtype, prtype) == FALSE) {
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/*************************************************************************
Sets a data type structure. */
UNIV_INLINE
void
@@ -143,23 +79,7 @@ dtype_get_charset_coll(
/*===================*/
ulint prtype) /* in: precise data type */
{
- return((prtype >> 16) & 0xFF);
-}
-
-/*************************************************************************
-Forms a precise type from the < 4.1.2 format precise type plus the
-charset-collation code. */
-ulint
-dtype_form_prtype(
-/*==============*/
- ulint old_prtype, /* in: the MySQL type code and the flags
- DATA_NONLATIN1 etc. */
- ulint charset_coll) /* in: MySQL charset-collation code */
-{
- ut_a(old_prtype < 256 * 256);
- ut_a(charset_coll < 256);
-
- return(old_prtype + (charset_coll << 16));
+ return((prtype >> 16) & 0xFFUL);
}
/*************************************************************************
@@ -237,9 +157,10 @@ dtype_new_store_for_order_and_null_size(
buf[0] = buf[0] | 128;
}
- if (type->prtype & DATA_NONLATIN1) {
- buf[0] = buf[0] | 64;
- }
+ /* In versions < 4.1.2 we had: if (type->prtype & DATA_NONLATIN1) {
+ buf[0] = buf[0] | 64;
+ }
+ */
buf[1] = (byte)(type->prtype & 0xFFUL);
@@ -271,10 +192,6 @@ dtype_read_for_order_and_null_size(
type->prtype = type->prtype | DATA_BINARY_TYPE;
}
- if (buf[0] & 64) {
- type->prtype = type->prtype | DATA_NONLATIN1;
- }
-
type->len = mach_read_from_2(buf + 2);
type->prtype = dtype_form_prtype(type->prtype,
@@ -303,10 +220,6 @@ dtype_new_read_for_order_and_null_size(
type->prtype = type->prtype | DATA_BINARY_TYPE;
}
- if (buf[0] & 64) {
- type->prtype = type->prtype | DATA_NONLATIN1;
- }
-
type->len = mach_read_from_2(buf + 2);
mach_read_from_2(buf + 4);
diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c
index 16d5c33cb35..fb8732f35be 100644
--- a/innobase/rem/rem0cmp.c
+++ b/innobase/rem/rem0cmp.c
@@ -331,7 +331,9 @@ cmp_data_data_slow(
if (cur_type->mtype >= DATA_FLOAT
|| (cur_type->mtype == DATA_BLOB
- && (cur_type->prtype & DATA_NONLATIN1))) {
+ && 0 == (cur_type->prtype & DATA_BINARY_TYPE)
+ && dtype_get_charset_coll(cur_type->prtype) !=
+ data_mysql_latin1_swedish_charset_coll)) {
return(cmp_whole_field(cur_type, data1, len1, data2, len2));
}
@@ -532,8 +534,10 @@ cmp_dtuple_rec_with_match(
}
if (cur_type->mtype >= DATA_FLOAT
- || (cur_type->mtype == DATA_BLOB
- && (cur_type->prtype & DATA_NONLATIN1))) {
+ || (cur_type->mtype == DATA_BLOB
+ && 0 == (cur_type->prtype & DATA_BINARY_TYPE)
+ && dtype_get_charset_coll(cur_type->prtype) !=
+ data_mysql_latin1_swedish_charset_coll)) {
ret = cmp_whole_field(cur_type,
dfield_get_data(dtuple_field), dtuple_f_len,
@@ -854,8 +858,10 @@ cmp_rec_rec_with_match(
}
if (cur_type->mtype >= DATA_FLOAT
- || (cur_type->mtype == DATA_BLOB
- && (cur_type->prtype & DATA_NONLATIN1))) {
+ || (cur_type->mtype == DATA_BLOB
+ && 0 == (cur_type->prtype & DATA_BINARY_TYPE)
+ && dtype_get_charset_coll(cur_type->prtype) !=
+ data_mysql_latin1_swedish_charset_coll)) {
ret = cmp_whole_field(cur_type,
rec1_b_ptr, rec1_f_len,
diff --git a/libmysql/client_settings.h b/libmysql/client_settings.h
index 4558f0f2abe..5ce0e021782 100644
--- a/libmysql/client_settings.h
+++ b/libmysql/client_settings.h
@@ -22,7 +22,7 @@ extern my_string mysql_unix_port;
CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION)
sig_handler pipe_sig_handler(int sig __attribute__((unused)));
-my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list);
+my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list, my_bool skip_free);
void read_user_name(char *name);
my_bool send_file_to_server(MYSQL *mysql, const char *filename);
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 548375a7de7..e88e34f8925 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -89,7 +89,7 @@ static void append_wild(char *to,char *end,const char *wild);
sig_handler pipe_sig_handler(int sig);
static ulong mysql_sub_escape_string(CHARSET_INFO *charset_info, char *to,
const char *from, ulong length);
-my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list);
+my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list, my_bool skip_free);
static my_bool mysql_client_init= 0;
static my_bool org_my_init_done= 0;
@@ -1667,14 +1667,14 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length)
}
if (simple_command(mysql, COM_PREPARE, query, length, 1))
{
- stmt_close(stmt, 1);
+ stmt_close(stmt, 1, 0);
DBUG_RETURN(0);
}
init_alloc_root(&stmt->mem_root,8192,0);
if ((*mysql->methods->read_prepare_result)(mysql, stmt))
{
- stmt_close(stmt, 1);
+ stmt_close(stmt, 1, 0);
DBUG_RETURN(0);
}
@@ -3313,7 +3313,7 @@ my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
}
-my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list)
+my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list, my_bool skip_free)
{
MYSQL *mysql;
DBUG_ENTER("mysql_stmt_close");
@@ -3322,7 +3322,8 @@ my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list)
if (!(mysql= stmt->mysql))
{
- my_free((gptr) stmt, MYF(MY_WME));
+ if (!skip_free)
+ my_free((gptr) stmt, MYF(MY_WME));
DBUG_RETURN(0);
}
mysql_stmt_free_result(stmt);
@@ -3330,7 +3331,7 @@ my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list)
{
char buff[4];
int4store(buff, stmt->stmt_id);
- if (simple_command(mysql, COM_CLOSE_STMT, buff, 4, 1))
+ if (skip_free || simple_command(mysql, COM_CLOSE_STMT, buff, 4, 1))
{
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
mysql->net.sqlstate);
@@ -3351,7 +3352,7 @@ my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list)
my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
{
- return stmt_close(stmt, 0);
+ return stmt_close(stmt, 0, 0);
}
/*
diff --git a/myisam/mi_check.c b/myisam/mi_check.c
index 4f6aa0b46d4..4d29838ecd0 100644
--- a/myisam/mi_check.c
+++ b/myisam/mi_check.c
@@ -409,7 +409,7 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
if (chk_index(param,info,keyinfo,share->state.key_root[key],info->buff,
&keys, param->key_crc+key,1))
DBUG_RETURN(-1);
- if(!(keyinfo->flag & HA_FULLTEXT))
+ if(!(keyinfo->flag & (HA_FULLTEXT | HA_SPATIAL)))
{
if (keys != info->state->records)
{
@@ -558,6 +558,10 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
DBUG_ENTER("chk_index");
DBUG_DUMP("buff",(byte*) buff,mi_getint(buff));
+ /* TODO: implement appropriate check for RTree keys */
+ if (keyinfo->flag & HA_SPATIAL)
+ DBUG_RETURN(0);
+
if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length)))
{
mi_check_print_error(param,"Not enough memory for keyblock");
@@ -1073,7 +1077,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend)
for (key=0 ; key < info->s->base.keys; key++)
{
if (key_checksum[key] != param->key_crc[key] &&
- !(info->s->keyinfo[key].flag & HA_FULLTEXT))
+ !(info->s->keyinfo[key].flag & (HA_FULLTEXT | HA_SPATIAL)))
{
mi_check_print_error(param,"Checksum for key: %2d doesn't match checksum for records",
key+1);
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index ad1f7785527..ddb5355f9ec 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -167,5 +167,5 @@ select hex(s1) from t1;
hex(s1)
41
drop table t1;
-create table t1 (a char(160) character set utf8, primary key(a));
-ERROR 42000: Specified key was too long; max key length is 255 bytes
+create table t1 (a text character set utf8, primary key(a(360)));
+ERROR 42000: Specified key was too long; max key length is 1000 bytes
diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result
index 2a47d0c048d..ab5338d383b 100644
--- a/mysql-test/r/gis-rtree.result
+++ b/mysql-test/r/gis-rtree.result
@@ -710,3 +710,43 @@ SELECT count(*) FROM t2;
count(*)
0
DROP TABLE t2;
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
+CREATE TABLE t1 (a geometry NOT NULL, SPATIAL (a));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+drop table t1;
diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result
index dca7b580378..115f15bacb6 100644
--- a/mysql-test/r/key.result
+++ b/mysql-test/r/key.result
@@ -185,3 +185,24 @@ NULL 2
a 1
a 2
drop table t1;
+create table t1 (i int, a char(200), b text, unique (a), unique (b(300))) charset utf8;
+insert t1 values (1, repeat('a',210), repeat('b', 310));
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+insert t1 values (2, repeat(0xD0B1,215), repeat(0xD0B1, 310));
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+select i, length(a), length(b), char_length(a), char_length(b) from t1;
+i length(a) length(b) char_length(a) char_length(b)
+1 200 310 200 310
+2 400 620 200 310
+select i from t1 where a=repeat(_utf8 'a',200);
+i
+1
+select i from t1 where a=repeat(_utf8 0xD0B1,200);
+i
+2
+select i from t1 where b=repeat(_utf8 'b',310);
+i
+1
+drop table t1;
diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result
index 1f3e12a33aa..1433c50f25c 100644
--- a/mysql-test/r/myisam.result
+++ b/mysql-test/r/myisam.result
@@ -322,11 +322,11 @@ CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
-CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), KEY t1 (a, b, c));
-ERROR 42000: Specified key was too long; max key length is 500 bytes
-CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255));
-ALTER TABLE t1 ADD INDEX t1 (a, b, c);
-ERROR 42000: Specified key was too long; max key length is 500 bytes
+CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), d varchar(255), e varchar(255), KEY t1 (a, b, c, d, e));
+ERROR 42000: Specified key was too long; max key length is 1000 bytes
+CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), d varchar(255), e varchar(255));
+ALTER TABLE t1 ADD INDEX t1 (a, b, c, d, e);
+ERROR 42000: Specified key was too long; max key length is 1000 bytes
DROP TABLE t1;
CREATE TABLE t1 (a int not null, b int, c int, key(b), key(c), key(a,b), key(c,a));
INSERT into t1 values (0, null, 0), (0, null, 1), (0, null, 2), (0, null,3), (1,1,4);
diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result
index a895325d1fc..d44face6512 100644
--- a/mysql-test/r/type_blob.result
+++ b/mysql-test/r/type_blob.result
@@ -346,16 +346,16 @@ HELLO MY 1
a 1
hello 1
drop table t1;
-create table t1 (a text, unique (a(300)));
-ERROR 42000: Specified key was too long; max key length is 255 bytes
-create table t1 (a text, key (a(300)));
+create table t1 (a text, unique (a(2100)));
+ERROR 42000: Specified key was too long; max key length is 1000 bytes
+create table t1 (a text, key (a(2100)));
Warnings:
-Warning 1071 Specified key was too long; max key length is 255 bytes
+Warning 1071 Specified key was too long; max key length is 1000 bytes
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` text,
- KEY `a` (`a`(255))
+ KEY `a` (`a`(1000))
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
CREATE TABLE t1 (
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index 6361f49fe55..797af89c6ad 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -104,4 +104,4 @@ drop table t1;
# UTF8 breaks primary keys for cols > 85 characters
#
--error 1071
-create table t1 (a char(160) character set utf8, primary key(a));
+create table t1 (a text character set utf8, primary key(a(360)));
diff --git a/mysql-test/t/gis-rtree.test b/mysql-test/t/gis-rtree.test
index 08ba8329b48..629a07a4913 100644
--- a/mysql-test/t/gis-rtree.test
+++ b/mysql-test/t/gis-rtree.test
@@ -67,3 +67,39 @@ while ($1)
}
DROP TABLE t2;
+
+drop table if exists t1;
+CREATE TABLE t1 (a geometry NOT NULL, SPATIAL (a));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+INSERT INTO t1 VALUES (GeomFromText("LINESTRING(100 100, 200 200, 300 300)"));
+check table t1;
+analyze table t1;
+drop table t1;
+
diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test
index 109cbb91e2f..cdaf6062771 100644
--- a/mysql-test/t/key.test
+++ b/mysql-test/t/key.test
@@ -191,3 +191,16 @@ SELECT * FROM t1;
INSERT INTO t1 (c) VALUES ('a'),('a');
SELECT * FROM t1;
drop table t1;
+
+#
+# longer keys
+#
+create table t1 (i int, a char(200), b text, unique (a), unique (b(300))) charset utf8;
+insert t1 values (1, repeat('a',210), repeat('b', 310));
+insert t1 values (2, repeat(0xD0B1,215), repeat(0xD0B1, 310));
+select i, length(a), length(b), char_length(a), char_length(b) from t1;
+select i from t1 where a=repeat(_utf8 'a',200);
+select i from t1 where a=repeat(_utf8 0xD0B1,200);
+select i from t1 where b=repeat(_utf8 'b',310);
+drop table t1;
+
diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test
index c407cba4800..65bc4f1fff6 100644
--- a/mysql-test/t/myisam.test
+++ b/mysql-test/t/myisam.test
@@ -337,10 +337,10 @@ drop table t1;
#
--error 1071
-CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), KEY t1 (a, b, c));
-CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255));
+CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), d varchar(255), e varchar(255), KEY t1 (a, b, c, d, e));
+CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), d varchar(255), e varchar(255));
--error 1071
-ALTER TABLE t1 ADD INDEX t1 (a, b, c);
+ALTER TABLE t1 ADD INDEX t1 (a, b, c, d, e);
DROP TABLE t1;
#
diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test
index 97c38057e72..cae64b9dd27 100644
--- a/mysql-test/t/type_blob.test
+++ b/mysql-test/t/type_blob.test
@@ -122,8 +122,8 @@ select d,count(*) from t1 group by d;
drop table t1;
-- error 1071
-create table t1 (a text, unique (a(300))); # should give an error
-create table t1 (a text, key (a(300))); # key is auto-truncated
+create table t1 (a text, unique (a(2100))); # should give an error
+create table t1 (a text, key (a(2100))); # key is auto-truncated
show create table t1;
drop table t1;
diff --git a/mysys/my_init.c b/mysys/my_init.c
index a7899c20442..fc178b0308b 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -19,10 +19,6 @@
#include "mysys_err.h"
#include <m_string.h>
#include <m_ctype.h>
-#ifdef HAVE_GETRUSAGE
-#include <sys/resource.h>
-/* extern int getrusage(int, struct rusage *); */
-#endif
#include <signal.h>
#ifdef VMS
#include <my_static.c>
diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h
index f79431a0b0b..6abadd48aeb 100644
--- a/mysys/mysys_priv.h
+++ b/mysys/mysys_priv.h
@@ -21,6 +21,10 @@
#include "system_wrappers.h"
#endif
+#ifdef HAVE_GETRUSAGE
+#include <sys/resource.h>
+#endif
+
#ifdef THREAD
#include <my_pthread.h>
extern pthread_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_keycache;
@@ -29,3 +33,4 @@ extern pthread_mutex_t THR_LOCK_charset;
#else
#include <my_no_pthread.h>
#endif
+
diff --git a/sql-common/client.c b/sql-common/client.c
index fc5004c4a82..a22ac22f08a 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -2199,7 +2199,7 @@ void STDCALL mysql_close(MYSQL *mysql)
for (element= mysql->stmts; element; element= next_element)
{
next_element= element->next;
- stmt_close((MYSQL_STMT *)element->data, 0);
+ stmt_close((MYSQL_STMT *)element->data, 0, 1);
}
mysql->stmts= 0;
}
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 1fbc468866c..3d226e42d82 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -755,11 +755,6 @@ innobase_init(void)
srv_set_thread_priorities = TRUE;
srv_query_thread_priority = QUERY_PRIOR;
}
-
- /* Store the default charset-collation number of this MySQL
- installation */
-
- data_mysql_default_charset_coll = (ulint)default_charset_info->number;
/* Set InnoDB initialization parameters according to the values
read from MySQL .cnf file */
@@ -875,12 +870,20 @@ innobase_init(void)
srv_print_verbose_log = mysql_embedded ? 0 : 1;
+ /* Store the default charset-collation number of this MySQL
+ installation */
+
+ data_mysql_default_charset_coll = (ulint)default_charset_info->number;
+
+ data_mysql_latin1_swedish_charset_coll =
+ (ulint)my_charset_latin1.number;
+
/* Store the latin1_swedish_ci character ordering table to InnoDB. For
non-latin1_swedish_ci charsets we use the MySQL comparison functions,
and consequently we do not need to know the ordering internally in
InnoDB. */
- ut_a(0 == ut_strcmp((char*)my_charset_latin1.name,
+ ut_a(0 == strcmp((char*)my_charset_latin1.name,
(char*)"latin1_swedish_ci"));
memcpy(srv_latin1_ordering, my_charset_latin1.sort_order, 256);
@@ -3260,7 +3263,6 @@ create_table_def(
ulint nulls_allowed;
ulint unsigned_type;
ulint binary_type;
- ulint nonlatin1_type;
ulint charset_no;
ulint i;
@@ -3290,17 +3292,8 @@ create_table_def(
unsigned_type = 0;
}
- if (col_type == DATA_BLOB
- && strcmp(field->charset()->name,
- "latin1_swedish_ci") != 0) {
- nonlatin1_type = DATA_NONLATIN1;
- } else {
- nonlatin1_type = 0;
- }
-
if (field->binary()) {
binary_type = DATA_BINARY_TYPE;
- nonlatin1_type = 0;
} else {
binary_type = 0;
}
@@ -3319,7 +3312,7 @@ create_table_def(
col_type, dtype_form_prtype(
(ulint)field->type()
| nulls_allowed | unsigned_type
- | nonlatin1_type | binary_type,
+ | binary_type,
+ charset_no),
field->pack_length(), 0);
}
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index 06663516011..ddffcfecc29 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -65,6 +65,7 @@ class ha_myisam: public handler
uint max_keys() const { return MI_MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
uint max_key_length() const { return MI_MAX_KEY_LENGTH; }
+ uint max_key_part_length() { return MI_MAX_KEY_LENGTH; }
uint checksum() const;
int open(const char *name, int mode, uint test_if_locked);
diff --git a/sql/hostname.cc b/sql/hostname.cc
index c9cb2a43963..c74d230bbcb 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -27,9 +27,6 @@
extern "C" { // Because of SCO 3.2V4.2
#endif
#if !defined( __WIN__) && !defined(OS2)
-#if !defined(__NETWARE__)
-#include <sys/resource.h>
-#endif /* __NETWARE__ */
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
diff --git a/sql/item.cc b/sql/item.cc
index eb2550fdbcc..5aaeffff5d2 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -969,8 +969,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
void Item_field::cleanup()
{
+ DBUG_ENTER("Item_field::cleanup");
Item_ident::cleanup();
field= result_field= 0;
+ DBUG_VOID_RETURN;
}
void Item::init_make_field(Send_field *tmp_field,
@@ -1613,9 +1615,11 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
void Item_ref::cleanup()
{
+ DBUG_ENTER("Item_ref::cleanup");
Item_ident::cleanup();
if (hook_ptr)
*hook_ptr= orig_item;
+ DBUG_VOID_RETURN;
}
diff --git a/sql/item.h b/sql/item.h
index 4d081905e0d..b06bc85d573 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -128,7 +128,13 @@ public:
virtual ~Item() { name=0; } /*lint -e1509 */
void set_name(const char *str,uint length, CHARSET_INFO *cs);
void init_make_field(Send_field *tmp_field,enum enum_field_types type);
- virtual void cleanup() { fixed=0; }
+ virtual void cleanup()
+ {
+ DBUG_ENTER("Item::cleanup");
+ DBUG_PRINT("info", ("Type: %d", (int)type()));
+ fixed=0;
+ DBUG_VOID_RETURN;
+ }
virtual void make_field(Send_field *field);
virtual bool fix_fields(THD *, struct st_table_list *, Item **);
virtual int save_in_field(Field *field, bool no_conversions);
@@ -413,6 +419,7 @@ public:
int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
Item *new_item() { return new Item_int(name,value,max_length); }
+ void cleanup() { fixed= 1; } // to prevent drop fixed flag
void print(String *str);
};
@@ -900,6 +907,8 @@ public:
enum Type type() const { return CACHE_ITEM; }
static Item_cache* get_cache(Item_result type);
table_map used_tables() const { return used_table_map; }
+ virtual void keep_array() {}
+ void cleanup() { fixed= 1; } // to prevent drop fixed flag
void print(String *str);
};
@@ -952,8 +961,10 @@ class Item_cache_row: public Item_cache
{
Item_cache **values;
uint item_count;
+ bool save_array;
public:
- Item_cache_row(): Item_cache(), values(0), item_count(2) {}
+ Item_cache_row()
+ :Item_cache(), values(0), item_count(2), save_array(0) {}
/*
'allocate' used only in row transformer, to preallocate space for row
@@ -994,10 +1005,16 @@ public:
bool check_cols(uint c);
bool null_inside();
void bring_value();
+ void keep_array() { save_array= 1; }
void cleanup()
{
+ DBUG_ENTER("Item_cache_row::cleanup");
Item_cache::cleanup();
- values= 0;
+ if (save_array)
+ bzero(values, item_count*sizeof(Item**));
+ else
+ values= 0;
+ DBUG_VOID_RETURN;
}
};
@@ -1023,8 +1040,10 @@ public:
Field *example() { return field_example; }
void cleanup()
{
+ DBUG_ENTER("Item_type_holder::cleanup");
Item::cleanup();
item_type= orig_type;
+ DBUG_VOID_RETURN;
}
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 1bba934cf8f..f0bc73e9501 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -500,7 +500,6 @@ bool Item_in_optimizer::fix_left(THD *thd,
}
-
bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
Item ** ref)
{
@@ -526,6 +525,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
return 0;
}
+
longlong Item_in_optimizer::val_int()
{
cache->store(args[0]);
@@ -539,18 +539,38 @@ longlong Item_in_optimizer::val_int()
return tmp;
}
+
+void Item_in_optimizer::keep_top_level_cache()
+{
+ cache->keep_array();
+ save_cache= 1;
+}
+
+
+void Item_in_optimizer::cleanup()
+{
+ DBUG_ENTER("Item_in_optimizer::cleanup");
+ Item_bool_func::cleanup();
+ if (!save_cache)
+ cache= 0;
+ DBUG_VOID_RETURN;
+}
+
+
bool Item_in_optimizer::is_null()
{
cache->store(args[0]);
return (null_value= (cache->null_value || args[1]->is_null()));
}
+
longlong Item_func_eq::val_int()
{
int value= cmp.compare();
return value == 0 ? 1 : 0;
}
+
/* Same as Item_func_eq, but NULL = NULL */
void Item_func_equal::fix_length_and_dec()
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 3c70a50502a..9d39ddf4e76 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -93,9 +93,10 @@ class Item_in_optimizer: public Item_bool_func
{
protected:
Item_cache *cache;
+ bool save_cache;
public:
Item_in_optimizer(Item *a, Item_in_subselect *b):
- Item_bool_func(a, (Item *)b), cache(0) {}
+ Item_bool_func(a, (Item *)b), cache(0), save_cache(0) {}
bool fix_fields(THD *, struct st_table_list *, Item **);
bool fix_left(THD *thd, struct st_table_list *tables, Item **ref);
bool is_null();
@@ -107,8 +108,10 @@ public:
Item_in_optimizer return NULL, else it evaluate Item_in_subselect.
*/
longlong val_int();
+ void cleanup();
const char *func_name() const { return "<in_optimizer>"; }
Item_cache **get_cache() { return &cache; }
+ void keep_top_level_cache();
};
class Comp_creator
@@ -209,9 +212,11 @@ public:
}
void cleanup()
{
+ DBUG_ENTER("Item_bool_rowready_func2::cleanup");
Item_bool_func2::cleanup();
tmp_arg[0]= orig_a;
tmp_arg[1]= orig_b;
+ DBUG_VOID_RETURN;
}
};
@@ -720,10 +725,12 @@ class Item_func_in :public Item_int_func
void fix_length_and_dec();
void cleanup()
{
+ DBUG_ENTER("Item_func_in::cleanup");
delete array;
delete in_item;
array= 0;
in_item= 0;
+ DBUG_VOID_RETURN;
}
optimize_type select_optimize() const
{ return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; }
diff --git a/sql/item_func.h b/sql/item_func.h
index 30f817d133b..3890e7c6de5 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -999,6 +999,7 @@ public:
join_key(0), ft_handler(0), table(0), master(0), concat(0) { }
void cleanup()
{
+ DBUG_ENTER("Item_func_match");
if (!master && ft_handler)
{
ft_handler->please->close_search(ft_handler);
@@ -1008,7 +1009,11 @@ public:
table->fulltext_searched=0;
}
if (concat)
+ {
delete concat;
+ concat= 0;
+ }
+ DBUG_VOID_RETURN;
}
enum Functype functype() const { return FT_FUNC; }
const char *func_name() const { return "match"; }
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 5b3cc326679..bfe41726f72 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -35,9 +35,9 @@ inline Item * and_items(Item* cond, Item *item)
}
Item_subselect::Item_subselect():
- Item_result_field(), value_assigned(0), substitution(0),
- engine(0), used_tables_cache(0), have_to_be_excluded(0),
- const_item_cache(1), engine_changed(0)
+ Item_result_field(), value_assigned(0), thd(0), substitution(0),
+ engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0),
+ const_item_cache(1), engine_changed(0), changed(0)
{
reset();
/*
@@ -54,10 +54,10 @@ void Item_subselect::init(st_select_lex *select_lex,
DBUG_ENTER("Item_subselect::init");
DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex));
+ unit= select_lex->master_unit();
if (select_lex->next_select())
- engine= new subselect_union_engine(select_lex->master_unit(), result,
- this);
+ engine= new subselect_union_engine(unit, result, this);
else
engine= new subselect_single_select_engine(select_lex, result, this);
DBUG_VOID_RETURN;
@@ -65,8 +65,26 @@ void Item_subselect::init(st_select_lex *select_lex,
void Item_subselect::cleanup()
{
+ DBUG_ENTER("Item_subselect::cleanup");
Item_result_field::cleanup();
- engine->cleanup();
+ if (old_engine)
+ {
+ engine->cleanup();
+ engine= old_engine;
+ old_engine= 0;
+ }
+ engine->cleanup();
+ reset();
+ value_assigned= 0;
+ DBUG_VOID_RETURN;
+}
+
+void Item_singlerow_subselect::cleanup()
+{
+ DBUG_ENTER("Item_singlerow_subselect::cleanup");
+ value= 0; row= 0;
+ Item_subselect::cleanup();
+ DBUG_VOID_RETURN;
}
Item_subselect::~Item_subselect()
@@ -85,13 +103,22 @@ Item_subselect::select_transformer(JOIN *join)
bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
{
engine->set_thd((thd= thd_param));
+ stmt= thd->current_statement;
char const *save_where= thd->where;
int res= engine->prepare();
+
+ // all transformetion is done (used by prepared statements)
+ changed= 1;
+
if (!res)
{
if (substitution)
{
+ // did we changed top item of WHERE condition
+ if (unit->outer_select()->where == (*ref))
+ unit->outer_select()->where= substitution; // correct WHERE for PS
+
(*ref)= substitution;
substitution->name= name;
if (have_to_be_excluded)
@@ -240,8 +267,12 @@ void Item_singlerow_subselect::reset()
Item_subselect::trans_res
Item_singlerow_subselect::select_transformer(JOIN *join)
{
+ if (changed)
+ return RES_OK;
+
SELECT_LEX *select_lex= join->select_lex;
-
+ Statement backup;
+
if (!select_lex->master_unit()->first_select()->next_select() &&
!select_lex->table_list.elements &&
select_lex->item_list.elements == 1 &&
@@ -275,20 +306,30 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
if (join->conds || join->having)
{
Item *cond;
+ if (stmt)
+ thd->set_n_backup_item_arena(stmt, &backup);
+
if (!join->having)
cond= join->conds;
else if (!join->conds)
cond= join->having;
else
if (!(cond= new Item_cond_and(join->conds, join->having)))
- return RES_ERROR;
+ goto err;
if (!(substitution= new Item_func_if(cond, substitution,
new Item_null())))
- return RES_ERROR;
+ goto err;
}
+ if (stmt)
+ thd->restore_backup_item_arena(stmt, &backup);
return RES_REDUCE;
}
return RES_OK;
+
+err:
+ if (stmt)
+ thd->restore_backup_item_arena(stmt, &backup);
+ return RES_ERROR;
}
void Item_singlerow_subselect::store(uint i, Item *item)
@@ -550,15 +591,22 @@ Item_in_subselect::single_value_transformer(JOIN *join,
{
DBUG_ENTER("Item_in_subselect::single_value_transformer");
+ if (changed)
+ {
+ DBUG_RETURN(RES_OK);
+ }
+
SELECT_LEX *select_lex= join->select_lex;
+ Statement backup;
- THD *thd_tmp= join->thd;
- thd_tmp->where= "scalar IN/ALL/ANY subquery";
+ thd->where= "scalar IN/ALL/ANY subquery";
+ if (stmt)
+ thd->set_n_backup_item_arena(stmt, &backup);
if (select_lex->item_list.elements > 1)
{
my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
- DBUG_RETURN(RES_ERROR);
+ goto err;
}
if ((abort_on_null || (upper_not && upper_not->top_level())) &&
@@ -567,7 +615,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (substitution)
{
// It is second (third, ...) SELECT of UNION => All is done
- DBUG_RETURN(RES_OK);
+ goto ok;
}
Item *subs;
@@ -597,10 +645,9 @@ Item_in_subselect::single_value_transformer(JOIN *join,
select_lex->item_list.empty();
select_lex->item_list.push_back(item);
- if (item->fix_fields(thd_tmp, join->tables_list, &item))
- {
- DBUG_RETURN(RES_ERROR);
- }
+ if (item->fix_fields(thd, join->tables_list, &item))
+ goto err;
+
subs= new Item_singlerow_subselect(select_lex);
}
else
@@ -611,16 +658,16 @@ Item_in_subselect::single_value_transformer(JOIN *join,
subs= new Item_maxmin_subselect(this, select_lex, func->l_op());
}
// left expression belong to outer select
- SELECT_LEX *current= thd_tmp->lex->current_select, *up;
- thd_tmp->lex->current_select= up= current->return_after_parsing();
- if (left_expr->fix_fields(thd_tmp, up->get_table_list(), &left_expr))
+ SELECT_LEX *current= thd->lex->current_select, *up;
+ thd->lex->current_select= up= current->return_after_parsing();
+ if (left_expr->fix_fields(thd, up->get_table_list(), &left_expr))
{
- thd_tmp->lex->current_select= current;
- DBUG_RETURN(RES_ERROR);
+ thd->lex->current_select= current;
+ goto err;
}
- thd_tmp->lex->current_select= current;
+ thd->lex->current_select= current;
substitution= func->create(left_expr, subs);
- DBUG_RETURN(RES_OK);
+ goto ok;
}
if (!substitution)
@@ -629,16 +676,16 @@ Item_in_subselect::single_value_transformer(JOIN *join,
SELECT_LEX_UNIT *unit= select_lex->master_unit();
substitution= optimizer= new Item_in_optimizer(left_expr, this);
- SELECT_LEX *current= thd_tmp->lex->current_select, *up;
+ SELECT_LEX *current= thd->lex->current_select, *up;
- thd_tmp->lex->current_select= up= current->return_after_parsing();
+ thd->lex->current_select= up= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter
- if (!optimizer || optimizer->fix_left(thd_tmp, up->get_table_list(), 0))
+ if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{
- thd_tmp->lex->current_select= current;
- DBUG_RETURN(RES_ERROR);
+ thd->lex->current_select= current;
+ goto err;
}
- thd_tmp->lex->current_select= current;
+ thd->lex->current_select= current;
/*
As far as Item_ref_in_optimizer do not substitude itself on fix_fields
@@ -665,12 +712,17 @@ Item_in_subselect::single_value_transformer(JOIN *join,
select_lex->ref_pointer_array,
(char *)"<ref>",
this->full_name()));
- join->having= and_items(join->having, item);
+ /*
+ AND and comparison functions can't be changed during fix_fields()
+ we can assign select_lex->having here, and pass 0 as last
+ argument (reference) to fix_fields()
+ */
+ select_lex->having= join->having= and_items(join->having, item);
select_lex->having_fix_field= 1;
- if (join->having->fix_fields(thd_tmp, join->tables_list, &join->having))
+ if (join->having->fix_fields(thd, join->tables_list, 0))
{
select_lex->having_fix_field= 0;
- DBUG_RETURN(RES_ERROR);
+ goto err;
}
select_lex->having_fix_field= 0;
}
@@ -687,39 +739,56 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (!abort_on_null)
{
having= new Item_is_not_null_test(this, having);
- join->having= (join->having ?
- new Item_cond_and(having, join->having) :
- having);
+ /*
+ Item_is_not_null_test can't be changed during fix_fields()
+ we can assign select_lex->having here, and pass 0 as last
+ argument (reference) to fix_fields()
+ */
+ select_lex->having=
+ join->having= (join->having ?
+ new Item_cond_and(having, join->having) :
+ having);
select_lex->having_fix_field= 1;
- if (join->having->fix_fields(thd_tmp, join->tables_list,
- &join->having))
+ if (join->having->fix_fields(thd, join->tables_list, 0))
{
select_lex->having_fix_field= 0;
- DBUG_RETURN(RES_ERROR);
+ goto err;
}
select_lex->having_fix_field= 0;
item= new Item_cond_or(item,
new Item_func_isnull(isnull));
}
item->name= (char *)in_additional_cond;
- join->conds= and_items(join->conds, item);
- if (join->conds->fix_fields(thd_tmp, join->tables_list, &join->conds))
- DBUG_RETURN(RES_ERROR);
+ /*
+ AND can't be changed during fix_fields()
+ we can assign select_lex->having here, and pass 0 as last
+ argument (reference) to fix_fields()
+ */
+ select_lex->where= join->conds= and_items(join->conds, item);
+ if (join->conds->fix_fields(thd, join->tables_list, 0))
+ goto err;
}
else
{
if (select_lex->master_unit()->first_select()->next_select())
{
- join->having= func->create(expr,
- new Item_null_helper(this, item,
- (char *)"<no matter>",
- (char *)"<result>"));
+ /*
+ comparison functions can't be changed during fix_fields()
+ we can assign select_lex->having here, and pass 0 as last
+ argument (reference) to fix_fields()
+ */
+ select_lex->having=
+ join->having=
+ func->create(expr,
+ new Item_null_helper(this, item,
+ (char *)"<no matter>",
+ (char *)"<result>"));
select_lex->having_fix_field= 1;
- if (join->having->fix_fields(thd_tmp, join->tables_list,
- &join->having))
+ if (join->having->fix_fields(thd, join->tables_list,
+ 0))
{
select_lex->having_fix_field= 0;
- DBUG_RETURN(RES_ERROR);
+ goto err;
}
select_lex->having_fix_field= 0;
}
@@ -730,18 +799,29 @@ Item_in_subselect::single_value_transformer(JOIN *join,
// fix_field of item will be done in time of substituting
substitution= item;
have_to_be_excluded= 1;
- if (thd_tmp->lex->describe)
+ if (thd->lex->describe)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number);
- push_warning(thd_tmp, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SELECT_REDUCED, warn_buff);
}
+ if (stmt)
+ thd->restore_backup_item_arena(stmt, &backup);
DBUG_RETURN(RES_REDUCE);
}
}
}
+
+ok:
+ if (stmt)
+ thd->restore_backup_item_arena(stmt, &backup);
DBUG_RETURN(RES_OK);
+
+err:
+ if (stmt)
+ thd->restore_backup_item_arena(stmt, &backup);
+ DBUG_RETURN(RES_ERROR);
}
@@ -750,15 +830,23 @@ Item_in_subselect::row_value_transformer(JOIN *join)
{
DBUG_ENTER("Item_in_subselect::row_value_transformer");
- THD *thd_tmp= join->thd;
- thd_tmp->where= "row IN/ALL/ANY subquery";
+ if (changed)
+ {
+ DBUG_RETURN(RES_OK);
+ }
+ Statement backup;
+ Item *item= 0;
+
+ thd->where= "row IN/ALL/ANY subquery";
+ if (stmt)
+ thd->set_n_backup_item_arena(stmt, &backup);
SELECT_LEX *select_lex= join->select_lex;
if (select_lex->item_list.elements != left_expr->cols())
{
my_error(ER_OPERAND_COLUMNS, MYF(0), left_expr->cols());
- DBUG_RETURN(RES_ERROR);
+ goto err;
}
if (!substitution)
@@ -767,62 +855,82 @@ Item_in_subselect::row_value_transformer(JOIN *join)
SELECT_LEX_UNIT *unit= select_lex->master_unit();
substitution= optimizer= new Item_in_optimizer(left_expr, this);
- SELECT_LEX *current= thd_tmp->lex->current_select, *up;
- thd_tmp->lex->current_select= up= current->return_after_parsing();
+ SELECT_LEX *current= thd->lex->current_select, *up;
+ thd->lex->current_select= up= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter
- if (!optimizer || optimizer->fix_left(thd_tmp, up->get_table_list(), 0))
+ if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{
- thd_tmp->lex->current_select= current;
- DBUG_RETURN(RES_ERROR);
+ thd->lex->current_select= current;
+ goto err;
}
- thd_tmp->lex->current_select= current;
+
+ // we will refer to apper level cache array => we have to save it in PS
+ optimizer->keep_top_level_cache();
+
+ thd->lex->current_select= current;
unit->uncacheable|= UNCACHEABLE_DEPENDENT;
}
- uint n= left_expr->cols();
-
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
- select_lex->setup_ref_array(thd_tmp,
+ select_lex->setup_ref_array(thd,
select_lex->order_list.elements +
select_lex->group_list.elements);
- Item *item= 0;
- List_iterator_fast<Item> li(select_lex->item_list);
- for (uint i= 0; i < n; i++)
{
- Item *func= new Item_ref_null_helper(this,
- select_lex->ref_pointer_array+i,
- (char *) "<no matter>",
- (char *) "<list ref>");
- func=
- eq_creator.create(new Item_ref((*optimizer->get_cache())->
- addr(i),
- NULL,
- (char *)"<no matter>",
+ uint n= left_expr->cols();
+ List_iterator_fast<Item> li(select_lex->item_list);
+ for (uint i= 0; i < n; i++)
+ {
+ Item *func= new Item_ref_null_helper(this,
+ select_lex->ref_pointer_array+i,
+ (char *) "<no matter>",
+ (char *) "<list ref>");
+ func=
+ eq_creator.create(new Item_ref((*optimizer->get_cache())->
+ addr(i),
+ NULL,
+ (char *)"<no matter>",
(char *)in_left_expr_name),
- func);
- item= and_items(item, func);
+ func);
+ item= and_items(item, func);
+ }
}
-
if (join->having || select_lex->with_sum_func ||
select_lex->group_list.first ||
!select_lex->table_list.elements)
{
- join->having= and_items(join->having, item);
+ /*
+ AND can't be changed during fix_fields()
+ we can assign select_lex->having here, and pass 0 as last
+ argument (reference) to fix_fields()
+ */
+ select_lex->having= join->having= and_items(join->having, item);
select_lex->having_fix_field= 1;
- if (join->having->fix_fields(thd_tmp, join->tables_list, &join->having))
+ if (join->having->fix_fields(thd, join->tables_list, 0))
{
select_lex->having_fix_field= 0;
- DBUG_RETURN(RES_ERROR);
+ goto err;
}
select_lex->having_fix_field= 0;
}
else
{
- join->conds= and_items(join->conds, item);
- if (join->conds->fix_fields(thd_tmp, join->tables_list, &join->having))
- DBUG_RETURN(RES_ERROR);
+ /*
+ AND can't be changed during fix_fields()
+ we can assign select_lex->having here, and pass 0 as last
+ argument (reference) to fix_fields()
+ */
+ select_lex->where= join->conds= and_items(join->conds, item);
+ if (join->conds->fix_fields(thd, join->tables_list, 0))
+ goto err;
}
+ if (stmt)
+ thd->restore_backup_item_arena(stmt, &backup);
DBUG_RETURN(RES_OK);
+
+err:
+ if (stmt)
+ thd->restore_backup_item_arena(stmt, &backup);
+ DBUG_RETURN(RES_ERROR);
}
@@ -894,13 +1002,31 @@ subselect_single_select_engine(st_select_lex *select,
this->select_lex= select_lex;
}
+
void subselect_single_select_engine::cleanup()
{
- prepared= 0;
- optimized= 0;
- executed= 0;
+ DBUG_ENTER("subselect_single_select_engine::cleanup");
+ prepared= optimized= executed= 0;
+ join= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+void subselect_union_engine::cleanup()
+{
+ DBUG_ENTER("subselect_union_engine::cleanup");
+ unit->reinit_exec_mechanism();
+ DBUG_VOID_RETURN;
+}
+
+
+void subselect_uniquesubquery_engine::cleanup()
+{
+ DBUG_ENTER("subselect_uniquesubquery_engine::cleanup");
+ DBUG_VOID_RETURN;
}
+
subselect_union_engine::subselect_union_engine(st_select_lex_unit *u,
select_subselect *result_arg,
Item_subselect *item_arg)
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index dc3d07540da..d550cde64b7 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -26,6 +26,7 @@ class JOIN;
class select_subselect;
class subselect_engine;
class Item_bool_func2;
+class Statement;
/* base class for subselects */
@@ -35,22 +36,30 @@ class Item_subselect :public Item_result_field
protected:
/* thread handler, will be assigned in fix_fields only */
THD *thd;
+ /* prepared statement, or 0 */
+ Statement *stmt;
/* substitution instead of subselect in case of optimization */
Item *substitution;
+ /* unit of subquery */
+ st_select_lex_unit *unit;
/* engine that perform execution of subselect (single select or union) */
subselect_engine *engine;
+ /* old engine if engine was changed */
+ subselect_engine *old_engine;
/* cache of used external tables */
table_map used_tables_cache;
/* allowed number of columns (1 for single value subqueries) */
uint max_columns;
/* work with 'substitution' */
bool have_to_be_excluded;
- /* cache of constante state */
+ /* cache of constant state */
bool const_item_cache;
public:
/* changed engine indicator */
bool engine_changed;
+ /* subquery is transformed */
+ bool changed;
enum trans_res {RES_OK, RES_REDUCE, RES_ERROR};
enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS,
@@ -94,6 +103,7 @@ public:
void print(String *str);
bool change_engine(subselect_engine *eng)
{
+ old_engine= engine;
engine= eng;
engine_changed= 1;
return eng == 0;
@@ -116,6 +126,7 @@ public:
Item_singlerow_subselect(st_select_lex *select_lex);
Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {}
+ void cleanup();
subs_type substype() { return SINGLEROW_SUBS; }
void reset();
@@ -200,13 +211,6 @@ public:
{}
- void cleanup()
- {
- Item_exists_subselect::cleanup();
- abort_on_null= 0;
- transformed= 0;
- upper_not= 0;
- }
subs_type substype() { return IN_SUBS; }
void reset()
{
@@ -269,7 +273,7 @@ public:
maybe_null= 0;
}
virtual ~subselect_engine() {}; // to satisfy compiler
- virtual void cleanup() {}
+ virtual void cleanup()= 0;
// set_thd should be called before prepare()
void set_thd(THD *thd_arg) { thd= thd_arg; }
@@ -318,6 +322,7 @@ public:
subselect_union_engine(st_select_lex_unit *u,
select_subselect *result,
Item_subselect *item);
+ void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
int exec();
@@ -345,6 +350,7 @@ public:
set_thd(thd_arg);
}
~subselect_uniquesubquery_engine();
+ void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
int exec();
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 10b50fa5b3b..879c5f99ebd 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1084,6 +1084,7 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)),
void Item_sum_count_distinct::cleanup()
{
+ DBUG_ENTER("Item_sum_count_distinct::cleanup");
Item_sum_int::cleanup();
/*
Free table and tree if they belong to this item (if item have not pointer
@@ -1104,6 +1105,7 @@ void Item_sum_count_distinct::cleanup()
use_tree= 0;
}
}
+ DBUG_VOID_RETURN;
}
@@ -1672,6 +1674,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct,
void Item_func_group_concat::cleanup()
{
+ DBUG_ENTER("Item_func_group_concat::cleanup");
/*
Free table and tree if they belong to this item (if item have not pointer
to original item from which was made copy => it own its objects )
@@ -1692,6 +1695,7 @@ void Item_func_group_concat::cleanup()
delete_tree(tree);
}
}
+ DBUG_VOID_RETURN;
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 0848886d6d8..11c95100db5 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -60,8 +60,10 @@ public:
Item_sum(THD *thd, Item_sum *item);
void cleanup()
{
+ DBUG_ENTER("Item_sum::cleanup");
Item_result_field::cleanup();
result_field=0;
+ DBUG_VOID_RETURN;
}
enum Type type() const { return SUM_FUNC_ITEM; }
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 43921a1438b..f5031f926af 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -350,6 +350,11 @@ inline THD *_current_thd(void)
#include "sql_udf.h"
#include "item.h"
typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
+/* sql_parse.cc */
+void free_items(Item *item);
+void cleanup_items(Item *item);
+class THD;
+void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
#include "sql_class.h"
#include "opt_range.h"
@@ -411,7 +416,6 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
bool mysql_change_db(THD *thd,const char *name);
void mysql_parse(THD *thd,char *inBuf,uint length);
bool is_update_query(enum enum_sql_command command);
-void free_items(Item *item);
bool alloc_query(THD *thd, char *packet, ulong packet_length);
void mysql_init_select(LEX *lex);
void mysql_init_query(THD *thd);
@@ -688,7 +692,6 @@ bool rm_temporary_table(enum db_type base, char *path);
void free_io_cache(TABLE *entry);
void intern_close_table(TABLE *entry);
bool close_thread_table(THD *thd, TABLE **table_ptr);
-void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
void close_temporary_tables(THD *thd);
TABLE_LIST * find_table_in_list(TABLE_LIST *table,
const char *db_name, const char *table_name);
@@ -766,9 +769,6 @@ uint check_word(TYPELIB *lib, const char *val, const char *end,
bool is_keyword(const char *name, uint len);
-/* sql_parse.cc */
-void free_items(Item *item);
-void cleanup_items(Item *item);
#define MY_DB_OPT_FILE "db.opt"
bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 08a1823edd2..37767c555e8 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2080,6 +2080,14 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
{
if (!wild_num)
return 0;
+ Statement *stmt= thd->current_statement, backup;
+
+ /*
+ If we are in preparing prepared statement phase then we have change
+ temporary mem_root to statement mem root to save changes of SELECT list
+ */
+ if (stmt)
+ thd->set_n_backup_item_arena(stmt, &backup);
reg2 Item *item;
List_iterator<Item> it(fields);
while ( wild_num && (item= it++))
@@ -2091,7 +2099,11 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
uint elem= fields.elements;
if (insert_fields(thd,tables,((Item_field*) item)->db_name,
((Item_field*) item)->table_name, &it))
+ {
+ if (stmt)
+ thd->restore_backup_item_arena(stmt, &backup);
return (-1);
+ }
if (sum_func_list)
{
/*
@@ -2104,6 +2116,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
wild_num--;
}
}
+ if (stmt)
+ thd->restore_backup_item_arena(stmt, &backup);
return 0;
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index e7f867ccd61..9ed604033ab 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -83,7 +83,7 @@ extern "C" void free_user_var(user_var_entry *entry)
** Thread specific functions
****************************************************************************/
-THD::THD():user_time(0), is_fatal_error(0),
+THD::THD():user_time(0), current_statement(0), is_fatal_error(0),
last_insert_id_used(0),
insert_id_used(0), rand_used(0), in_lock_tables(0),
global_read_lock(0), bootstrap(0)
@@ -1247,6 +1247,27 @@ void Statement::set_statement(Statement *stmt)
}
+void Statement::set_n_backup_item_arena(Statement *set, Statement *backup)
+{
+ backup->set_item_arena(this);
+ set_item_arena(set);
+}
+
+
+void Statement::restore_backup_item_arena(Statement *set, Statement *backup)
+{
+ set->set_item_arena(this);
+ set_item_arena(backup);
+ // reset backup mem_root to avoid its freeing
+ init_alloc_root(&backup->mem_root, 0, 0);
+}
+
+void Statement::set_item_arena(Statement *set)
+{
+ mem_root= set->mem_root;
+ free_list= set->free_list;
+}
+
Statement::~Statement()
{
free_root(&mem_root, MYF(0));
diff --git a/sql/sql_class.h b/sql/sql_class.h
index b0899428f32..6816d141dac 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -427,7 +427,7 @@ class Statement
public:
/* FIXME: must be private */
LEX main_lex;
-public:
+
/*
Uniquely identifies each statement object in thread scope; change during
statement lifetime. FIXME: must be const
@@ -476,7 +476,7 @@ public:
char *query;
uint32 query_length; // current query length
/*
- List of items created in the parser for this query. Every item puts
+ List of items created in the parser for this query. Every item puts
itself to the list on creation (see Item::Item() for details))
*/
Item *free_list;
@@ -503,6 +503,32 @@ public:
void set_statement(Statement *stmt);
/* return class type */
virtual Type type() const;
+
+ inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); }
+ inline gptr calloc(unsigned int size)
+ {
+ gptr ptr;
+ if ((ptr=alloc_root(&mem_root,size)))
+ bzero((char*) ptr,size);
+ return ptr;
+ }
+ inline char *strdup(const char *str)
+ { return strdup_root(&mem_root,str); }
+ inline char *strmake(const char *str, uint size)
+ { return strmake_root(&mem_root,str,size); }
+ inline char *memdup(const char *str, uint size)
+ { return memdup_root(&mem_root,str,size); }
+ inline char *memdup_w_gap(const char *str, uint size, uint gap)
+ {
+ gptr ptr;
+ if ((ptr=alloc_root(&mem_root,size+gap)))
+ memcpy(ptr,str,size);
+ return ptr;
+ }
+
+ void set_n_backup_item_arena(Statement *set, Statement *backup);
+ void restore_backup_item_arena(Statement *set, Statement *backup);
+ void Statement::set_item_arena(Statement *set);
};
@@ -690,6 +716,10 @@ public:
Vio* active_vio;
#endif
/*
+ Current prepared Statement if there one, or 0
+ */
+ Statement *current_statement;
+ /*
next_insert_id is set on SET INSERT_ID= #. This is used as the next
generated auto_increment value in handler.cc
*/
@@ -850,34 +880,14 @@ public:
return 0;
#endif
}
- inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); }
- inline gptr calloc(unsigned int size)
- {
- gptr ptr;
- if ((ptr=alloc_root(&mem_root,size)))
- bzero((char*) ptr,size);
- return ptr;
- }
- inline char *strdup(const char *str)
- { return strdup_root(&mem_root,str); }
- inline char *strmake(const char *str, uint size)
- { return strmake_root(&mem_root,str,size); }
- inline char *memdup(const char *str, uint size)
- { return memdup_root(&mem_root,str,size); }
- inline char *memdup_w_gap(const char *str, uint size, uint gap)
- {
- gptr ptr;
- if ((ptr=alloc_root(&mem_root,size+gap)))
- memcpy(ptr,str,size);
- return ptr;
- }
- bool convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
- const char *from, uint from_length,
- CHARSET_INFO *from_cs);
inline gptr trans_alloc(unsigned int size)
{
return alloc_root(&transaction.mem_root,size);
}
+
+ bool convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
+ const char *from, uint from_length,
+ CHARSET_INFO *from_cs);
void add_changed_table(TABLE *table);
void add_changed_table(const char *key, long key_length);
CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length);
@@ -900,6 +910,33 @@ public:
}
inline CHARSET_INFO *charset() { return variables.character_set_client; }
void update_charset();
+
+ inline void allocate_temporary_memory_pool_for_ps_preparing()
+ {
+ DBUG_ASSERT(current_statement!=0);
+ /*
+ We do not want to have in PS memory all that junk,
+ which will be created by preparation => substitute memory
+ from original thread pool.
+
+ We know that PS memory pool is now copied to THD, we move it back
+ to allow some code use it.
+ */
+ current_statement->set_item_arena(this);
+ init_sql_alloc(&mem_root,
+ variables.query_alloc_block_size,
+ variables.query_prealloc_size);
+ free_list= 0;
+ }
+ inline void free_temporary_memory_pool_for_ps_preparing()
+ {
+ DBUG_ASSERT(current_statement!=0);
+ cleanup_items(current_statement->free_list);
+ free_items(free_list);
+ close_thread_tables(this); // to close derived tables
+ free_root(&mem_root, MYF(0));
+ set_item_arena(current_statement);
+ }
};
/* Flags for the THD::system_thread (bitmap) variable */
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index d93134a3a0c..ce7aa4d02db 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1500,11 +1500,17 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
{
if (ref_pointer_array)
return 0;
+
+ /*
+ We have to create array in prepared statement memory if it is
+ prepared statement
+ */
+ Statement *stmt= thd->current_statement ? thd->current_statement : thd;
return (ref_pointer_array=
- (Item **)thd->alloc(sizeof(Item*) *
- (item_list.elements +
- select_n_having_items +
- order_group_num)* 5)) == 0;
+ (Item **)stmt->alloc(sizeof(Item*) *
+ (item_list.elements +
+ select_n_having_items +
+ order_group_num)* 5)) == 0;
}
@@ -1629,7 +1635,11 @@ void st_select_lex::print_limit(THD *thd, String *str)
/*
There are st_select_lex::add_table_to_list &
- st_select_lex::set_lock_for_tables in sql_parse.cc
+ st_select_lex::set_lock_for_tables are in sql_parse.cc
st_select_lex::print is in sql_select.h
+
+ st_select_lex_unit::prepare, st_select_lex_unit::exec,
+ st_select_lex_unit::cleanup, st_select_lex_unit::reinit_exec_mechanism
+ are in sql_union.cc
*/
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 3f56be18c4a..17cccd75697 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -355,6 +355,8 @@ public:
int prepare(THD *thd, select_result *result, ulong additional_options);
int exec();
int cleanup();
+ inline void unclean() { cleaned= 0; }
+ void reinit_exec_mechanism();
bool check_updateable(char *db, char *table);
void print(String *str);
diff --git a/sql/sql_list.h b/sql/sql_list.h
index c7faef88358..0bbc0f87944 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -286,7 +286,7 @@ protected:
inline T** ref(void) { return (T**) 0; }
public:
- List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
+ inline List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
inline void rewind(void) { base_list_iterator::rewind(); }
void sublist(List<T> &list_arg, uint el_arg)
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 3e51844e8cf..7c2913bc495 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -621,8 +621,18 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
(grant_option && check_grant(thd,privilege,table_list,0,0)))
DBUG_RETURN(1);
#endif
+
+ /*
+ open temporary memory pool for temporary data allocated by derived
+ tables & preparation procedure
+ */
+ thd->allocate_temporary_memory_pool_for_ps_preparing();
if (open_and_lock_tables(thd, table_list))
- DBUG_RETURN(1);
+ {
+ thd->free_temporary_memory_pool_for_ps_preparing();
+ DBUG_RETURN(1);
+ }
+
table= table_list->table;
if ((values= its++))
@@ -631,7 +641,11 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
ulong counter= 0;
if (check_insert_fields(thd,table,fields,*values,1))
+ {
+ thd->free_temporary_memory_pool_for_ps_preparing();
DBUG_RETURN(1);
+ }
+ thd->free_temporary_memory_pool_for_ps_preparing();
value_count= values->elements;
its.rewind();
@@ -648,6 +662,10 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
}
}
}
+ else
+ {
+ thd->free_temporary_memory_pool_for_ps_preparing();
+ }
if (send_prep_stmt(stmt, 0))
DBUG_RETURN(1);
DBUG_RETURN(0);
@@ -677,12 +695,21 @@ static bool mysql_test_upd_fields(Prepared_statement *stmt,
(grant_option && check_grant(thd,UPDATE_ACL,table_list,0,0)))
DBUG_RETURN(1);
#endif
+
+ /*
+ open temporary memory pool for temporary data allocated by derived
+ tables & preparation procedure
+ */
+ thd->allocate_temporary_memory_pool_for_ps_preparing();
+
if (open_and_lock_tables(thd, table_list))
- DBUG_RETURN(1);
+ goto err;
if (setup_tables(table_list) ||
- setup_fields(thd, 0, table_list, fields, 1, 0, 0) ||
- setup_conds(thd, table_list, &conds) || thd->net.report_error)
- DBUG_RETURN(1);
+ setup_fields(thd, 0, table_list, fields, 1, 0, 0) ||
+ setup_conds(thd, table_list, &conds) || thd->net.report_error)
+ goto err;
+
+ thd->free_temporary_memory_pool_for_ps_preparing();
/*
Currently return only column list info only, and we are not
@@ -691,6 +718,9 @@ static bool mysql_test_upd_fields(Prepared_statement *stmt,
if (send_prep_stmt(stmt, 0))
DBUG_RETURN(1);
DBUG_RETURN(0);
+err:
+ thd->free_temporary_memory_pool_for_ps_preparing();
+ DBUG_RETURN(1);
}
/*
@@ -735,41 +765,51 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
if ((&lex->select_lex != lex->all_selects_list &&
lex->unit.create_total_list(thd, lex, &tables)))
DBUG_RETURN(1);
-
+
+ /*
+ open temporary memory pool for temporary data allocated by derived
+ tables & preparation procedure
+ */
+ thd->allocate_temporary_memory_pool_for_ps_preparing();
if (open_and_lock_tables(thd, tables))
- DBUG_RETURN(1);
+ goto err;
if (lex->describe)
{
if (send_prep_stmt(stmt, 0))
- DBUG_RETURN(1);
+ goto err;
}
else
{
if (!result && !(result= new select_send()))
{
send_error(thd, ER_OUT_OF_RESOURCES);
- DBUG_RETURN(1);
+ goto err;
}
- JOIN *join= new JOIN(thd, fields, select_options, result);
thd->used_tables= 0; // Updated by setup_fields
- if (join->prepare(&select_lex->ref_pointer_array,
- (TABLE_LIST*)select_lex->get_table_list(),
- wild_num, conds, og_num, order, group, having, proc,
- select_lex, unit))
- DBUG_RETURN(1);
+ if (unit->prepare(thd, result, 0))
+ goto err_prep;
+
if (send_prep_stmt(stmt, fields.elements) ||
thd->protocol_simple.send_fields(&fields, 0)
#ifndef EMBEDDED_LIBRARY
- || net_flush(&thd->net)
+ || net_flush(&thd->net)
#endif
- )
- DBUG_RETURN(1);
- join->cleanup();
+ )
+ goto err_prep;
+
+ unit->cleanup();
}
- DBUG_RETURN(0);
+ thd->free_temporary_memory_pool_for_ps_preparing();
+ DBUG_RETURN(0);
+
+err_prep:
+ unit->cleanup();
+err:
+ thd->free_temporary_memory_pool_for_ps_preparing();
+ DBUG_RETURN(1);
}
@@ -898,6 +938,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
thd->stmt_backup.set_statement(thd);
thd->set_statement(stmt);
+ thd->current_statement= stmt;
if (alloc_query(thd, packet, packet_length))
goto alloc_query_err;
@@ -925,9 +966,9 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
sl->prep_where= sl->where;
}
- cleanup_items(thd->free_list);
stmt->set_statement(thd);
thd->set_statement(&thd->stmt_backup);
+ thd->current_statement= 0;
if (init_param_items(stmt))
goto init_param_err;
@@ -944,8 +985,14 @@ init_param_err:
alloc_query_err:
/* Statement map deletes statement on erase */
thd->stmt_map.erase(stmt);
+ thd->current_statement= 0;
DBUG_RETURN(1);
insert_stmt_err:
+ stmt->set_statement(thd);
+ thd->set_statement(&thd->stmt_backup);
+ /* Statement map deletes statement on erase */
+ thd->stmt_map.erase(stmt);
+ thd->current_statement= 0;
delete stmt;
DBUG_RETURN(1);
}
@@ -1010,24 +1057,36 @@ void mysql_stmt_execute(THD *thd, char *packet)
/* Fix ORDER list */
for (order=(ORDER *)sl->order_list.first ; order ; order=order->next)
order->item= (Item **)(order+1);
+
+ /*
+ TODO: When the new table structure is ready, then have a status bit
+ to indicate the table is altered, and re-do the setup_*
+ and open the tables back.
+ */
+ for (TABLE_LIST *tables= (TABLE_LIST*) sl->table_list.first;
+ tables;
+ tables= tables->next)
+ {
+ tables->table= 0; // safety - nasty init
+ tables->table_list= 0;
+ }
+
+ {
+ SELECT_LEX_UNIT *unit= sl->master_unit();
+ unit->unclean();
+ unit->types.empty();
+ // for derived tables & PS (which can't be reset by Item_subquery)
+ unit->reinit_exec_mechanism();
+ }
}
- /*
- TODO: When the new table structure is ready, then have a status bit
- to indicate the table is altered, and re-do the setup_*
- and open the tables back.
- */
- for (TABLE_LIST *tables= (TABLE_LIST*) stmt->lex->select_lex.table_list.first;
- tables;
- tables= tables->next)
- tables->table= 0; // safety - nasty init
#ifndef EMBEDDED_LIBRARY
if (stmt->param_count && setup_params_data(stmt))
- DBUG_VOID_RETURN;
+ goto end;
#else
if (stmt->param_count && (*stmt->setup_params_data)(stmt))
- DBUG_VOID_RETURN;
+ goto end;
#endif
if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -1048,8 +1107,10 @@ void mysql_stmt_execute(THD *thd, char *packet)
free_items(thd->free_list);
cleanup_items(stmt->free_list);
+ close_thread_tables(thd); // to close derived tables
free_root(&thd->mem_root, MYF(0));
thd->set_statement(&thd->stmt_backup);
+end:
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 7ae25efebc6..7c1a5ad67b4 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -327,8 +327,7 @@ JOIN::prepare(Item ***rref_pointer_array,
// Is it subselect
{
Item_subselect *subselect;
- if ((subselect= select_lex->master_unit()->item) &&
- select_lex->linkage != GLOBAL_OPTIONS_TYPE)
+ if ((subselect= select_lex->master_unit()->item))
{
Item_subselect::trans_res res;
if ((res= subselect->select_transformer(this)) !=
@@ -1519,10 +1518,10 @@ JOIN::cleanup()
lock=0; // It's faster to unlock later
join_free(1);
- if (exec_tmp_table1)
- free_tmp_table(thd, exec_tmp_table1);
- if (exec_tmp_table2)
- free_tmp_table(thd, exec_tmp_table2);
+ if (exec_tmp_table1)
+ free_tmp_table(thd, exec_tmp_table1);
+ if (exec_tmp_table2)
+ free_tmp_table(thd, exec_tmp_table2);
delete select;
delete_dynamic(&keyuse);
delete procedure;
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 2f55ec6e211..a05fa44cfc9 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -453,3 +453,9 @@ int st_select_lex_unit::cleanup()
}
DBUG_RETURN(error);
}
+
+
+void st_select_lex_unit::reinit_exec_mechanism()
+{
+ prepared= optimized= executed= 0;
+}
diff --git a/tests/client_test.c b/tests/client_test.c
index eda168d7230..d9a180e3c1e 100644
--- a/tests/client_test.c
+++ b/tests/client_test.c
@@ -8189,6 +8189,90 @@ static void test_bug2247()
fprintf(stdout, "OK");
}
+
+
+static void test_subqueries()
+{
+ MYSQL_STMT *stmt;
+ int rc, i;
+ const char *query= "SELECT (SELECT SUM(a+b) FROM t2 where t1.b=t2.b GROUP BY t1.a LIMIT 1) as scalar_s, exists (select 1 from t2 where t2.a/2=t1.a) as exists_s, a in (select a+3 from t2) as in_s, (a-1,b-1) in (select a,b from t2) as in_row_s FROM t1, (select a x, b y from t2) tt WHERE x=a";
+
+ myheader("test_subquery");
+
+ rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2");
+ myquery(rc);
+
+ rc= mysql_query(mysql,"CREATE TABLE t1 (a int , b int);");
+ myquery(rc);
+
+ rc= mysql_query(mysql,
+ "insert into t1 values (1,1), (2, 2), (3,3), (4,4), (5,5);");
+ myquery(rc);
+
+ rc= mysql_query(mysql,"create table t2 select * from t1;");
+ myquery(rc);
+
+ stmt= mysql_prepare(mysql, query, strlen(query));
+ mystmt_init(stmt);
+ for (i= 0; i < 3; i++)
+ {
+ rc= mysql_execute(stmt);
+ mystmt(stmt, rc);
+ assert(5 == my_process_stmt_result(stmt));
+ }
+ mysql_stmt_close(stmt);
+
+ rc= mysql_query(mysql, "DROP TABLE t1,t2");
+ myquery(rc);
+}
+
+
+static void test_bad_union()
+{
+ MYSQL_STMT *stmt;
+ const char *query= "SELECT 1, 2 union SELECT 1";
+
+ myheader("test_bad_union");
+
+ stmt= mysql_prepare(mysql, query, strlen(query));
+ assert(stmt == 0);
+ myerror(NULL);
+}
+
+static void test_distinct()
+{
+ MYSQL_STMT *stmt;
+ int rc, i;
+ const char *query=
+ "SELECT 2+count(distinct b), group_concat(a) FROM t1 group by a";
+
+ myheader("test_subquery");
+
+ rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+ myquery(rc);
+
+ rc= mysql_query(mysql,"CREATE TABLE t1 (a int , b int);");
+ myquery(rc);
+
+ rc= mysql_query(mysql,
+ "insert into t1 values (1,1), (2, 2), (3,3), (4,4), (5,5),\
+(1,10), (2, 20), (3,30), (4,40), (5,50)\;");
+ myquery(rc);
+
+ for (i= 0; i < 3; i++)
+ {
+ stmt= mysql_prepare(mysql, query, strlen(query));
+ mystmt_init(stmt);
+ rc= mysql_execute(stmt);
+ mystmt(stmt, rc);
+ assert(5 == my_process_stmt_result(stmt));
+ mysql_stmt_close(stmt);
+ }
+
+ rc= mysql_query(mysql, "DROP TABLE t1");
+ myquery(rc);
+}
+
/*
Test for bug#2248 "mysql_fetch without prior mysql_execute hangs"
*/
@@ -8385,6 +8469,9 @@ int main(int argc, char **argv)
test_count= 1;
start_time= time((time_t *)0);
+
+ test_subqueries();
+
client_query(); /* simple client query test */
#if NOT_YET_WORKING
/* Used for internal new development debugging */
@@ -8437,7 +8524,8 @@ int main(int argc, char **argv)
client_use_result(); /* usage of mysql_use_result() */
test_tran_bdb(); /* transaction test on BDB table type */
test_tran_innodb(); /* transaction test on InnoDB table type */
- test_prepare_ext(); /* test prepare with all types conversion -- TODO */
+ test_prepare_ext(); /* test prepare with all types
+ conversion -- TODO */
test_prepare_syntax(); /* syntax check for prepares */
test_field_names(); /* test for field names */
test_field_flags(); /* test to help .NET provider team */
@@ -8450,7 +8538,7 @@ int main(int argc, char **argv)
test_stmt_close(); /* mysql_stmt_close() test -- hangs */
test_prepare_field_result(); /* prepare meta info */
test_multi_stmt(); /* multi stmt test */
- test_multi_statements(); /* test multi statement execution */
+ test_multi_statements();/* test multi statement execution */
test_store_result(); /* test the store_result */
test_store_result1(); /* test store result without buffers */
test_store_result2(); /* test store result for misc case */
@@ -8497,6 +8585,10 @@ int main(int argc, char **argv)
test_bug2247(); /* test that mysql_stmt_affected_rows() returns
number of rows affected by last prepared
statement execution */
+ test_subqueries(); /* repeatable subqueries */
+ test_bad_union(); /* correct setup of UNION */
+ test_distinct(); /* distinct aggregate functions */
+
end_time= time((time_t *)0);
total_time+= difftime(end_time, start_time);