diff --git a/.bzrignore b/.bzrignore index b8fac778709..0b5bb0bc33e 100644 --- a/.bzrignore +++ b/.bzrignore @@ -361,6 +361,7 @@ libmysqld/item_func.cc libmysqld/item_geofunc.cc libmysqld/item_row.cc libmysqld/item_strfunc.cc +libmysqld/item_subselect.cc libmysqld/item_sum.cc libmysqld/item_timefunc.cc libmysqld/item_uniq.cc @@ -396,6 +397,7 @@ libmysqld/sql_command libmysqld/sql_crypt.cc libmysqld/sql_db.cc libmysqld/sql_delete.cc +libmysqld/sql_derived.cc libmysqld/sql_do.cc libmysqld/sql_handler.cc libmysqld/sql_help.cc 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/client/client_priv.h b/client/client_priv.h index 910de1f03e9..0c71d72c0b4 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -43,4 +43,5 @@ enum options_client OPT_PROMPT, OPT_IGN_LINES,OPT_TRANSACTION,OPT_MYSQL_PROTOCOL, OPT_SHARED_MEMORY_BASE_NAME, OPT_FRM, OPT_SKIP_OPTIMIZATION, OPT_COMPATIBLE, OPT_RECONNECT, OPT_DELIMITER, OPT_SECURE_AUTH, + OPT_OPEN_FILES_LIMIT }; diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 82a57961c11..50c6e8ca6dc 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -33,6 +33,7 @@ ulong server_id = 0; // needed by net_serv.c ulong bytes_sent = 0L, bytes_received = 0L; ulong mysqld_net_retry_count = 10L; +ulong open_files_limit; uint test_flags = 0; static uint opt_protocol= 0; static FILE *result_file; @@ -68,7 +69,7 @@ static MYSQL* safe_connect(); class Load_log_processor { - char target_dir_name[MY_NFILE]; + char target_dir_name[FN_REFLEN]; int target_dir_name_len; DYNAMIC_ARRAY file_names; @@ -429,6 +430,10 @@ static struct my_option my_long_options[] = {"read-from-remote-server", 'R', "Read binary logs from a MySQL server", (gptr*) &remote_opt, (gptr*) &remote_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"open_files_limit", OPT_OPEN_FILES_LIMIT, + "Used to reserve file descriptors for usage by this program", + (gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG, + REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0}, {"short-form", 's', "Just show the queries, no extra info.", (gptr*) &short_form, (gptr*) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -878,6 +883,7 @@ int main(int argc, char** argv) exit(1); } + my_set_max_open_files(open_files_limit); if (remote_opt) mysql = safe_connect(); @@ -915,6 +921,7 @@ int main(int argc, char** argv) mysql_close(mysql); cleanup(); free_defaults(defaults_argv); + my_free_open_file_info(); my_end(0); exit(exit_value); DBUG_RETURN(exit_value); // Keep compilers happy diff --git a/configure.in b/configure.in index bd337ca72cd..8c167adae4a 100644 --- a/configure.in +++ b/configure.in @@ -1824,29 +1824,32 @@ AC_TYPE_SIGNAL MYSQL_TYPE_QSORT AC_FUNC_UTIME_NULL AC_FUNC_VPRINTF -AC_CHECK_FUNCS(alarm bmove \ - chsize ftruncate rint finite isnan fpsetmask fpresetsticky\ - cuserid fcntl fconvert poll \ - getrusage getpwuid getcwd getrlimit getwd index stpcpy locking longjmp \ - perror pread realpath readlink rename \ - socket strnlen madvise mallinfo mkstemp \ - strtol strtoul strtoll strtoull snprintf tempnam thr_setconcurrency \ - gethostbyaddr_r gethostbyname_r getpwnam \ - bfill bzero bcmp strstr strpbrk strerror \ - tell isinf memcpy memmove \ - setupterm strcasecmp sighold vidattr lrand48 localtime_r gmtime_r \ - sigset sigthreadmask pthread_sigmask pthread_setprio pthread_setprio_np \ - pthread_setschedparam pthread_attr_setprio pthread_attr_setschedparam \ - pthread_attr_create pthread_getsequence_np pthread_attr_setstacksize \ - pthread_attr_getstacksize pthread_key_delete \ - pthread_condattr_create rwlock_init pthread_rwlock_rdlock \ - fsync fdatasync fchmod getpass getpassphrase initgroups mlockall) +AC_CHECK_FUNCS(alarm bcmp bfill bmove bzero chsize cuserid fchmod fcntl \ + fconvert fdatasync finite fpresetsticky fpsetmask fsync ftruncate \ + getcwd gethostbyaddr_r gethostbyname_r getpass getpassphrase getpwnam \ + getpwuid getrlimit getrusage getwd gmtime_r index initgroups isnan \ + localtime_r locking longjmp lrand48 madvise mallinfo memcpy memmove \ + mkstemp mlockall perror poll pread pthread_attr_create \ + pthread_attr_getstacksize pthread_attr_setprio pthread_attr_setschedparam \ + pthread_attr_setstacksize pthread_condattr_create pthread_getsequence_np \ + pthread_key_delete pthread_rwlock_rdlock pthread_setprio \ + pthread_setprio_np pthread_setschedparam pthread_sigmask readlink \ + realpath rename rint rwlock_init setupterm sighold sigset sigthreadmask \ + snprintf socket stpcpy strcasecmp strerror strnlen strpbrk strstr strtol \ + strtoll strtoul strtoull tell tempnam thr_setconcurrency vidattr) + +# isinf() could be a function or a macro (HPUX) +AC_MSG_CHECKING(for isinf with ) +AC_TRY_LINK([#include ], [float f = 0.0; isinf(f)], + AC_MSG_RESULT(yes) AC_DEFINE(HAVE_ISINF,,[isinf() macro or function]), + AC_MSG_RESULT(no)) + CFLAGS="$ORG_CFLAGS" # Sanity check: We chould not have any fseeko symbol unless # large_file_support=yes -AC_CHECK_FUNCS(fseeko, +AC_CHECK_FUNC(fseeko, [if test "$large_file_support" = no -a "$IS_LINUX" = "true"; then AC_MSG_ERROR("Found fseeko symbol but large_file_support is not enabled!"); diff --git a/include/config-win.h b/include/config-win.h index 10490fd2f91..abc1aa7a6ee 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -323,7 +323,7 @@ inline double ulonglong2double(ulonglong value) #define FN_ROOTDIR "\\" #define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */ #define FN_NO_CASE_SENCE /* Files are not case-sensitive */ -#define MY_NFILE 1024 +#define OS_FILE_LIMIT 2048 #define DO_NOT_REMOVE_THREAD_WRAPPERS #define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V)) diff --git a/include/ft_global.h b/include/ft_global.h index c30b0665216..94f6ad9ef51 100644 --- a/include/ft_global.h +++ b/include/ft_global.h @@ -52,7 +52,7 @@ extern const char *ft_precompiled_stopwords[]; extern ulong ft_min_word_len; extern ulong ft_max_word_len; extern ulong ft_query_expansion_limit; -extern const char *ft_boolean_syntax; +extern char ft_boolean_syntax[15]; int ft_init_stopwords(void); void ft_free_stopwords(void); @@ -63,6 +63,7 @@ void ft_free_stopwords(void); #define FT_EXPAND 4 /* query expansion */ FT_INFO *ft_init_search(uint,void *, uint, byte *, uint, byte *); +my_bool ft_boolean_check_syntax_string(const byte *); #ifdef __cplusplus } diff --git a/include/my_global.h b/include/my_global.h index 4a1786f70e2..a8078f579ee 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -384,8 +384,8 @@ typedef unsigned short ushort; #define sgn(a) (((a) < 0) ? -1 : ((a) > 0) ? 1 : 0) #define swap(t,a,b) { register t dummy; dummy = a; a = b; b = dummy; } #define test(a) ((a) ? 1 : 0) -#define set_if_bigger(a,b) { if ((a) < (b)) (a)=(b); } -#define set_if_smaller(a,b) { if ((a) > (b)) (a)=(b); } +#define set_if_bigger(a,b) do { if ((a) < (b)) (a)=(b); } while(0) +#define set_if_smaller(a,b) do { if ((a) > (b)) (a)=(b); } while(0) #define test_all_bits(a,b) (((a) & (b)) == (b)) #define set_bits(type, bit_count) (sizeof(type)*8 <= (bit_count) ? ~(type) 0 : ((((type) 1) << (bit_count)) - (type) 1)) #define array_elements(A) ((uint) (sizeof(A)/sizeof(A[0]))) @@ -535,7 +535,10 @@ typedef SOCKET_SIZE_TYPE size_socket; #define FN_LIBCHAR '/' #define FN_ROOTDIR "/" #endif -#define MY_NFILE 1024 /* This is only used to save filenames */ +#endif +#define MY_NFILE 64 /* This is only used to save filenames */ +#ifndef OS_FILE_LIMIT +#define OS_FILE_LIMIT 65535 #endif /* #define EXT_IN_LIBNAME */ diff --git a/include/my_sys.h b/include/my_sys.h index d3e69a61962..9254f29ee72 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -202,26 +202,13 @@ extern char NEAR curr_dir[]; /* Current directory for user */ extern int (*error_handler_hook)(uint my_err, const char *str,myf MyFlags); extern int (*fatal_error_handler_hook)(uint my_err, const char *str, myf MyFlags); +extern uint my_file_limit; /* charsets */ extern CHARSET_INFO *default_charset_info; extern CHARSET_INFO *all_charsets[256]; extern CHARSET_INFO compiled_charsets[]; -extern uint get_charset_number(const char *cs_name, uint cs_flags); -extern uint get_collation_number(const char *name); -extern const char *get_charset_name(uint cs_number); - -extern CHARSET_INFO *get_charset(uint cs_number, myf flags); -extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags); -extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, - uint cs_flags, myf my_flags); -extern void free_charsets(void); -extern char *get_charsets_dir(char *buf); -extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2); -extern my_bool init_compiled_charsets(myf flags); -extern void add_compiled_collation(CHARSET_INFO *cs); - /* statistics */ extern ulong my_cache_w_requests, my_cache_write, my_cache_r_requests, my_cache_read; @@ -288,14 +275,16 @@ enum file_type FILE_BY_MKSTEMP, FILE_BY_DUP }; -extern struct my_file_info +struct st_my_file_info { my_string name; enum file_type type; #if defined(THREAD) && !defined(HAVE_PREAD) pthread_mutex_t mutex; #endif -} my_file_info[MY_NFILE]; +}; + +extern struct st_my_file_info *my_file_info; typedef struct st_my_tmpdir { @@ -747,6 +736,23 @@ extern uint my_bit_log2(ulong value); extern uint my_count_bits(ulonglong v); extern void my_sleep(ulong m_seconds); extern ulong crc32(ulong crc, const uchar *buf, uint len); +extern uint my_set_max_open_files(uint files); +void my_free_open_file_info(void); + +/* character sets */ +extern uint get_charset_number(const char *cs_name, uint cs_flags); +extern uint get_collation_number(const char *name); +extern const char *get_charset_name(uint cs_number); + +extern CHARSET_INFO *get_charset(uint cs_number, myf flags); +extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags); +extern CHARSET_INFO *get_charset_by_csname(const char *cs_name, + uint cs_flags, myf my_flags); +extern void free_charsets(void); +extern char *get_charsets_dir(char *buf); +extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2); +extern my_bool init_compiled_charsets(myf flags); +extern void add_compiled_collation(CHARSET_INFO *cs); #ifdef __WIN__ extern my_bool have_tcpip; /* Is set if tcpip is used */ diff --git a/innobase/data/data0type.c b/innobase/data/data0type.c index f505cdfb0a2..a1cd34acd23 100644 --- a/innobase/data/data0type.c +++ b/innobase/data/data0type.c @@ -12,7 +12,15 @@ Created 1/16/1996 Heikki Tuuri #include "data0type.ic" #endif -dtype_t dtype_binary_val = {DATA_BINARY, 0, 0, 0, 0}; +/* At the database startup we store the default-charset collation number of +this MySQL installation to this global variable. If we have < 4.1.2 format +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}; dtype_t* dtype_binary = &dtype_binary_val; /************************************************************************* diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c index d6b1b7261ad..5fc2f26fc31 100644 --- a/innobase/dict/dict0crea.c +++ b/innobase/dict/dict0crea.c @@ -1315,7 +1315,7 @@ loop: if (error == DB_DUPLICATE_KEY) { mutex_enter(&dict_foreign_err_mutex); - ut_sprintf_timestamp(dict_foreign_err_buf); + ut_sprintf_timestamp(ebuf); sprintf(ebuf + strlen(ebuf), " Error in foreign key constraint creation for table %.500s.\n" "A foreign key constraint of name %.500s\n" diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index e9076db08f3..07c4ef3c683 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -360,6 +360,15 @@ dict_load_columns( field = rec_get_nth_field(rec, 6, &len); prtype = mach_read_from_4(field); + if (dtype_is_non_binary_string_type(mtype, prtype) + && dtype_get_charset_coll(prtype) == 0) { + /* This is a non-binary string type, and the table + was created with < 4.1.2. Use the default charset. */ + + prtype = dtype_form_prtype(prtype, + data_mysql_default_charset_coll); + } + field = rec_get_nth_field(rec, 7, &len); col_len = mach_read_from_4(field); diff --git a/innobase/include/data0type.h b/innobase/include/data0type.h index f202230bb94..00a0845ace8 100644 --- a/innobase/include/data0type.h +++ b/innobase/include/data0type.h @@ -11,6 +11,9 @@ 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; @@ -18,31 +21,79 @@ typedef struct dtype_struct dtype_t; data type */ extern dtype_t* dtype_binary; -/* Data main types of SQL data */ -#define DATA_VARCHAR 1 /* character varying */ -#define DATA_CHAR 2 /* fixed length character */ +/*-------------------------------------------*/ +/* The 'MAIN TYPE' of a column */ +#define DATA_VARCHAR 1 /* character varying of the + latin1_swedish_ci charset-collation */ +#define DATA_CHAR 2 /* fixed length character of the + latin1_swedish_ci charset-collation */ #define DATA_FIXBINARY 3 /* binary string of fixed length */ #define DATA_BINARY 4 /* binary string */ -#define DATA_BLOB 5 /* binary large object, or a TEXT type; if - prtype & DATA_NONLATIN1 != 0 the data must - be compared by MySQL as a whole field; if - prtype & DATA_BINARY_TYPE == 0, then this is - actually a TEXT column */ +#define DATA_BLOB 5 /* binary large object, or a TEXT type; + if prtype & DATA_BINARY_TYPE == 0, then this is + 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 */ + /* Data types >= DATA_FLOAT must be compared using the whole field, not as binary strings */ + #define DATA_FLOAT 9 #define DATA_DOUBLE 10 #define DATA_DECIMAL 11 /* decimal number stored as an ASCII string */ -#define DATA_VARMYSQL 12 /* non-latin1 varying length char */ -#define DATA_MYSQL 13 /* non-latin1 fixed length char */ +#define DATA_VARMYSQL 12 /* any charset varying length char */ +#define DATA_MYSQL 13 /* any charset fixed length char */ + /* NOTE that 4.1.1 used DATA_MYSQL and + DATA_VARMYSQL for all character sets, and the + charset-collation for tables created with it + can also be latin1_swedish_ci */ #define DATA_MTYPE_MAX 63 /* dtype_store_for_order_and_null_size() requires the values are <= 63 */ /*-------------------------------------------*/ -/* In the lowest byte in the precise type we store the MySQL type code -(not applicable for system columns). */ +/* The 'PRECISE TYPE' of a column */ +/* +Tables created by a MySQL user have the following convention: + +- In the least significant byte in the precise type we store the MySQL type +code (not applicable for system columns). + +- In the second least significant byte we OR flags DATA_NOT_NULL, +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 +< 4.0.14 we do not actually know if it is a BLOB or a TEXT column. Since there +are no indexes on prefixes of BLOB or TEXT columns in < 4.0.14, this is no +problem, though. + +Note that versions < 4.1.2 or < 5.0.1 did not store the charset code to the +precise type, since the charset was always the default charset of the MySQL +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. +*/ #define DATA_ENGLISH 4 /* English language character string: this is a relic from pre-MySQL time and only used @@ -69,7 +120,7 @@ be less than 256 */ #define DATA_MIX_ID_LEN 9 /* maximum stored length for mix id (in a compressed dulint form) */ #define DATA_N_SYS_COLS 4 /* number of system columns defined above */ -/*-------------------------------------------*/ + /* Flags ORed to the precise data type */ #define DATA_NOT_NULL 256 /* this is ORed to the precise type when the column is declared as NOT NULL */ @@ -79,19 +130,53 @@ 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 a DATA_BLOB (actually - TEXT) of a non-latin1 type, this is ORed to - the precise type: this only holds for tables - created with >= MySQL-4.0.14 */ +/* #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 alphabetical order for a single field and decide the storage size of an SQL null*/ -#define DATA_ORDER_NULL_TYPE_BUF_SIZE 4 -/* In the >= 4.1.x storage format we need 2 bytes more for the charset */ +#define DATA_ORDER_NULL_TYPE_BUF_SIZE 4 +/* In the >= 4.1.x storage format we add 2 bytes more so that we can also +store the charset-collation number; one byte is left unused, though */ #define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6 +/************************************************************************* +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( +/*=================*/ + /* out: TRUE if string type */ + ulint mtype); /* in: InnoDB main data type code: DATA_CHAR, ... */ +/************************************************************************* +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 */ +/************************************************************************* +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. */ + +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 */ /************************************************************************* Sets a data type structure. */ UNIV_INLINE @@ -126,6 +211,22 @@ dtype_get_prtype( /*=============*/ dtype_t* type); /************************************************************************* +Gets the MySQL charset-collation code for MySQL string types. */ +UNIV_INLINE +ulint +dtype_get_charset_coll( +/*===================*/ + ulint prtype);/* in: precise data type */ +/************************************************************************* +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 */ +/************************************************************************* Gets the type length. */ UNIV_INLINE ulint @@ -225,9 +326,8 @@ dtype_print( struct dtype_struct{ ulint mtype; /* main data type */ ulint prtype; /* precise type; MySQL data type */ - ulint chrset; /* MySQL character set code */ - /* remaining two fields do not affect alphabetical ordering: */ + /* the remaining two fields do not affect alphabetical ordering: */ ulint len; /* length */ ulint prec; /* precision */ diff --git a/innobase/include/data0type.ic b/innobase/include/data0type.ic index 5d39b3e430b..41127a65183 100644 --- a/innobase/include/data0type.ic +++ b/innobase/include/data0type.ic @@ -8,6 +8,70 @@ 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 TRUE. */ +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 @@ -27,7 +91,6 @@ dtype_set( type->prtype = prtype; type->len = len; type->prec = prec; - type->chrset = 0; ut_ad(dtype_validate(type)); } @@ -72,6 +135,33 @@ dtype_get_prtype( return(type->prtype); } +/************************************************************************* +Gets the MySQL charset-collation code for MySQL string types. */ +UNIV_INLINE +ulint +dtype_get_charset_coll( +/*===================*/ + ulint prtype) /* in: precise data type */ +{ + return((prtype >> 16) & 0xFFUL); +} + +/************************************************************************* +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)); +} + /************************************************************************* Gets the type length. */ UNIV_INLINE @@ -147,20 +237,25 @@ 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); mach_write_to_2(buf + 2, type->len & 0xFFFFUL); - mach_write_to_2(buf + 4, type->chrset & 0xFFFFUL); + mach_write_to_2(buf + 4, dtype_get_charset_coll(type->prtype)); + + /* Note that the second last byte is left unused, because the + charset-collation code is always < 256 */ } /************************************************************************** Reads to a type the stored information which determines its alphabetical -ordering and the storage size of an SQL NULL value. */ +ordering and the storage size of an SQL NULL value. This is the < 4.1.x +storage format. */ UNIV_INLINE void dtype_read_for_order_and_null_size( @@ -177,17 +272,16 @@ 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, + data_mysql_default_charset_coll); } /************************************************************************** Reads to a type the stored information which determines its alphabetical -ordering and the storage size of an SQL NULL value. This is the 4.1.x storage -format. */ +ordering and the storage size of an SQL NULL value. This is the >= 4.1.x +storage format. */ UNIV_INLINE void dtype_new_read_for_order_and_null_size( @@ -195,6 +289,8 @@ dtype_new_read_for_order_and_null_size( dtype_t* type, /* in: type struct */ byte* buf) /* in: buffer for stored type order info */ { + ulint charset_coll; + ut_ad(6 == DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); type->mtype = buf[0] & 63; @@ -204,14 +300,28 @@ 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); - type->chrset = mach_read_from_2(buf + 4); -} + mach_read_from_2(buf + 4); + + charset_coll = mach_read_from_2(buf + 4); + + if (dtype_is_string_type(type->mtype)) { + ut_a(charset_coll < 256); + + if (charset_coll == 0) { + /* This insert buffer record was inserted with MySQL + version < 4.1.2, and the charset-collation code was not + explicitly stored to dtype->prtype at that time. It + must be the default charset-collation of this MySQL + installation. */ + + charset_coll = data_mysql_default_charset_coll; + } + + type->prtype = dtype_form_prtype(type->prtype, charset_coll); + } +} /*************************************************************************** Returns the size of a fixed size data type, 0 if not a fixed size type. */ diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c index abfba3a31c9..86818168db9 100644 --- a/innobase/rem/rem0cmp.c +++ b/innobase/rem/rem0cmp.c @@ -61,10 +61,11 @@ must be a copy of the the one in ha_innobase.cc! */ int innobase_mysql_cmp( -/*===============*/ +/*===============*/ /* out: 1, 0, -1, if a is greater, equal, less than b, respectively */ - int mysql_type, /* in: MySQL type */ + int mysql_type, /* in: MySQL type */ + uint charset_number, /* in: number of the charset */ unsigned char* a, /* in: data field */ unsigned int a_length, /* in: data field length, not UNIV_SQL_NULL */ @@ -97,16 +98,28 @@ cmp_types_are_equal( dtype_t* type1, /* in: type 1 */ dtype_t* type2) /* in: type 2 */ { - if ((type1->mtype == DATA_VARCHAR && type2->mtype == DATA_CHAR) - || (type1->mtype == DATA_CHAR && type2->mtype == DATA_VARCHAR) - || (type1->mtype == DATA_FIXBINARY && type2->mtype == DATA_BINARY) - || (type1->mtype == DATA_BINARY && type2->mtype == DATA_FIXBINARY) - || (type1->mtype == DATA_MYSQL && type2->mtype == DATA_VARMYSQL) - || (type1->mtype == DATA_VARMYSQL && type2->mtype == DATA_MYSQL)) { + if (dtype_is_non_binary_string_type(type1->mtype, type1->prtype) + && dtype_is_non_binary_string_type(type2->mtype, type2->prtype)) { - return(TRUE); + /* Both are non-binary string types: they can be compared if + and only if the charset-collation is the same */ + + if (dtype_get_charset_coll(type1->prtype) + == dtype_get_charset_coll(type2->prtype)) { + return(TRUE); + } + + return(FALSE); } + if (dtype_is_binary_string_type(type1->mtype, type1->prtype) + && dtype_is_binary_string_type(type2->mtype, type2->prtype)) { + + /* Both are binary string types: they can be compared */ + + return(TRUE); + } + if (type1->mtype != type2->mtype) { return(FALSE); @@ -128,11 +141,6 @@ cmp_types_are_equal( return(FALSE); } - if (type1->mtype == DATA_BLOB && (type1->prtype & DATA_BINARY_TYPE) - != (type2->prtype & DATA_BINARY_TYPE)) { - return(FALSE); - } - return(TRUE); } @@ -269,6 +277,7 @@ cmp_whole_field( return(innobase_mysql_cmp( (int)(type->prtype & DATA_MYSQL_TYPE_MASK), + (uint)dtype_get_charset_coll(type->prtype), a, a_length, b, b_length)); default: fprintf(stderr, @@ -322,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)); } @@ -523,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, @@ -845,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/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c index 37e148fe001..6084c70102f 100644 --- a/innobase/trx/trx0sys.c +++ b/innobase/trx/trx0sys.c @@ -45,43 +45,6 @@ or there was no master log position info inside InnoDB. */ char trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN]; ib_longlong trx_sys_mysql_master_log_pos = -1; -/* Do NOT merge this to the 4.1 code base! */ -ibool trx_sys_downgrading_from_4_1_1 = FALSE; - -/******************************************************************** -Do NOT merge this to the 4.1 code base! -Marks the trx sys header when we have successfully downgraded from the >= 4.1.1 -multiple tablespace format back to the 4.0 format. */ - -void -trx_sys_mark_downgraded_from_4_1_1(void) -/*====================================*/ -{ - page_t* page; - byte* doublewrite; - mtr_t mtr; - - /* Let us mark to the trx_sys header that the downgrade has been - done. */ - - mtr_start(&mtr); - - page = buf_page_get(TRX_SYS_SPACE, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr); - buf_page_dbg_add_level(page, SYNC_NO_ORDER_CHECK); - - doublewrite = page + TRX_SYS_DOUBLEWRITE; - - mlog_write_ulint(doublewrite + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED, - TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N + 1, - MLOG_4BYTES, &mtr); - mtr_commit(&mtr); - - /* Flush the modified pages to disk and make a checkpoint */ - log_make_checkpoint_at(ut_dulint_max, TRUE); - - trx_sys_downgrading_from_4_1_1 = FALSE; -} - /******************************************************************** Determines if a page number is located inside the doublewrite buffer. */ @@ -388,31 +351,6 @@ trx_sys_doublewrite_init_or_restore_pages( == TRX_SYS_DOUBLEWRITE_MAGIC_N) { /* The doublewrite buffer has been created */ - /* Do NOT merge to the 4.1 code base! */ - if (mach_read_from_4(doublewrite - + TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED) - == TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N) { - - fprintf(stderr, -"InnoDB: You are downgrading from the multiple tablespace format of\n" -"InnoDB: >= MySQL-4.1.1 back to the old format of MySQL-4.0.\n" -"InnoDB:\n" -"InnoDB: MAKE SURE that the mysqld server is idle, and purge and the insert\n" -"InnoDB: buffer merge have run to completion under >= 4.1.1 before trying to\n" -"InnoDB: downgrade! You can determine this by looking at SHOW INNODB STATUS:\n" -"InnoDB: if the Main thread is 'waiting for server activity' and SHOW\n" -"InnoDB: PROCESSLIST shows that you have ended all other connections\n" -"InnoDB: to mysqld, then purge and the insert buffer merge have been\n" -"InnoDB: completed.\n" -"InnoDB: If you have already created tables in >= 4.1.1, then those\n" -"InnoDB: tables cannot be used under 4.0.\n" -"InnoDB: NOTE THAT this downgrade procedure has not been properly tested!\n" -"InnoDB: The safe way to downgrade is to dump all InnoDB tables and recreate\n" -"InnoDB: the whole tablespace.\n"); - - trx_sys_downgrading_from_4_1_1 = TRUE; - } - trx_doublewrite_init(doublewrite); block1 = trx_doublewrite->block1; diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index 678abc91859..0a5d0936d76 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -50,7 +50,7 @@ mysysheaders = mysys_priv.h my_static.h vioheaders = vio_priv.h mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ my_create.lo my_delete.lo mf_tempfile.lo my_open.lo \ - my_read.lo my_write.lo errors.lo \ + my_file.lo my_read.lo my_write.lo errors.lo \ my_error.lo my_getwd.lo my_div.lo \ mf_pack.lo my_messnc.lo mf_dirname.lo mf_fn_ext.lo\ mf_wcomp.lo typelib.lo safemalloc.lo my_alloc.lo \ 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 8da695c5a9d..d9b01caf0ea 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; @@ -1666,14 +1666,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); } @@ -3312,7 +3312,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"); @@ -3321,7 +3321,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); @@ -3329,7 +3330,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); @@ -3350,7 +3351,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/ltconfig b/ltconfig index c4a16f77012..cc52d4b824f 100755 --- a/ltconfig +++ b/ltconfig @@ -2877,6 +2877,9 @@ DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" +# compatibility with ancient libtool :) +SED=sed + # Used on cygwin: assembler. AS="$AS" diff --git a/ltmain.sh b/ltmain.sh index 8bf1b20bc85..953f6e71761 100644 --- a/ltmain.sh +++ b/ltmain.sh @@ -132,7 +132,7 @@ win32_libid () { if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ grep -E 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then win32_nmres=`eval $NM -f posix -A $1 | \ - sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'` + $SED -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'` if test "X$win32_nmres" = "Ximport" ; then win32_libid_type="x86 archive import" else diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index 1e3d47577d2..38afbb527d5 100644 --- a/myisam/ft_nlq_search.c +++ b/myisam/ft_nlq_search.c @@ -174,7 +174,7 @@ static int walk_and_push(FT_SUPERDOC *from, { DBUG_ENTER("walk_and_copy"); from->doc.weight+=from->tmp_weight*from->word_ptr->weight; - set_if_smaller(best->elements, ft_query_expansion_limit-1) + set_if_smaller(best->elements, ft_query_expansion_limit-1); queue_insert(best, (byte *)& from->doc); DBUG_RETURN(0); } diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index f68bf3f030c..250e92566b7 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -73,6 +73,26 @@ FT_WORD * ft_linearize(TREE *wtree) DBUG_RETURN(wlist); } +my_bool ft_boolean_check_syntax_string(const byte *str) +{ + uint i, j; + + if (!str || + (strlen(str)+1 != sizeof(ft_boolean_syntax)) || + (str[0] != ' ' && str[1] != ' ')) + return 1; + for (i=0; i 127 || my_isalnum(default_charset_info, str[i])) + return 1; + for (j=0; jstate.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/myisam/myisamlog.c b/myisam/myisamlog.c index c9b00be7d9e..82f6277ce25 100644 --- a/myisam/myisamlog.c +++ b/myisam/myisamlog.c @@ -60,7 +60,6 @@ static int file_info_compare(void *cmp_arg, void *a,void *b); static int test_if_open(struct file_info *key,element_count count, struct test_if_open_param *param); static void fix_blob_pointers(MI_INFO *isam,byte *record); -static uint set_maximum_open_files(uint); static int test_when_accessed(struct file_info *key,element_count count, struct st_access_param *access_param); static void file_info_free(struct file_info *info); @@ -89,9 +88,8 @@ int main(int argc, char **argv) log_filename=myisam_log_filename; get_options(&argc,&argv); - /* Nr of isam-files */ - max_files=(set_maximum_open_files(min(max_files,8))-6)/2; - + /* Number of MyISAM files we can have open at one time */ + max_files= (my_set_max_open_files(min(max_files,8))-6)/2; if (update) printf("Trying to %s MyISAM files according to log '%s'\n", (recover ? "recover" : "update"),log_filename); @@ -123,6 +121,7 @@ int main(int argc, char **argv) printf("Had to do %d re-open because of too few possibly open files\n", re_open_count); VOID(mi_panic(HA_PANIC_CLOSE)); + my_free_open_file_info(); my_end(test_info ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR); exit(error); return 0; /* No compiler warning */ @@ -732,38 +731,6 @@ static void fix_blob_pointers(MI_INFO *info, byte *record) } } -static uint set_maximum_open_files(uint maximum_files) -{ -#if defined(HAVE_GETRUSAGE) && defined(RLIMIT_NOFILE) - struct rlimit rlimit; - int old_max; - - if (maximum_files > MY_NFILE) - maximum_files=MY_NFILE; /* Don't crash my_open */ - - if (!getrlimit(RLIMIT_NOFILE,&rlimit)) - { - old_max=rlimit.rlim_max; - if (maximum_files && (int) maximum_files > old_max) - rlimit.rlim_max=maximum_files; - rlimit.rlim_cur=rlimit.rlim_max; - if (setrlimit(RLIMIT_NOFILE,&rlimit)) - { - if (old_max != (int) maximum_files) - { /* Set as much as we can */ - rlimit.rlim_max=rlimit.rlim_cur=old_max; - setrlimit(RLIMIT_NOFILE,&rlimit); - } - } - getrlimit(RLIMIT_NOFILE,&rlimit); /* Read if broken setrlimit */ - if (maximum_files && maximum_files < rlimit.rlim_cur) - VOID(fprintf(stderr,"Warning: Error from setrlimit: Max open files is %d\n",old_max)); - return rlimit.rlim_cur; - } -#endif - return min(maximum_files,MY_NFILE); -} - /* close the file with hasn't been accessed for the longest time */ /* ARGSUSED */ diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index b7498ab2bc7..ad1f7785527 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -168,4 +168,4 @@ hex(s1) 41 drop table t1; create table t1 (a char(160) character set utf8, primary key(a)); -ERROR HY000: Incorrect sub part key. The used key part isn't a string, the used length is longer than the key part or the storage engine doesn't support unique sub keys +ERROR 42000: Specified key was too long; max key length is 255 bytes diff --git a/mysql-test/r/fulltext_var.result b/mysql-test/r/fulltext_var.result index 89d477c1a7c..cdbbfc3f5ea 100644 --- a/mysql-test/r/fulltext_var.result +++ b/mysql-test/r/fulltext_var.result @@ -1,3 +1,4 @@ +drop table if exists t1; show variables like "ft\_%"; Variable_name Value ft_boolean_syntax + -><()~*:""&| @@ -5,3 +6,33 @@ ft_min_word_len 4 ft_max_word_len 84 ft_query_expansion_limit 20 ft_stopword_file (built-in) +create table t1 (b text not null); +insert t1 values ('aaaaaa bbbbbb cccccc'); +insert t1 values ('bbbbbb cccccc'); +insert t1 values ('aaaaaa cccccc'); +select * from t1 where match b against ('+aaaaaa bbbbbb' in boolean mode); +b +aaaaaa bbbbbb cccccc +aaaaaa cccccc +set ft_boolean_syntax=' +-><()~*:""&|'; +ERROR HY000: Variable 'ft_boolean_syntax' is a GLOBAL variable and should be set with SET GLOBAL +set global ft_boolean_syntax=' +-><()~*:""&|'; +select * from t1 where match b against ('+aaaaaa bbbbbb' in boolean mode); +b +aaaaaa bbbbbb cccccc +bbbbbb cccccc +set global ft_boolean_syntax='@ -><()~*:""&|'; +select * from t1 where match b against ('+aaaaaa bbbbbb' in boolean mode); +b +aaaaaa bbbbbb cccccc +bbbbbb cccccc +aaaaaa cccccc +select * from t1 where match b against ('+aaaaaa @bbbbbb' in boolean mode); +b +aaaaaa bbbbbb cccccc +bbbbbb cccccc +set global ft_boolean_syntax='@ -><()~*:""@|'; +ERROR 42000: Variable 'ft_boolean_syntax' can't be set to the value of '@ -><()~*:""@|' +set global ft_boolean_syntax='+ -><()~*:""@!|'; +ERROR 42000: Variable 'ft_boolean_syntax' can't be set to the value of '+ -><()~*:""@!|' +drop table t1; 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/myisam.result b/mysql-test/r/myisam.result index 278b9f41480..1f3e12a33aa 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -323,10 +323,10 @@ 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 +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 +ERROR 42000: Specified key was too long; max key length is 500 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 330464fe669..a895325d1fc 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -346,9 +346,17 @@ 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))); -ERROR HY000: Incorrect sub part key. The used key part isn't a string, the used length is longer than the key part or the storage engine doesn't support unique sub keys -create table t1 (a text, key (a(255))); +Warnings: +Warning 1071 Specified key was too long; max key length is 255 bytes +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` text, + KEY `a` (`a`(255)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; CREATE TABLE t1 ( t1_id bigint(21) NOT NULL auto_increment, diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 49b1ed94757..6361f49fe55 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -103,5 +103,5 @@ drop table t1; # Bug 2699 # UTF8 breaks primary keys for cols > 85 characters # ---error 1089 +--error 1071 create table t1 (a char(160) character set utf8, primary key(a)); diff --git a/mysql-test/t/fulltext_var.test b/mysql-test/t/fulltext_var.test index 71213d1195a..8cc8acf60a6 100644 --- a/mysql-test/t/fulltext_var.test +++ b/mysql-test/t/fulltext_var.test @@ -1,5 +1,27 @@ # # Fulltext configurable parameters # +--disable_warnings +drop table if exists t1; +--enable_warnings show variables like "ft\_%"; + +create table t1 (b text not null); +insert t1 values ('aaaaaa bbbbbb cccccc'); +insert t1 values ('bbbbbb cccccc'); +insert t1 values ('aaaaaa cccccc'); +select * from t1 where match b against ('+aaaaaa bbbbbb' in boolean mode); +-- error 1229 +set ft_boolean_syntax=' +-><()~*:""&|'; +set global ft_boolean_syntax=' +-><()~*:""&|'; +select * from t1 where match b against ('+aaaaaa bbbbbb' in boolean mode); +set global ft_boolean_syntax='@ -><()~*:""&|'; +select * from t1 where match b against ('+aaaaaa bbbbbb' in boolean mode); +select * from t1 where match b against ('+aaaaaa @bbbbbb' in boolean mode); +-- error 1231 +set global ft_boolean_syntax='@ -><()~*:""@|'; +-- error 1231 +set global ft_boolean_syntax='+ -><()~*:""@!|'; +drop table t1; + 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/type_blob.test b/mysql-test/t/type_blob.test index c826e59b29d..97c38057e72 100644 --- a/mysql-test/t/type_blob.test +++ b/mysql-test/t/type_blob.test @@ -121,8 +121,10 @@ select c,count(*) from t1 group by c; select d,count(*) from t1 group by d; drop table t1; -!$1089 create table t1 (a text, key (a(300))); # should give an error -create table t1 (a text, key (a(255))); +-- 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 +show create table t1; drop table t1; # diff --git a/mysys/Makefile.am b/mysys/Makefile.am index bd508b8de12..eb6d21c360a 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -25,8 +25,8 @@ noinst_HEADERS = mysys_priv.h my_static.h \ my_os2cond.c my_os2dirsrch.c my_os2dirsrch.h \ my_os2dlfcn.c my_os2file64.c my_os2mutex.c \ my_os2thread.c my_os2tls.c -libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ - mf_path.c mf_loadpath.c\ +libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c \ + mf_path.c mf_loadpath.c my_file.c \ my_open.c my_create.c my_dup.c my_seek.c my_read.c \ my_pread.c my_write.c \ mf_keycache.c mf_keycaches.c my_crc32.c \ diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 52b7f153e0d..689391537f8 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -1961,7 +1961,7 @@ int key_cache_write(KEY_CACHE *keycache, else if (! (block->status & BLOCK_CHANGED)) link_to_changed_list(keycache, block); - set_if_smaller(block->offset, offset) + set_if_smaller(block->offset, offset); set_if_bigger(block->length, read_length+offset); if (! (block->status & BLOCK_ERROR)) diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index 2961e57d28f..34a03391bc4 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -68,7 +68,7 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size, */ void reset_root_defaults(MEM_ROOT *mem_root, uint block_size, - uint pre_alloc_size) + uint pre_alloc_size __attribute__((unused))) { mem_root->block_size= block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8; #if !(defined(HAVE_purify) && defined(EXTRA_DEBUG)) diff --git a/mysys/my_div.c b/mysys/my_div.c index 777ffe403d7..9141ff4fcc5 100644 --- a/mysys/my_div.c +++ b/mysys/my_div.c @@ -27,7 +27,7 @@ my_string my_filename(File fd) { DBUG_ENTER("my_filename"); - if (fd >= MY_NFILE) + if ((uint) fd >= (uint) my_file_limit) DBUG_RETURN((char*) "UNKNOWN"); if (fd >= 0 && my_file_info[fd].type != UNOPEN) { diff --git a/mysys/my_dup.c b/mysys/my_dup.c index df298780e3e..4b7434e29ea 100644 --- a/mysys/my_dup.c +++ b/mysys/my_dup.c @@ -32,7 +32,7 @@ File my_dup(File file, myf MyFlags) DBUG_ENTER("my_dup"); DBUG_PRINT("my",("file: %d MyFlags: %d", MyFlags)); fd = dup(file); - filename= (((int) file < MY_NFILE) ? + filename= (((uint) file < my_file_limit) ? my_file_info[(int) file].name : "Unknown"); DBUG_RETURN(my_register_filename(fd, filename, FILE_BY_DUP, EE_FILENOTFOUND, MyFlags)); diff --git a/mysys/my_file.c b/mysys/my_file.c new file mode 100644 index 00000000000..6a9d39cf944 --- /dev/null +++ b/mysys/my_file.c @@ -0,0 +1,147 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "mysys_priv.h" +#include "my_static.h" +#include + +/* + set how many open files we want to be able to handle + + SYNOPSIS + set_maximum_open_files() + max_file_limit Files to open + + NOTES + The request may not fulfilled becasue of system limitations + + RETURN + Files available to open. + May be more or less than max_file_limit! +*/ + +#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) && !defined(HAVE_mit_thread) + +#ifndef RLIM_INFINITY +#define RLIM_INFINITY ((uint) 0xffffffff) +#endif + +static uint set_max_open_files(uint max_file_limit) +{ + struct rlimit rlimit; + uint old_cur; + DBUG_ENTER("set_max_open_files"); + DBUG_PRINT("enter",("files: %u", max_file_limit)); + + if (!getrlimit(RLIMIT_NOFILE,&rlimit)) + { + old_cur= (uint) rlimit.rlim_cur; + DBUG_PRINT("info", ("rlim_cur: %u rlim_max: %u", + (uint) rlimit.rlim_cur, + (uint) rlimit.rlim_max)); + if (rlimit.rlim_cur == RLIM_INFINITY) + rlimit.rlim_cur = max_file_limit; + if (rlimit.rlim_cur >= max_file_limit) + DBUG_RETURN(rlimit.rlim_cur); /* purecov: inspected */ + rlimit.rlim_cur= rlimit.rlim_max= max_file_limit; + if (setrlimit(RLIMIT_NOFILE, &rlimit)) + max_file_limit= old_cur; /* Use original value */ + else + { + rlimit.rlim_cur= 0; /* Safety if next call fails */ + (void) getrlimit(RLIMIT_NOFILE,&rlimit); + DBUG_PRINT("info", ("rlim_cur: %u", (uint) rlimit.rlim_cur)); + if (rlimit.rlim_cur) /* If call didn't fail */ + max_file_limit= (uint) rlimit.rlim_cur; + } + } + DBUG_PRINT("exit",("max_file_limit: %u", max_file_limit)); + DBUG_RETURN(max_file_limit); +} + +#elif defined (OS2) + +static uint set_max_open_files(uint max_file_limit) +{ + LONG cbReqCount; + ULONG cbCurMaxFH0; + APIRET ulrc; + DBUG_ENTER("set_max_open_files"); + + /* get current limit */ + cbReqCount = 0; + DosSetRelMaxFH( &cbReqCount, &cbCurMaxFH0); + + /* set new limit */ + if ((cbReqCount = max_file_limit - cbCurMaxFH0) > 0) + ulrc = DosSetRelMaxFH( &cbReqCount, &cbCurMaxFH); + DBUG_RETURN(cbCurMaxFH0); +} + +#else +static int set_max_open_files(uint max_file_limit) +{ + /* We don't know the limit. Return best guess */ + return min(max_file_limit, OS_FILE_LIMIT); +} +#endif + + +/* + Change number of open files + + SYNOPSIS: + my_set_max_open_files() + files Number of requested files + + RETURN + number of files available for open +*/ + +uint my_set_max_open_files(uint files) +{ + struct st_my_file_info *tmp; + DBUG_ENTER("my_set_max_open_files"); + DBUG_PRINT("enter",("files: %u my_file_limit: %u", files, my_file_limit)); + + files= set_max_open_files(min(files, OS_FILE_LIMIT)); + if (files <= MY_NFILE) + DBUG_RETURN(files); + + if (!(tmp= (struct st_my_file_info*) my_malloc(sizeof(*tmp) * files, + MYF(MY_WME)))) + DBUG_RETURN(MY_NFILE); + + /* Copy any initialized files */ + memcpy((char*) tmp, (char*) my_file_info, sizeof(*tmp) * my_file_limit); + my_free_open_file_info(); /* Free if already allocated */ + my_file_info= tmp; + my_file_limit= files; + DBUG_PRINT("exit",("files: %u", files)); + DBUG_RETURN(files); +} + + +void my_free_open_file_info() +{ + DBUG_ENTER("my_free_file_info"); + if (my_file_info != my_file_info_default) + { + my_free((char*) my_file_info, MYF(0)); + my_file_info= my_file_info_default; + } + DBUG_VOID_RETURN; +} diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c index d3b0b90f9c5..8906a288b11 100644 --- a/mysys/my_fopen.c +++ b/mysys/my_fopen.c @@ -42,7 +42,7 @@ FILE *my_fopen(const char *FileName, int Flags, myf MyFlags) on some OS (SUNOS). Actually the filename save isn't that important so we can ignore if this doesn't work. */ - if ((uint) fileno(fd) >= MY_NFILE) + if ((uint) fileno(fd) >= my_file_limit) { thread_safe_increment(my_stream_opened,&THR_LOCK_open); DBUG_RETURN(fd); /* safeguard */ @@ -91,7 +91,7 @@ int my_fclose(FILE *fd, myf MyFlags) } else my_stream_opened--; - if ((uint) file < MY_NFILE && my_file_info[file].type != UNOPEN) + if ((uint) file < my_file_limit && my_file_info[file].type != UNOPEN) { my_file_info[file].type = UNOPEN; my_free(my_file_info[file].name, MYF(MY_ALLOW_ZERO_PTR)); @@ -123,11 +123,11 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags) { pthread_mutex_lock(&THR_LOCK_open); my_stream_opened++; - if (Filedes < MY_NFILE) + if ((uint) Filedes < (uint) my_file_limit) { if (my_file_info[Filedes].type != UNOPEN) { - my_file_opened--; /* File is opened with my_open ! */ + my_file_opened--; /* File is opened with my_open ! */ } else { diff --git a/mysys/my_open.c b/mysys/my_open.c index 97f21724e1c..ca5c0d8683f 100644 --- a/mysys/my_open.c +++ b/mysys/my_open.c @@ -86,7 +86,7 @@ int my_close(File fd, myf MyFlags) if (MyFlags & (MY_FAE | MY_WME)) my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),my_filename(fd),errno); } - if ((uint) fd < MY_NFILE && my_file_info[fd].type != UNOPEN) + if ((uint) fd < my_file_limit && my_file_info[fd].type != UNOPEN) { my_free(my_file_info[fd].name, MYF(0)); #if defined(THREAD) && !defined(HAVE_PREAD) @@ -115,7 +115,7 @@ File my_register_filename(File fd, const char *FileName, enum file_type { if ((int) fd >= 0) { - if ((int) fd >= MY_NFILE) + if ((uint) fd >= my_file_limit) { #if defined(THREAD) && !defined(HAVE_PREAD) (void) my_close(fd,MyFlags); diff --git a/mysys/my_static.c b/mysys/my_static.c index b24ef28b7b1..5f034555156 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -34,7 +34,9 @@ int NEAR my_umask=0664, NEAR my_umask_dir=0777; #ifndef THREAD int NEAR my_errno=0; #endif -struct my_file_info my_file_info[MY_NFILE]= {{0,UNOPEN}}; +struct st_my_file_info my_file_info_default[MY_NFILE]= {{0,UNOPEN}}; +uint my_file_limit= MY_NFILE; +struct st_my_file_info *my_file_info= my_file_info_default; /* From mf_brkhant */ int NEAR my_dont_interrupt=0; diff --git a/mysys/my_static.h b/mysys/my_static.h index 08d1a93692f..bb408aa808d 100644 --- a/mysys/my_static.h +++ b/mysys/my_static.h @@ -68,6 +68,8 @@ extern byte *sf_min_adress,*sf_max_adress; extern uint sf_malloc_count; extern struct st_irem *sf_malloc_root; +extern struct st_my_file_info my_file_info_default[MY_NFILE]; + #if defined(THREAD) && !defined(__WIN__) extern sigset_t my_signals; /* signals blocked by mf_brkhant */ #endif diff --git a/sql-common/client.c b/sql-common/client.c index 36b2c6122dd..a4ec7db6515 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2197,7 +2197,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 161b9fe6c32..40ba7ab1cef 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -290,7 +290,7 @@ convert_error_code_to_mysql( } else if (error == (int) DB_CANNOT_DROP_CONSTRAINT) { - return(HA_ERR_ROW_IS_REFERENCED); + return(HA_ERR_ROW_IS_REFERENCED); } else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) { @@ -755,7 +755,7 @@ innobase_init(void) srv_set_thread_priorities = TRUE; srv_query_thread_priority = QUERY_PRIOR; } - + /* Set InnoDB initialization parameters according to the values read from MySQL .cnf file */ @@ -870,16 +870,22 @@ innobase_init(void) srv_print_verbose_log = mysql_embedded ? 0 : 1; - if (strcmp(default_charset_info->name, "latin1") == 0) { + /* Store the default charset-collation number of this MySQL + installation */ - /* Store the character ordering table to InnoDB. - For non-latin1 charsets we use the MySQL comparison - functions, and consequently we do not need to know - the ordering internally in InnoDB. */ + data_mysql_default_charset_coll = (ulint)default_charset_info->number; - memcpy(srv_latin1_ordering, - default_charset_info->sort_order, 256); - } + 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, + (char*)"latin1_swedish_ci")); + memcpy(srv_latin1_ordering, my_charset_latin1.sort_order, 256); /* Since we in this module access directly the fields of a trx struct, and due to different headers and flags it might happen that @@ -1661,10 +1667,10 @@ reset_null_bits( extern "C" { /***************************************************************** -InnoDB uses this function is to compare two data fields for which the -data type is such that we must use MySQL code to compare them. NOTE that the -prototype of this function is in rem0cmp.c in InnoDB source code! -If you change this function, remember to update the prototype there! */ +InnoDB uses this function to compare two data fields for which the data type +is such that we must use MySQL code to compare them. NOTE that the prototype +of this function is in rem0cmp.c in InnoDB source code! If you change this +function, remember to update the prototype there! */ int innobase_mysql_cmp( @@ -1672,6 +1678,7 @@ innobase_mysql_cmp( /* out: 1, 0, -1, if a is greater, equal, less than b, respectively */ int mysql_type, /* in: MySQL type */ + uint charset_number, /* in: number of the charset */ unsigned char* a, /* in: data field */ unsigned int a_length, /* in: data field length, not UNIV_SQL_NULL */ @@ -1679,6 +1686,7 @@ innobase_mysql_cmp( unsigned int b_length) /* in: data field length, not UNIV_SQL_NULL */ { + CHARSET_INFO* charset; enum_field_types mysql_tp; int ret; @@ -1695,9 +1703,27 @@ innobase_mysql_cmp( case FIELD_TYPE_MEDIUM_BLOB: case FIELD_TYPE_BLOB: case FIELD_TYPE_LONG_BLOB: - // BAR TODO: Discuss with heikki.tuuri@innodb.com - // so that he sends CHARSET_INFO for the field to this function. - ret = my_strnncoll(default_charset_info, + /* Use the charset number to pick the right charset struct for + the comparison. Since the MySQL function get_charset may be + slow before Bar removes the mutex operation there, we first + look at 2 common charsets directly. */ + + if (charset_number == default_charset_info->number) { + charset = default_charset_info; + } else if (charset_number == my_charset_latin1.number) { + charset = &my_charset_latin1; + } else { + charset = get_charset(charset_number, MYF(MY_WME)); + + if (charset == NULL) { + fprintf(stderr, +"InnoDB: fatal error: InnoDB needs charset %lu for doing a comparison,\n" +"InnoDB: but MySQL cannot find that charset.\n", (ulong)charset_number); + ut_a(0); + } + } + + ret = my_strnncoll(charset, a, a_length, b, b_length); if (ret < 0) { @@ -1724,9 +1750,9 @@ get_innobase_type_from_mysql_type( /* out: DATA_BINARY, DATA_VARCHAR, ... */ Field* field) /* in: MySQL field */ { - /* The following asserts check that the MySQL type code fits in - 8 bits: this is used in ibuf and also when DATA_NOT_NULL is - ORed to the type */ + /* The following asserts try to check that the MySQL type code fits in + 8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to + the type */ DBUG_ASSERT((ulint)FIELD_TYPE_STRING < 256); DBUG_ASSERT((ulint)FIELD_TYPE_VAR_STRING < 256); @@ -1741,8 +1767,8 @@ get_innobase_type_from_mysql_type( return(DATA_BINARY); } else if (strcmp( - default_charset_info->name, - "latin1") == 0) { + field->charset()->name, + "latin1_swedish_ci") == 0) { return(DATA_VARCHAR); } else { return(DATA_VARMYSQL); @@ -1751,8 +1777,8 @@ get_innobase_type_from_mysql_type( return(DATA_FIXBINARY); } else if (strcmp( - default_charset_info->name, - "latin1") == 0) { + field->charset()->name, + "latin1_swedish_ci") == 0) { return(DATA_CHAR); } else { return(DATA_MYSQL); @@ -3237,7 +3263,7 @@ create_table_def( ulint nulls_allowed; ulint unsigned_type; ulint binary_type; - ulint nonlatin1_type; + ulint charset_no; ulint i; DBUG_ENTER("create_table_def"); @@ -3266,24 +3292,28 @@ create_table_def( unsigned_type = 0; } - if (col_type == DATA_BLOB - && strcmp(default_charset_info->name, "latin1") != 0) { - nonlatin1_type = DATA_NONLATIN1; - } else { - nonlatin1_type = 0; - } - if (field->binary()) { binary_type = DATA_BINARY_TYPE; - nonlatin1_type = 0; } else { binary_type = 0; } + charset_no = 0; + + if (dtype_is_string_type(col_type)) { + + charset_no = (ulint)field->charset()->number; + + ut_a(charset_no < 256); /* in ut0type.h we assume that + the number fits in one byte */ + } + dict_mem_table_add_col(table, (char*) field->field_name, - col_type, (ulint)field->type() + col_type, dtype_form_prtype( + (ulint)field->type() | nulls_allowed | unsigned_type - | nonlatin1_type | binary_type, + | binary_type, + + charset_no), field->pack_length(), 0); } @@ -3467,7 +3497,7 @@ ha_innobase::create( /* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020, but we play safe here */ - DBUG_RETURN(HA_ERR_TO_BIG_ROW); + DBUG_RETURN(HA_ERR_TO_BIG_ROW); } /* Get the transaction associated with the current thd, or create one @@ -3681,7 +3711,7 @@ ha_innobase::delete_table( int error; trx_t* parent_trx; trx_t* trx; - THD *thd= current_thd; + THD *thd= current_thd; char norm_name[1000]; DBUG_ENTER("ha_innobase::delete_table"); @@ -4408,7 +4438,7 @@ ha_innobase::get_foreign_key_create_info(void) prebuilt->trx->op_info = (char*)""; return(str); -} +} /*********************************************************************** Checks if a table is referenced by a foreign key. The MySQL manual states that @@ -4649,10 +4679,10 @@ ha_innobase::external_lock( if (trx->isolation_level == TRX_ISO_SERIALIZABLE && prebuilt->select_lock_type == LOCK_NONE && (thd->options - & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { + & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { - /* To get serializable execution, we let InnoDB - conceptually add 'LOCK IN SHARE MODE' to all SELECTs + /* To get serializable execution, we let InnoDB + conceptually add 'LOCK IN SHARE MODE' to all SELECTs which otherwise would have been consistent reads. An exception is consistent reads in the AUTOCOMMIT=1 mode: we know that they are read-only transactions, and they 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 ""; } 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"); - SELECT_LEX *select_lex= join->select_lex; + if (changed) + { + DBUG_RETURN(RES_OK); + } - THD *thd_tmp= join->thd; - thd_tmp->where= "scalar IN/ALL/ANY subquery"; + SELECT_LEX *select_lex= join->select_lex; + Statement backup; + + 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 *)"", 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 *)"", - (char *)"")); + /* + 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 *)"", + (char *)"")); 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 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 *) "", - (char *) ""); - func= - eq_creator.create(new Item_ref((*optimizer->get_cache())-> - addr(i), - NULL, - (char *)"", + uint n= left_expr->cols(); + List_iterator_fast 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 *) "", + (char *) ""); + func= + eq_creator.create(new Item_ref((*optimizer->get_cache())-> + addr(i), + NULL, + (char *)"", (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 54b8c486673..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); @@ -779,7 +779,8 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create); extern time_t start_time; extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], - mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[]; + mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[], + opt_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; #define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list)) extern MY_TMPDIR mysql_tmpdir_list; extern const char *command_name[]; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4feadd8ac20..af61d624464 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -183,9 +183,6 @@ inline void reset_floating_point_exceptions() #else #include // For thr_setconcurency() #endif -#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) && !defined(HAVE_mit_thread) -#define SET_RLIMIT_NOFILE -#endif #ifdef SOLARIS extern "C" int gethostname(char *name, int namelen); @@ -318,7 +315,8 @@ char* log_error_file_ptr= log_error_file; char mysql_real_data_home[FN_REFLEN], language[LIBLEN],reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN], max_sort_char,*mysqld_user,*mysqld_chroot, *opt_init_file, - *opt_init_connect, *opt_init_slave; + *opt_init_connect, *opt_init_slave, + opt_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; const char *opt_date_time_formats[3]; @@ -492,9 +490,6 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg); static pthread_handler_decl(handle_connections_shared_memory,arg); #endif extern "C" pthread_handler_decl(handle_slave,arg); -#ifdef SET_RLIMIT_NOFILE -static uint set_maximum_open_files(uint max_file_limit); -#endif static ulong find_bit_type(const char *x, TYPELIB *bit_lib); static void clean_up(bool print_message); static void clean_up_mutexes(void); @@ -919,6 +914,7 @@ void clean_up(bool print_message) #ifdef USE_RAID end_raid(); #endif + my_free_open_file_info(); my_free((char*) global_system_variables.date_format, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) global_system_variables.time_format, @@ -2108,28 +2104,32 @@ static int init_common_variables(const char *conf_file_name, int argc, DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname, server_version, SYSTEM_TYPE,MACHINE_TYPE)); -#if defined( SET_RLIMIT_NOFILE) || defined( OS2) /* connections and databases needs lots of files */ { - uint wanted_files=10+(uint) max(max_connections*5, - max_connections+table_cache_size*2); + uint files, wanted_files; + + wanted_files= 10+(uint) max(max_connections*5, + max_connections+table_cache_size*2); set_if_bigger(wanted_files, open_files_limit); - // Note that some system returns 0 if we succeed here: - uint files=set_maximum_open_files(wanted_files); - if (files && files < wanted_files && ! open_files_limit) + files= my_set_max_open_files(wanted_files); + + if (files < wanted_files) { - max_connections= (ulong) min((files-10),max_connections); - table_cache_size= (ulong) max((files-10-max_connections)/2,64); - DBUG_PRINT("warning", - ("Changed limits: max_connections: %ld table_cache: %ld", - max_connections,table_cache_size)); - sql_print_error("Warning: Changed limits: max_connections: %ld table_cache: %ld",max_connections,table_cache_size); + if (!open_files_limit) + { + max_connections= (ulong) min((files-10),max_connections); + table_cache_size= (ulong) max((files-10-max_connections)/2,64); + DBUG_PRINT("warning", + ("Changed limits: max_open_files: %u max_connections: %ld table_cache: %ld", + files, max_connections, table_cache_size)); + sql_print_error("Warning: Changed limits: max_open_files: %u max_connections: %ld table_cache: %ld", + files, max_connections, table_cache_size); + } + else + sql_print_error("Warning: Could not increase number of max_open_files to more than %u (request: %u)", files, wanted_files); } open_files_limit= files; } -#else - open_files_limit= 0; /* Can't set or detect limit */ -#endif unireg_init(opt_specialflag); /* Set up extern variabels */ if (init_errmessage()) /* Read error messages from file */ return 1; @@ -3603,7 +3603,7 @@ enum options_mysqld OPT_BACK_LOG, OPT_BINLOG_CACHE_SIZE, OPT_CONNECT_TIMEOUT, OPT_DELAYED_INSERT_TIMEOUT, OPT_DELAYED_INSERT_LIMIT, OPT_DELAYED_QUEUE_SIZE, - OPT_FLUSH_TIME, OPT_FT_MIN_WORD_LEN, + OPT_FLUSH_TIME, OPT_FT_MIN_WORD_LEN, OPT_FT_BOOLEAN_SYNTAX, OPT_FT_MAX_WORD_LEN, OPT_FT_QUERY_EXPANSION_LIMIT, OPT_FT_STOPWORD_FILE, OPT_INTERACTIVE_TIMEOUT, OPT_JOIN_BUFF_SIZE, OPT_KEY_BUFFER_SIZE, OPT_KEY_CACHE_BLOCK_SIZE, @@ -3926,7 +3926,8 @@ Disable with --skip-bdb (will save memory).", 0, 0, 0, 0}, {"master-password", OPT_MASTER_PASSWORD, "The password the slave thread will authenticate with when connecting to the master. If not set, an empty password is assumed.The value in master.info will take precedence if it can be read.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + (gptr*)&master_password, (gptr*)&master_password, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"master-port", OPT_MASTER_PORT, "The port the master is listening on. If not set, the compiled setting of MYSQL_PORT is assumed. If you have not tinkered with configure options, this should be 3306. The value in master.info will take precedence if it can be read.", (gptr*) &master_port, (gptr*) &master_port, 0, GET_UINT, REQUIRED_ARG, @@ -4257,6 +4258,10 @@ replicating a LOAD DATA INFILE command.", "A dedicated thread is created to flush all tables at the given interval.", (gptr*) &flush_time, (gptr*) &flush_time, 0, GET_ULONG, REQUIRED_ARG, FLUSH_TIME, 0, LONG_TIMEOUT, 0, 1, 0}, + { "ft_boolean_syntax", OPT_FT_BOOLEAN_SYNTAX, + "List of operators for MATCH ... AGAINST ( ... IN BOOLEAN MODE)", + 0, 0, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { "ft_min_word_len", OPT_FT_MIN_WORD_LEN, "The minimum length of the word to be included in a FULLTEXT index. Note: FULLTEXT indexes must be rebuilt after changing this variable.", (gptr*) &ft_min_word_len, (gptr*) &ft_min_word_len, 0, GET_ULONG, @@ -4506,7 +4511,7 @@ The minimum value for this variable is 4096.", {"open_files_limit", OPT_OPEN_FILES_LIMIT, "If this is not 0, then mysqld will use this value to reserve file descriptors to use with setrlimit(). If this value is 0 then mysqld will reserve max_connections*5 or max_connections + table_cache*2 (whichever is larger) number of files.", (gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG, - REQUIRED_ARG, 0, 0, 65535, 0, 1, 0}, + REQUIRED_ARG, 0, 0, OS_FILE_LIMIT, 0, 1, 0}, {"preload_buffer_size", OPT_PRELOAD_BUFFER_SIZE, "The size of the buffer that is allocated when preloading indexes", (gptr*) &global_system_variables.preload_buff_size, @@ -5435,8 +5440,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case OPT_STORAGE_ENGINE: { - if ((enum db_type)((global_system_variables.table_type= - ha_resolve_by_name(argument, strlen(argument)))) == DB_TYPE_UNKNOWN) + if ((enum db_type)((global_system_variables.table_type= + ha_resolve_by_name(argument, strlen(argument)))) == DB_TYPE_UNKNOWN) { fprintf(stderr,"Unknown table type: %s\n",argument); exit(1); @@ -5608,8 +5613,13 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), global_system_variables.sql_mode= fix_sql_mode(global_system_variables. sql_mode); } - case OPT_MASTER_PASSWORD: - master_password=argument; + case OPT_FT_BOOLEAN_SYNTAX: + if (ft_boolean_check_syntax_string(argument)) + { + fprintf(stderr, "Invalid ft-boolean-syntax string: %s\n", argument); + exit(1); + } + strmake(opt_ft_boolean_syntax, argument, sizeof(ft_boolean_syntax)-1); break; case OPT_SKIP_SAFEMALLOC: #ifdef SAFEMALLOC @@ -5658,6 +5668,8 @@ static void get_options(int argc,char **argv) int ho_error; my_getopt_register_get_addr(mysql_getopt_value); + strmake(opt_ft_boolean_syntax, ft_boolean_syntax, + sizeof(ft_boolean_syntax)-1); if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); if (argc > 0) @@ -5713,6 +5725,9 @@ static void get_options(int argc,char **argv) table_alias_charset= (lower_case_table_names ? files_charset_info : &my_charset_bin); + strmake(ft_boolean_syntax, opt_ft_boolean_syntax, + sizeof(ft_boolean_syntax)-1); + if (opt_short_log_format) opt_specialflag|= SPECIAL_SHORT_LOG_FORMAT; if (opt_log_queries_not_using_indexes) @@ -5812,95 +5827,6 @@ static void fix_paths(void) } -/* - set how many open files we want to be able to handle - - SYNOPSIS - set_maximum_open_files() - max_file_limit Files to open - - NOTES - The request may not fulfilled becasue of system limitations - - RETURN - Files available to open -*/ - -#ifdef SET_RLIMIT_NOFILE - -#ifndef RLIM_INFINITY -#define RLIM_INFINITY ((uint) 0xffffffff) -#endif - -static uint set_maximum_open_files(uint max_file_limit) -{ - struct rlimit rlimit; - uint old_cur; - DBUG_ENTER("set_maximum_open_files"); - DBUG_PRINT("enter",("files: %u", max_file_limit)); - - if (!getrlimit(RLIMIT_NOFILE,&rlimit)) - { - old_cur= (uint) rlimit.rlim_cur; - DBUG_PRINT("info", ("rlim_cur: %u rlim_max: %u", - (uint) rlimit.rlim_cur, - (uint) rlimit.rlim_max)); - if (rlimit.rlim_cur >= max_file_limit || - rlimit.rlim_cur == RLIM_INFINITY) - DBUG_RETURN(rlimit.rlim_cur); /* purecov: inspected */ - rlimit.rlim_cur= rlimit.rlim_max= max_file_limit; - if (setrlimit(RLIMIT_NOFILE,&rlimit)) - { - if (global_system_variables.log_warnings) - sql_print_error("Warning: setrlimit couldn't increase number of open files to more than %u (request: %u)", - old_cur, max_file_limit); /* purecov: inspected */ - max_file_limit= old_cur; - } - else - { - rlimit.rlim_cur= 0; // Safety if next call fails - (void) getrlimit(RLIMIT_NOFILE,&rlimit); - DBUG_PRINT("info", ("rlim_cur: %u", (uint) rlimit.rlim_cur)); - if ((uint) rlimit.rlim_cur < max_file_limit && - global_system_variables.log_warnings) - sql_print_error("Warning: setrlimit returned ok, but didn't change limits. Max open files is %u (request: %u)", - (uint) rlimit.rlim_cur, - max_file_limit); /* purecov: inspected */ - max_file_limit= (uint) rlimit.rlim_cur; - } - } - DBUG_PRINT("exit",("max_file_limit: %u", max_file_limit)); - DBUG_RETURN(max_file_limit); -} -#endif - - -#ifdef OS2 -static uint set_maximum_open_files(uint max_file_limit) -{ - LONG cbReqCount; - ULONG cbCurMaxFH, cbCurMaxFH0; - APIRET ulrc; - DBUG_ENTER("set_maximum_open_files"); - - // get current limit - cbReqCount = 0; - DosSetRelMaxFH( &cbReqCount, &cbCurMaxFH0); - - // set new limit - cbReqCount = max_file_limit - cbCurMaxFH0; - ulrc = DosSetRelMaxFH( &cbReqCount, &cbCurMaxFH); - if (ulrc) { - sql_print_error("Warning: DosSetRelMaxFH couldn't increase number of open files to more than %d", - cbCurMaxFH0); - cbCurMaxFH = cbCurMaxFH0; - } - - DBUG_RETURN(cbCurMaxFH); -} -#endif - - /* Return a bitfield from a string of substrings separated by ',' returns ~(ulong) 0 on error. diff --git a/sql/set_var.cc b/sql/set_var.cc index 7f5cf9503bf..f3728ce9e5d 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -19,18 +19,18 @@ To add a new variable, one has to do the following: - - If the variable is thread specific, add it to 'system_variables' struct. - If not, add it to mysqld.cc and an declaration in 'mysql_priv.h' - - Don't forget to initialize new fields in global_system_variables and - max_system_variables! - Use one of the 'sys_var... classes from set_var.h or write a specific one for the variable type. - Define it in the 'variable definition list' in this file. - If the variable should be changeable or one should be able to access it with @@variable_name, it should be added to the 'list of all variables' - list in this file. + list (sys_variables) in this file. + - If the variable is thread specific, add it to 'system_variables' struct. + If not, add it to mysqld.cc and an declaration in 'mysql_priv.h' - If the variable should be changed from the command line, add a definition of it in the my_option structure list in mysqld.dcc + - Don't forget to initialize new fields in global_system_variables and + max_system_variables! - If the variable should show up in 'show variables' add it to the init_vars[] struct in this file @@ -73,9 +73,12 @@ TYPELIB delay_key_write_typelib= array_elements(delay_key_write_type_names)-1, "", delay_key_write_type_names }; -static bool sys_check_charset(THD *thd, set_var *var); +static int sys_check_charset(THD *thd, set_var *var); static bool sys_update_charset(THD *thd, set_var *var); static void sys_set_default_charset(THD *thd, enum_var_type type); +static int sys_check_ftb_syntax(THD *thd, set_var *var); +static bool sys_update_ftb_syntax(THD *thd, set_var * var); +static void sys_default_ftb_syntax(THD *thd, enum_var_type type); static bool sys_update_init_connect(THD*, set_var*); static void sys_default_init_connect(THD*, enum_var_type type); static bool sys_update_init_slave(THD*, set_var*); @@ -119,12 +122,6 @@ sys_var_str sys_charset_system("character_set_system", sys_check_charset, sys_update_charset, sys_set_default_charset); -sys_var_str sys_init_connect("init_connect", 0, - sys_update_init_connect, - sys_default_init_connect); -sys_var_str sys_init_slave("init_slave", 0, - sys_update_init_slave, - sys_default_init_slave); sys_var_character_set_database sys_character_set_database("character_set_database"); sys_var_character_set_client sys_character_set_client("character_set_client"); sys_var_character_set_connection sys_character_set_connection("character_set_connection"); @@ -150,6 +147,16 @@ sys_var_long_ptr sys_expire_logs_days("expire_logs_days", &expire_logs_days); sys_var_bool_ptr sys_flush("flush", &myisam_flush); sys_var_long_ptr sys_flush_time("flush_time", &flush_time); +sys_var_str sys_ft_boolean_syntax("ft_boolean_syntax", + sys_check_ftb_syntax, + sys_update_ftb_syntax, + sys_default_ftb_syntax); +sys_var_str sys_init_connect("init_connect", 0, + sys_update_init_connect, + sys_default_init_connect); +sys_var_str sys_init_slave("init_slave", 0, + sys_update_init_slave, + sys_default_init_slave); sys_var_thd_ulong sys_interactive_timeout("interactive_timeout", &SV::net_interactive_timeout); sys_var_thd_ulong sys_join_buffer_size("join_buffer_size", @@ -318,7 +325,7 @@ sys_var_thd_ulong sys_net_wait_timeout("wait_timeout", #ifdef HAVE_INNOBASE_DB sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct", &srv_max_buf_pool_modified_pct); -#endif +#endif /* Time/date/datetime formats */ @@ -450,6 +457,7 @@ sys_var *sys_variables[]= &sys_expire_logs_days, &sys_flush, &sys_flush_time, + &sys_ft_boolean_syntax, &sys_foreign_key_checks, &sys_group_concat_max_len, &sys_identity, @@ -593,7 +601,7 @@ struct show_var_st init_vars[]= { {sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS}, {sys_flush.name, (char*) &sys_flush, SHOW_SYS}, {sys_flush_time.name, (char*) &sys_flush_time, SHOW_SYS}, - {"ft_boolean_syntax", (char*) ft_boolean_syntax, SHOW_CHAR}, + {sys_ft_boolean_syntax.name,(char*) &ft_boolean_syntax, SHOW_CHAR}, {"ft_min_word_len", (char*) &ft_min_word_len, SHOW_LONG}, {"ft_max_word_len", (char*) &ft_max_word_len, SHOW_LONG}, {"ft_query_expansion_limit",(char*) &ft_query_expansion_limit, SHOW_LONG}, @@ -775,6 +783,18 @@ bool sys_var::check(THD *thd, set_var *var) return 0; } +bool sys_var_str::check(THD *thd, set_var *var) +{ + int res; + if (!check_func) + return 0; + + if ((res=(*check_func)(thd, var)) < 0) + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, + var->value->str_value.ptr()); + return res; +} + /* Functions to check and update variables */ @@ -837,13 +857,37 @@ static void sys_default_init_slave(THD* thd, enum_var_type type) update_sys_var_str(&sys_init_slave, &LOCK_sys_init_slave, 0); } +static int sys_check_ftb_syntax(THD *thd, set_var *var) +{ + if (thd->master_access & SUPER_ACL) + return ft_boolean_check_syntax_string(var->value->str_value.c_ptr()) ? + -1 : 0; + else + { + my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); + return 1; + } +} + +static bool sys_update_ftb_syntax(THD *thd, set_var * var) +{ + strmake(ft_boolean_syntax, var->value->str_value.c_ptr(), + sizeof(ft_boolean_syntax)-1); + return 0; +} + +static void sys_default_ftb_syntax(THD *thd, enum_var_type type) +{ + strmake(ft_boolean_syntax, opt_ft_boolean_syntax, + sizeof(ft_boolean_syntax)-1); +} /* The following 3 functions need to be changed in 4.1 when we allow one to change character sets */ -static bool sys_check_charset(THD *thd, set_var *var) +static int sys_check_charset(THD *thd, set_var *var) { return 0; } @@ -1898,7 +1942,7 @@ byte *sys_var_key_cache_param::value_ptr(THD *thd, enum_var_type type, key_cache= &zero_key_cache; return (byte*) key_cache + offset ; } - + bool sys_var_key_buffer_size::update(THD *thd, set_var *var) { @@ -1993,14 +2037,14 @@ bool sys_var_key_cache_long::update(THD *thd, set_var *var) pthread_mutex_lock(&LOCK_global_system_variables); KEY_CACHE *key_cache= get_key_cache(base_name); - + if (!key_cache && !(key_cache= create_key_cache(base_name->str, base_name->length))) { error= 1; goto end; } - + /* Abort if some other thread is changing the key cache TODO: This should be changed so that we wait until the previous diff --git a/sql/set_var.h b/sql/set_var.h index 85871c90ebb..9087a3e023e 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -35,7 +35,7 @@ enum enum_var_type OPT_DEFAULT, OPT_SESSION, OPT_GLOBAL }; -typedef bool (*sys_check_func)(THD *, set_var *); +typedef int (*sys_check_func)(THD *, set_var *); typedef bool (*sys_update_func)(THD *, set_var *); typedef void (*sys_after_update_func)(THD *,enum_var_type); typedef void (*sys_set_default_func)(THD *, enum_var_type); @@ -143,10 +143,7 @@ public: :sys_var(name_arg), check_func(check_func_arg), update_func(update_func_arg),set_default_func(set_default_func_arg) {} - bool check(THD *thd, set_var *var) - { - return check_func ? (*check_func)(thd, var) : 0; - } + bool check(THD *thd, set_var *var); bool update(THD *thd, set_var *var) { return (*update_func)(thd, var); diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index ed9b7c3931a..49d74165dbd 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -72,9 +72,9 @@ character-set=latin1 "Not unique table/alias: '%-.64s'", "Invalid default value for '%-.64s'", "Multiple primary key defined", -"Too many keys specified. Max %d keys allowed", +"Too many keys specified; max %d keys allowed", "Too many key parts specified. Max %d parts allowed", -"Specified key was too long. Max key length is %d", +"Specified key was too long; max key length is %d bytes", "Key column '%-.64s' doesn't exist in table", "BLOB column '%-.64s' can't be used in key specification with the used table type", "Too big column length for column '%-.64s' (max = %d). Use BLOB instead", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 7bfd2264178..4282c5326af 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -76,7 +76,7 @@ character-set=koi8r "Указано несколько первичных ключей", "Указано слишком много ключей. Разрешается указывать не более %d ключей", "Указано слишком много частей составного ключа. Разрешается указывать не более %d частей", -"Указан слишком длинный ключ. Максимальная длина ключа составляет %d", +"Указан слишком длинный ключ. Максимальная длина ключа составляет %d байт", "Ключевой столбец '%-.64s' в таблице не существует", "Столбец типа BLOB '%-.64s' не может быть использован как значение ключа в таблице такого типа", "Слишком большая длина столбца '%-.64s' (максимум = %d). Используйте тип BLOB вместо текущего", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 722e96ec5a7..fa312fcc4b4 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -79,7 +79,7 @@ character-set=koi8u "Первинного ключа визначено неодноразово", "Забагато ключ╕в зазначено. Дозволено не б╕льше %d ключ╕в", "Забагато частин ключа зазначено. Дозволено не б╕льше %d частин", -"Зазначений ключ задовгий. Найб╕льша довжина ключа %d", +"Зазначений ключ задовгий. Найб╕льша довжина ключа %d байт╕в", "Ключовий стовбець '%-.64s' не ╕сну╓ у таблиц╕", "BLOB стовбець '%-.64s' не може бути використаний у визначенн╕ ключа в цьому тип╕ таблиц╕", "Задовга довжина стовбця '%-.64s' (max = %d). Використайте тип BLOB", diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b11c71b6ff7..5cfe6f7a870 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2080,6 +2080,14 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List &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 it(fields); while ( wild_num && (item= it++)) @@ -2091,7 +2099,11 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List &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 &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); }; @@ -689,6 +715,10 @@ public: #ifdef SIGNAL_WITH_VIO_CLOSE 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_db.cc b/sql/sql_db.cc index 0323e90a166..7bf1268597b 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -58,9 +58,9 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0) { ulong length; - CHARSET_INFO *cs= (create && create->default_table_charset) ? - create->default_table_charset : - thd->variables.collation_server; + CHARSET_INFO *cs= ((create && create->default_table_charset) ? + create->default_table_charset : + thd->variables.collation_server); length= my_sprintf(buf,(buf, "default-character-set=%s\ndefault-collation=%s\n", cs->csname,cs->name)); @@ -116,9 +116,10 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) { if (!strncmp(buf,"default-character-set", (pos-buf))) { - if (!(create->default_table_charset= get_charset_by_csname(pos+1, - MY_CS_PRIMARY, - MYF(0)))) + if (!(create->default_table_charset= + get_charset_by_csname(pos+1, + MY_CS_PRIMARY, + MYF(0)))) { sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1); } 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_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_table.cc b/sql/sql_table.cc index 8d1d64e9491..ee11b7b9da0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -853,26 +853,35 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, { if ((length=column->length) > file->max_key_length() || length > file->max_key_part_length()) - { - my_error(ER_WRONG_SUB_KEY,MYF(0)); - DBUG_RETURN(-1); - } + { + length=min(file->max_key_length(), file->max_key_part_length()); + if (key->type == Key::MULTIPLE) + { + /* not a critical problem */ + char warn_buff[MYSQL_ERRMSG_SIZE]; + sprintf(warn_buff,ER(ER_TOO_LONG_KEY),length); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TOO_LONG_KEY, warn_buff); + } + else + { + my_error(ER_TOO_LONG_KEY,MYF(0),length); + DBUG_RETURN(-1); + } + } } - /* TODO HF What's this for??? */ - else if (f_is_geom(sql_field->pack_flag)) - { - } - else if (column->length > length || - ((f_is_packed(sql_field->pack_flag) || - ((file->table_flags() & HA_NO_PREFIX_CHAR_KEYS) && - (key_info->flags & HA_NOSAME))) && - column->length != length)) - { - my_error(ER_WRONG_SUB_KEY,MYF(0)); - DBUG_RETURN(-1); - } - if (!(file->table_flags() & HA_NO_PREFIX_CHAR_KEYS)) - length=column->length; + else if (!f_is_geom(sql_field->pack_flag) && + (column->length > length || + ((f_is_packed(sql_field->pack_flag) || + ((file->table_flags() & HA_NO_PREFIX_CHAR_KEYS) && + (key_info->flags & HA_NOSAME))) && + column->length != length))) + { + my_error(ER_WRONG_SUB_KEY,MYF(0)); + DBUG_RETURN(-1); + } + else if (!(file->table_flags() & HA_NO_PREFIX_CHAR_KEYS)) + length=column->length; } else if (length == 0) { @@ -882,8 +891,20 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, } if (length > file->max_key_part_length()) { - my_error(ER_WRONG_SUB_KEY,MYF(0)); - DBUG_RETURN(-1); + length=file->max_key_part_length(); + if (key->type == Key::MULTIPLE) + { + /* not a critical problem */ + char warn_buff[MYSQL_ERRMSG_SIZE]; + sprintf(warn_buff,ER(ER_TOO_LONG_KEY),length); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TOO_LONG_KEY, warn_buff); + } + else + { + my_error(ER_TOO_LONG_KEY,MYF(0),length); + DBUG_RETURN(-1); + } } key_part_info->length=(uint16) length; /* Use packed keys for long strings on the first column */ 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/strings/strtod.c b/strings/strtod.c index ea6acbac6c4..63633b6808f 100644 --- a/strings/strtod.c +++ b/strings/strtod.c @@ -36,7 +36,7 @@ static double scaler1[] = { 1.0, 10.0, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 }; -// let's use a static array for not to accumulate the error +/* let's use a static array for not to accumulate the error */ static double pastpoint[] = { 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16, 1e-17, 1e-18, 1e-19, 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);