summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am10
-rw-r--r--sql/cache_manager.cc10
-rw-r--r--sql/cache_manager.h10
-rw-r--r--sql/convert.cc26
-rw-r--r--sql/custom_conf.h6
-rw-r--r--sql/derror.cc40
-rw-r--r--sql/des_key_file.cc107
-rw-r--r--sql/field.cc245
-rw-r--r--sql/field.h160
-rw-r--r--sql/field_conv.cc6
-rw-r--r--sql/filesort.cc18
-rw-r--r--sql/frm_crypt.cc6
-rw-r--r--sql/gen_lex_hash.cc17
-rw-r--r--sql/ha_berkeley.cc44
-rw-r--r--sql/ha_berkeley.h7
-rw-r--r--sql/ha_heap.cc45
-rw-r--r--sql/ha_heap.h9
-rw-r--r--sql/ha_innodb.cc (renamed from sql/ha_innobase.cc)149
-rw-r--r--sql/ha_innodb.h (renamed from sql/ha_innobase.h)46
-rw-r--r--sql/ha_isam.cc19
-rw-r--r--sql/ha_isam.h18
-rw-r--r--sql/ha_isammrg.cc10
-rw-r--r--sql/ha_isammrg.h11
-rw-r--r--sql/ha_myisam.cc72
-rw-r--r--sql/ha_myisam.h21
-rw-r--r--sql/ha_myisammrg.cc16
-rw-r--r--sql/ha_myisammrg.h6
-rw-r--r--sql/handler.cc17
-rw-r--r--sql/handler.h11
-rw-r--r--sql/hash_filo.cc6
-rw-r--r--sql/hash_filo.h6
-rw-r--r--sql/hostname.cc6
-rw-r--r--sql/init.cc6
-rw-r--r--sql/item.cc6
-rw-r--r--sql/item.h16
-rw-r--r--sql/item_buff.cc6
-rw-r--r--sql/item_cmpfunc.cc6
-rw-r--r--sql/item_cmpfunc.h6
-rw-r--r--sql/item_create.cc41
-rw-r--r--sql/item_create.h7
-rw-r--r--sql/item_func.cc70
-rw-r--r--sql/item_func.h67
-rw-r--r--sql/item_strfunc.cc284
-rw-r--r--sql/item_strfunc.h26
-rw-r--r--sql/item_sum.cc10
-rw-r--r--sql/item_sum.h10
-rw-r--r--sql/item_timefunc.cc18
-rw-r--r--sql/item_timefunc.h126
-rw-r--r--sql/item_uniq.cc6
-rw-r--r--sql/item_uniq.h6
-rw-r--r--sql/key.cc8
-rw-r--r--sql/lex.h20
-rw-r--r--sql/lex_symbol.h6
-rw-r--r--sql/lock.cc6
-rw-r--r--sql/matherr.c6
-rw-r--r--sql/mf_iocache.cc10
-rw-r--r--sql/mini_client.cc102
-rw-r--r--sql/mini_client.h7
-rw-r--r--sql/my_lock.c6
-rw-r--r--sql/mysql_priv.h44
-rw-r--r--sql/mysqld.cc306
-rw-r--r--sql/net_pkg.cc17
-rw-r--r--sql/net_serv.cc154
-rw-r--r--sql/opt_range.h6
-rw-r--r--sql/opt_sum.cc6
-rw-r--r--sql/password.c6
-rw-r--r--sql/procedure.cc6
-rw-r--r--sql/procedure.h6
-rw-r--r--sql/records.cc7
-rw-r--r--sql/repl_failsafe.cc22
-rw-r--r--sql/sql_acl.cc75
-rw-r--r--sql/sql_acl.h8
-rw-r--r--sql/sql_analyse.cc12
-rw-r--r--sql/sql_analyse.h6
-rw-r--r--sql/sql_base.cc27
-rw-r--r--sql/sql_cache.cc3458
-rw-r--r--sql/sql_cache.h418
-rw-r--r--sql/sql_class.cc13
-rw-r--r--sql/sql_class.h100
-rw-r--r--sql/sql_crypt.cc6
-rw-r--r--sql/sql_crypt.h6
-rw-r--r--sql/sql_db.cc16
-rw-r--r--sql/sql_delete.cc145
-rw-r--r--sql/sql_do.cc34
-rw-r--r--sql/sql_handler.cc59
-rw-r--r--sql/sql_insert.cc44
-rw-r--r--sql/sql_lex.cc6
-rw-r--r--sql/sql_lex.h13
-rw-r--r--sql/sql_list.cc6
-rw-r--r--sql/sql_list.h6
-rw-r--r--sql/sql_load.cc15
-rw-r--r--sql/sql_manager.cc8
-rw-r--r--sql/sql_map.cc6
-rw-r--r--sql/sql_map.h6
-rw-r--r--sql/sql_parse.cc567
-rw-r--r--sql/sql_rename.cc8
-rw-r--r--sql/sql_select.cc317
-rw-r--r--sql/sql_select.h29
-rw-r--r--sql/sql_show.cc92
-rw-r--r--sql/sql_string.cc29
-rw-r--r--sql/sql_string.h29
-rw-r--r--sql/sql_table.cc170
-rw-r--r--sql/sql_test.cc6
-rw-r--r--sql/sql_udf.cc17
-rw-r--r--sql/sql_udf.h6
-rw-r--r--sql/sql_union.cc46
-rw-r--r--sql/sql_update.cc453
-rw-r--r--sql/sql_yacc.yy308
-rw-r--r--sql/stacktrace.c8
-rw-r--r--sql/structs.h6
-rw-r--r--sql/table.cc17
-rw-r--r--sql/table.h6
-rw-r--r--sql/thr_malloc.cc6
-rw-r--r--sql/time.cc8
-rw-r--r--sql/udf_example.cc6
-rw-r--r--sql/uniques.cc4
-rw-r--r--sql/unireg.cc26
-rw-r--r--sql/unireg.h6
118 files changed, 7488 insertions, 1823 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 4621443f4d2..e1ed9ad8915 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -51,12 +51,12 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
sql_manager.h sql_map.h sql_string.h unireg.h \
field.h handler.h \
ha_isammrg.h ha_isam.h ha_myisammrg.h\
- ha_heap.h ha_myisam.h ha_berkeley.h ha_innobase.h \
+ ha_heap.h ha_myisam.h ha_berkeley.h ha_innodb.h \
opt_range.h opt_ft.h \
sql_select.h structs.h table.h sql_udf.h hash_filo.h\
lex.h lex_symbol.h sql_acl.h sql_crypt.h \
log_event.h mini_client.h sql_repl.h slave.h \
- stacktrace.h sql_sort.h
+ stacktrace.h sql_sort.h sql_cache.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
@@ -67,14 +67,14 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
mysqld.cc password.c hash_filo.cc hostname.cc \
convert.cc sql_parse.cc sql_yacc.yy \
sql_base.cc table.cc sql_select.cc sql_insert.cc \
- sql_update.cc sql_delete.cc uniques.cc \
+ sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
procedure.cc item_uniq.cc sql_test.cc \
log.cc log_event.cc init.cc derror.cc sql_acl.cc \
- unireg.cc \
+ unireg.cc des_key_file.cc \
time.cc opt_range.cc opt_sum.cc opt_ft.cc \
records.cc filesort.cc handler.cc \
ha_heap.cc ha_myisam.cc ha_myisammrg.cc \
- ha_berkeley.cc ha_innobase.cc \
+ ha_berkeley.cc ha_innodb.cc \
ha_isam.cc ha_isammrg.cc \
sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
diff --git a/sql/cache_manager.cc b/sql/cache_manager.cc
index 9aec222909a..307fe331e5c 100644
--- a/sql/cache_manager.cc
+++ b/sql/cache_manager.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -117,7 +117,7 @@ void *cache_manager::alloc(uint size)
{
void *llist;
void *abs_ptr;
-
+
size=ALIGN_SIZE(size+HEADER_LENGTH+SUFFIX_LENGTH);
if (!(llist = find_in_llist(size)))
{
@@ -127,7 +127,7 @@ void *cache_manager::alloc(uint size)
}
size_of_found_block=int4korr((char*) llist) & ALLOC_MASK;
// if (size_of_found_block < SMALLEST_BLOCK)
-
+
abs_ptr = link_into_abs(llist);
return abs_ptr;
}
diff --git a/sql/cache_manager.h b/sql/cache_manager.h
index fc3b8f7016a..d422a86ea8e 100644
--- a/sql/cache_manager.h
+++ b/sql/cache_manager.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -59,7 +59,3 @@ class cache_manager {
bool *dealloc(void *); /* Deallocate blocks (with *ptr_arg) */
void clear(void); /* Clear the cache */
};
-
-
-
-
diff --git a/sql/convert.cc b/sql/convert.cc
index 3e0fbf18ace..7a06208759c 100644
--- a/sql/convert.cc
+++ b/sql/convert.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -397,19 +397,19 @@ static unsigned char win1251ukr_koi8_ukr[256] = {
****************************************************************************/
-CONVERT conv_cp1251_koi8("cp1251_koi8", cp1251_koi8, koi8_cp1251);
+CONVERT conv_cp1251_koi8("cp1251_koi8", cp1251_koi8, koi8_cp1251, 1);
#ifdef DEFINE_ALL_CHARACTER_SETS
-CONVERT conv_cp1250_latin2("cp1250_latin2", t1250_til2, til2_t1250);
-CONVERT conv_kam_latin2("kam_latin2", tkam_til2, til2_tkam);
-CONVERT conv_mac_latin2("mac_latin2", tmac_til2, til2_tmac);
-CONVERT conv_macce_latin2("macce_latin2", tmacce_til2, til2_tmacce);
-CONVERT conv_pc2_latin2("pc2_latin2", tpc2_til2, til2_tpc2);
-CONVERT conv_vga_latin2("vga_latin2", tvga_til2, til2_tvga);
-CONVERT conv_koi8_cp1251("koi8_cp1251", koi8_cp1251, cp1251_koi8);
+CONVERT conv_cp1250_latin2("cp1250_latin2", t1250_til2, til2_t1250, 2);
+CONVERT conv_kam_latin2("kam_latin2", tkam_til2, til2_tkam, 3);
+CONVERT conv_mac_latin2("mac_latin2", tmac_til2, til2_tmac, 4);
+CONVERT conv_macce_latin2("macce_latin2", tmacce_til2, til2_tmacce, 5);
+CONVERT conv_pc2_latin2("pc2_latin2", tpc2_til2, til2_tpc2, 6);
+CONVERT conv_vga_latin2("vga_latin2", tvga_til2, til2_tvga, 7);
+CONVERT conv_koi8_cp1251("koi8_cp1251", koi8_cp1251, cp1251_koi8, 8);
CONVERT conv_win1251ukr_koi8_ukr("win1251ukr_koi8_ukr", win1251ukr_koi8_ukr,
- koi8_ukr_win1251ukr);
+ koi8_ukr_win1251ukr, 9);
CONVERT conv_koi8_ukr_win1251ukr("koi8_ukr_win1251ukr", koi8_ukr_win1251ukr,
- win1251ukr_koi8_ukr);
+ win1251ukr_koi8_ukr, 10);
#endif /* DEFINE_ALL_CHARACTER_SETS */
CONVERT *convert_tables[]= {
diff --git a/sql/custom_conf.h b/sql/custom_conf.h
index af6012e28ec..19ced12bfbb 100644
--- a/sql/custom_conf.h
+++ b/sql/custom_conf.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/derror.cc b/sql/derror.cc
index bda0690ae7d..7ebe6e4b3c5 100644
--- a/sql/derror.cc
+++ b/sql/derror.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -44,7 +44,7 @@ static void read_texts(const char *file_name,const char ***point,
uint error_messages)
{
register uint i;
- uint ant,funktpos,length,textant;
+ uint count,funktpos,length,textcount;
File file;
char name[FN_REFLEN];
const char *buff;
@@ -64,36 +64,38 @@ static void read_texts(const char *file_name,const char ***point,
if (head[0] != (uchar) 254 || head[1] != (uchar) 254 ||
head[2] != 2 || head[3] != 1)
goto err; /* purecov: inspected */
- textant=head[4];
- length=uint2korr(head+6); ant=uint2korr(head+8);
+ textcount=head[4];
+ length=uint2korr(head+6); count=uint2korr(head+8);
- if (ant < error_messages)
+ if (count < error_messages)
{
- fprintf(stderr,"\n%s: Fatal error: Error message file '%s' had only %d error messages, but it should have at least %d error messages.\n\
-Check that the above file is the right version for this program!\n\n",
- my_progname,name,ant,error_messages);
+ sql_print_error("\
+Error message file '%s' had only %d error messages,\n\
+but it should contain at least %d error messages.\n\
+Check that the above file is the right version for this program!",
+ name,count,error_messages);
VOID(my_close(file,MYF(MY_WME)));
unireg_abort(1);
}
x_free((gptr) *point); /* Free old language */
if (!(*point= (const char**)
- my_malloc((uint) (length+ant*sizeof(char*)),MYF(0))))
+ my_malloc((uint) (length+count*sizeof(char*)),MYF(0))))
{
funktpos=2; /* purecov: inspected */
goto err; /* purecov: inspected */
}
- buff= (char*) (*point + ant);
+ buff= (char*) (*point + count);
- if (my_read(file,(byte*) buff,(uint) ant*2,MYF(MY_NABP))) goto err;
- for (i=0, pos= (uchar*) buff ; i< ant ; i++)
+ if (my_read(file,(byte*) buff,(uint) count*2,MYF(MY_NABP))) goto err;
+ for (i=0, pos= (uchar*) buff ; i< count ; i++)
{
(*point)[i]=buff+uint2korr(pos);
pos+=2;
}
if (my_read(file,(byte*) buff,(uint) length,MYF(MY_NABP))) goto err;
- for (i=1 ; i < textant ; i++)
+ for (i=1 ; i < textcount ; i++)
{
point[i]= *point +uint2korr(head+10+i+i);
}
@@ -103,18 +105,18 @@ Check that the above file is the right version for this program!\n\n",
err:
switch (funktpos) {
case 2:
- buff="\n%s: Fatal error: Not enough memory for messagefile '%s'\n\n";
+ buff="Not enough memory for messagefile '%s'";
break;
case 1:
- buff="\n%s: Fatal error: Can't read from messagefile '%s'\n\n";
+ buff="Can't read from messagefile '%s'";
break;
default:
- buff="\n%s: Fatal error: Can't find messagefile '%s'\n\n";
+ buff="Can't find messagefile '%s'";
break;
}
if (file != FERR)
VOID(my_close(file,MYF(MY_WME)));
- fprintf(stderr,buff,my_progname,name);
+ sql_print_error(buff,name);
unireg_abort(1);
} /* read_texts */
diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc
new file mode 100644
index 00000000000..d9c924b5a3c
--- /dev/null
+++ b/sql/des_key_file.cc
@@ -0,0 +1,107 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 <mysql_priv.h>
+#include <m_ctype.h>
+
+#ifdef HAVE_OPENSSL
+
+struct st_des_keyschedule des_keyschedule[10];
+uint des_default_key;
+pthread_mutex_t LOCK_des_key_file;
+static int initialized;
+
+/*
+ Function which loads DES keys from plaintext file into memory on MySQL
+ server startup and on command FLUSH DES_KEY_FILE.
+ Blame tonu@spam.ee on bugs ;)
+
+ RETURN
+ 0 ok
+ 1 Error
+*/
+
+bool
+load_des_key_file(const char *file_name)
+{
+ bool result=1;
+ File file;
+ IO_CACHE io;
+ DBUG_ENTER("load_des_key_file");
+ DBUG_PRINT("enter",("name: %s",file_name));
+
+ if (!initialized)
+ {
+ initialized=1;
+ pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST);
+ }
+
+ VOID(pthread_mutex_lock(&LOCK_des_key_file));
+ if ((file=my_open(file_name,O_RDONLY | O_BINARY ,MYF(MY_WME))) < 0 ||
+ init_io_cache(&io, file, IO_SIZE*2, READ_CACHE, 0, 0, MYF(MY_WME)))
+ goto error;
+
+ bzero((char*) des_keyschedule,sizeof(struct st_des_keyschedule) * 10);
+ des_default_key=15; // Impossible key
+ for (;;)
+ {
+ char *start, *end;
+ char buf[1024], offset;
+ st_des_keyblock keyblock;
+ uint length;
+
+ if (!(length=my_b_gets(&io,buf,sizeof(buf)-1)))
+ break; // End of file
+ offset=buf[0];
+ if (offset >= '0' && offset <= '9') // If ok key
+ {
+ offset=(char) (offset - '0');
+ // Remove newline and possible other control characters
+ for (start=buf+1 ; isspace(*start) ; start++) ;
+ end=buf+length;
+ for (end=strend(buf) ; end > start && !isgraph(end[-1]) ; end--) ;
+
+ if (start != end)
+ {
+ des_cblock ivec;
+ bzero((char*) &ivec,sizeof(ivec));
+ // We make good 24-byte (168 bit) key from given plaintext key with MD5
+ EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
+ (uchar *) start, (int) (end-start),1,
+ (uchar *) &keyblock,
+ ivec);
+ des_set_key_unchecked(&keyblock.key1,des_keyschedule[(int)offset].ks1);
+ des_set_key_unchecked(&keyblock.key2,des_keyschedule[(int)offset].ks2);
+ des_set_key_unchecked(&keyblock.key3,des_keyschedule[(int)offset].ks3);
+ if (des_default_key == 15)
+ des_default_key= (uint) offset; // use first as def.
+ }
+ }
+ else if (offset != '#')
+ sql_print_error("load_des_file: Found wrong key_number: %c",offset);
+ }
+ result=0;
+
+error:
+ if (file >= 0)
+ {
+ my_close(file,MYF(0));
+ end_io_cache(&io);
+ }
+ VOID(pthread_mutex_unlock(&LOCK_des_key_file));
+ DBUG_RETURN(result);
+}
+#endif /* HAVE_OPENSSL */
diff --git a/sql/field.cc b/sql/field.cc
index 2f98d2e0fe8..2a0d0160d00 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -219,14 +219,15 @@ static bool test_if_real(const char *str,int length)
****************************************************************************/
Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg)
- :ptr(ptr_arg),null_ptr(null_ptr_arg),null_bit(null_bit_arg),
- table(table_arg),query_id(0),key_start(0),part_of_key(0),part_of_sortkey(0),
- table_name(table_arg ? table_arg->table_name : 0),
- field_name(field_name_arg), unireg_check(unireg_check_arg),
- field_length(length_arg)
+ :ptr(ptr_arg),null_ptr(null_ptr_arg),
+ table(table_arg),table_name(table_arg ? table_arg->table_name : 0),
+ field_name(field_name_arg),
+ query_id(0),key_start(0),part_of_key(0),part_of_sortkey(0),
+ unireg_check(unireg_check_arg),
+ field_length(length_arg),null_bit(null_bit_arg)
{
flags=null_ptr ? 0: NOT_NULL_FLAG;
}
@@ -242,8 +243,8 @@ void Field::copy_from_tmp(int row_offset)
memcpy(ptr,ptr+row_offset,pack_length());
if (null_ptr)
{
- *null_ptr= ((null_ptr[0] & (uchar) ~(uint) null_bit) |
- null_ptr[row_offset] & (uchar) null_bit);
+ *null_ptr= (uchar) ((null_ptr[0] & (uchar) ~(uint) null_bit) |
+ null_ptr[row_offset] & (uchar) null_bit);
}
}
@@ -1049,7 +1050,7 @@ void Field_short::sort_string(char *to,uint length __attribute__((unused)))
if (unsigned_flag)
to[0] = ptr[0];
else
- to[0] = ptr[0] ^ 128; /* Revers signbit */
+ to[0] = (char) (ptr[0] ^ 128); /* Revers signbit */
to[1] = ptr[1];
}
else
@@ -1058,7 +1059,7 @@ void Field_short::sort_string(char *to,uint length __attribute__((unused)))
if (unsigned_flag)
to[0] = ptr[1];
else
- to[0] = ptr[1] ^ 128; /* Revers signbit */
+ to[0] = (char) (ptr[1] ^ 128); /* Revers signbit */
to[1] = ptr[0];
}
}
@@ -1129,12 +1130,12 @@ void Field_medium::store(double nr)
}
else if (nr >= (double) (long) (1L << 24))
{
- ulong tmp=(ulong) (1L << 24)-1L;
+ uint32 tmp=(uint32) (1L << 24)-1L;
int3store(ptr,tmp);
current_thd->cuted_fields++;
}
else
- int3store(ptr,(ulong) nr);
+ int3store(ptr,(uint32) nr);
}
else
{
@@ -1171,7 +1172,7 @@ void Field_medium::store(longlong nr)
current_thd->cuted_fields++;
}
else
- int3store(ptr,(ulong) nr);
+ int3store(ptr,(uint32) nr);
}
else
{
@@ -1449,7 +1450,7 @@ int Field_long::cmp(const char *a_ptr, const char *b_ptr)
longget(b,b_ptr);
}
if (unsigned_flag)
- return ((ulong) a < (ulong) b) ? -1 : ((ulong) a > (ulong) b) ? 1 : 0;
+ return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
@@ -1461,7 +1462,7 @@ void Field_long::sort_string(char *to,uint length __attribute__((unused)))
if (unsigned_flag)
to[0] = ptr[0];
else
- to[0] = ptr[0] ^ 128; /* Revers signbit */
+ to[0] = (char) (ptr[0] ^ 128); /* Revers signbit */
to[1] = ptr[1];
to[2] = ptr[2];
to[3] = ptr[3];
@@ -1472,7 +1473,7 @@ void Field_long::sort_string(char *to,uint length __attribute__((unused)))
if (unsigned_flag)
to[0] = ptr[3];
else
- to[0] = ptr[3] ^ 128; /* Revers signbit */
+ to[0] = (char) (ptr[3] ^ 128); /* Revers signbit */
to[1] = ptr[2];
to[2] = ptr[1];
to[3] = ptr[0];
@@ -1660,7 +1661,7 @@ void Field_longlong::sort_string(char *to,uint length __attribute__((unused)))
if (unsigned_flag)
to[0] = ptr[0];
else
- to[0] = ptr[0] ^ 128; /* Revers signbit */
+ to[0] = (char) (ptr[0] ^ 128); /* Revers signbit */
to[1] = ptr[1];
to[2] = ptr[2];
to[3] = ptr[3];
@@ -1675,7 +1676,7 @@ void Field_longlong::sort_string(char *to,uint length __attribute__((unused)))
if (unsigned_flag)
to[0] = ptr[7];
else
- to[0] = ptr[7] ^ 128; /* Revers signbit */
+ to[0] = (char) (ptr[7] ^ 128); /* Revers signbit */
to[1] = ptr[6];
to[2] = ptr[5];
to[3] = ptr[4];
@@ -1910,7 +1911,7 @@ void Field_float::sort_string(char *to,uint length __attribute__((unused)))
{ /* make complement */
uint i;
for (i=0 ; i < sizeof(nr); i++)
- tmp[i]=tmp[i] ^ (uchar) 255;
+ tmp[i]= (uchar) (tmp[i] ^ (uchar) 255);
}
else
{
@@ -2278,10 +2279,10 @@ void Field_timestamp::store(longlong nr)
{
part1=(long) (nr/LL(1000000));
part2=(long) (nr - (longlong) part1*LL(1000000));
- l_time.year= part1/10000L; part1%=10000L;
+ l_time.year= (int) (part1/10000L); part1%=10000L;
l_time.month= (int) part1 / 100;
- l_time.day= (int) part1 % 100;
- l_time.hour= part2/10000L; part2%=10000L;
+ l_time.day= (int) part1 % 100;
+ l_time.hour= (int) (part2/10000L); part2%=10000L;
l_time.minute=(int) part2 / 100;
l_time.second=(int) part2 % 100;
timestamp=my_gmt_sec(&l_time);
@@ -2295,7 +2296,7 @@ void Field_timestamp::store(longlong nr)
}
else
#endif
- longstore(ptr,(ulong)timestamp);
+ longstore(ptr,(uint32) timestamp);
}
@@ -2596,7 +2597,7 @@ void Field_time::store(longlong nr)
double Field_time::val_real(void)
{
- ulong j= (ulong) uint3korr(ptr);
+ uint32 j= (uint32) uint3korr(ptr);
return (double) j;
}
@@ -2632,19 +2633,19 @@ bool Field_time::get_time(TIME *ltime)
ltime->neg= 1;
tmp=-tmp;
}
- ltime->hour=tmp/10000;
+ ltime->hour= (int) (tmp/10000);
tmp-=ltime->hour*10000;
- ltime->minute= tmp/100;
- ltime->second= tmp % 100;
+ ltime->minute= (int) tmp/100;
+ ltime->second= (int) tmp % 100;
ltime->second_part=0;
return 0;
}
int Field_time::cmp(const char *a_ptr, const char *b_ptr)
{
- long a,b;
- a=(long) sint3korr(a_ptr);
- b=(long) sint3korr(b_ptr);
+ int32 a,b;
+ a=(int32) sint3korr(a_ptr);
+ b=(int32) sint3korr(b_ptr);
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
@@ -2755,14 +2756,14 @@ void Field_year::sql_type(String &res) const
** Stored as a 4 byte unsigned int
****************************************************************************/
-void Field_date::store(const char *from,uint len)
+void Field_date::store(const char *from, uint len)
{
TIME l_time;
- ulong tmp;
+ uint32 tmp;
if (str_to_TIME(from,len,&l_time,1) == TIMESTAMP_NONE)
tmp=0;
else
- tmp=(ulong) l_time.year*10000L + (ulong) (l_time.month*100+l_time.day);
+ tmp=(uint32) l_time.year*10000L + (uint32) (l_time.month*100+l_time.day);
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -2934,7 +2935,7 @@ void Field_newdate::store(double nr)
void Field_newdate::store(longlong nr)
{
- long tmp;
+ int32 tmp;
if (nr >= LL(100000000) && nr <= LL(99991231235959))
nr=nr/LL(1000000); // Timestamp to date
if (nr < 0L || nr > 99991231L)
@@ -2944,16 +2945,16 @@ void Field_newdate::store(longlong nr)
}
else
{
- tmp=(long) nr;
+ tmp=(int32) nr;
if (tmp)
{
if (tmp < YY_PART_YEAR*10000L) // Fix short dates
- tmp+=20000000L;
+ tmp+= (uint32) 20000000L;
else if (tmp < 999999L)
- tmp+=19000000L;
+ tmp+= (uint32) 19000000L;
}
- uint month=((tmp/100) % 100);
- uint day= tmp%100;
+ uint month= (uint) ((tmp/100) % 100);
+ uint day= (uint) (tmp%100);
if (month > 12 || day > 31)
{
tmp=0L; // Don't allow date to change
@@ -2962,7 +2963,7 @@ void Field_newdate::store(longlong nr)
else
tmp= day + month*32 + (tmp/10000)*16*32;
}
- int3store(ptr,tmp);
+ int3store(ptr,(int32) tmp);
}
void Field_newdate::store_time(TIME *ltime,timestamp_type type)
@@ -2987,7 +2988,7 @@ double Field_newdate::val_real(void)
longlong Field_newdate::val_int(void)
{
- ulong j=uint3korr(ptr);
+ ulong j= uint3korr(ptr);
j= (j % 32L)+(j / 32L % 16L)*100L + (j/(16L*32L))*10000L;
return (longlong) j;
}
@@ -2997,25 +2998,25 @@ String *Field_newdate::val_str(String *val_buffer,
{
val_buffer->alloc(field_length);
val_buffer->length(field_length);
- ulong tmp=(ulong) uint3korr(ptr);
+ uint32 tmp=(uint32) uint3korr(ptr);
int part;
char *pos=(char*) val_buffer->ptr()+10;
/* Open coded to get more speed */
- *pos--=0;
+ *pos--=0; // End NULL
part=(int) (tmp & 31);
- *pos--='0'+part%10;
- *pos--='0'+part/10;
- *pos--='-';
+ *pos--= (char) ('0'+part%10);
+ *pos--= (char) ('0'+part/10);
+ *pos--= '-';
part=(int) (tmp >> 5 & 15);
- *pos--='0'+part%10;
- *pos--='0'+part/10;
- *pos--='-';
+ *pos--= (char) ('0'+part%10);
+ *pos--= (char) ('0'+part/10);
+ *pos--= '-';
part=(int) (tmp >> 9);
- *pos--='0'+part%10; part/=10;
- *pos--='0'+part%10; part/=10;
- *pos--='0'+part%10; part/=10;
- *pos='0'+part;
+ *pos--= (char) ('0'+part%10); part/=10;
+ *pos--= (char) ('0'+part%10); part/=10;
+ *pos--= (char) ('0'+part%10); part/=10;
+ *pos= (char) ('0'+part);
return val_buffer;
}
@@ -3023,7 +3024,7 @@ bool Field_newdate::get_date(TIME *ltime,bool fuzzydate)
{
if (is_null())
return 1;
- ulong tmp=(ulong) uint3korr(ptr);
+ uint32 tmp=(uint32) uint3korr(ptr);
bzero((char*) ltime,sizeof(*ltime));
ltime->day= tmp & 31;
ltime->month= (tmp >> 5) & 15;
@@ -3039,9 +3040,9 @@ bool Field_newdate::get_time(TIME *ltime)
int Field_newdate::cmp(const char *a_ptr, const char *b_ptr)
{
- ulong a,b;
- a=(ulong) uint3korr(a_ptr);
- b=(ulong) uint3korr(b_ptr);
+ uint32 a,b;
+ a=(uint32) uint3korr(a_ptr);
+ b=(uint32) uint3korr(b_ptr);
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
@@ -3175,44 +3176,44 @@ String *Field_datetime::val_str(String *val_buffer,
pos=(char*) val_buffer->ptr()+19;
*pos--=0;
- *pos--='0'+(char) (part2%10); part2/=10;
- *pos--='0'+(char) (part2%10); part3= (int) (part2 / 10);
- *pos--=':';
- *pos--='0'+(char) (part3%10); part3/=10;
- *pos--='0'+(char) (part3%10); part3/=10;
- *pos--=':';
- *pos--='0'+(char) (part3%10); part3/=10;
- *pos--='0'+(char) part3;
- *pos--=' ';
- *pos--='0'+(char) (part1%10); part1/=10;
- *pos--='0'+(char) (part1%10); part1/=10;
- *pos--='-';
- *pos--='0'+(char) (part1%10); part1/=10;
- *pos--='0'+(char) (part1%10); part3= (int) (part1/10);
- *pos--='-';
- *pos--='0'+(char) (part3%10); part3/=10;
- *pos--='0'+(char) (part3%10); part3/=10;
- *pos--='0'+(char) (part3%10); part3/=10;
- *pos='0'+(char) part3;
+ *pos--= (char) ('0'+(char) (part2%10)); part2/=10;
+ *pos--= (char) ('0'+(char) (part2%10)); part3= (int) (part2 / 10);
+ *pos--= ':';
+ *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
+ *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
+ *pos--= ':';
+ *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
+ *pos--= (char) ('0'+(char) part3);
+ *pos--= ' ';
+ *pos--= (char) ('0'+(char) (part1%10)); part1/=10;
+ *pos--= (char) ('0'+(char) (part1%10)); part1/=10;
+ *pos--= '-';
+ *pos--= (char) ('0'+(char) (part1%10)); part1/=10;
+ *pos--= (char) ('0'+(char) (part1%10)); part3= (int) (part1/10);
+ *pos--= '-';
+ *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
+ *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
+ *pos--= (char) ('0'+(char) (part3%10)); part3/=10;
+ *pos=(char) ('0'+(char) part3);
return val_buffer;
}
bool Field_datetime::get_date(TIME *ltime,bool fuzzydate)
{
longlong tmp=Field_datetime::val_int();
- long part1,part2;
- part1=(long) (tmp/LL(1000000));
- part2=(long) (tmp - (ulonglong) part1*LL(1000000));
+ uint32 part1,part2;
+ part1=(uint32) (tmp/LL(1000000));
+ part2=(uint32) (tmp - (ulonglong) part1*LL(1000000));
ltime->time_type= TIMESTAMP_FULL;
- ltime->neg=0;
- ltime->second_part=0;
- ltime->second= part2%100;
- ltime->minute= part2/100%100;
- ltime->hour= part2/10000;
- ltime->day= part1%100;
- ltime->month= part1/100%100;
- ltime->year= part1/10000;
+ ltime->neg= 0;
+ ltime->second_part= 0;
+ ltime->second= (int) (part2%100);
+ ltime->minute= (int) (part2/100%100);
+ ltime->hour= (int) (part2/10000);
+ ltime->day= (int) (part1%100);
+ ltime->month= (int) (part1/100%100);
+ ltime->year= (int) (part1/10000);
return (!fuzzydate && (!ltime->month || !ltime->day)) ? 1 : 0;
}
@@ -3331,7 +3332,7 @@ void Field_string::store(longlong nr)
{
char buff[22];
char *end=longlong10_to_str(nr,buff,-10);
- Field_string::store(buff,end-buff);
+ Field_string::store(buff,(uint) (end-buff));
}
@@ -3522,7 +3523,7 @@ void Field_varstring::store(longlong nr)
{
char buff[22];
char *end=longlong10_to_str(nr,buff,-10);
- Field_varstring::store(buff,end-buff);
+ Field_varstring::store(buff,(uint) (end-buff));
}
@@ -3613,9 +3614,9 @@ char *Field_varstring::pack(char *to, const char *from, uint max_length)
uint length=uint2korr(from);
if (length > max_length)
length=max_length;
- *to++= (length & 255);
+ *to++= (char) (length & 255);
if (max_length > 255)
- *to++= (uchar) (length >> 8);
+ *to++= (char) (length >> 8);
if (length)
memcpy(to, from+2, length);
return to+length;
@@ -3704,7 +3705,7 @@ uint Field_varstring::max_packed_col_length(uint max_length)
** packlength slot and may be from 1-4.
****************************************************************************/
-Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint blob_pack_length,
bool binary_arg)
@@ -3721,7 +3722,7 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
}
-void Field_blob::store_length(ulong number)
+void Field_blob::store_length(uint32 number)
{
switch (packlength) {
case 1:
@@ -3748,9 +3749,9 @@ void Field_blob::store_length(ulong number)
shortstore(ptr,(unsigned short) number);
break;
case 3:
- if (number > (ulong) (1L << 24))
+ if (number > (uint32) (1L << 24))
{
- number= (ulong) (1L << 24)-1L;
+ number= (uint32) (1L << 24)-1L;
current_thd->cuted_fields++;
}
int3store(ptr,number);
@@ -3768,11 +3769,11 @@ void Field_blob::store_length(ulong number)
}
-ulong Field_blob::get_length(const char *pos)
+uint32 Field_blob::get_length(const char *pos)
{
switch (packlength) {
case 1:
- return (ulong) (uchar) pos[0];
+ return (uint32) (uchar) pos[0];
case 2:
{
uint16 tmp;
@@ -3782,10 +3783,10 @@ ulong Field_blob::get_length(const char *pos)
else
#endif
shortget(tmp,pos);
- return (ulong) tmp;
+ return (uint32) tmp;
}
case 3:
- return (ulong) uint3korr(pos);
+ return (uint32) uint3korr(pos);
case 4:
{
uint32 tmp;
@@ -3795,7 +3796,7 @@ ulong Field_blob::get_length(const char *pos)
else
#endif
longget(tmp,pos);
- return (ulong) tmp;
+ return (uint32) tmp;
}
}
return 0; // Impossible
@@ -3841,14 +3842,14 @@ void Field_blob::store(const char *from,uint len)
void Field_blob::store(double nr)
{
value.set(nr);
- Field_blob::store(value.ptr(),value.length());
+ Field_blob::store(value.ptr(),(uint) value.length());
}
void Field_blob::store(longlong nr)
{
value.set(nr);
- Field_blob::store(value.ptr(),value.length());
+ Field_blob::store(value.ptr(), (uint) value.length());
}
@@ -3859,7 +3860,7 @@ double Field_blob::val_real(void)
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0.0;
- ulong length=get_length(ptr);
+ uint32 length=get_length(ptr);
char save=blob[length]; // Ok to patch blob in NISAM
blob[length]=0;
@@ -3875,7 +3876,7 @@ longlong Field_blob::val_int(void)
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0;
- ulong length=get_length(ptr);
+ uint32 length=get_length(ptr);
char save=blob[length]; // Ok to patch blob in NISAM
blob[length]=0;
@@ -3898,8 +3899,8 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
}
-int Field_blob::cmp(const char *a,ulong a_length, const char *b,
- ulong b_length)
+int Field_blob::cmp(const char *a,uint32 a_length, const char *b,
+ uint32 b_length)
{
int diff;
if (binary_flag)
@@ -3933,11 +3934,11 @@ int Field_blob::cmp_binary_offset(uint row_offset)
int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
- ulong max_length)
+ uint32 max_length)
{
char *a,*b;
uint diff;
- ulong a_length,b_length;
+ uint32 a_length,b_length;
memcpy_fixed(&a,a_ptr+packlength,sizeof(char*));
memcpy_fixed(&b,b_ptr+packlength,sizeof(char*));
a_length=get_length(a_ptr);
@@ -3956,9 +3957,9 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
void Field_blob::get_key_image(char *buff,uint length)
{
length-=HA_KEY_BLOB_LENGTH;
- ulong blob_length=get_length(ptr);
+ uint32 blob_length=get_length(ptr);
char *blob;
- if ((ulong) length > blob_length)
+ if ((uint32) length > blob_length)
{
#ifdef HAVE_purify
bzero(buff+2+blob_length, (length-blob_length));
@@ -4052,7 +4053,7 @@ char *Field_blob::pack(char *to, const char *from, uint max_length)
{
char *save=ptr;
ptr=(char*) from;
- ulong length=get_length(); // Length of from string
+ uint32 length=get_length(); // Length of from string
if (length > max_length)
{
ptr=to;
@@ -4075,7 +4076,7 @@ char *Field_blob::pack(char *to, const char *from, uint max_length)
const char *Field_blob::unpack(char *to, const char *from)
{
memcpy(to,from,packlength);
- ulong length=get_length(from);
+ uint32 length=get_length(from);
from+=packlength;
if (length)
memcpy_fixed(to+packlength, &from, sizeof(from));
@@ -4140,7 +4141,7 @@ char *Field_blob::pack_key(char *to, const char *from, uint max_length)
{
char *save=ptr;
ptr=(char*) from;
- ulong length=get_length(); // Length of from string
+ uint32 length=get_length(); // Length of from string
if (length > max_length)
length=max_length;
*to++= (uchar) length;
@@ -4163,9 +4164,9 @@ char *Field_blob::pack_key_from_key_image(char *to, const char *from,
uint length=uint2korr(from);
if (length > max_length)
length=max_length;
- *to++= (length & 255);
+ *to++= (char) (length & 255);
if (max_length > 255)
- *to++= (uchar) (length >> 8);
+ *to++= (char) (length >> 8);
if (length)
memcpy(to, from+2, length);
return to+length;
@@ -4278,7 +4279,7 @@ void Field_enum::store(const char *from,uint length)
conv=buff;
}
my_errno=0;
- tmp=strtoul(conv,&end,10);
+ tmp=(uint) strtoul(conv,&end,10);
if (my_errno || end != conv+length || tmp > typelib->count)
{
tmp=0;
@@ -4548,7 +4549,7 @@ bool Field_enum::eq_def(Field *field)
if (!Field::eq_def(field))
return 0;
TYPELIB *from_lib=((Field_enum*) field)->typelib;
-
+
if (typelib->count < from_lib->count)
return 0;
for (uint i=0 ; i < from_lib->count ; i++)
@@ -4558,7 +4559,7 @@ bool Field_enum::eq_def(Field *field)
}
bool Field_num::eq_def(Field *field)
-{
+{
if (!Field::eq_def(field))
return 0;
Field_num *from_num= (Field_num*) field;
@@ -4624,7 +4625,7 @@ uint pack_length_to_packflag(uint type)
Field *make_field(char *ptr, uint32 field_length,
- uchar *null_pos, uint null_bit,
+ uchar *null_pos, uchar null_bit,
uint pack_flag,
Field::utype unireg_check,
TYPELIB *interval,
diff --git a/sql/field.h b/sql/field.h
index e2af9853512..a9b257f0c3a 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1,23 +1,23 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
/*
-** Because of the function new_field all field classes that have static
-** variables must declare the size_of() member function.
+ Because of the function new_field() all field classes that have static
+ variables must declare the size_of() member function.
*/
#ifdef __GNUC__
@@ -37,21 +37,22 @@ public:
static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
static void operator delete(void *ptr_arg, size_t size) {} /*lint -e715 */
- enum utype { NONE,DATE,SHIELD,NOEMPTY,CASEUP,PNR,BGNR,PGNR,YES,NO,REL,
- CHECK,EMPTY,UNKNOWN_FIELD,CASEDN,NEXT_NUMBER,INTERVAL_FIELD,
- BIT_FIELD, TIMESTAMP_FIELD,CAPITALIZE,BLOB_FIELD};
- char *ptr; // Position to field in record
+ char *ptr; // Position to field in record
uchar *null_ptr; // Byte where null_bit is
- uint8 null_bit; // And position to it
struct st_table *table; // Pointer for table
- ulong query_id; // For quick test of used fields
- key_map key_start,part_of_key,part_of_sortkey;// Field is part of these keys.
- const char *table_name,*field_name;
- utype unireg_check;
- uint32 field_length; // Length of field
- uint16 flags;
-
- Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,uint null_bit_arg,
+ const char *table_name,*field_name;
+ ulong query_id; // For quick test of used fields
+ // Field is part of the following keys
+ key_map key_start,part_of_key,part_of_sortkey;
+ enum utype { NONE,DATE,SHIELD,NOEMPTY,CASEUP,PNR,BGNR,PGNR,YES,NO,REL,
+ CHECK,EMPTY,UNKNOWN_FIELD,CASEDN,NEXT_NUMBER,INTERVAL_FIELD,
+ BIT_FIELD, TIMESTAMP_FIELD,CAPITALIZE,BLOB_FIELD};
+ utype unireg_check;
+ uint32 field_length; // Length of field
+ uint16 flags;
+ uchar null_bit; // Bit used to test null bit
+
+ Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,uchar null_bit_arg,
utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg);
virtual ~Field() {}
@@ -77,7 +78,7 @@ public:
virtual enum_field_types real_type() const { return type(); }
inline int cmp(const char *str) { return cmp(ptr,str); }
virtual int cmp(const char *,const char *)=0;
- virtual int cmp_binary(const char *a,const char *b, ulong max_length=~0L)
+ virtual int cmp_binary(const char *a,const char *b, uint32 max_length=~0L)
{ return memcmp(a,b,pack_length()); }
virtual int cmp_offset(uint row_offset)
{ return memcmp(ptr,ptr+row_offset,pack_length()); }
@@ -92,7 +93,7 @@ public:
// Caller beware: sql_type can change str.Ptr, so check
// ptr() to see if it changed if you are using your own buffer
// in str and restore it with set() if needed
-
+
virtual uint size_of() const =0; // For new field
inline bool is_null(uint row_offset=0)
{ return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : table->null_row; }
@@ -101,30 +102,30 @@ public:
inline void set_null(int row_offset=0)
{ if (null_ptr) null_ptr[row_offset]|= null_bit; }
inline void set_notnull(int row_offset=0)
- { if (null_ptr) null_ptr[row_offset]&= ~null_bit; }
+ { if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; }
inline bool maybe_null(void) { return null_ptr != 0 || table->maybe_null; }
inline bool real_maybe_null(void) { return null_ptr != 0; }
virtual void make_field(Send_field *)=0;
virtual void sort_string(char *buff,uint length)=0;
virtual bool optimize_range();
virtual bool store_for_compare() { return 0; }
- inline Field *new_field(struct st_table *new_table)
- {
- Field *tmp= (Field*) sql_memdup((char*) this,size_of());
- if (tmp)
- {
- tmp->table=new_table;
- tmp->key_start=tmp->part_of_key=tmp->part_of_sortkey=0;
- tmp->unireg_check=Field::NONE;
- tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG | ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
- tmp->reset_fields();
- }
- return tmp;
- }
- inline void move_field(char *ptr_arg,uchar *null_ptr_arg,uint null_bit_arg)
+ Field *new_field(MEM_ROOT *root, struct st_table *new_table)
+ {
+ Field *tmp= (Field*) memdup_root(root,(char*) this,size_of());
+ if (tmp)
{
- ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg;
+ tmp->table=new_table;
+ tmp->key_start=tmp->part_of_key=tmp->part_of_sortkey=0;
+ tmp->unireg_check=Field::NONE;
+ tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG | ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
+ tmp->reset_fields();
}
+ return tmp;
+ }
+ inline void move_field(char *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg)
+ {
+ ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg;
+ }
inline void move_field(char *ptr_arg) { ptr=ptr_arg; }
inline void move_field(my_ptrdiff_t ptr_diff)
{
@@ -157,7 +158,7 @@ public:
bool send(THD *thd, String *packet);
virtual char *pack(char* to, const char *from, uint max_length=~(uint) 0)
{
- uint length=pack_length();
+ uint32 length=pack_length();
memcpy(to,from,length);
return to+length;
}
@@ -212,10 +213,10 @@ public:
const uint8 dec;
bool zerofill,unsigned_flag; // Purify cannot handle bit fields
Field_num(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg, utype unireg_check_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
struct st_table *table_arg,
- uint dec_arg,bool zero_arg,bool unsigned_arg)
+ uint8 dec_arg,bool zero_arg,bool unsigned_arg)
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg),
dec(dec_arg),zerofill(zero_arg),unsigned_flag(unsigned_arg)
@@ -230,7 +231,7 @@ public:
void add_zerofill_and_unsigned(String &res) const;
friend class create_field;
void make_field(Send_field *);
- uint decimals() const { return dec; }
+ uint decimals() const { return (uint) dec; }
uint size_of() const { return sizeof(*this); }
bool eq_def(Field *field);
};
@@ -239,7 +240,7 @@ public:
class Field_str :public Field {
public:
Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg, utype unireg_check_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
struct st_table *table_arg)
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
@@ -256,10 +257,10 @@ public:
class Field_decimal :public Field_num {
public:
Field_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
- uint dec_arg,bool zero_arg,bool unsigned_arg)
+ uint8 dec_arg,bool zero_arg,bool unsigned_arg)
:Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg,
dec_arg, zero_arg,unsigned_arg)
@@ -285,7 +286,7 @@ public:
class Field_tiny :public Field_num {
public:
Field_tiny(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
bool zero_arg, bool unsigned_arg)
@@ -314,7 +315,7 @@ public:
class Field_short :public Field_num {
public:
Field_short(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
bool zero_arg, bool unsigned_arg)
@@ -343,7 +344,7 @@ public:
class Field_medium :public Field_num {
public:
Field_medium(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
bool zero_arg, bool unsigned_arg)
@@ -372,7 +373,7 @@ public:
class Field_long :public Field_num {
public:
Field_long(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
bool zero_arg, bool unsigned_arg)
@@ -407,7 +408,7 @@ public:
class Field_longlong :public Field_num {
public:
Field_longlong(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
bool zero_arg, bool unsigned_arg)
@@ -442,10 +443,10 @@ public:
class Field_float :public Field_num {
public:
Field_float(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
- uint dec_arg,bool zero_arg,bool unsigned_arg)
+ uint8 dec_arg,bool zero_arg,bool unsigned_arg)
:Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg,
dec_arg, zero_arg,unsigned_arg)
@@ -469,16 +470,16 @@ public:
class Field_double :public Field_num {
public:
Field_double(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
- uint dec_arg,bool zero_arg,bool unsigned_arg)
+ uint8 dec_arg,bool zero_arg,bool unsigned_arg)
:Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg,
dec_arg, zero_arg,unsigned_arg)
{}
Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
- struct st_table *table_arg, uint dec_arg)
+ struct st_table *table_arg, uint8 dec_arg)
:Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
NONE, field_name_arg, table_arg,dec_arg,0,0)
{}
@@ -567,7 +568,7 @@ public:
class Field_year :public Field_tiny {
public:
Field_year(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg)
:Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
@@ -586,12 +587,16 @@ public:
class Field_date :public Field_str {
public:
- Field_date(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ Field_date(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg)
:Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg)
{}
+ Field_date(bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg)
+ :Field_str((char*) 0,10, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg) {}
enum_field_types type() const { return FIELD_TYPE_DATE;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
enum Item_result cmp_type () const { return INT_RESULT; }
@@ -612,7 +617,7 @@ public:
class Field_newdate :public Field_str {
public:
- Field_newdate(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ Field_newdate(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg)
:Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
@@ -643,12 +648,16 @@ public:
class Field_time :public Field_str {
public:
- Field_time(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ Field_time(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg)
:Field_str(ptr_arg, 8, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg)
{}
+ Field_time(bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg)
+ :Field_str((char*) 0,8, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg) {}
enum_field_types type() const { return FIELD_TYPE_TIME;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
enum Item_result cmp_type () const { return INT_RESULT; }
@@ -671,12 +680,16 @@ public:
class Field_datetime :public Field_str {
public:
- Field_datetime(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ Field_datetime(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg)
:Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg)
{}
+ Field_datetime(bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg)
+ :Field_str((char*) 0,19, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg) {}
enum_field_types type() const { return FIELD_TYPE_DATETIME;}
#ifdef HAVE_LONG_LONG
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
@@ -705,7 +718,7 @@ class Field_string :public Field_str {
bool binary_flag;
public:
Field_string(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,bool binary_arg)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
@@ -760,7 +773,7 @@ class Field_varstring :public Field_str {
bool binary_flag;
public:
Field_varstring(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,bool binary_arg)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
@@ -813,7 +826,7 @@ class Field_blob :public Field_str {
String value; // For temporaries
bool binary_flag;
public:
- Field_blob(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint blob_pack_length,
bool binary_arg);
@@ -837,21 +850,22 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
int cmp(const char *,const char*);
- int cmp(const char *a, ulong a_length, const char *b, ulong b_length);
+ int cmp(const char *a, uint32 a_length, const char *b, uint32 b_length);
int cmp_offset(uint offset);
- int cmp_binary(const char *a,const char *b, ulong max_length=~0L);
+ int cmp_binary(const char *a,const char *b, uint32 max_length=~0L);
int cmp_binary_offset(uint row_offset);
int key_cmp(const byte *,const byte*);
int key_cmp(const byte *str, uint length);
uint32 key_length() const { return 0; }
void sort_string(char *buff,uint length);
- uint32 pack_length() const { return (uint32) (packlength+table->blob_ptr_size); }
- void reset(void) { bzero(ptr,packlength+sizeof(char*)); }
+ uint32 pack_length() const
+ { return (uint32) (packlength+table->blob_ptr_size); }
+ void reset(void) { bzero(ptr, packlength+sizeof(char*)); }
void reset_fields() { bzero((char*) &value,sizeof(value)); }
- void store_length(ulong number);
- inline ulong get_length(uint row_offset=0)
+ void store_length(uint32 number);
+ inline uint32 get_length(uint row_offset=0)
{ return get_length(ptr+row_offset); }
- ulong get_length(const char *ptr);
+ uint32 get_length(const char *ptr);
bool binary() const { return binary_flag; }
inline void get_ptr(char **str)
{
@@ -862,7 +876,7 @@ public:
memcpy(ptr,length,packlength);
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
}
- inline void set_ptr(ulong length,char *data)
+ inline void set_ptr(uint32 length,char *data)
{
store_length(length);
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
@@ -902,7 +916,7 @@ protected:
public:
TYPELIB *typelib;
Field_enum(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint packlength_arg,
TYPELIB *typelib_arg)
@@ -939,7 +953,7 @@ public:
class Field_set :public Field_enum {
public:
Field_set(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
- uint null_bit_arg,
+ uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint32 packlength_arg,
TYPELIB *typelib_arg)
@@ -1022,7 +1036,7 @@ public:
Field *make_field(char *ptr, uint32 field_length,
- uchar *null_pos, uint null_bit,
+ uchar *null_pos, uchar null_bit,
uint pack_flag, Field::utype unireg_check,
TYPELIB *interval, const char *field_name,
struct st_table *table);
@@ -1065,7 +1079,7 @@ bool test_if_int(const char *str,int length);
#define f_is_zerofill(x) ((x) & FIELDFLAG_ZEROFILL)
#define f_is_packed(x) ((x) & FIELDFLAG_PACK)
#define f_packtype(x) (((x) >> FIELDFLAG_PACK_SHIFT) & 15)
-#define f_decimals(x) (((x) >> FIELDFLAG_DEC_SHIFT) & FIELDFLAG_MAX_DEC)
+#define f_decimals(x) ((uint8) (((x) >> FIELDFLAG_DEC_SHIFT) & FIELDFLAG_MAX_DEC))
#define f_is_alpha(x) (!f_is_num(x))
#define f_is_binary(x) ((x) & FIELDFLAG_BINARY)
#define f_is_enum(x) ((x) & FIELDFLAG_INTERVAL)
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 606edd84c74..c7a6d778953 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 16eedb94c59..a5f42d5731e 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -69,7 +69,7 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
{
int error;
ulong memavl;
- uint maxbuffer,skr;
+ uint maxbuffer;
BUFFPEK *buffpek;
ha_rows records;
uchar **sort_keys;
@@ -163,7 +163,7 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
&tempfile, selected_records_file)) ==
HA_POS_ERROR)
goto err;
- maxbuffer= my_b_tell(&buffpek_pointers)/sizeof(*buffpek);
+ maxbuffer= (uint) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek));
if (maxbuffer == 0) // The whole set is in memory
{
@@ -267,14 +267,14 @@ static BUFFPEK *read_buffpek_from_file(IO_CACHE *buffpek_pointers, uint count)
if (tmp)
{
if (reinit_io_cache(buffpek_pointers,READ_CACHE,0L,0,0) ||
- my_b_read(buffpek_pointers, (char*) tmp, length))
+ my_b_read(buffpek_pointers, (byte*) tmp, length))
{
my_free((char*) tmp, MYF(0));
tmp=0;
}
}
DBUG_RETURN(tmp);
-}
+}
@@ -398,10 +398,12 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
/* Skriver en buffert med nycklar till filen */
-static int write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
- IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
+static int
+write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
+ IO_CACHE *buffpek_pointers, IO_CACHE *tempfile)
{
uint sort_length;
+ uchar **end;
BUFFPEK buffpek;
DBUG_ENTER("write_keys");
@@ -419,10 +421,10 @@ static int write_keys(SORTPARAM *param, register uchar **sort_keys, uint count,
if ((ha_rows) count > param->max_rows)
count=(uint) param->max_rows; /* purecov: inspected */
buffpek.count=(ha_rows) count;
- for (uchar **end=sort_keys+count ; sort_keys != end ; sort_keys++)
+ for (end=sort_keys+count ; sort_keys != end ; sort_keys++)
if (my_b_write(tempfile,(byte*) *sort_keys,(uint) sort_length))
goto err;
- if (my_b_write(buffpek_pointers, (char*) &buffpek, sizeof(buffpek)))
+ if (my_b_write(buffpek_pointers, (byte*) &buffpek, sizeof(buffpek)))
goto err;
DBUG_RETURN(0);
diff --git a/sql/frm_crypt.cc b/sql/frm_crypt.cc
index 629e4ffab95..8dd70900648 100644
--- a/sql/frm_crypt.cc
+++ b/sql/frm_crypt.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index 4e5d6fb3111..7ebdbcd8ba8 100644
--- a/sql/gen_lex_hash.cc
+++ b/sql/gen_lex_hash.cc
@@ -279,8 +279,17 @@ void print_arrays()
for (i=0;i<size;i++)
{
- ulong order = tab_index_function ((i < how_long_symbols) ? symbols[i].name : sql_functions[i - how_long_symbols].name,function_plus,function_type);
+ const char *name= ((i < how_long_symbols) ?
+ symbols[i].name :
+ sql_functions[i - how_long_symbols].name);
+ ulong order = tab_index_function(name,function_plus,function_type);
order %= function_mod;
+ /* This should never be true */
+ if (prva[order] != max_symbol)
+ {
+ fprintf(stderr,"Error: Got duplicate value for symbol '%s'\n",name);
+ exit(1);
+ }
prva [order] = i;
}
@@ -331,11 +340,11 @@ static struct option long_options[] =
static void usage(int version)
{
- printf("%s Ver 3.2 Distrib %s, for %s (%s)\n",
+ printf("%s Ver 3.3 Distrib %s, for %s (%s)\n",
my_progname, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
if (version)
return;
- puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB, by Sinisa and Monty");
+ puts("Copyright (C) 2001 MySQL AB, by Sinisa and Monty");
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
puts("This program generates a perfect hashing function for the sql_lex.cc");
printf("Usage: %s [OPTIONS]\n", my_progname);
@@ -527,7 +536,7 @@ int main(int argc,char **argv)
function_mod=best_mod; function_plus=best_add;
make_char_table(best_t1,best_t2,best_type);
- printf("/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB\n\
+ printf("/* Copyright (C) 2001 MySQL AB\n\
This program is free software; you can redistribute it and/or modify\n\
it under the terms of the GNU General Public License as published by\n\
the Free Software Foundation; either version 2 of the License, or\n\
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 3cb14b5e72f..614d1b5abf5 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -1043,7 +1043,7 @@ int ha_berkeley::restore_keys(DB_TXN *trans, key_map changed_keys,
break; /* purecov: inspected */
}
}
-
+
err:
DBUG_ASSERT(error != DB_KEYEXIST);
DBUG_RETURN(error);
@@ -1454,6 +1454,37 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
DBUG_RETURN(error);
}
+/*
+ Read last key is solved by reading the next key and then reading
+ the previous key
+*/
+
+int ha_berkeley::index_read_last(byte * buf, const byte * key, uint key_len)
+{
+ DBT row;
+ int error;
+ KEY *key_info= &table->key_info[active_index];
+ DBUG_ENTER("ha_berkeley::index_read");
+
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ bzero((char*) &row,sizeof(row));
+
+ /* read of partial key */
+ pack_key(&last_key, active_index, key_buff, key, key_len);
+ /* Store for compare */
+ memcpy(key_buff2, key_buff, (key_len=last_key.size));
+ key_info->handler.bdb_return_if_eq= 1;
+ error=read_row(cursor->c_get(cursor, &last_key, &row, DB_SET_RANGE),
+ (char*) buf, active_index, &row, (DBT*) 0, 0);
+ key_info->handler.bdb_return_if_eq= 0;
+ bzero((char*) &row,sizeof(row));
+ if (read_row(cursor->c_get(cursor, &last_key, &row, DB_PREV),
+ (char*) buf, active_index, &row, &last_key, 1) ||
+ berkeley_key_cmp(table, key_info, key_buff2, key_len))
+ error=HA_ERR_KEY_NOT_FOUND;
+ DBUG_RETURN(error);
+}
+
int ha_berkeley::index_next(byte * buf)
{
@@ -1565,12 +1596,13 @@ int ha_berkeley::rnd_pos(byte * buf, byte *pos)
{
DBT db_pos;
statistic_increment(ha_read_rnd_count,&LOCK_status);
+ DBUG_ENTER("ha_berkeley::rnd_pos");
active_index= (uint) -1; // Don't delete via cursor
- return read_row(file->get(file, transaction,
- get_pos(&db_pos, pos),
- &current_row, 0),
- (char*) buf, primary_key, &current_row, (DBT*) 0, 0);
+ DBUG_RETURN(read_row(file->get(file, transaction,
+ get_pos(&db_pos, pos),
+ &current_row, 0),
+ (char*) buf, primary_key, &current_row, (DBT*) 0, 0));
}
void ha_berkeley::position(const byte *record)
@@ -2176,7 +2208,7 @@ static BDB_SHARE *get_share(const char *table_name, TABLE *table)
char *tmp_name;
DB **key_file;
u_int32_t *key_type;
-
+
if ((share=(BDB_SHARE *)
my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
&share, sizeof(*share),
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
index 561e06229fa..587d70265fa 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -89,8 +89,8 @@ class ha_berkeley: public handler
int_option_flag(HA_READ_NEXT | HA_READ_PREV |
HA_REC_NOT_IN_SEQ |
HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
- HA_LONGLONG_KEYS | HA_NULL_KEY | HA_HAVE_KEY_READ_ONLY |
- HA_BLOB_KEY | HA_NOT_EXACT_COUNT | HA_NO_FULLTEXT_KEY |
+ HA_NULL_KEY | HA_HAVE_KEY_READ_ONLY |
+ HA_BLOB_KEY | HA_NOT_EXACT_COUNT |
HA_PRIMARY_KEY_IN_READ_INDEX | HA_DROP_BEFORE_CREATE |
HA_AUTO_PART_KEY),
changed_rows(0),last_dup_key((uint) -1),version(0),using_ignore(0)
@@ -98,6 +98,7 @@ class ha_berkeley: public handler
}
~ha_berkeley() {}
const char *table_type() const { return "BerkeleyDB"; }
+ const char *index_type(uint key_number) { return "BTREE"; }
const char **bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
@@ -107,6 +108,7 @@ class ha_berkeley: public handler
uint extra_rec_buf_length() { return BDB_HIDDEN_PRIMARY_KEY_LENGTH; }
ha_rows estimate_number_of_rows();
bool fast_key_read() { return 1;}
+ key_map keys_to_use_for_scanning() { return ~(key_map) 0; }
bool has_transactions() { return 1;}
int open(const char *name, int mode, uint test_if_locked);
@@ -121,6 +123,7 @@ class ha_berkeley: public handler
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
+ int index_read_last(byte * buf, const byte * key, uint key_len);
int index_next(byte * buf);
int index_next_same(byte * buf, const byte *key, uint keylen);
int index_prev(byte * buf);
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index eff69893502..5f482bca1e8 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -33,7 +33,7 @@ const char **ha_heap::bas_ext() const
int ha_heap::open(const char *name, int mode, uint test_if_locked)
{
- uint key,part,parts,mem_per_row=0;
+ uint key,parts,mem_per_row=0;
ulong max_rows;
HP_KEYDEF *keydef;
HP_KEYSEG *seg;
@@ -48,24 +48,38 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked)
for (key=0 ; key < table->keys ; key++)
{
KEY *pos=table->key_info+key;
+ KEY_PART_INFO *key_part= pos->key_part;
+ KEY_PART_INFO *key_part_end= key_part+pos->key_parts;
+
mem_per_row += (pos->key_length + (sizeof(char*) * 2));
-
+
keydef[key].keysegs=(uint) pos->key_parts;
- keydef[key].flag = (pos->flags & HA_NOSAME);
+ keydef[key].flag = (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
keydef[key].seg=seg;
-
- for (part=0 ; part < pos->key_parts ; part++)
+
+ for (; key_part != key_part_end ; key_part++, seg++)
{
- uint flag=pos->key_part[part].key_type;
+ uint flag=key_part->key_type;
+ Field *field=key_part->field;
if (!f_is_packed(flag) &&
f_packtype(flag) == (int) FIELD_TYPE_DECIMAL &&
!(flag & FIELDFLAG_BINARY))
seg->type= (int) HA_KEYTYPE_TEXT;
else
seg->type= (int) HA_KEYTYPE_BINARY;
- seg->start=(uint) pos->key_part[part].offset;
- seg->length=(uint) pos->key_part[part].length;
- seg++;
+ seg->start=(uint) key_part->offset;
+ seg->length=(uint) key_part->length;
+ if (field->null_ptr)
+ {
+ seg->null_bit=field->null_bit;
+ seg->null_pos= (uint) (field->null_ptr-
+ (uchar*) table->record[0]);
+ }
+ else
+ {
+ seg->null_bit=0;
+ seg->null_pos=0;
+ }
}
}
mem_per_row += MY_ALIGN(table->reclength+1, sizeof(char*));
@@ -77,7 +91,8 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked)
table->max_rows : max_rows),
table->min_rows);
my_free((gptr) keydef,MYF(0));
- info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
+ if (file)
+ info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
ref_length=sizeof(HEAP_PTR);
return (!file ? errno : 0);
}
@@ -147,7 +162,7 @@ int ha_heap::index_prev(byte * buf)
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
-
+
int ha_heap::index_first(byte * buf)
{
statistic_increment(ha_read_first_count,&LOCK_status);
@@ -227,7 +242,7 @@ int ha_heap::delete_all_rows()
int ha_heap::external_lock(THD *thd, int lock_type)
{
return 0; // No external locking
-}
+}
THR_LOCK_DATA **ha_heap::store_lock(THD *thd,
THR_LOCK_DATA **to,
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index 6b7e9c6c626..c8f29dea53c 100644
--- a/sql/ha_heap.h
+++ b/sql/ha_heap.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -31,11 +31,12 @@ class ha_heap: public handler
ha_heap(TABLE *table): handler(table), file(0) {}
~ha_heap() {}
const char *table_type() const { return "HEAP"; }
+ const char *index_type(uint key_number) { return "HASH"; }
const char **bas_ext() const;
ulong option_flag() const
{ return (HA_READ_RND_SAME | HA_NO_INDEX | HA_ONLY_WHOLE_INDEX |
HA_WRONG_ASCII_ORDER | HA_KEYPOS_TO_RNDPOS | HA_NO_BLOBS |
- HA_REC_NOT_IN_SEQ | HA_NO_FULLTEXT_KEY); }
+ HA_NULL_KEY | HA_REC_NOT_IN_SEQ | HA_NOT_READ_PREFIX_LAST); }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
diff --git a/sql/ha_innobase.cc b/sql/ha_innodb.cc
index b96eb86dbc1..8941481a95f 100644
--- a/sql/ha_innobase.cc
+++ b/sql/ha_innodb.cc
@@ -21,7 +21,7 @@ InnoDB */
- Ask Monty if strings of different languages can exist in the same
database. Answer: in near future yes, but not yet.
*/
-
+
#ifdef __GNUC__
#pragma implementation // gcc: Class implementation
#endif
@@ -35,7 +35,7 @@ InnoDB */
#define MAX_ULONG_BIT ((ulong) 1 << (sizeof(ulong)*8-1))
-#include "ha_innobase.h"
+#include "ha_innodb.h"
/* We must declare this here because we undef SAFE_MUTEX below */
pthread_mutex_t innobase_mutex;
@@ -439,7 +439,7 @@ innobase_parse_data_file_paths_and_sizes(void)
&& *(str + 1) == 'a'
&& *(str + 2) == 'w') {
str += 3;
-
+
if (srv_data_file_is_raw_partition[i] == 0) {
srv_data_file_is_raw_partition[i] = SRV_OLD_RAW;
}
@@ -536,7 +536,7 @@ innobase_init(void)
{
int err;
bool ret;
- char current_lib[2], *default_path;
+ char current_lib[3], *default_path;
DBUG_ENTER("innobase_init");
@@ -580,7 +580,7 @@ innobase_init(void)
ret = innobase_parse_data_file_paths_and_sizes();
if (ret == FALSE) {
- fprintf(stderr, "InnoDB: syntax error in innodb_data_file_path\n");
+ sql_print_error("InnoDB: syntax error in innodb_data_file_path");
DBUG_RETURN(TRUE);
}
@@ -623,7 +623,7 @@ innobase_init(void)
For non-latin1 charsets we use the MySQL comparison
functions, and consequently we do not need to know
the ordering internally in InnoDB. */
-
+
memcpy(srv_latin1_ordering,
default_charset_info->sort_order, 256);
}
@@ -765,7 +765,7 @@ innobase_rollback(
}
srv_conc_exit_innodb();
-
+
trx_mark_sql_stat_end(trx);
DBUG_RETURN(convert_error_code_to_mysql(error));
@@ -928,13 +928,13 @@ ha_innobase::open(
if (NULL == (ib_table = dict_table_get(norm_name, NULL))) {
- fprintf(stderr,
-"InnoDB: Error: cannot find table %s from the internal data dictionary\n"
-"InnoDB: of InnoDB though the .frm file for the table exists. Maybe you\n"
-"InnoDB: have deleted and recreated InnoDB data files but have forgotten\n"
-"InnoDB: to delete the corresponding .frm files of InnoDB tables, or you\n"
-"InnoDB: have moved .frm files to another database?\n",
- norm_name);
+ sql_print_error("InnoDB error:\n\
+Cannot find table %s from the internal data dictionary\n\
+of InnoDB though the .frm file for the table exists. Maybe you\n\
+have deleted and recreated InnoDB data files but have forgotten\n\
+to delete the corresponding .frm files of InnoDB tables, or you\n\
+have moved .frm files to another database?",
+ norm_name);
free_share(share);
my_free((char*) upd_buff, MYF(0));
@@ -974,7 +974,7 @@ ha_innobase::open(
->clust_index_was_generated = TRUE;
ref_length = DATA_ROW_ID_LEN + 10;
-
+
DBUG_ASSERT(key_used_on_scan == MAX_KEY);
}
@@ -1288,7 +1288,7 @@ build_template(
} else {
/* We are building a temporary table: fetch all
columns */
-
+
templ_type = ROW_MYSQL_WHOLE_ROW;
}
}
@@ -1425,7 +1425,7 @@ ha_innobase::write_row(
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
int error;
longlong auto_inc;
-
+
DBUG_ENTER("ha_innobase::write_row");
statistic_increment(ha_write_count, &LOCK_status);
@@ -1443,7 +1443,7 @@ ha_innobase::write_row(
/* Fetch the value the user possibly has set in the
autoincrement field */
-
+
auto_inc = table->next_number_field->val_int();
/* In replication and also otherwise the auto-inc column
@@ -1471,7 +1471,7 @@ ha_innobase::write_row(
auto-inc column */
user_thd->next_insert_id = auto_inc;
}
-
+
if (auto_inc != 0) {
/* This call will calculate the max of the
current value and the value supplied by the user, if
@@ -1490,11 +1490,11 @@ ha_innobase::write_row(
srv_conc_exit_innodb();
if (error != DB_SUCCESS) {
-
+
error = convert_error_code_to_mysql(error);
goto func_exit;
}
-
+
dict_table_autoinc_update(prebuilt->table, auto_inc);
} else {
srv_conc_enter_innodb(prebuilt->trx);
@@ -1505,7 +1505,7 @@ ha_innobase::write_row(
prebuilt);
if (error != DB_SUCCESS) {
srv_conc_exit_innodb();
-
+
error = convert_error_code_to_mysql(
error);
goto func_exit;
@@ -1523,13 +1523,13 @@ ha_innobase::write_row(
user_thd->next_insert_id = auto_inc;
}
}
-
+
/* Set the 'in_update_remember_pos' flag to FALSE to
make sure all columns are fetched in the select done by
update_auto_increment */
prebuilt->in_update_remember_pos = FALSE;
-
+
update_auto_increment();
if (auto_inc == 0) {
@@ -1543,15 +1543,15 @@ ha_innobase::write_row(
srv_conc_exit_innodb();
if (error != DB_SUCCESS) {
-
+
error = convert_error_code_to_mysql(error);
goto func_exit;
}
-
+
dict_table_autoinc_initialize(prebuilt->table,
auto_inc);
}
-
+
/* We have to set sql_stat_start to TRUE because
update_auto_increment has called a select, and
has reset that flag; row_insert_for_mysql has to
@@ -2008,6 +2008,24 @@ ha_innobase::index_read(
DBUG_RETURN(error);
}
+
+/*
+ The following functions works like index_read, but it find the last
+ row with the current index prefix.
+ This code is disabled until Heikki has verified that InnoDB support the
+ HA_READ_PREFIX_LAST flag and removed the HA_NOT_READ_PREFIX_LAST
+ flag from ha_innodb.h
+*/
+
+int
+ha_innobase::index_read_last(mysql_byte *buf,
+ const mysql_byte *key_ptr,
+ uint key_len)
+{
+ return index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST);
+}
+
+
/************************************************************************
Changes the active index of a handle. */
@@ -2034,17 +2052,14 @@ ha_innobase::change_active_index(
prebuilt->index=dict_table_get_index_noninline(prebuilt->table, key->name);
if (!prebuilt->index)
{
- fprintf(stderr,
- "InnoDB: Could not find key n:o %u with name %s from dict cache\n"
- "InnoDB: for table %s\n", keynr, key->name,
- prebuilt->table->name);
+ sql_print_error("Innodb could not find key n:o %u with name %s from dict cache for table %s", keynr, key->name, prebuilt->table->name);
return(1);
}
}
else
prebuilt->index = dict_table_get_first_index_noninline(prebuilt->table);
- assert(prebuilt->search_tuple);
+ assert(prebuilt->search_tuple != 0);
dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
@@ -2108,7 +2123,7 @@ ha_innobase::general_fetch(
DBUG_ENTER("general_fetch");
srv_conc_enter_innodb(prebuilt->trx);
-
+
ret = row_search_for_mysql((byte*)buf, 0, prebuilt, match_mode,
direction);
srv_conc_exit_innodb();
@@ -2244,7 +2259,7 @@ ha_innobase::rnd_init(
bool scan) /* in: ???????? */
{
int err;
-
+
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
if (prebuilt->clust_index_was_generated) {
@@ -2331,7 +2346,7 @@ ha_innobase::rnd_pos(
if (error) {
DBUG_RETURN(error);
}
-
+
error = index_read(buf, pos, ref_stored_len, HA_READ_KEY_EXACT);
change_active_index(keynr);
@@ -2473,11 +2488,11 @@ ha_innobase::external_lock(
}
if (trx->auto_inc_lock) {
-
+
/* If we had reserved the auto-inc lock for
some table in this SQL statement, we release
it now */
-
+
srv_conc_enter_innodb(trx);
row_unlock_table_autoinc_for_mysql(trx);
srv_conc_exit_innodb();
@@ -2757,12 +2772,12 @@ ha_innobase::create(
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
-
+
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
innobase_table = dict_table_get(norm_name, NULL);
- assert(innobase_table);
+ assert(innobase_table != 0);
/* Tell the InnoDB server that there might be work for
utility threads: */
@@ -2812,7 +2827,7 @@ ha_innobase::delete_table(
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
-
+
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
/* Tell the InnoDB server that there might be work for
@@ -2846,9 +2861,9 @@ innobase_drop_database(
char* ptr;
int error;
char namebuf[10000];
-
+
ptr = strend(path) - 2;
-
+
while (ptr >= path && *ptr != '\\' && *ptr != '/') {
ptr--;
len++;
@@ -2859,7 +2874,7 @@ innobase_drop_database(
memcpy(namebuf, ptr, len);
namebuf[len] = '/';
namebuf[len + 1] = '\0';
-
+
trx = trx_allocate_for_mysql();
error = row_drop_database_for_mysql(namebuf, trx);
@@ -2867,7 +2882,7 @@ innobase_drop_database(
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
-
+
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
/* Tell the InnoDB server that there might be work for
@@ -2920,7 +2935,7 @@ ha_innobase::rename_table(
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
-
+
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
/* Tell the InnoDB server that there might be work for
@@ -2961,7 +2976,8 @@ ha_innobase::records_in_range(
KEY* key;
dict_index_t* index;
mysql_byte* key_val_buff2 = (mysql_byte*) my_malloc(
- table->reclength,
+ table->reclength
+ + table->max_key_length + 100,
MYF(MY_WME));
dtuple_t* range_start;
dtuple_t* range_end;
@@ -2976,7 +2992,7 @@ ha_innobase::records_in_range(
if (prebuilt->trx) {
prebuilt->trx->op_info = (char*) "estimating range size";
}
-
+
active_index = keynr;
key = table->key_info + active_index;
@@ -3012,7 +3028,7 @@ ha_innobase::records_in_range(
if (prebuilt->trx) {
prebuilt->trx->op_info = (char*) "";
}
-
+
DBUG_RETURN((ha_rows) n_rows);
}
@@ -3032,7 +3048,7 @@ ha_innobase::estimate_number_of_rows(void)
dict_index_t* index;
ulonglong estimate;
ulonglong data_file_length;
-
+
if (prebuilt->trx) {
prebuilt->trx->op_info =
(char*) "estimating upper bound of table size";
@@ -3040,16 +3056,19 @@ ha_innobase::estimate_number_of_rows(void)
DBUG_ENTER("info");
- dict_update_statistics(prebuilt->table);
-
index = dict_table_get_first_index_noninline(prebuilt->table);
-
+
data_file_length = ((ulonglong) index->stat_n_leaf_pages)
* UNIV_PAGE_SIZE;
- /* Calculate a minimum length for a clustered index record */
- estimate = data_file_length / dict_index_calc_min_rec_len(index);
-
+ /* Calculate a minimum length for a clustered index record and from
+ that an upper bound for the number of rows. Since we only calculate
+ new statistics in row0mysql.c when a tablehas grown
+ by a threshold factor, we must add a safety factor 2 in front
+ of the formula below. */
+
+ estimate = 2 * data_file_length / dict_index_calc_min_rec_len(index);
+
if (prebuilt->trx) {
prebuilt->trx->op_info = (char*) "";
}
@@ -3096,7 +3115,7 @@ ha_innobase::info(
if (prebuilt->trx) {
prebuilt->trx->op_info = (char*) "calculating table stats";
}
-
+
ib_table = prebuilt->table;
if (flag & HA_STATUS_TIME) {
@@ -3146,11 +3165,11 @@ ha_innobase::info(
if (rec_per_key == 0) {
rec_per_key = 1;
}
-
+
table->key_info[i].rec_per_key[j]
= rec_per_key;
}
-
+
index = dict_table_get_next_index_noninline(index);
}
}
@@ -3170,7 +3189,7 @@ ha_innobase::info(
if (prebuilt->trx) {
prebuilt->trx->op_info = (char*) "";
}
-
+
DBUG_VOID_RETURN;
}
@@ -3190,7 +3209,7 @@ ha_innobase::check(
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
ulint ret;
-
+
if (prebuilt->mysql_template == NULL) {
/* Build the template; we will use a dummy template
in index scans done in checking */
@@ -3203,7 +3222,7 @@ ha_innobase::check(
if (ret == DB_SUCCESS) {
return(HA_ADMIN_OK);
}
-
+
return(HA_ADMIN_CORRUPT);
}
@@ -3221,7 +3240,7 @@ ha_innobase::update_table_comment(
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
uint length = strlen(comment);
- char* str = my_malloc(length + 200, MYF(0));
+ char* str = my_malloc(length + 550, MYF(0));
char* pos;
if (!str) {
@@ -3240,8 +3259,8 @@ ha_innobase::update_table_comment(
/* We assume 150 bytes of space to print info */
- dict_print_info_on_foreign_keys(pos, 150, prebuilt->table);
-
+ dict_print_info_on_foreign_keys(pos, 500, prebuilt->table);
+
return(str);
}
@@ -3380,7 +3399,7 @@ ha_innobase::get_auto_increment()
prebuilt->select_lock_type = LOCK_X;
prebuilt->trx->mysql_n_tables_locked += 1;
-
+
error=index_last(table->record[1]);
if (error) {
diff --git a/sql/ha_innobase.h b/sql/ha_innodb.h
index 83e43b1d662..fb10975f30a 100644
--- a/sql/ha_innobase.h
+++ b/sql/ha_innodb.h
@@ -1,7 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
- && Innobase Oy
-
- -This file is modified from ha_berkeley.h of MySQL distribution-
+/* Copyright (C) 2000 MySQL AB && Innobase Oy
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
@@ -17,13 +14,17 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/*
+ This file is based on ha_berkeley.h of MySQL distribution
+
+ This file defines the Innodb handler: the interface between MySQL and
+ Innodb
+*/
+
#ifdef __GNUC__
#pragma interface /* gcc class implementation */
#endif
-/* This file defines the Innobase handler: the interface between MySQL and
-Innobase */
-
typedef struct st_innobase_share {
THR_LOCK lock;
pthread_mutex_t mutex;
@@ -32,11 +33,11 @@ typedef struct st_innobase_share {
} INNOBASE_SHARE;
-/* The class defining a handle to an Innobase table */
+/* The class defining a handle to an Innodb table */
class ha_innobase: public handler
{
void* innobase_prebuilt; /* (row_prebuilt_t*) prebuilt
- struct in Innobase, used to save
+ struct in Innodb, used to save
CPU */
THD* user_thd; /* the thread handle of the user
currently using the handle; this is
@@ -50,7 +51,7 @@ class ha_innobase: public handler
byte* upd_buff; /* buffer used in updates */
byte* key_val_buff; /* buffer used in converting
search key values from MySQL format
- to Innobase format */
+ to Innodb format */
uint ref_stored_len; /* length of the key value stored to
'ref' buffer of the handle, if any */
ulong int_option_flag;
@@ -78,11 +79,11 @@ class ha_innobase: public handler
HA_REC_NOT_IN_SEQ |
HA_KEYPOS_TO_RNDPOS | HA_LASTKEY_ORDER |
HA_HAVE_KEY_READ_ONLY | HA_READ_NOT_EXACT_KEY |
- HA_LONGLONG_KEYS | HA_NULL_KEY |
- HA_NOT_EXACT_COUNT | HA_NO_FULLTEXT_KEY |
+ HA_NULL_KEY |
+ HA_NOT_EXACT_COUNT |
HA_NO_WRITE_DELAYED |
HA_PRIMARY_KEY_IN_READ_INDEX |
- HA_DROP_BEFORE_CREATE |
+ HA_DROP_BEFORE_CREATE | HA_NOT_READ_PREFIX_LAST |
HA_NO_PREFIX_CHAR_KEYS),
last_dup_key((uint) -1),
start_of_scan(0)
@@ -91,15 +92,21 @@ class ha_innobase: public handler
~ha_innobase() {}
const char* table_type() const { return("InnoDB");}
+ const char *index_type(uint key_number) { return "BTREE"; }
const char** bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
- /* An InnoDB page must store >= 2 keys:
- max key length is therefore set to 7000
- bytes */
- uint max_key_length() const { return 7000; }
+ /* An InnoDB page must store >= 2 keys;
+ a secondary key record must also contain the
+ primary key value:
+ max key length is therefore set to slightly
+ less than 1 / 4 of page size which is 16 kB;
+ but currently MySQL does not work with keys
+ whose size is > MAX_KEY_LENGTH */
+ uint max_key_length() const { return((MAX_KEY_LENGTH <= 3500) ?
+ MAX_KEY_LENGTH : 3500);}
bool fast_key_read() { return 1;}
key_map keys_to_use_for_scanning() { return ~(key_map) 0; }
bool has_transactions() { return 1;}
@@ -116,9 +123,10 @@ class ha_innobase: public handler
int index_init(uint index);
int index_end();
int index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag);
+ uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint index, const byte * key,
- uint key_len, enum ha_rkey_function find_flag);
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_read_last(byte * buf, const byte * key, uint key_len);
int index_next(byte * buf);
int index_next_same(byte * buf, const byte *key, uint keylen);
int index_prev(byte * buf);
diff --git a/sql/ha_isam.cc b/sql/ha_isam.cc
index 1a950ce0a9d..4b8c40f8fe6 100644
--- a/sql/ha_isam.cc
+++ b/sql/ha_isam.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -109,6 +109,15 @@ int ha_isam::index_read_idx(byte * buf, uint index, const byte * key,
return !error ? 0 : my_errno ? my_errno : -1;
}
+int ha_isam::index_read_last(byte * buf, const byte * key, uint key_len)
+{
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ int error=nisam_rkey(file, buf, active_index, key, key_len,
+ HA_READ_PREFIX_LAST);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return !error ? 0 : my_errno ? my_errno : -1;
+}
+
int ha_isam::index_next(byte * buf)
{
statistic_increment(ha_read_next_count,&LOCK_status);
@@ -124,7 +133,7 @@ int ha_isam::index_prev(byte * buf)
table->status=error ? STATUS_NOT_FOUND: 0;
return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
}
-
+
int ha_isam::index_first(byte * buf)
{
statistic_increment(ha_read_first_count,&LOCK_status);
@@ -236,7 +245,7 @@ int ha_isam::reset(void)
int ha_isam::external_lock(THD *thd, int lock_type)
{
return nisam_lock_database(file,lock_type);
-}
+}
THR_LOCK_DATA **ha_isam::store_lock(THD *thd,
diff --git a/sql/ha_isam.h b/sql/ha_isam.h
index 5e01edcf889..4194632ddbe 100644
--- a/sql/ha_isam.h
+++ b/sql/ha_isam.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -33,11 +33,12 @@ class ha_isam: public handler
int_option_flag(HA_READ_NEXT | HA_READ_PREV | HA_READ_RND_SAME |
HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
HA_HAVE_KEY_READ_ONLY | HA_READ_NOT_EXACT_KEY |
- HA_LONGLONG_KEYS | HA_KEY_READ_WRONG_STR | HA_DUPP_POS |
- HA_NOT_DELETE_WITH_CACHE | HA_NO_FULLTEXT_KEY)
+ HA_KEY_READ_WRONG_STR | HA_DUPP_POS |
+ HA_NOT_DELETE_WITH_CACHE)
{}
~ha_isam() {}
const char *table_type() const { return "ISAM"; }
+ const char *index_type(uint key_number) { return "BTREE"; }
const char **bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
@@ -56,6 +57,7 @@ class ha_isam: public handler
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
+ int index_read_last(byte * buf, const byte * key, uint key_len);
int index_next(byte * buf);
int index_prev(byte * buf);
int index_first(byte * buf);
@@ -80,9 +82,3 @@ class ha_isam: public handler
enum thr_lock_type lock_type);
};
-
-
-
-
-
-
diff --git a/sql/ha_isammrg.cc b/sql/ha_isammrg.cc
index 41fb99fe867..b110ffba2f9 100644
--- a/sql/ha_isammrg.cc
+++ b/sql/ha_isammrg.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -110,7 +110,7 @@ int ha_isammrg::index_prev(byte * buf)
{
return (my_errno=HA_ERR_WRONG_COMMAND);
}
-
+
int ha_isammrg::index_first(byte * buf)
{
return (my_errno=HA_ERR_WRONG_COMMAND);
@@ -179,7 +179,7 @@ int ha_isammrg::reset(void)
int ha_isammrg::external_lock(THD *thd, int lock_type)
{
return !mrg_lock_database(file,lock_type) ? 0 : my_errno ? my_errno : -1;
-}
+}
uint ha_isammrg::lock_count(void) const
{
diff --git a/sql/ha_isammrg.h b/sql/ha_isammrg.h
index c8eb7dd9f69..1ee0b0e2547 100644
--- a/sql/ha_isammrg.h
+++ b/sql/ha_isammrg.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -32,8 +32,9 @@ class ha_isammrg: public handler
~ha_isammrg() {}
const char *table_type() const { return "MRG_ISAM"; }
const char **bas_ext() const;
- ulong option_flag() const { return HA_READ_RND_SAME | HA_KEYPOS_TO_RNDPOS
- | HA_REC_NOT_IN_SEQ | HA_NO_FULLTEXT_KEY;}
+ ulong option_flag() const { return (HA_READ_RND_SAME | HA_KEYPOS_TO_RNDPOS |
+ HA_NOT_READ_PREFIX_LAST |
+ HA_REC_NOT_IN_SEQ); }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return 0; }
uint max_key_parts() const { return 0; }
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 7a8585975cc..78ac9f3b309 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -80,9 +80,8 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
net_store_data(packet, msgbuf);
if (my_net_write(&thd->net, (char*)thd->packet.ptr(), thd->packet.length()))
- fprintf(stderr,
- "Failed on my_net_write, writing to stderr instead: %s\n",
- msgbuf);
+ sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
+ msgbuf);
return;
}
@@ -122,6 +121,13 @@ const char **ha_myisam::bas_ext() const
{ static const char *ext[]= { ".MYD",".MYI", NullS }; return ext; }
+const char *ha_myisam::index_type(uint key_number)
+{
+ return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
+ "FULLTEXT" :
+ "BTREE");
+}
+
int ha_myisam::net_read_dump(NET* net)
{
int data_fd = file->dfile;
@@ -130,7 +136,7 @@ int ha_myisam::net_read_dump(NET* net)
my_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME));
for(;;)
{
- uint packet_len = my_net_read(net);
+ ulong packet_len = my_net_read(net);
if (!packet_len)
break ; // end of file
if (packet_len == packet_error)
@@ -139,7 +145,7 @@ int ha_myisam::net_read_dump(NET* net)
error= -1;
goto err;
}
- if (my_write(data_fd, (byte*)net->read_pos, packet_len,
+ if (my_write(data_fd, (byte*)net->read_pos, (uint) packet_len,
MYF(MY_WME|MY_FNABP)))
{
error = errno;
@@ -426,7 +432,7 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
error = HA_ADMIN_INVALID;
goto err;
}
-
+
if (my_copy(fn_format(src_path, table->path,"", reg_ext, MY_UNPACK_FILENAME),
dst_path,
MYF(MY_WME | MY_HOLD_ORIGINAL_MODES)))
@@ -771,6 +777,14 @@ int ha_myisam::index_read_idx(byte * buf, uint index, const byte * key,
return error;
}
+int ha_myisam::index_read_last(byte * buf, const byte * key, uint key_len)
+{
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ int error=mi_rkey(file,buf,active_index, key, key_len, HA_READ_PREFIX_LAST);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
int ha_myisam::index_next(byte * buf)
{
statistic_increment(ha_read_next_count,&LOCK_status);
@@ -883,7 +897,7 @@ void ha_myisam::info(uint flag)
raid_type=info.raid_type;
raid_chunks=info.raid_chunks;
raid_chunksize=info.raid_chunksize;
-
+
/*
Set data_file_name and index_file_name to point at the symlink value
if table is symlinked (Ie; Real name is not same as generated name)
@@ -967,7 +981,7 @@ void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
}
-int ha_myisam::create(const char *name, register TABLE *form,
+int ha_myisam::create(const char *name, register TABLE *table,
HA_CREATE_INFO *info)
{
int error;
@@ -979,20 +993,20 @@ int ha_myisam::create(const char *name, register TABLE *form,
MI_KEYDEF *keydef;
MI_COLUMNDEF *recinfo,*recinfo_pos;
MI_KEYSEG *keyseg;
- uint options=form->db_options_in_use;
+ uint options=table->db_options_in_use;
DBUG_ENTER("ha_myisam::create");
type=HA_KEYTYPE_BINARY; // Keep compiler happy
if (!(my_multi_malloc(MYF(MY_WME),
- &recinfo,(form->fields*2+2)*sizeof(MI_COLUMNDEF),
- &keydef, form->keys*sizeof(MI_KEYDEF),
+ &recinfo,(table->fields*2+2)*sizeof(MI_COLUMNDEF),
+ &keydef, table->keys*sizeof(MI_KEYDEF),
&keyseg,
- ((form->key_parts + form->keys) * sizeof(MI_KEYSEG)),
+ ((table->key_parts + table->keys) * sizeof(MI_KEYSEG)),
0)))
DBUG_RETURN(1);
- pos=form->key_info;
- for (i=0; i < form->keys ; i++, pos++)
+ pos=table->key_info;
+ for (i=0; i < table->keys ; i++, pos++)
{
keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT));
keydef[i].seg=keyseg;
@@ -1035,7 +1049,7 @@ int ha_myisam::create(const char *name, register TABLE *form,
{
keydef[i].seg[j].null_bit=field->null_bit;
keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
- (uchar*) form->record[0]);
+ (uchar*) table->record[0]);
}
else
{
@@ -1053,19 +1067,19 @@ int ha_myisam::create(const char *name, register TABLE *form,
keydef[i].seg[j].flag|=HA_BLOB_PART;
/* save number of bytes used to pack length */
keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
- form->blob_ptr_size);
+ table->blob_ptr_size);
}
}
keyseg+=pos->key_parts;
}
recpos=0; recinfo_pos=recinfo;
- while (recpos < (uint) form->reclength)
+ while (recpos < (uint) table->reclength)
{
Field **field,*found=0;
- minpos=form->reclength; length=0;
+ minpos=table->reclength; length=0;
- for (field=form->field ; *field ; field++)
+ for (field=table->field ; *field ; field++)
{
if ((fieldpos=(*field)->offset()) >= recpos &&
fieldpos <= minpos)
@@ -1111,7 +1125,7 @@ int ha_myisam::create(const char *name, register TABLE *form,
{
recinfo_pos->null_bit=found->null_bit;
recinfo_pos->null_pos= (uint) (found->null_ptr-
- (uchar*) form->record[0]);
+ (uchar*) table->record[0]);
}
else
{
@@ -1126,20 +1140,23 @@ int ha_myisam::create(const char *name, register TABLE *form,
}
MI_CREATE_INFO create_info;
bzero((char*) &create_info,sizeof(create_info));
- create_info.max_rows=form->max_rows;
- create_info.reloc_rows=form->min_rows;
+ create_info.max_rows=table->max_rows;
+ create_info.reloc_rows=table->min_rows;
create_info.auto_increment=(info->auto_increment_value ?
info->auto_increment_value -1 :
(ulonglong) 0);
- create_info.data_file_length=(ulonglong) form->max_rows*form->avg_row_length;
+ create_info.data_file_length= ((ulonglong) table->max_rows *
+ table->avg_row_length);
create_info.raid_type=info->raid_type;
- create_info.raid_chunks=info->raid_chunks ? info->raid_chunks : RAID_DEFAULT_CHUNKS;
- create_info.raid_chunksize=info->raid_chunksize ? info->raid_chunksize : RAID_DEFAULT_CHUNKSIZE;
+ create_info.raid_chunks= (info->raid_chunks ? info->raid_chunks :
+ RAID_DEFAULT_CHUNKS);
+ create_info.raid_chunksize=(info->raid_chunksize ? info->raid_chunksize :
+ RAID_DEFAULT_CHUNKSIZE);
create_info.data_file_name= info->data_file_name;
create_info.index_file_name=info->index_file_name;
error=mi_create(fn_format(buff,name,"","",2+4),
- form->keys,keydef,
+ table->keys,keydef,
(uint) (recinfo_pos-recinfo), recinfo,
0, (MI_UNIQUEDEF*) 0,
&create_info,
@@ -1170,7 +1187,7 @@ longlong ha_myisam::get_auto_increment()
longlong nr;
int error;
- byte key[MAX_KEY_LENGTH];
+ byte key[MI_MAX_KEY_LENGTH];
(void) extra(HA_EXTRA_KEYREAD);
key_copy(key,table,table->next_number_index,
table->next_number_key_offset);
@@ -1214,4 +1231,3 @@ int ha_myisam::ft_read(byte * buf)
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
-
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index eba2bde7d59..75655a2b505 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -45,20 +45,22 @@ class ha_myisam: public handler
public:
ha_myisam(TABLE *table): handler(table), file(0),
int_option_flag(HA_READ_NEXT | HA_READ_PREV | HA_READ_RND_SAME |
- HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
+ HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER | HA_LASTKEY_ORDER |
HA_HAVE_KEY_READ_ONLY | HA_READ_NOT_EXACT_KEY |
- HA_LONGLONG_KEYS | HA_NULL_KEY |
+ HA_NULL_KEY |
+ HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
HA_DUPP_POS | HA_BLOB_KEY | HA_AUTO_PART_KEY),
enable_activate_all_index(1)
{}
~ha_myisam() {}
const char *table_type() const { return "MyISAM"; }
+ const char *index_type(uint key_number);
const char **bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return MI_MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
- uint max_key_length() const { return MAX_KEY_LENGTH; }
+ uint max_key_length() const { return MI_MAX_KEY_LENGTH; }
int open(const char *name, int mode, uint test_if_locked);
int close(void);
@@ -69,6 +71,7 @@ class ha_myisam: public handler
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
+ int index_read_last(byte * buf, const byte * key, uint key_len);
int index_next(byte * buf);
int index_prev(byte * buf);
int index_first(byte * buf);
@@ -76,9 +79,15 @@ class ha_myisam: public handler
int index_next_same(byte *buf, const byte *key, uint keylen);
int index_end() { ft_handler=NULL; return 0; }
int ft_init()
- { if(!ft_handler) return 1; ft_handler->please->reinit_search(ft_handler); return 0; }
- FT_INFO *ft_init_ext(uint mode, uint inx,const byte *key, uint keylen, bool presort)
- { return ft_init_search(mode, file,inx,(byte*) key,keylen,presort); }
+ {
+ if (!ft_handler)
+ return 1;
+ ft_handler->please->reinit_search(ft_handler);
+ return 0;
+ }
+ FT_INFO *ft_init_ext(uint mode, uint inx,const byte *key, uint keylen,
+ bool presort)
+ { return ft_init_search(mode, file,inx,(byte*) key,keylen,presort); }
int ft_read(byte *buf);
int rnd_init(bool scan=1);
int rnd_next(byte *buf);
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index d82c202baa3..63a23fb708f 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -38,10 +38,15 @@ const char **ha_myisammrg::bas_ext() const
int ha_myisammrg::open(const char *name, int mode, uint test_if_locked)
{
char name_buff[FN_REFLEN];
+ DBUG_PRINT("info", ("ha_myisammrg::open"));
if (!(file=myrg_open(fn_format(name_buff,name,"","",2 | 4), mode,
test_if_locked)))
+ {
+ DBUG_PRINT("info", ("ha_myisammrg::open exit %d", my_errno));
return (my_errno ? my_errno : -1);
-
+ }
+ DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc..."))
+ myrg_extrafunc(file, &query_cache_invalidate_by_MyISAM_filename);
if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
myrg_extra(file,HA_EXTRA_NO_WAIT_LOCK);
@@ -107,6 +112,15 @@ int ha_myisammrg::index_read_idx(byte * buf, uint index, const byte * key,
return error;
}
+int ha_myisammrg::index_read_last(byte * buf, const byte * key, uint key_len)
+{
+ statistic_increment(ha_read_key_count,&LOCK_status);
+ int error=myrg_rkey(file,buf,active_index, key, key_len,
+ HA_READ_PREFIX_LAST);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
int ha_myisammrg::index_next(byte * buf)
{
statistic_increment(ha_read_next_count,&LOCK_status);
diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h
index b97baa0703c..2ab3a807543 100644
--- a/sql/ha_myisammrg.h
+++ b/sql/ha_myisammrg.h
@@ -35,10 +35,10 @@ class ha_myisammrg: public handler
ulong option_flag() const
{ return (HA_REC_NOT_IN_SEQ | HA_READ_NEXT |
HA_READ_PREV | HA_READ_RND_SAME |
- HA_HAVE_KEY_READ_ONLY | HA_NO_FULLTEXT_KEY |
+ HA_HAVE_KEY_READ_ONLY |
HA_KEYPOS_TO_RNDPOS | HA_READ_ORDER |
HA_LASTKEY_ORDER | HA_READ_NOT_EXACT_KEY |
- HA_LONGLONG_KEYS | HA_NULL_KEY | HA_BLOB_KEY); }
+ HA_NULL_KEY | HA_BLOB_KEY); }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return MI_MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
@@ -55,6 +55,7 @@ class ha_myisammrg: public handler
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
+ int index_read_last(byte * buf, const byte * key, uint key_len);
int index_next(byte * buf);
int index_prev(byte * buf);
int index_first(byte * buf);
@@ -74,4 +75,5 @@ class ha_myisammrg: public handler
enum thr_lock_type lock_type);
void update_create_info(HA_CREATE_INFO *create_info);
void append_create_info(String *packet);
+ MYRG_INFO *myrg_info() { return file; }
};
diff --git a/sql/handler.cc b/sql/handler.cc
index 9bf9b25f76f..e56bdb916bf 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -33,7 +33,7 @@
#include "ha_berkeley.h"
#endif
#ifdef HAVE_INNOBASE_DB
-#include "ha_innobase.h"
+#include "ha_innodb.h"
#endif
#include <myisampack.h>
#include <errno.h>
@@ -258,6 +258,8 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
error=1;
}
trans->innodb_active_trans=0;
+ if (trans == &thd->transaction.all)
+ query_cache.invalidate(Query_cache_table::INNODB);
}
#endif
if (error && trans == &thd->transaction.all && mysql_bin_log.is_open())
@@ -336,7 +338,7 @@ int ha_delete_table(enum db_type table_type, const char *path)
delete file;
return error;
}
-
+
void ha_store_ptr(byte *buff, uint pack_length, my_off_t pos)
{
switch (pack_length) {
@@ -423,9 +425,8 @@ int handler::ha_open(const char *name, int mode, int test_if_locked)
{
if (table->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
table->db_stat|=HA_READ_ONLY;
- }
- if (!error)
- {
+ (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
+
if (!alloc_root_inited(&table->mem_root)) // If temporary table
ref=(byte*) sql_alloc(ALIGN_SIZE(ref_length)*2);
else
diff --git a/sql/handler.h b/sql/handler.h
index 98358c3b3e4..aa809b333b4 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -55,12 +55,11 @@
#define HA_REC_NOT_IN_SEQ 64 /* ha_info don't return recnumber;
It returns a position to ha_r_rnd */
#define HA_ONLY_WHOLE_INDEX 128 /* Can't use part key searches */
-#define HA_RSAME_NO_INDEX 256 /* RSAME can't restore index */
+#define HA_NOT_READ_PREFIX_LAST 256 /* RSAME can't restore index */
#define HA_WRONG_ASCII_ORDER 512 /* Can't use sorting through key */
#define HA_HAVE_KEY_READ_ONLY 1024 /* Can read only keys (no record) */
#define HA_READ_NOT_EXACT_KEY 2048 /* Can read record after/before key */
#define HA_NO_INDEX 4096 /* No index needed for next/prev */
-#define HA_LONGLONG_KEYS 8192 /* Can have longlong as key */
#define HA_KEY_READ_WRONG_STR 16384 /* keyread returns converted strings */
#define HA_NULL_KEY 32768 /* One can have keys with NULL */
#define HA_DUPP_POS 65536 /* ha_position() gives dupp row */
@@ -76,7 +75,8 @@
#define HA_NOT_DELETE_WITH_CACHE (HA_NOT_READ_AFTER_KEY*2)
#define HA_NO_TEMP_TABLES (HA_NOT_DELETE_WITH_CACHE*2)
#define HA_NO_PREFIX_CHAR_KEYS (HA_NO_TEMP_TABLES*2)
-#define HA_NO_FULLTEXT_KEY (HA_NO_PREFIX_CHAR_KEYS*2)
+#define HA_CAN_FULLTEXT (HA_NO_PREFIX_CHAR_KEYS*2)
+#define HA_CAN_SQL_HANDLER (HA_CAN_FULLTEXT*2)
/* Parameters for open() (in register form->filestat) */
/* HA_GET_INFO does an implicit HA_ABORT_IF_LOCKED */
@@ -235,6 +235,7 @@ public:
virtual bool has_transactions(){ return 0;}
virtual uint extra_rec_buf_length() { return 0; }
virtual ha_rows estimate_number_of_rows() { return records+EXTRA_RECORDS; }
+ virtual const char *index_type(uint key_number) { return "";}
virtual int index_init(uint idx) { active_index=idx; return 0;}
virtual int index_end() {return 0; }
@@ -254,6 +255,10 @@ public:
virtual int index_first(byte * buf)=0;
virtual int index_last(byte * buf)=0;
virtual int index_next_same(byte *buf, const byte *key, uint keylen);
+ virtual int index_read_last(byte * buf, const byte * key, uint key_len)
+ {
+ return (my_errno=HA_ERR_WRONG_COMMAND);
+ }
virtual int ft_init()
{ return -1; }
virtual FT_INFO *ft_init_ext(uint mode,uint inx,const byte *key, uint keylen,
diff --git a/sql/hash_filo.cc b/sql/hash_filo.cc
index 990d2d662d6..b85f8054f10 100644
--- a/sql/hash_filo.cc
+++ b/sql/hash_filo.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/hash_filo.h b/sql/hash_filo.h
index 69301479ec7..b8d45f0d3be 100644
--- a/sql/hash_filo.h
+++ b/sql/hash_filo.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/hostname.cc b/sql/hostname.cc
index bc812341337..7d4e4a8ca75 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/init.cc b/sql/init.cc
index e6606b82b7c..df06ddd41ef 100644
--- a/sql/init.cc
+++ b/sql/init.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/item.cc b/sql/item.cc
index 1f8d653e612..c081fd9dd5f 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/item.h b/sql/item.h
index a52860528f1..5028f25c6b8 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -64,7 +64,7 @@ public:
virtual longlong val_int()=0;
virtual String *val_str(String*)=0;
virtual void make_field(Send_field *field)=0;
- virtual Field *tmp_table_field() { return 0; }
+ virtual Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return 0; }
virtual const char *full_name() const { return name ? name : "???"; }
virtual double val_result() { return val(); }
virtual longlong val_int_result() { return val_int(); }
@@ -128,7 +128,7 @@ public:
{
return field->result_type();
}
- Field *tmp_table_field() { return result_field; }
+ Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; }
bool get_date(TIME *ltime,bool fuzzydate);
bool get_time(TIME *ltime);
bool is_null() { return field->is_null(); }
@@ -206,14 +206,14 @@ public:
Item_real(const char *str_arg,uint length) :value(atof(str_arg))
{
name=(char*) str_arg;
- decimals=nr_of_decimals(str_arg);
+ decimals=(uint8) nr_of_decimals(str_arg);
max_length=length;
}
Item_real(const char *str,double val_arg,uint decimal_par,uint length)
:value(val_arg)
{
name=(char*) str;
- decimals=decimal_par;
+ decimals=(uint8) decimal_par;
max_length=length;
}
Item_real(double value_par) :value(value_par) {}
@@ -308,7 +308,7 @@ public:
Field *result_field; /* Save result here */
Item_result_field() :result_field(0) {}
~Item_result_field() {} /* Required with gcc 2.95 */
- Field *tmp_table_field() { return result_field; }
+ Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; }
table_map used_tables() const { return 1; }
virtual void fix_length_and_dec()=0;
};
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index 61e1f5498a9..b55a4dc66a0 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 8d2a4d491c4..0c83698e60a 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 9ed3e86d6e8..c9c7d5654d6 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 55f8bb140a9..6f64e9517ba 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -65,7 +65,9 @@ Item *create_func_ceiling(Item* a)
Item *create_func_connection_id(void)
{
- return new Item_int("CONNECTION_ID()",(longlong) current_thd->thread_id,10);
+ THD *thd=current_thd;
+ thd->safe_to_cache_query=0;
+ return new Item_int("CONNECTION_ID()",(longlong) thd->thread_id,10);
}
Item *create_func_conv(Item* a, Item *b, Item *c)
@@ -131,7 +133,9 @@ Item *create_func_floor(Item* a)
Item *create_func_found_rows(void)
{
- return new Item_int("FOUND_ROWS()",(longlong) current_thd->found_rows(),21);
+ THD *thd=current_thd;
+ thd->safe_to_cache_query=0;
+ return new Item_int("FOUND_ROWS()",(longlong) thd->found_rows(),21);
}
Item *create_func_from_days(Item* a)
@@ -141,13 +145,13 @@ Item *create_func_from_days(Item* a)
Item *create_func_get_lock(Item* a, Item *b)
{
+ current_thd->safe_to_cache_query=0;
return new Item_func_get_lock(a, b);
}
Item *create_func_hex(Item *a)
{
- return new Item_func_conv(a,new Item_int((int32) 10,2),
- new Item_int((int32) 16,2));
+ return new Item_func_hex(a);
}
Item *create_func_inet_ntoa(Item* a)
@@ -196,6 +200,11 @@ Item *create_func_length(Item* a)
return new Item_func_length(a);
}
+Item *create_func_bit_length(Item* a)
+{
+ return new Item_func_bit_length(a);
+}
+
Item *create_func_char_length(Item* a)
{
return new Item_func_char_length(a);
@@ -279,6 +288,7 @@ Item *create_func_radians(Item *a)
Item *create_func_release_lock(Item* a)
{
+ current_thd->safe_to_cache_query=0;
return new Item_func_release_lock(a);
}
@@ -379,10 +389,27 @@ Item *create_func_year(Item* a)
Item *create_load_file(Item* a)
{
+ current_thd->safe_to_cache_query=0;
return new Item_load_file(a);
}
Item *create_wait_for_master_pos(Item* a, Item* b)
{
+ current_thd->safe_to_cache_query=0;
return new Item_master_pos_wait(a, b);
}
+
+Item *create_func_cast(Item *a, Item_cast cast_type)
+{
+ Item *res;
+ LINT_INIT(res);
+ switch (cast_type) {
+ case ITEM_CAST_BINARY: res= new Item_func_binary(a); break;
+ case ITEM_CAST_SIGNED_INT: res= new Item_func_signed(a); break;
+ case ITEM_CAST_UNSIGNED_INT: res= new Item_func_unsigned(a); break;
+ case ITEM_CAST_DATE: res= new Item_date_typecast(a); break;
+ case ITEM_CAST_TIME: res= new Item_time_typecast(a); break;
+ case ITEM_CAST_DATETIME: res= new Item_datetime_typecast(a); break;
+ }
+ return res;
+}
diff --git a/sql/item_create.h b/sql/item_create.h
index 54d2ff035ea..580596505da 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -22,6 +22,7 @@ Item *create_func_ascii(Item* a);
Item *create_func_asin(Item* a);
Item *create_func_bin(Item* a);
Item *create_func_bit_count(Item* a);
+Item *create_func_bit_length(Item* a);
Item *create_func_ceiling(Item* a);
Item *create_func_char_length(Item* a);
Item *create_func_connection_id(void);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index ff6a102fe1f..209fbea1674 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1421,7 +1421,7 @@ void item_user_lock_release(ULL *ull)
char buf[256];
String tmp(buf,sizeof(buf));
tmp.length(0);
- tmp.append("SELECT release_lock(\"");
+ tmp.append("DO RELEASE_LOCK(\"");
tmp.append(ull->key,ull->key_length);
tmp.append("\")");
thd->query_length=tmp.length();
@@ -1445,7 +1445,7 @@ longlong Item_master_pos_wait::val_int()
THD* thd = current_thd;
String *log_name = args[0]->val_str(&value);
int event_count;
-
+
null_value=0;
if (thd->slave_thread || !log_name || !log_name->length())
{
@@ -1498,14 +1498,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
thd->mysys_var->current_mutex= &LOCK_user_locks;
thd->mysys_var->current_cond= &ull->cond;
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec=time((time_t*) 0)+(time_t) lock_timeout;
- abstime.ts_nsec=0;
-#else
- abstime.tv_sec=time((time_t*) 0)+(time_t) lock_timeout;
- abstime.tv_nsec=0;
-#endif
-
+ set_timespec(abstime,lock_timeout);
while (!thd->killed &&
(error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime))
!= ETIME && error != ETIMEDOUT && ull->locked) ;
@@ -1593,14 +1586,7 @@ longlong Item_func_get_lock::val_int()
thd->mysys_var->current_mutex= &LOCK_user_locks;
thd->mysys_var->current_cond= &ull->cond;
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec=time((time_t*) 0)+(time_t) timeout;
- abstime.ts_nsec=0;
-#else
- abstime.tv_sec=time((time_t*) 0)+(time_t) timeout;
- abstime.tv_nsec=0;
-#endif
-
+ set_timespec(abstime,timeout);
while (!thd->killed &&
(error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime))
!= ETIME && error != ETIMEDOUT && ull->locked) ;
@@ -1861,6 +1847,16 @@ Item_func_set_user_var::val_str(String *str)
}
+void Item_func_set_user_var::print(String *str)
+{
+ str->append('(');
+ str->append(name.str,name.length);
+ str->append(":=",2);
+ args[0]->print(str);
+ str->append(')');
+}
+
+
user_var_entry *Item_func_get_user_var::get_entry()
{
if (!entry || ! entry->value)
@@ -1953,6 +1949,34 @@ enum Item_result Item_func_get_user_var::result_type() const
return entry->type;
}
+
+void Item_func_get_user_var::print(String *str)
+{
+ str->append('@');
+ str->append(name.str,name.length);
+ str->append(')');
+}
+
+bool Item_func_get_user_var::eq(const Item *item) const
+{
+ /* Assume we don't have rtti */
+ if (this == item)
+ return 1; // Same item is same.
+ /* Check if other type is also a get_user_var() object */
+#ifdef FIX_THIS
+ if (item->eq == &Item_func_get_user_var::eq)
+ return 0;
+#else
+ if (item->type() != FUNC_ITEM ||
+ ((Item_func*) item)->func_name() != func_name())
+ return 0;
+#endif
+ Item_func_get_user_var *other=(Item_func_get_user_var*) item;
+ return (name.length == other->name.length &&
+ !memcmp(name.str, other->name.str, name.length));
+}
+
+
longlong Item_func_inet_aton::val_int()
{
uint byte_result = 0;
@@ -2021,7 +2045,9 @@ void Item_func_match::init_search(bool no_order)
}
ft_handler=table->file->ft_init_ext(mode, key,
- ft_tmp->ptr(), ft_tmp->length(), join_key && !no_order);
+ (byte*) ft_tmp->ptr(),
+ ft_tmp->length(),
+ join_key && !no_order);
if (join_key)
{
@@ -2172,7 +2198,7 @@ bool Item_func_match::eq(const Item *item) const
double Item_func_match::val()
{
- if (ft_handler==NULL)
+ if (ft_handler == NULL)
return -1.0;
if (join_key)
@@ -2186,10 +2212,10 @@ double Item_func_match::val()
if (key == NO_SUCH_KEY)
{
String *a=concat->val_str(&value);
- if (null_value=(a==0))
+ if ((null_value= (a==0)))
return 0;
return ft_handler->please->find_relevance(ft_handler,
- (byte *)a->ptr(), a->length());
+ (byte *)a->ptr(), a->length());
}
else
return ft_handler->please->find_relevance(ft_handler, record, 0);
diff --git a/sql/item_func.h b/sql/item_func.h
index 2bf272f24ed..f7794028998 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -135,6 +135,11 @@ public:
longlong val_int() { return (longlong) val(); }
enum Item_result result_type () const { return REAL_RESULT; }
void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_double(max_length, maybe_null, name,t_arg,decimals);
+ }
};
class Item_num_func :public Item_func
@@ -164,6 +169,11 @@ class Item_num_op :public Item_func
void fix_length_and_dec() { fix_num_length_and_dec(); find_num_type(); }
void find_num_type(void);
bool is_null() { (void) val(); return null_value; }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return args[0]->result_type() == INT_RESULT ? ((max_length > 11) ? (Field *)new Field_longlong(max_length,maybe_null,name, t_arg,unsigned_flag) : (Field *)new Field_long(max_length,maybe_null,name, t_arg,unsigned_flag)) : (Field *) new Field_double(max_length, maybe_null, name,t_arg,decimals);
+ }
};
@@ -179,8 +189,34 @@ public:
String *val_str(String*str);
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec() { decimals=0; max_length=21; }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return (max_length > 11) ? (Field *)new Field_longlong(max_length,maybe_null,name, t_arg,unsigned_flag) : (Field *)new Field_long(max_length,maybe_null,name, t_arg,unsigned_flag);
+ }
+};
+
+class Item_func_signed :public Item_int_func
+{
+public:
+ Item_func_signed(Item *a) :Item_int_func(a) {}
+ double val() { return args[0]->val(); }
+ longlong val_int() { return args[0]->val_int(); }
+ void fix_length_and_dec()
+ { decimals=0; max_length=args[0]->max_length; unsigned_flag=0; }
};
+class Item_func_unsigned :public Item_int_func
+{
+public:
+ Item_func_unsigned(Item *a) :Item_int_func(a) {}
+ double val() { return args[0]->val(); }
+ longlong val_int() { return args[0]->val_int(); }
+ void fix_length_and_dec()
+ { decimals=0; max_length=args[0]->max_length; unsigned_flag=1; }
+};
+
+
class Item_func_plus :public Item_num_op
{
public:
@@ -486,6 +522,14 @@ public:
void fix_length_and_dec() { max_length=10; }
};
+class Item_func_bit_length :public Item_func_length
+{
+public:
+ Item_func_bit_length(Item *a) :Item_func_length(a) {}
+ longlong val_int() { return Item_func_length::val_int()*8; }
+ const char *func_name() const { return "bit_length"; }
+};
+
class Item_func_char_length :public Item_int_func
{
String value;
@@ -820,6 +864,7 @@ public:
enum Item_result result_type () const { return cached_result_type; }
bool fix_fields(THD *thd,struct st_table_list *tables);
void fix_length_and_dec();
+ void print(String *str);
const char *func_name() const { return "set_user_var"; }
};
@@ -838,13 +883,16 @@ public:
longlong val_int();
String *val_str(String* str);
void fix_length_and_dec();
+ void print(String *str);
enum Item_result result_type() const;
const char *func_name() const { return "get_user_var"; }
bool const_item() const { return const_var_flag; }
table_map used_tables() const
{ return const_var_flag ? 0 : RAND_TABLE_BIT; }
+ bool eq(const Item *item) const;
};
+
class Item_func_inet_aton : public Item_int_func
{
public:
@@ -862,18 +910,18 @@ class Item_func_match :public Item_real_func
{
public:
List<Item> fields;
- Item *concat;
String value;
TABLE *table;
- uint key, mode;
- bool join_key;
Item_func_match *master;
FT_INFO * ft_handler;
+ Item *concat;
byte *record;
+ uint key, mode;
+ bool join_key;
Item_func_match(List<Item> &a, Item *b): Item_real_func(b),
- fields(a), table(0), join_key(0), master(0), ft_handler(0),
- key(0), concat(0) {}
+ fields(a), table(0), master(0), ft_handler(0),
+ concat(0), key(0), join_key(0) {}
~Item_func_match()
{
if (!master && ft_handler)
@@ -912,3 +960,12 @@ public:
const char *func_name() const { return "match_bool"; }
};
+/* For type casts */
+
+enum Item_cast
+{
+ ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT,
+ ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME
+};
+
+Item *create_func_cast(Item *a, Item_cast cast_type);
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 08d8fb7c38b..c64fdc7a049 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -75,7 +75,11 @@ String *Item_func_md5::val_str(String *str)
my_MD5Init (&context);
my_MD5Update (&context,(unsigned char *) sptr->ptr(), sptr->length());
my_MD5Final (digest, &context);
- str->alloc(32); // Ensure that memory is free
+ if (str->alloc(32)) // Ensure that memory is free
+ {
+ null_value=1;
+ return 0;
+ }
sprintf((char *) str->ptr(),
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3],
@@ -201,133 +205,167 @@ void Item_func_concat::fix_length_and_dec()
}
}
-#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
-#define ascii_to_bin(c) ((c)<=57 ? (c)-46 : (c)<=90 ? (c)-53 : (c)-59)
-
/*
- Function des_encrypt() by tonu@spam.ee
- Works only if compiled with OpenSSL library support.
- Output always starts with magic char "1" and all
- encrypted output is encoded into ASCII-protected
- container.
- Original input is returned as output if input string
- begins with magic "1". Credit card number always begin
- with 4,5 or 6.
+ Function des_encrypt() by tonu@spam.ee & monty
+ Works only if compiled with OpenSSL library support.
+ This returns a binary string where first character is
+ CHAR(128 | key-number).
+ If one uses a string key key_number is 127.
Encryption result is longer than original by formula:
- new_length=(8-(original_length % 8))*2+1
+ new_length= org_length + (8-(org_length % 8))+1
*/
String *Item_func_des_encrypt::val_str(String *str)
{
- String *res =args[0]->val_str(str);
#ifdef HAVE_OPENSSL
- des_key_schedule ks1, ks2, ks3;
- des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
- struct {
- des_cblock key1, key2, key3; // 8 bytes each
- } keyblock;
+ des_cblock ivec;
+ struct st_des_keyblock keyblock;
+ struct st_des_keyschedule keyschedule;
+ const char *append_str="********";
+ uint key_number, res_length, tail;
+ String *res= args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
- if (res->length() == 0)
+ if ((res_length=res->length()) == 0)
return &empty_string;
- if(res->c_ptr()[0]!='1') { // Skip encryption if already encrypted
+
+ if (arg_count == 1)
+ {
+ /* Protect against someone doing FLUSH DES_KEY_FILE */
+ VOID(pthread_mutex_lock(&LOCK_des_key_file));
+ keyschedule= des_keyschedule[key_number=des_default_key];
+ VOID(pthread_mutex_unlock(&LOCK_des_key_file));
+ }
+ else if (args[1]->result_type() == INT_RESULT)
+ {
+ key_number= (uint) args[1]->val_int();
+ if (key_number > 9)
+ goto error;
+ VOID(pthread_mutex_lock(&LOCK_des_key_file));
+ keyschedule= des_keyschedule[key_number];
+ VOID(pthread_mutex_unlock(&LOCK_des_key_file));
+ }
+ else
+ {
String *keystr=args[1]->val_str(&tmp_value);
+ if (!keystr)
+ goto error;
+ key_number=127; // User key string
+
/* We make good 24-byte (168 bit) key from given plaintext key with MD5 */
+ bzero((char*) &ivec,sizeof(ivec));
EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
- (uchar *)keystr->c_ptr(),
- (int)keystr->length(),1,(uchar *)&keyblock,ivec);
- des_set_key_unchecked(&keyblock.key1,ks1); // Here we set all 64-bit keys
- des_set_key_unchecked(&keyblock.key2,ks2); // (56 effective) one by one
- des_set_key_unchecked(&keyblock.key3,ks3);
- /*
- The problem: DES algorithm requires original data to be in 8-bytes
- chunks. Missing bytes get filled with zeros and result of encryption
- can be up to 7 bytes longer than original string. When decrypted,
- we do not know the size of original string :(
- We add one byte with value 0x0..0x7 to original plaintext marking
- change of string length
- */
- uchar tail= 7-( res->length() %8); // 0..7 marking real offsets 1..8
- for(int i=0 ; i < tail ; ++i) res->append('*');
- res->append(tail); // Write tail length 0..7 to last pos
- str->length(res->length());
- des_ede3_cbc_encrypt( // Real encryption
- (const uchar*)(res->c_ptr()),
- (uchar*)(str->c_ptr()),
- res->length(), ks1, ks2, ks3, &ivec, TRUE);
- res->set((const char*)"1",(uint)1);
- for(uint i=0 ; i < str->length() ; ++i)
- {
- res->append(bin_to_ascii((uchar)str->c_ptr()[i] & 0x3f));
- res->append(bin_to_ascii(((uchar)str->c_ptr()[i] >> 5 ) & 0x3f));
- }
- }
- return res;
-#else
+ (uchar*) keystr->ptr(), (int) keystr->length(),
+ 1, (uchar*) &keyblock,ivec);
+ des_set_key_unchecked(&keyblock.key1,keyschedule.ks1);
+ des_set_key_unchecked(&keyblock.key2,keyschedule.ks2);
+ des_set_key_unchecked(&keyblock.key3,keyschedule.ks3);
+ }
+
+ /*
+ The problem: DES algorithm requires original data to be in 8-bytes
+ chunks. Missing bytes get filled with '*'s and result of encryption
+ can be up to 8 bytes longer than original string. When decrypted,
+ we do not know the size of original string :(
+ We add one byte with value 0x1..0x8 as the last byte of the padded
+ string marking change of string length.
+ */
+
+ tail= (8-(res_length) % 8); // 1..8 marking extra length
+ res_length+=tail;
+ if (tail && res->append(append_str, tail) || tmp_value.alloc(res_length+1))
+ goto error;
+ (*res)[res_length-1]=tail; // save extra length
+ tmp_value.length(res_length+1);
+ tmp_value[0]=(char) (128 | key_number);
+ // Real encryption
+ bzero((char*) &ivec,sizeof(ivec));
+ des_ede3_cbc_encrypt((const uchar*) (res->ptr()),
+ (uchar*) (tmp_value.ptr()+1),
+ res_length,
+ keyschedule.ks1,
+ keyschedule.ks2,
+ keyschedule.ks3,
+ &ivec, TRUE);
+ return &tmp_value;
+
+error:
+#endif /* HAVE_OPENSSL */
null_value=1;
return 0;
-#endif /* HAVE_OPENSSL */
}
+
String *Item_func_des_decrypt::val_str(String *str)
{
- String *res =args[0]->val_str(str);
#ifdef HAVE_OPENSSL
des_key_schedule ks1, ks2, ks3;
- des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
- struct {
- des_cblock key1, key2, key3; // 8 bytes each
- } keyblock;
-
+ des_cblock ivec;
+ struct st_des_keyblock keyblock;
+ struct st_des_keyschedule keyschedule;
+ String *res= args[0]->val_str(str);
+ uint length=res->length(),tail;
if ((null_value=args[0]->null_value))
return 0;
- if (res->length() == 0)
- return &empty_string;
-
- if(res->c_ptr()[0]=='1') // Skip decryption if not encrypted
+ length=res->length();
+ if (length < 9 || (length % 8) != 1 || !((*res)[0] & 128))
+ return res; // Skip decryption if not encrypted
+
+ if (arg_count == 1) // If automatic uncompression
{
- str->set((const char*)0,(uint)0);
- for(uint i=1 ; i < res->length() ; i+=2)
- {
- str->append((ascii_to_bin(res->c_ptr()[i]))
- | (ascii_to_bin(res->c_ptr()[i+1]) << 5 ));
- }
-
+ uint key_number=(uint) (*res)[0] & 127;
+ // Check if automatic key and that we have privilege to uncompress using it
+ if (!(current_thd->master_access & PROCESS_ACL) || key_number > 9)
+ goto error;
+ VOID(pthread_mutex_lock(&LOCK_des_key_file));
+ keyschedule= des_keyschedule[key_number];
+ VOID(pthread_mutex_unlock(&LOCK_des_key_file));
+ }
+ else
+ {
+ // We make good 24-byte (168 bit) key from given plaintext key with MD5
String *keystr=args[1]->val_str(&tmp_value);
- int32 mode=0;
- if(arg_count == 3 && !args[2]->null_value)
- mode=args[2]->val_int();
- /* We make good 24-byte (168 bit) key from given plaintext key with MD5 */
+ if (!keystr)
+ goto error;
+
+ bzero((char*) &ivec,sizeof(ivec));
EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
- (uchar *)keystr->c_ptr(),
- (int)keystr->length(),1,(uchar *)&keyblock,ivec);
- des_set_key_unchecked(&keyblock.key1,ks1); // Here we set all 64-bit keys
- des_set_key_unchecked(&keyblock.key2,ks2); // (56 effective) one by one
- des_set_key_unchecked(&keyblock.key3,ks3);
- res->length(str->length());
- des_ede3_cbc_encrypt( // Real decryption
- (const uchar*)(str->c_ptr()),
- (uchar*)(res->c_ptr()),
- str->length(),
- ks1, ks2, ks3, &ivec, FALSE);
- uchar tail=(res->c_ptr()[res->length()-1]) & 0x7;
- if((res->length() > ((uint)1+tail))) // We should avoid negative length
- res->length(res->length()-1-tail); // (can happen with wrong key)
- }
- return res;
-#else
+ (uchar*) keystr->ptr(),(int) keystr->length(),
+ 1,(uchar*) &keyblock,ivec);
+ // Here we set all 64-bit keys (56 effective) one by one
+ des_set_key_unchecked(&keyblock.key1,keyschedule.ks1);
+ des_set_key_unchecked(&keyblock.key2,keyschedule.ks2);
+ des_set_key_unchecked(&keyblock.key3,keyschedule.ks3);
+ }
+ if (tmp_value.alloc(length-1))
+ goto error;
+
+ bzero((char*) &ivec,sizeof(ivec));
+ des_ede3_cbc_encrypt((const uchar*) res->ptr()+1,
+ (uchar*) (tmp_value.ptr()),
+ length-1,
+ keyschedule.ks1,
+ keyschedule.ks2,
+ keyschedule.ks3,
+ &ivec, FALSE);
+ /* Restore old length of key */
+ if ((tail=(uint) (uchar) tmp_value[length-2]) > 8)
+ goto error; // Wrong key
+ tmp_value.length(length-1-tail);
+ return &tmp_value;
+
+error:
+#endif /* HAVE_OPENSSL */
null_value=1;
return 0;
-#endif /* HAVE_OPENSSL */
}
-
/*
-** concat with separator. First arg is the separator
-** concat_ws takes at least two arguments.
+ concat with separator. First arg is the separator
+ concat_ws takes at least two arguments.
*/
String *Item_func_concat_ws::val_str(String *str)
@@ -1117,6 +1155,7 @@ String *Item_func_password::val_str(String *str)
return str;
}
+#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
String *Item_func_encrypt::val_str(String *str)
{
@@ -1248,9 +1287,9 @@ String *Item_func_soundex::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
- if (str_value.alloc(max(res->length(),4)))
+ if (tmp_value.alloc(max(res->length(),4)))
return str; /* purecov: inspected */
- char *to= (char *) str_value.ptr();
+ char *to= (char *) tmp_value.ptr();
char *from= (char *) res->ptr(), *end=from+res->length();
while (from != end && isspace(*from)) // Skip pre-space
@@ -1274,11 +1313,11 @@ String *Item_func_soundex::val_str(String *str)
last_ch = ch; // save code of last input letter
} // for next double-letter check
}
- for (end=(char*) str_value.ptr()+4 ; to < end ; to++)
+ for (end=(char*) tmp_value.ptr()+4 ; to < end ; to++)
*to = '0';
*to=0; // end string
- str_value.length((uint) (to-str_value.ptr()));
- return &str_value;
+ tmp_value.length((uint) (to-tmp_value.ptr()));
+ return &tmp_value;
}
@@ -1733,6 +1772,45 @@ String *Item_func_conv::val_str(String *str)
return str;
}
+
+String *Item_func_hex::val_str(String *str)
+{
+ if (args[0]->result_type() != STRING_RESULT)
+ {
+ /* Return hex of unsigned longlong value */
+ longlong dec= args[0]->val_int();
+ char ans[65],*ptr;
+ if ((null_value= args[0]->null_value))
+ return 0;
+ ptr= longlong2str(dec,ans,16);
+ if (str->copy(ans,(uint32) (ptr-ans)))
+ return &empty_string; // End of memory
+ return str;
+ }
+
+ /* Convert given string to a hex string, character by character */
+ String *res= args[0]->val_str(str);
+ const char *from, *end;
+ char *to;
+ if (!res || tmp_value.alloc(res->length()*2))
+ {
+ null_value=1;
+ return 0;
+ }
+ null_value=0;
+ tmp_value.length(res->length()*2);
+ for (from=res->ptr(), end=from+res->length(), to= (char*) tmp_value.ptr();
+ from != end ;
+ from++, to+=2)
+ {
+ uint tmp=(uint) (uchar) *from;
+ to[0]=_dig_vec[tmp >> 4];
+ to[1]=_dig_vec[tmp & 15];
+ }
+ return &tmp_value;
+}
+
+
#include <my_dir.h> // For my_stat
String *Item_load_file::val_str(String *str)
@@ -1854,7 +1932,7 @@ String* Item_func_inet_ntoa::val_str(String* str)
// we handle the possibility of an 8-byte IP address
// however, we do not want to confuse those who are just using
// 4 byte ones
-
+
for (p= buf + 8; p > buf+4 && p[-1] == 0 ; p-- ) ;
num[3]='.';
while (p-- > buf)
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 31c832c8ddb..1279a5099d5 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -35,6 +35,11 @@ public:
double val();
enum Item_result result_type () const { return STRING_RESULT; }
void left_right_max_length();
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return (max_length > 255) ? (Field *)new Field_blob(max_length,maybe_null, name,t_arg, binary) : (Field *) new Field_string(max_length,maybe_null, name,t_arg, binary);
+ }
};
class Item_func_md5 :public Item_str_func
@@ -228,9 +233,9 @@ class Item_func_des_encrypt :public Item_str_func
public:
Item_func_des_encrypt(Item *a) :Item_str_func(a) {}
Item_func_des_encrypt(Item *a, Item *b): Item_str_func(a,b) {}
- Item_func_des_encrypt(Item *a, Item *b, Item *c): Item_str_func(a,b,c) {}
String *val_str(String *);
- void fix_length_and_dec() { maybe_null=1; max_length = args[0]->max_length; }
+ void fix_length_and_dec()
+ { maybe_null=1; max_length = args[0]->max_length+8; }
const char *func_name() const { return "des_encrypt"; }
};
@@ -240,7 +245,6 @@ class Item_func_des_decrypt :public Item_str_func
public:
Item_func_des_decrypt(Item *a) :Item_str_func(a) {}
Item_func_des_decrypt(Item *a, Item *b): Item_str_func(a,b) {}
- Item_func_des_decrypt(Item *a, Item *b, Item *c): Item_str_func(a,b,c) {}
String *val_str(String *);
void fix_length_and_dec() { maybe_null=1; max_length = args[0]->max_length; }
const char *func_name() const { return "des_decrypt"; }
@@ -298,6 +302,7 @@ public:
class Item_func_soundex :public Item_str_func
{
+ String tmp_value;
public:
Item_func_soundex(Item *a) :Item_str_func(a) {}
String *val_str(String *);
@@ -413,12 +418,25 @@ public:
void fix_length_and_dec() { decimals=0; max_length=64; }
};
+
+class Item_func_hex :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_hex(Item *a) :Item_str_func(a) {}
+ const char *func_name() const { return "hex"; }
+ String *val_str(String *);
+ void fix_length_and_dec() { decimals=0; max_length=args[0]->max_length*2; }
+};
+
+
class Item_func_binary :public Item_str_func
{
public:
Item_func_binary(Item *a) :Item_str_func(a) {}
const char *func_name() const { return "binary"; }
- String *val_str(String *a) { return (args[0]->val_str(a)); }
+ String *val_str(String *a)
+ { a=args[0]->val_str(a); null_value=args[0]->null_value; return a; }
void fix_length_and_dec() { binary=1; max_length=args[0]->max_length; }
void print(String *str) { print_op(str); }
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 431d8b56e6a..e8f16e3ed56 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -967,7 +967,7 @@ bool Item_sum_count_distinct::setup(THD *thd)
table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
table->no_rows=1;
-
+
// no blobs, otherwise it would be MyISAM
if (table->db_type == DB_TYPE_HEAP)
{
@@ -976,7 +976,7 @@ bool Item_sum_count_distinct::setup(THD *thd)
// to make things easier for dump_leaf if we ever have to dump to MyISAM
restore_record(table,2);
-
+
if (table->fields == 1)
{
/*
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 18b0c3ff577..4840ae8298d 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -159,7 +159,7 @@ class Item_sum_count_distinct :public Item_sum_int
// are just markers for deleted and NULLs. We want to skip them since
// they will just bloat the tree without providing any valuable info
int rec_offset;
-
+
// If there are no blobs, we can use a tree, which
// is faster than heap table. In that case, we still use the table
// to help get things set up, but we insert nothing in it
@@ -167,7 +167,7 @@ class Item_sum_count_distinct :public Item_sum_int
bool always_null; // Set to 1 if the result is always NULL
int tree_to_myisam();
-
+
friend int composite_key_cmp(void* arg, byte* key1, byte* key2);
friend int dump_leaf(byte* key, uint32 count __attribute__((unused)),
Item_sum_count_distinct* item);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index b198900d24e..8f55a02b020 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -672,7 +672,7 @@ String *Item_func_date_format::val_str(String *str)
else
size=format_length(format);
if (format == str)
- str=&str_value; // Save result here
+ str= &str_value; // Save result here
if (str->alloc(size))
{
null_value=1;
@@ -1123,3 +1123,13 @@ longlong Item_extract::val_int()
}
return 0; // Impossible
}
+
+
+void Item_typecast::print(String *str)
+{
+ str->append("CAST(");
+ args[0]->print(str);
+ str->append(" AS ");
+ str->append(func_name());
+ str->append(')');
+}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 1343cdad390..32b85e7f028 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -229,6 +229,33 @@ public:
const char *func_name() const { return "date"; }
void fix_length_and_dec() { decimals=0; max_length=10; }
bool save_in_field(Field *to);
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_DATE);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_date(maybe_null, name, t_arg);
+ }
+};
+
+
+class Item_date_func :public Item_str_func
+{
+public:
+ Item_date_func() :Item_str_func() {}
+ Item_date_func(Item *a) :Item_str_func(a) {}
+ Item_date_func(Item *a,Item *b) :Item_str_func(a,b) {}
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_DATETIME);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_datetime(maybe_null, name, t_arg);
+ }
};
@@ -247,6 +274,15 @@ public:
{ str_value.set(buff,buff_length); return &str_value; }
const char *func_name() const { return "curtime"; }
void fix_length_and_dec();
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_TIME);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_time(maybe_null, name, t_arg);
+ }
};
@@ -263,15 +299,15 @@ public:
};
-class Item_func_now :public Item_func
+class Item_func_now :public Item_date_func
{
longlong value;
char buff[20];
uint buff_length;
TIME ltime;
public:
- Item_func_now() :Item_func() {}
- Item_func_now(Item *a) :Item_func(a) {}
+ Item_func_now() :Item_date_func() {}
+ Item_func_now(Item *a) :Item_date_func(a) {}
enum Item_result result_type () const { return STRING_RESULT; }
double val() { return (double) value; }
longlong val_int() { return value; }
@@ -307,16 +343,16 @@ public:
};
-class Item_func_from_unixtime :public Item_func
+class Item_func_from_unixtime :public Item_date_func
{
public:
- Item_func_from_unixtime(Item *a) :Item_func(a) {}
+ Item_func_from_unixtime(Item *a) :Item_date_func(a) {}
double val() { return (double) Item_func_from_unixtime::val_int(); }
longlong val_int();
String *val_str(String *str);
const char *func_name() const { return "from_unixtime"; }
void fix_length_and_dec() { decimals=0; max_length=19; }
- enum Item_result result_type () const { return STRING_RESULT; }
+// enum Item_result result_type () const { return STRING_RESULT; }
bool get_date(TIME *res,bool fuzzy_date);
};
@@ -330,6 +366,15 @@ public:
String *val_str(String *);
void fix_length_and_dec() { maybe_null=1; max_length=13; }
const char *func_name() const { return "sec_to_time"; }
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_TIME);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_time(maybe_null, name, t_arg);
+ }
};
enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY,
@@ -339,7 +384,7 @@ enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY,
INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
INTERVAL_MINUTE_SECOND};
-class Item_date_add_interval :public Item_str_func
+class Item_date_add_interval :public Item_date_func
{
const interval_type int_type;
String value;
@@ -347,7 +392,7 @@ class Item_date_add_interval :public Item_str_func
public:
Item_date_add_interval(Item *a,Item *b,interval_type type_arg,bool neg_arg)
- :Item_str_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {}
+ :Item_date_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {}
String *val_str(String *);
const char *func_name() const { return "date_add_interval"; }
void fix_length_and_dec() { maybe_null=1; max_length=19; value.alloc(32);}
@@ -368,3 +413,62 @@ class Item_extract :public Item_int_func
const char *func_name() const { return "extract"; }
void fix_length_and_dec();
};
+
+class Item_typecast :public Item_str_func
+{
+public:
+ Item_typecast(Item *a) :Item_str_func(a) {}
+ String *val_str(String *a)
+ { a=args[0]->val_str(a); null_value=args[0]->null_value; return a; }
+ void fix_length_and_dec() { max_length=args[0]->max_length; }
+ void print(String *str);
+};
+
+
+class Item_date_typecast :public Item_typecast
+{
+public:
+ Item_date_typecast(Item *a) :Item_typecast(a) {}
+ const char *func_name() const { return "date"; }
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_DATE);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_date(maybe_null, name, t_arg);
+ }
+};
+
+class Item_time_typecast :public Item_typecast
+{
+public:
+ Item_time_typecast(Item *a) :Item_typecast(a) {}
+ const char *func_name() const { return "time"; }
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_TIME);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_time(maybe_null, name, t_arg);
+ }
+};
+
+class Item_datetime_typecast :public Item_typecast
+{
+public:
+ Item_datetime_typecast(Item *a) :Item_typecast(a) {}
+ const char *func_name() const { return "datetime"; }
+ void make_field(Send_field *tmp_field)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_DATETIME);
+ }
+ Field *tmp_table_field(TABLE *t_arg)
+ {
+ if (!t_arg) return result_field;
+ return new Field_datetime(maybe_null, name, t_arg);
+ }
+};
diff --git a/sql/item_uniq.cc b/sql/item_uniq.cc
index 80ed6433fd8..88e0cbbc0e6 100644
--- a/sql/item_uniq.cc
+++ b/sql/item_uniq.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index ff11222e2ee..4be64ecc74a 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/key.cc b/sql/key.cc
index b6fb260bf36..d2f483e3d73 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -258,7 +258,7 @@ bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields)
key_part++)
{
Item_field *field;
-
+
if (key_part->field == table->timestamp_field)
return 1; // Can't be used for update
diff --git a/sql/lex.h b/sql/lex.h
index 894fdfb5362..6bee4152e48 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -76,6 +76,7 @@ static SYMBOL symbols[] = {
{ "BOOLEAN", SYM(BOOLEAN_SYM),0,0},
{ "BOTH", SYM(BOTH),0,0},
{ "BY", SYM(BY),0,0},
+ { "CACHE", SYM(CACHE_SYM),0,0},
{ "CASCADE", SYM(CASCADE),0,0},
{ "CASE", SYM(CASE_SYM),0,0},
{ "CHAR", SYM(CHAR_SYM),0,0},
@@ -110,16 +111,19 @@ static SYMBOL symbols[] = {
{ "DAY_SECOND", SYM(DAY_SECOND_SYM),0,0},
{ "DEC", SYM(DECIMAL_SYM),0,0},
{ "DECIMAL", SYM(DECIMAL_SYM),0,0},
+ { "DES_KEY_FILE", SYM(DES_KEY_FILE),0,0},
{ "DEFAULT", SYM(DEFAULT),0,0},
{ "DELAYED", SYM(DELAYED_SYM),0,0},
{ "DELAY_KEY_WRITE", SYM(DELAY_KEY_WRITE_SYM),0,0},
{ "DELETE", SYM(DELETE_SYM),0,0},
+ { "DEMAND", SYM(DEMAND_SYM),0,0},
{ "DESC", SYM(DESC),0,0},
{ "DESCRIBE", SYM(DESCRIBE),0,0},
{ "DIRECTORY", SYM(DIRECTORY_SYM),0,0},
{ "DISABLE", SYM(DISABLE_SYM),0,0},
{ "DISTINCT", SYM(DISTINCT),0,0},
{ "DISTINCTROW", SYM(DISTINCT),0,0}, /* Access likes this */
+ { "DO", SYM(DO_SYM),0,0},
{ "DOUBLE", SYM(DOUBLE_SYM),0,0},
{ "DROP", SYM(DROP),0,0},
{ "DUMPFILE", SYM(DUMPFILE),0,0},
@@ -223,6 +227,7 @@ static SYMBOL symbols[] = {
{ "MASTER_SERVER_ID", SYM(MASTER_SERVER_ID_SYM),0,0},
{ "MASTER_USER", SYM(MASTER_USER_SYM),0,0},
{ "MAX_ROWS", SYM(MAX_ROWS),0,0},
+ { "MAX_QUERIES_PER_HOUR", SYM(MAX_QUERIES_PER_HOUR), 0,0},
{ "MATCH", SYM(MATCH),0,0},
{ "MEDIUMBLOB", SYM(MEDIUMBLOB),0,0},
{ "MEDIUMTEXT", SYM(MEDIUMTEXT),0,0},
@@ -247,6 +252,7 @@ static SYMBOL symbols[] = {
{ "NOT", SYM(NOT),0,0},
{ "NULL", SYM(NULL_SYM),0,0},
{ "NUMERIC", SYM(NUMERIC_SYM),0,0},
+ { "OFF", SYM(OFF),0,0},
{ "ON", SYM(ON),0,0},
{ "OPEN", SYM(OPEN_SYM),0,0},
{ "OPTIMIZE", SYM(OPTIMIZE),0,0},
@@ -267,6 +273,7 @@ static SYMBOL symbols[] = {
{ "PROCESS" , SYM(PROCESS),0,0},
{ "PROCESSLIST", SYM(PROCESSLIST_SYM),0,0},
{ "PRIVILEGES", SYM(PRIVILEGES),0,0},
+ { "QUERY", SYM(QUERY_SYM),0,0},
{ "QUICK", SYM(QUICK),0,0},
{ "RAID0", SYM(RAID_0_SYM),0,0},
{ "READ", SYM(READ_SYM),0,0},
@@ -294,6 +301,7 @@ static SYMBOL symbols[] = {
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0},
{ "SESSION", SYM(SESSION_SYM),0,0},
{ "SET", SYM(SET),0,0},
+ { "SIGNED", SYM(SIGNED_SYM),0,0},
{ "SHARE", SYM(SHARE_SYM),0,0},
{ "SHOW", SYM(SHOW),0,0},
{ "SHUTDOWN", SYM(SHUTDOWN),0,0},
@@ -305,12 +313,15 @@ static SYMBOL symbols[] = {
{ "SQL_BIG_SELECTS", SYM(SQL_BIG_SELECTS),0,0},
{ "SQL_BIG_TABLES", SYM(SQL_BIG_TABLES),0,0},
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
+ { "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
{ "SQL_CALC_FOUND_ROWS", SYM(SQL_CALC_FOUND_ROWS),0,0},
{ "SQL_LOG_BIN", SYM(SQL_LOG_BIN),0,0},
{ "SQL_LOG_OFF", SYM(SQL_LOG_OFF),0,0},
{ "SQL_LOG_UPDATE", SYM(SQL_LOG_UPDATE),0,0},
{ "SQL_LOW_PRIORITY_UPDATES", SYM(SQL_LOW_PRIORITY_UPDATES),0,0},
{ "SQL_MAX_JOIN_SIZE",SYM(SQL_MAX_JOIN_SIZE), 0, 0},
+ { "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM), 0, 0},
+ { "SQL_QUERY_CACHE_TYPE",SYM(SQL_QUERY_CACHE_TYPE_SYM), 0, 0},
{ "SQL_QUOTE_SHOW_CREATE",SYM(SQL_QUOTE_SHOW_CREATE), 0, 0},
{ "SQL_SAFE_UPDATES", SYM(SQL_SAFE_UPDATES),0,0},
{ "SQL_SELECT_LIMIT", SYM(SQL_SELECT_LIMIT),0,0},
@@ -382,7 +393,9 @@ static SYMBOL sql_functions[] = {
{ "BIT_COUNT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_bit_count)},
{ "BIT_OR", SYM(BIT_OR),0,0},
{ "BIT_AND", SYM(BIT_AND),0,0},
+ { "CAST", SYM(CAST_SYM),0,0},
{ "CEILING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)},
+ { "BIT_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_bit_length)},
{ "CHAR_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_char_length)},
{ "CHARACTER_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_char_length)},
{ "COALESCE", SYM(COALESCE),0,0},
@@ -390,6 +403,7 @@ static SYMBOL sql_functions[] = {
{ "CONCAT_WS", SYM(CONCAT_WS),0,0},
{ "CONNECTION_ID", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_connection_id)},
{ "CONV", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_conv)},
+ { "CONVERT", SYM(CONVERT_SYM),0,0},
{ "COUNT", SYM(COUNT_SYM),0,0},
{ "COS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cos)},
{ "COT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cot)},
@@ -404,8 +418,8 @@ static SYMBOL sql_functions[] = {
{ "DAYOFYEAR", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_dayofyear)},
{ "DECODE", SYM(DECODE_SYM),0,0},
{ "DEGREES", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_degrees)},
- { "DES_ENCRYPT", SYM(DES_ENCRYPT),0,0},
- { "DES_DECRYPT", SYM(DES_DECRYPT),0,0},
+ { "DES_ENCRYPT", SYM(DES_ENCRYPT_SYM),0,0},
+ { "DES_DECRYPT", SYM(DES_DECRYPT_SYM),0,0},
{ "ELT", SYM(ELT_FUNC),0,0},
{ "ENCODE", SYM(ENCODE_SYM),0,0},
{ "ENCRYPT", SYM(ENCRYPT),0,0},
@@ -489,9 +503,9 @@ static SYMBOL sql_functions[] = {
{ "TO_DAYS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_to_days)},
{ "TRIM", SYM(TRIM),0,0},
{ "UCASE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
- { "UPPER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
{ "UNIQUE_USERS", SYM(UNIQUE_USERS),0,0},
{ "UNIX_TIMESTAMP", SYM(UNIX_TIMESTAMP),0,0},
+ { "UPPER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
{ "USER", SYM(USER),0,0},
{ "VERSION", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)},
{ "WEEK", SYM(WEEK_SYM),0,0},
diff --git a/sql/lex_symbol.h b/sql/lex_symbol.h
index a011e27b59e..9fff1751b1b 100644
--- a/sql/lex_symbol.h
+++ b/sql/lex_symbol.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/lock.cc b/sql/lock.cc
index 520821629e3..9f4f23b01e3 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/matherr.c b/sql/matherr.c
index ed18438cd0c..ea0c15d2feb 100644
--- a/sql/matherr.c
+++ b/sql/matherr.c
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc
index 2a7b25eab2f..1bc65eebd23 100644
--- a/sql/mf_iocache.cc
+++ b/sql/mf_iocache.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -50,14 +50,14 @@ extern "C" {
int _my_b_net_read(register IO_CACHE *info, byte *Buffer,
uint Count __attribute__((unused)))
{
- int read_length;
+ ulong read_length;
NET *net= &(current_thd)->net;
DBUG_ENTER("_my_b_net_read");
if (!info->end_of_file)
DBUG_RETURN(1); /* because my_b_get (no _) takes 1 byte at a time */
read_length=my_net_read(net);
- if (read_length == (int) packet_error)
+ if (read_length == packet_error)
{
info->error= -1;
DBUG_RETURN(1);
diff --git a/sql/mini_client.cc b/sql/mini_client.cc
index a43e5710e60..a5879081566 100644
--- a/sql/mini_client.cc
+++ b/sql/mini_client.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -22,21 +22,15 @@
in case we decide to make them external at some point
*/
+#ifdef EMBEDDED_LIBRARY
+#define net_read_timeout net_read_timeout1
+#define net_write_timeout net_write_timeout1
+#endif
+
#if defined(__WIN__)
#include <winsock.h>
-#include <odbcinst.h>
-/* Disable alarms */
-typedef my_bool ALARM;
-#define thr_alarm_init(A) (*(A))=0
-#define thr_alarm_in_use(A) (*(A))
-#define thr_end_alarm(A)
-#define thr_alarm(A,B,C) local_thr_alarm((A),(B),(C))
-inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
-{
- *A=1;
- return 0;
-}
-#define thr_got_alarm(A) 0
+#include <odbcinst.h> /* QQ: Is this really needed ? */
+#define DONT_USE_THR_ALARM
#endif
#include <my_global.h>
@@ -53,12 +47,7 @@ inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __a
#include "mysqld_error.h"
#include "errmsg.h"
-#ifdef EMBEDDED_LIBRARY
-#define net_read_timeout net_read_timeout1
-#define net_write_timeout net_write_timeout1
-#endif
-
-#if defined( OS2) && defined( MYSQL_SERVER)
+#if defined( OS2) && defined(MYSQL_SERVER)
#undef ER
#define ER CER
#endif
@@ -82,18 +71,17 @@ extern "C" { // Because of SCO 3.2V4.2
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
-#endif
+#endif /*!defined(MSDOS) && !defined(__WIN__) */
#ifdef HAVE_SYS_UN_H
# include <sys/un.h>
#endif
#if defined(THREAD)
#include <my_pthread.h> /* because of signal() */
-#include <thr_alarm.h>
#endif
+#include <thr_alarm.h>
#ifndef INADDR_NONE
#define INADDR_NONE -1
#endif
-
}
static void mc_free_rows(MYSQL_DATA *cur);
@@ -808,7 +796,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
#endif /* HAVE_OPENSSL */
int3store(buff+2,max_allowed_packet);
-
+
if (user && user[0])
strmake(buff+5,user,32);
else
@@ -1046,7 +1034,7 @@ int mc_mysql_query(MYSQL *mysql, const char *query, uint length)
DBUG_ENTER("mysql_real_query");
DBUG_PRINT("enter",("handle: %lx",mysql));
DBUG_PRINT("query",("Query = \"%s\"",query));
- if(!length)
+ if (!length)
length = strlen(query);
if (mc_simple_command(mysql,COM_QUERY,query,length,1))
DBUG_RETURN(-1);
@@ -1055,58 +1043,62 @@ int mc_mysql_query(MYSQL *mysql, const char *query, uint length)
static int mc_send_file_to_server(MYSQL *mysql, const char *filename)
{
- int fd, readcount;
- char buf[IO_SIZE*15],*tmp_name;
+ int fd, readcount, result= -1;
+ uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE);
+ char *buf, tmp_name[FN_REFLEN];
DBUG_ENTER("send_file_to_server");
- fn_format(buf,filename,"","",4); /* Convert to client format */
- if (!(tmp_name=my_strdup(buf,MYF(0))))
+ if (!(buf=my_malloc(packet_length,MYF(0))))
{
strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY));
DBUG_RETURN(-1);
}
+
+ fn_format(tmp_name,filename,"","",4); /* Convert to client format */
if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0)
{
+ my_net_write(&mysql->net,"",0); // Server needs one packet
+ net_flush(&mysql->net);
mysql->net.last_errno=EE_FILENOTFOUND;
- sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno);
- strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1);
- my_net_write(&mysql->net,"",0); net_flush(&mysql->net);
- my_free(tmp_name,MYF(0));
- DBUG_RETURN(-1);
+ my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1,
+ EE(mysql->net.last_errno),tmp_name, errno);
+ goto err;
}
- while ((readcount = (int) my_read(fd,(byte*) buf,sizeof(buf),MYF(0))) > 0)
+ while ((readcount = (int) my_read(fd,(byte*) buf,packet_length,MYF(0))) > 0)
{
if (my_net_write(&mysql->net,buf,readcount))
{
+ DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file"));
mysql->net.last_errno=CR_SERVER_LOST;
strmov(mysql->net.last_error,ER(mysql->net.last_errno));
- DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file"));
- (void) my_close(fd,MYF(0));
- my_free(tmp_name,MYF(0));
- DBUG_RETURN(-1);
+ goto err;
}
}
- (void) my_close(fd,MYF(0));
/* Send empty packet to mark end of file */
if (my_net_write(&mysql->net,"",0) || net_flush(&mysql->net))
{
mysql->net.last_errno=CR_SERVER_LOST;
sprintf(mysql->net.last_error,ER(mysql->net.last_errno),errno);
- my_free(tmp_name,MYF(0));
- DBUG_RETURN(-1);
+ goto err;
}
if (readcount < 0)
{
mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */
- sprintf(buf,EE(mysql->net.last_errno),tmp_name,errno);
- strmake(mysql->net.last_error,buf,sizeof(mysql->net.last_error)-1);
- my_free(tmp_name,MYF(0));
- DBUG_RETURN(-1);
+ my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1,
+ tmp_name,errno);
+ goto err;
}
- DBUG_RETURN(0);
+ result=0; // Ok
+
+err:
+ if (fd >= 0)
+ (void) my_close(fd,MYF(0));
+ my_free(buf,MYF(0));
+ DBUG_RETURN(result);
}
+
/* Get the length of next field. Change parameter to point at fieldstart */
static ulong mc_net_field_length(uchar **packet)
{
@@ -1186,7 +1178,7 @@ static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
if ((pkt_len=mc_net_safe_read(mysql)) == packet_error)
DBUG_RETURN(0);
if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA),
- MYF(MY_WME | MY_ZEROFILL))))
+ MYF(MY_ZEROFILL))))
{
net->last_errno=CR_OUT_OF_MEMORY;
strmov(net->last_error,ER(net->last_errno));
@@ -1373,7 +1365,7 @@ MYSQL_RES *mc_mysql_store_result(MYSQL *mysql)
mysql->status=MYSQL_STATUS_READY; /* server is ready */
if (!(result=(MYSQL_RES*) my_malloc(sizeof(MYSQL_RES)+
sizeof(ulong)*mysql->field_count,
- MYF(MY_WME | MY_ZEROFILL))))
+ MYF(MY_ZEROFILL))))
{
mysql->net.last_errno=CR_OUT_OF_MEMORY;
strmov(mysql->net.last_error, ER(mysql->net.last_errno));
@@ -1396,11 +1388,3 @@ MYSQL_RES *mc_mysql_store_result(MYSQL *mysql)
mysql->fields=0; /* fields is now in result */
DBUG_RETURN(result); /* Data fetched */
}
-
-
-
-
-
-
-
-
diff --git a/sql/mini_client.h b/sql/mini_client.h
index 1e17d34244e..6721b072080 100644
--- a/sql/mini_client.h
+++ b/sql/mini_client.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -49,4 +49,3 @@ int mc_mysql_select_db(MYSQL *mysql, const char *db);
void mc_end_server(MYSQL *mysql);
#endif
-
diff --git a/sql/my_lock.c b/sql/my_lock.c
index 19d38fd9c79..9b4ac502e57 100644
--- a/sql/my_lock.c
+++ b/sql/my_lock.c
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 12a043250a5..8ccf0de27d6 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -149,7 +149,7 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
#define SELECT_SMALL_RESULT 8
#define SELECT_BIG_RESULT 16
#define OPTION_FOUND_ROWS 32
-#define SELECT_HIGH_PRIORITY 64 /* Intern */
+#define OPTION_TO_QUERY_CACHE 64
#define SELECT_NO_JOIN_CACHE 256 /* Intern */
#define OPTION_BIG_TABLES 512 /* for SQL OPTION */
@@ -180,6 +180,7 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
#define SELECT_NO_UNLOCK (QUERY_NO_GOOD_INDEX_USED*2)
#define TMP_TABLE_ALL_COLUMNS (SELECT_NO_UNLOCK*2)
+
#define MODE_REAL_AS_FLOAT 1
#define MODE_PIPES_AS_CONCAT 2
#define MODE_ANSI_QUOTES 4
@@ -248,7 +249,7 @@ inline THD *_current_thd(void)
#include "item.h"
#include "sql_class.h"
#include "opt_range.h"
-
+#include "sql_cache.h"
int mysql_create_db(THD *thd, char *db, uint create_info, bool silent);
int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
@@ -262,7 +263,8 @@ 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);
void mysql_init_select(LEX *lex);
-void mysql_new_select(LEX *lex);
+bool mysql_new_select(LEX *lex);
+void mysql_init_multi_delete(LEX *lex);
void init_max_user_conn(void);
void free_max_user_conn(void);
pthread_handler_decl(handle_one_connection,arg);
@@ -275,15 +277,16 @@ bool do_command(THD *thd);
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length);
bool check_stack_overrun(THD *thd,char *dummy);
-bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables);
+bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables);
void table_cache_init(void);
void table_cache_free(void);
uint cached_tables(void);
void kill_mysql(void);
void close_connection(NET *net,uint errcode=0,bool lock=1);
bool check_access(THD *thd,uint access,const char *db=0,uint *save_priv=0,
- bool no_grant=0);
-bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables);
+ bool no_grant=0, bool no_errors=0);
+bool check_table_access(THD *thd,uint want_access, TABLE_LIST *tables,
+ bool no_errors=0);
bool check_process_priv(THD *thd=0);
int mysql_backup_table(THD* thd, TABLE_LIST* table_list);
@@ -330,7 +333,7 @@ int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
ulong select_type,select_result *result);
int mysql_union(THD *thd,LEX *lex,select_result *result);
-Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
+Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item_result_field ***copy_func, Field **from_field,
bool group,bool modify_item);
int mysql_create_table(THD *thd,const char *db, const char *table_name,
@@ -395,6 +398,24 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name);
Field *find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables);
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
bool check_grant,bool allow_rowid);
+#ifdef HAVE_OPENSSL
+struct st_des_keyblock
+{
+ des_cblock key1, key2, key3;
+};
+struct st_des_keyschedule
+{
+ des_key_schedule ks1, ks2, ks3;
+};
+extern char *des_key_file;
+extern struct st_des_keyschedule des_keyschedule[10];
+extern uint des_default_key;
+extern pthread_mutex_t LOCK_des_key_file;
+bool load_des_key_file(const char *file_name);
+#endif /* HAVE_OPENSSL */
+
+/* sql_do.cc */
+int mysql_do(THD *thd, List<Item> &values);
/* sql_list.c */
int mysqld_show_dbs(THD *thd,const char *wild);
@@ -416,7 +437,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables);
/* sql_handler.cc */
int mysql_ha_open(THD *thd, TABLE_LIST *tables);
-int mysql_ha_close(THD *thd, TABLE_LIST *tables);
+int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok=0);
int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
@@ -492,7 +513,7 @@ int write_record(TABLE *table,COPY_INFO *info);
/* bits set in manager_status */
#define MANAGER_BERKELEY_LOG_CLEANUP (1L << 0)
extern ulong volatile manager_status;
-extern bool volatile manager_thread_in_use;
+extern bool volatile manager_thread_in_use, mqh_used;
extern pthread_t manager_thread;
extern pthread_mutex_t LOCK_manager;
extern pthread_cond_t COND_manager;
@@ -543,6 +564,7 @@ extern ulong select_full_range_join_count,select_full_join_count,
slave_open_temp_tables;
extern uint test_flags,select_errors,ha_open_options;
extern ulong thd_startup_options, slow_launch_threads, slow_launch_time;
+extern ulong query_cache_startup_type;
extern time_t start_time;
extern const char *command_name[];
extern I_List<THD> threads;
@@ -578,7 +600,8 @@ extern ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
what_to_log,flush_time,opt_sql_mode,
max_tmp_tables,max_heap_table_size,query_buff_size,
lower_case_table_names,thread_stack,thread_stack_min,
- binlog_cache_size, max_binlog_cache_size,record_rnd_cache_size;
+ binlog_cache_size, max_binlog_cache_size, record_rnd_cache_size;
+extern ulong com_stat[(uint) SQLCOM_END], com_other;
extern ulong specialflag, current_pid;
extern bool low_priority_updates, using_update_log;
extern bool opt_sql_bin_update, opt_safe_show_db, opt_warnings,
@@ -698,7 +721,6 @@ void hostname_cache_refresh(void);
bool get_interval_info(const char *str,uint length,uint count,
long *values);
/* sql_cache */
-
extern bool sql_cache_init();
extern void sql_cache_free();
extern int sql_cache_hit(THD *thd, char *inBuf, uint length);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 6d99db62f12..b6e33a32b74 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -27,7 +27,7 @@
#include "ha_berkeley.h"
#endif
#ifdef HAVE_INNOBASE_DB
-#include "ha_innobase.h"
+#include "ha_innodb.h"
#endif
#include "ha_myisam.h"
#include <nisam.h>
@@ -114,8 +114,13 @@ typedef fp_except fp_except_t;
inline void reset_floating_point_exceptions()
{
/* Don't fall for overflow, underflow,divide-by-zero or loss of precision */
- fpsetmask(~(FP_X_INV | FP_X_DNML | FP_X_OFL | FP_X_UFL |
- FP_X_DZ | FP_X_IMP));
+#if defined(__i386__)
+ fpsetmask(~(FP_X_INV | FP_X_DNML | FP_X_OFL | FP_X_UFL | FP_X_DZ |
+ FP_X_IMP));
+#else
+ fpsetmask(~(FP_X_INV | FP_X_OFL | FP_X_UFL | FP_X_DZ |
+ FP_X_IMP));
+#endif
}
#else
#define reset_floating_point_exceptions()
@@ -223,6 +228,7 @@ static bool opt_log,opt_update_log,opt_bin_log,opt_slow_log,opt_noacl,
bool opt_sql_bin_update = 0, opt_log_slave_updates = 0, opt_safe_show_db=0,
opt_show_slave_auth_info = 0, opt_old_rpl_compat = 0,
opt_safe_user_create = 0, opt_no_mix_types = 0;
+volatile bool mqh_used = 0;
FILE *bootstrap_file=0;
int segfaulted = 0; // ensure we do not enter SIGSEGV handler twice
@@ -240,6 +246,7 @@ char glob_hostname[FN_REFLEN];
#include "sslopt-vars.h"
#ifdef HAVE_OPENSSL
+char *des_key_file = 0;
struct st_VioSSLAcceptorFd * ssl_acceptor_fd = 0;
#endif /* HAVE_OPENSSL */
@@ -266,8 +273,10 @@ ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
net_interactive_timeout, slow_launch_time = 2L,
net_read_timeout,net_write_timeout,slave_open_temp_tables=0,
open_files_limit=0, max_binlog_size, record_rnd_cache_size;
+ulong com_stat[(uint) SQLCOM_END], com_other;
ulong slave_net_timeout;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
+ulong query_cache_size=0, query_cache_limit=0, query_cache_startup_type=1;
volatile ulong cached_thread_count=0;
// replication parameters, if master_host is not NULL, we are a slave
@@ -360,7 +369,10 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
LOCK_server_id,
LOCK_user_conn, LOCK_slave_list, LOCK_active_mi;
-pthread_cond_t COND_refresh,COND_thread_count;
+Query_cache query_cache;
+
+pthread_cond_t COND_refresh,COND_thread_count,COND_binlog_update,
+ COND_slave_stopped, COND_slave_start;
pthread_cond_t COND_thread_cache,COND_flush_thread_cache;
pthread_t signal_thread;
pthread_attr_t connection_attrib;
@@ -369,10 +381,12 @@ enum db_type default_table_type=DB_TYPE_MYISAM;
#ifdef __WIN__
#undef getpid
#include <process.h>
+#if !defined(EMBEDDED_LIBRARY)
HANDLE hEventShutdown;
#include "nt_servc.h"
static NTService Service; // Service object for WinNT
#endif
+#endif
#ifdef OS2
pthread_cond_t eventShutdown;
@@ -385,6 +399,7 @@ static void get_options(int argc,char **argv);
static char *get_relative_path(const char *path);
static void fix_paths(void);
static pthread_handler_decl(handle_connections_sockets,arg);
+static pthread_handler_decl(kill_server_thread,arg);
static int bootstrap(FILE *file);
static void close_server_sock();
static bool read_init_file(char *file_name);
@@ -436,15 +451,7 @@ static void close_connections(void)
if (pthread_kill(select_thread,THR_CLIENT_ALARM))
break; // allready dead
#endif
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec=time(NULL)+2; // Bsd 2.1
- abstime.ts_nsec=0;
-#else
- struct timeval tv;
- gettimeofday(&tv,0);
- abstime.tv_sec=tv.tv_sec+2;
- abstime.tv_nsec=tv.tv_usec*1000;
-#endif
+ set_timespec(abstime, 2);
for (uint tmp=0 ; tmp < 10 ; tmp++)
{
error=pthread_cond_timedwait(&COND_thread_count,&LOCK_thread_count,
@@ -603,8 +610,9 @@ void kill_mysql(void)
#ifdef SIGNALS_DONT_BREAK_READ
close_server_sock(); /* force accept to wake up */
#endif
-
+
#if defined(__WIN__)
+#if !defined(EMBEDDED_LIBRARY)
{
if (!SetEvent(hEventShutdown))
{
@@ -617,22 +625,30 @@ void kill_mysql(void)
CloseHandle(hEvent);
*/
}
+#endif
#elif defined(OS2)
pthread_cond_signal( &eventShutdown); // post semaphore
#elif defined(HAVE_PTHREAD_KILL)
- if (pthread_kill(signal_thread,SIGTERM)) /* End everything nicely */
- {
- DBUG_PRINT("error",("Got error %d from pthread_kill",errno)); /* purecov: inspected */
- }
-#else
- kill(current_pid,SIGTERM);
+ if (pthread_kill(signal_thread,SIGTERM)) /* End everything nicely */
+ {
+ DBUG_PRINT("error",("Got error %d from pthread_kill",errno)); /* purecov: inspected */
+ }
+#elif !defined(SIGNALS_DONT_BREAK_READ)
+ kill(current_pid,SIGTERM);
#endif
- DBUG_PRINT("quit",("After pthread_kill"));
- shutdown_in_progress=1; // Safety if kill didn't work
-#ifdef SIGNALS_DONT_BREAK_READ
+ DBUG_PRINT("quit",("After pthread_kill"));
+ shutdown_in_progress=1; // Safety if kill didn't work
+#ifdef SIGNALS_DONT_BREAK_READ
+ if (!abort_loop)
+ {
+ pthread_t tmp;
abort_loop=1;
+ if (pthread_create(&tmp,&connection_attrib, kill_server_thread,
+ (void*) 0))
+ sql_print_error("Error: Can't create thread to kill server");
+ }
#endif
- DBUG_VOID_RETURN;
+ DBUG_VOID_RETURN;
}
@@ -677,7 +693,7 @@ static void __cdecl kill_server(int sig_ptr)
#ifdef USE_ONE_SIGNAL_HAND
-pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
+static pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
{
my_thread_init(); // Initialize new thread
kill_server(0);
@@ -730,9 +746,11 @@ void clean_up(bool print_message)
DBUG_PRINT("exit",("clean_up"));
if (cleanup_done++)
return; /* purecov: inspected */
+ if (use_slave_mask)
+ bitmap_free(&slave_error_mask);
acl_free(1);
grant_free();
- sql_cache_free();
+ query_cache.destroy();
table_cache_free();
hostname_cache_free();
item_user_lock_free();
@@ -1471,7 +1489,7 @@ static void *signal_hand(void *arg __attribute__((unused)))
(void*) sig))
sql_print_error("Error: Can't create thread to kill server");
#else
- kill_server((void*) sig); // MIT THREAD has a alarm thread
+ kill_server((void*) sig); // MIT THREAD has a alarm thread
#endif
}
break;
@@ -1549,8 +1567,9 @@ pthread_handler_decl(handle_shutdown,arg)
/* this call should create the message queue for this thread */
PeekMessage(&msg, NULL, 1, 65534,PM_NOREMOVE);
-
+#if !defined(EMBEDDED_LIBRARY)
if (WaitForSingleObject(hEventShutdown,INFINITE)==WAIT_OBJECT_0)
+#endif
kill_server(MYSQL_KILL_SIGNAL);
return 0;
}
@@ -1745,9 +1764,11 @@ int main(int argc, char **argv)
opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher);
DBUG_PRINT("info",("ssl_acceptor_fd: %p",ssl_acceptor_fd));
if (!ssl_acceptor_fd)
- opt_use_ssl=0;
- /* having ssl_acceptor_fd!=0 signals the use of SSL */
+ opt_use_ssl = 0;
+ /* having ssl_acceptor_fd != 0 signals the use of SSL */
}
+ if (des_key_file)
+ load_des_key_file(des_key_file);
#endif /* HAVE_OPENSSL */
#ifdef HAVE_LIBWRAP
@@ -1796,7 +1817,7 @@ int main(int argc, char **argv)
#endif
select_thread=pthread_self();
select_thread_in_use=1;
- if (use_temp_pool && bitmap_init(&temp_pool,1024))
+ if (use_temp_pool && bitmap_init(&temp_pool,1024,1))
unireg_abort(1);
/*
@@ -1812,12 +1833,13 @@ int main(int argc, char **argv)
server_init();
table_cache_init();
hostname_cache_init();
- sql_cache_init();
+ query_cache.result_size_limit(query_cache_limit);
+ query_cache.resize(query_cache_size);
randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
reset_floating_point_exceptions();
init_thr_lock();
init_slave_list();
-
+
/* Setup log files */
if (opt_log)
open_log(&mysql_log, glob_hostname, opt_logname, ".log", LOG_NORMAL);
@@ -1928,7 +1950,7 @@ The server will not act as a slave.");
}
if (!opt_noacl)
(void) grant_init();
- if (max_user_connections)
+ if (max_user_connections || mqh_used)
init_max_user_conn();
#ifdef HAVE_DLOPEN
@@ -1951,7 +1973,7 @@ The server will not act as a slave.");
}
}
(void) thr_setconcurrency(concurrency); // 10 by default
-#ifdef __WIN__ //IRENA
+#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) //IRENA
{
hEventShutdown=CreateEvent(0, FALSE, FALSE, "MySqlShutdown");
pthread_t hThread;
@@ -2048,6 +2070,7 @@ The server will not act as a slave.");
sql_print_error("After lock_thread_count");
#endif
#else
+#if !defined(EMBEDDED_LIBRARY)
if (Service.IsNT())
{
if(start_mode)
@@ -2067,13 +2090,14 @@ The server will not act as a slave.");
if(hEventShutdown) CloseHandle(hEventShutdown);
}
#endif
+#endif
#ifdef HAVE_OPENSSL
my_free((gptr)ssl_acceptor_fd,MYF(MY_ALLOW_ZERO_PTR));
#endif /* HAVE_OPENSSL */
/* Wait until cleanup is done */
(void) pthread_mutex_lock(&LOCK_thread_count);
DBUG_PRINT("quit", ("Got thread_count mutex for clean up wait"));
-
+
while (!ready_to_exit)
{
DBUG_PRINT("quit", ("not yet ready to exit"));
@@ -2087,7 +2111,7 @@ The server will not act as a slave.");
}
-#ifdef __WIN__
+#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
/* ------------------------------------------------------------------------
main and thread entry function for Win32
(all this is needed only to run mysqld as a service on WinNT)
@@ -2273,7 +2297,7 @@ static void create_new_thread(THD *thd)
(void) pthread_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN;
}
-
+
(void) pthread_mutex_unlock(&LOCK_thread_count);
}
}
@@ -2422,18 +2446,21 @@ pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
fromhost(&req);
if (!hosts_access(&req))
{
- // This may be stupid but refuse() includes an exit(0)
- // which we surely don't want...
- // clean_exit() - same stupid thing ...
+ /*
+ This may be stupid but refuse() includes an exit(0)
+ which we surely don't want...
+ clean_exit() - same stupid thing ...
+ */
syslog(deny_severity, "refused connect from %s", eval_client(&req));
if (req.sink)
((void (*)(int))req.sink)(req.fd);
- // C++ sucks (the gibberish in front just translates the supplied
- // sink function pointer in the req structure from a void (*sink)();
- // to a void(*sink)(int) if you omit the cast, the C++ compiler
- // will cry...
-
+ /*
+ C++ sucks (the gibberish in front just translates the supplied
+ sink function pointer in the req structure from a void (*sink)();
+ to a void(*sink)(int) if you omit the cast, the C++ compiler
+ will cry...
+ */
(void) shutdown(new_sock,2); // This looks fine to me...
(void) closesocket(new_sock);
continue;
@@ -2461,7 +2488,8 @@ pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
if (!(thd= new THD))
{
- (void) shutdown(new_sock,2); VOID(closesocket(new_sock));
+ (void) shutdown(new_sock,2);
+ VOID(closesocket(new_sock));
continue;
}
if (!(vio_tmp=vio_new(new_sock,
@@ -2646,7 +2674,8 @@ enum options {
OPT_SHOW_SLAVE_AUTH_INFO, OPT_OLD_RPL_COMPAT,
OPT_SLAVE_LOAD_TMPDIR, OPT_NO_MIX_TYPE,
OPT_RPL_RECOVERY_RANK,OPT_INIT_RPL_ROLE,
- OPT_RELAY_LOG, OPT_RELAY_LOG_INDEX, OPT_RELAY_LOG_INFO_FILE
+ OPT_RELAY_LOG, OPT_RELAY_LOG_INDEX, OPT_RELAY_LOG_INFO_FILE,
+ OPT_SLAVE_SKIP_ERRORS, OPT_DES_KEY_FILE
};
static struct option long_options[] = {
@@ -2674,6 +2703,7 @@ static struct option long_options[] = {
{"character-sets-dir", required_argument, 0, (int) OPT_CHARSETS_DIR},
{"datadir", required_argument, 0, 'h'},
{"debug", optional_argument, 0, '#'},
+ {"des-key-file", required_argument, 0, (int) OPT_DES_KEY_FILE},
{"default-character-set", required_argument, 0, 'C'},
{"default-table-type", required_argument, 0, (int) OPT_TABLE_TYPE},
{"delay-key-write-for-all-tables",
@@ -2799,6 +2829,8 @@ static struct option long_options[] = {
{"relay-log-info-file", required_argument, 0,
(int) OPT_RELAY_LOG_INFO_FILE},
{"slave-load-tmpdir", required_argument, 0, (int) OPT_SLAVE_LOAD_TMPDIR},
+ {"slave-skip-errors", required_argument, 0,
+ (int) OPT_SLAVE_SKIP_ERRORS},
{"socket", required_argument, 0, (int) OPT_SOCKET},
{"sql-bin-update-same", no_argument, 0, (int) OPT_SQL_BIN_UPDATE_SAME},
{"sql-mode", required_argument, 0, (int) OPT_SQL_MODE},
@@ -2871,9 +2903,9 @@ CHANGEABLE_VAR changeable_vars[] = {
(long*) &innobase_additional_mem_pool_size, 1*1024*1024L, 512*1024L,
~0L, 0, 1024},
{"innodb_file_io_threads",
- (long*) &innobase_file_io_threads, 9, 4, 64, 0, 1},
+ (long*) &innobase_file_io_threads, 4, 4, 64, 0, 1},
{"innodb_lock_wait_timeout",
- (long*) &innobase_lock_wait_timeout, 1024 * 1024 * 1024, 1,
+ (long*) &innobase_lock_wait_timeout, 50, 1,
1024 * 1024 * 1024, 0, 1},
{"innodb_thread_concurrency",
(long*) &innobase_thread_concurrency, 8, 1, 1000, 0, 1},
@@ -2915,7 +2947,7 @@ CHANGEABLE_VAR changeable_vars[] = {
{ "max_write_lock_count", (long*) &max_write_lock_count,
~0L, 1, ~0L, 0, 1 },
{ "myisam_bulk_insert_tree_size", (long*) &myisam_bulk_insert_tree_size,
- 8192*1024, 4, ~0L, 0, 1 },
+ 8192*1024, 0, ~0L, 0, 1 },
{ "myisam_block_size", (long*) &opt_myisam_block_size,
MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH, MI_MAX_KEY_BLOCK_LENGTH,
0, MI_MIN_KEY_BLOCK_LENGTH },
@@ -2938,6 +2970,12 @@ CHANGEABLE_VAR changeable_vars[] = {
0, 0, 65535, 0, 1},
{ "query_buffer_size", (long*) &query_buff_size,
0, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, IO_SIZE },
+ { "query_cache_limit", (long*) &query_cache_limit,
+ 1024*1024L, 0, ULONG_MAX, 0, 1},
+ { "query_cache_size", (long*) &query_cache_size,
+ 0, 0, ULONG_MAX, 0, 1},
+ { "query_cache_startup_type",(long*) &query_cache_startup_type,
+ 1, 0, 2, 0, 1},
{ "record_buffer", (long*) &my_default_record_cache_size,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE },
{ "record_rnd_buffer", (long*) &record_rnd_cache_size,
@@ -2992,7 +3030,7 @@ struct show_var_st init_vars[]= {
{"ft_min_word_len", (char*) &ft_min_word_len, SHOW_LONG},
{"ft_max_word_len", (char*) &ft_max_word_len, SHOW_LONG},
{"ft_max_word_len_for_sort",(char*) &ft_max_word_len_for_sort, SHOW_LONG},
- {"ft_boolean_syntax", ft_boolean_syntax, SHOW_CHAR},
+ {"ft_boolean_syntax", (char*) ft_boolean_syntax, SHOW_CHAR},
{"have_bdb", (char*) &have_berkeley_db, SHOW_HAVE},
{"have_innodb", (char*) &have_innodb, SHOW_HAVE},
{"have_isam", (char*) &have_isam, SHOW_HAVE},
@@ -3066,6 +3104,9 @@ struct show_var_st init_vars[]= {
{"record_rnd_buffer", (char*) &record_rnd_cache_size, SHOW_LONG},
{"rpl_recovery_rank", (char*) &rpl_recovery_rank, SHOW_LONG},
{"query_buffer_size", (char*) &query_buff_size, SHOW_LONG},
+ {"query_cache_limit", (char*) &query_cache.query_cache_limit, SHOW_LONG},
+ {"query_cache_size", (char*) &query_cache.query_cache_size, SHOW_LONG},
+ {"query_cache_startup_type",(char*) &query_cache_startup_type, SHOW_LONG},
{"safe_show_database", (char*) &opt_safe_show_db, SHOW_BOOL},
{"server_id", (char*) &server_id, SHOW_LONG},
{"slave_net_timeout", (char*) &slave_net_timeout, SHOW_LONG},
@@ -3099,6 +3140,71 @@ struct show_var_st status_vars[]= {
{"Aborted_connects", (char*) &aborted_connects, SHOW_LONG},
{"Bytes_received", (char*) &bytes_received, SHOW_LONG},
{"Bytes_sent", (char*) &bytes_sent, SHOW_LONG},
+ {"Com_admin_commands", (char*) &com_other, SHOW_LONG},
+ {"Com_alter_table", (char*) (com_stat+(uint) SQLCOM_ALTER_TABLE),SHOW_LONG},
+ {"Com_analyze", (char*) (com_stat+(uint) SQLCOM_ANALYZE),SHOW_LONG},
+ {"Com_backup_table", (char*) (com_stat+(uint) SQLCOM_BACKUP_TABLE),SHOW_LONG},
+ {"Com_begin", (char*) (com_stat+(uint) SQLCOM_BEGIN),SHOW_LONG},
+ {"Com_change_db", (char*) (com_stat+(uint) SQLCOM_CHANGE_DB),SHOW_LONG},
+ {"Com_change_master", (char*) (com_stat+(uint) SQLCOM_CHANGE_MASTER),SHOW_LONG},
+ {"Com_check", (char*) (com_stat+(uint) SQLCOM_CHECK),SHOW_LONG},
+ {"Com_commit", (char*) (com_stat+(uint) SQLCOM_COMMIT),SHOW_LONG},
+ {"Com_create_db", (char*) (com_stat+(uint) SQLCOM_CREATE_DB),SHOW_LONG},
+ {"Com_create_function", (char*) (com_stat+(uint) SQLCOM_CREATE_FUNCTION),SHOW_LONG},
+ {"Com_create_index", (char*) (com_stat+(uint) SQLCOM_CREATE_INDEX),SHOW_LONG},
+ {"Com_create_table", (char*) (com_stat+(uint) SQLCOM_CREATE_TABLE),SHOW_LONG},
+ {"Com_delete", (char*) (com_stat+(uint) SQLCOM_DELETE),SHOW_LONG},
+ {"Com_delete_multi", (char*) (com_stat+(uint) SQLCOM_DELETE_MULTI),SHOW_LONG},
+ {"Com_drop_db", (char*) (com_stat+(uint) SQLCOM_DROP_DB),SHOW_LONG},
+ {"Com_drop_function", (char*) (com_stat+(uint) SQLCOM_DROP_FUNCTION),SHOW_LONG},
+ {"Com_drop_index", (char*) (com_stat+(uint) SQLCOM_DROP_INDEX),SHOW_LONG},
+ {"Com_drop_table", (char*) (com_stat+(uint) SQLCOM_DROP_TABLE),SHOW_LONG},
+ {"Com_flush", (char*) (com_stat+(uint) SQLCOM_FLUSH),SHOW_LONG},
+ {"Com_grant", (char*) (com_stat+(uint) SQLCOM_GRANT),SHOW_LONG},
+ {"Com_ha_close", (char*) (com_stat+(uint) SQLCOM_HA_CLOSE),SHOW_LONG},
+ {"Com_ha_open", (char*) (com_stat+(uint) SQLCOM_HA_OPEN),SHOW_LONG},
+ {"Com_ha_read", (char*) (com_stat+(uint) SQLCOM_HA_READ),SHOW_LONG},
+ {"Com_insert", (char*) (com_stat+(uint) SQLCOM_INSERT),SHOW_LONG},
+ {"Com_insert_select", (char*) (com_stat+(uint) SQLCOM_INSERT_SELECT),SHOW_LONG},
+ {"Com_kill", (char*) (com_stat+(uint) SQLCOM_KILL),SHOW_LONG},
+ {"Com_load", (char*) (com_stat+(uint) SQLCOM_LOAD),SHOW_LONG},
+ {"Com_load_master_data", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_DATA),SHOW_LONG},
+ {"Com_load_master_table", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_TABLE),SHOW_LONG},
+ {"Com_lock_tables", (char*) (com_stat+(uint) SQLCOM_LOCK_TABLES),SHOW_LONG},
+ {"Com_optimize", (char*) (com_stat+(uint) SQLCOM_OPTIMIZE),SHOW_LONG},
+ {"Com_purge", (char*) (com_stat+(uint) SQLCOM_PURGE),SHOW_LONG},
+ {"Com_rename_table", (char*) (com_stat+(uint) SQLCOM_RENAME_TABLE),SHOW_LONG},
+ {"Com_repair", (char*) (com_stat+(uint) SQLCOM_REPAIR),SHOW_LONG},
+ {"Com_replace", (char*) (com_stat+(uint) SQLCOM_REPLACE),SHOW_LONG},
+ {"Com_replace_select", (char*) (com_stat+(uint) SQLCOM_REPLACE_SELECT),SHOW_LONG},
+ {"Com_reset", (char*) (com_stat+(uint) SQLCOM_RESET),SHOW_LONG},
+ {"Com_restore_table", (char*) (com_stat+(uint) SQLCOM_RESTORE_TABLE),SHOW_LONG},
+ {"Com_revoke", (char*) (com_stat+(uint) SQLCOM_REVOKE),SHOW_LONG},
+ {"Com_rollback", (char*) (com_stat+(uint) SQLCOM_ROLLBACK),SHOW_LONG},
+ {"Com_select", (char*) (com_stat+(uint) SQLCOM_SELECT),SHOW_LONG},
+ {"Com_set_option", (char*) (com_stat+(uint) SQLCOM_SET_OPTION),SHOW_LONG},
+ {"Com_show_binlog_events", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOG_EVENTS),SHOW_LONG},
+ {"Com_show_binlogs", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOGS),SHOW_LONG},
+ {"Com_show_create", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE),SHOW_LONG},
+ {"Com_show_databases", (char*) (com_stat+(uint) SQLCOM_SHOW_DATABASES),SHOW_LONG},
+ {"Com_show_fields", (char*) (com_stat+(uint) SQLCOM_SHOW_FIELDS),SHOW_LONG},
+ {"Com_show_grants", (char*) (com_stat+(uint) SQLCOM_SHOW_GRANTS),SHOW_LONG},
+ {"Com_show_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG},
+ {"Com_show_logs", (char*) (com_stat+(uint) SQLCOM_SHOW_LOGS),SHOW_LONG},
+ {"Com_show_master_stat", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG},
+ {"Com_show_new_master", (char*) (com_stat+(uint) SQLCOM_SHOW_NEW_MASTER),SHOW_LONG},
+ {"Com_show_open_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_OPEN_TABLES),SHOW_LONG},
+ {"Com_show_processlist", (char*) (com_stat+(uint) SQLCOM_SHOW_PROCESSLIST),SHOW_LONG},
+ {"Com_show_slave_hosts", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_HOSTS),SHOW_LONG},
+ {"Com_show_slave_stat", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG},
+ {"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG},
+ {"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG},
+ {"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG},
+ {"Com_slave_start", (char*) (com_stat+(uint) SQLCOM_SLAVE_START),SHOW_LONG},
+ {"Com_slave_stop", (char*) (com_stat+(uint) SQLCOM_SLAVE_STOP),SHOW_LONG},
+ {"Com_truncate", (char*) (com_stat+(uint) SQLCOM_TRUNCATE),SHOW_LONG},
+ {"Com_unlock_tables", (char*) (com_stat+(uint) SQLCOM_UNLOCK_TABLES),SHOW_LONG},
+ {"Com_update", (char*) (com_stat+(uint) SQLCOM_UPDATE),SHOW_LONG},
{"Connections", (char*) &thread_id, SHOW_LONG_CONST},
{"Created_tmp_disk_tables", (char*) &created_tmp_disk_tables,SHOW_LONG},
{"Created_tmp_tables", (char*) &created_tmp_tables, SHOW_LONG},
@@ -3129,8 +3235,17 @@ struct show_var_st status_vars[]= {
{"Open_streams", (char*) &my_stream_opened, SHOW_INT_CONST},
{"Opened_tables", (char*) &opened_tables, SHOW_LONG},
{"Questions", (char*) 0, SHOW_QUESTION},
- {"Rpl_status", (char*) 0,
- SHOW_RPL_STATUS},
+ {"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_CONST},
+ {"Qcache_inserts", (char*) &query_cache.inserts, SHOW_LONG},
+ {"Qcache_hits", (char*) &query_cache.hits, SHOW_LONG},
+ {"Qcache_not_cached", (char*) &query_cache.refused, SHOW_LONG},
+ {"Qcache_free_memory", (char*) &query_cache.free_memory,
+ SHOW_LONG_CONST},
+ {"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks,
+ SHOW_LONG_CONST},
+ {"Qcache_total_blocks", (char*) &query_cache.total_blocks,
+ SHOW_LONG_CONST},
+ {"Rpl_status", (char*) 0, SHOW_RPL_STATUS},
{"Select_full_join", (char*) &select_full_join_count, SHOW_LONG},
{"Select_full_range_join", (char*) &select_full_range_join_count, SHOW_LONG},
{"Select_range", (char*) &select_range_count, SHOW_LONG},
@@ -3145,29 +3260,29 @@ struct show_var_st status_vars[]= {
{"Sort_rows", (char*) &filesort_rows, SHOW_LONG},
{"Sort_scan", (char*) &filesort_scan_count, SHOW_LONG},
#ifdef HAVE_OPENSSL
- {"ssl_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT},
- {"ssl_finished_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_GOOD},
- {"ssl_finished_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_GOOD},
- {"ssl_accept_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE},
- {"ssl_connect_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE},
- {"ssl_callback_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_CB_HITS},
- {"ssl_session_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_HITS},
- {"ssl_session_cache_misses", (char*) 0, SHOW_SSL_CTX_SESS_MISSES},
- {"ssl_session_cache_timeouts", (char*) 0, SHOW_SSL_CTX_SESS_TIMEOUTS},
- {"ssl_used_session_cache_entries",(char*) 0, SHOW_SSL_CTX_SESS_NUMBER},
- {"ssl_client_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT},
- {"ssl_session_cache_overflows", (char*) 0, SHOW_SSL_CTX_SESS_CACHE_FULL},
- {"ssl_session_cache_size", (char*) 0, SHOW_SSL_CTX_SESS_GET_CACHE_SIZE},
- {"ssl_session_cache_mode", (char*) 0, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE},
- {"ssl_sessions_reused", (char*) 0, SHOW_SSL_SESSION_REUSED},
- {"ssl_ctx_verify_mode", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_MODE},
- {"ssl_ctx_verify_depth", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_DEPTH},
- {"ssl_verify_mode", (char*) 0, SHOW_SSL_GET_VERIFY_MODE},
- {"ssl_verify_depth", (char*) 0, SHOW_SSL_GET_VERIFY_DEPTH},
- {"ssl_version", (char*) 0, SHOW_SSL_GET_VERSION},
- {"ssl_cipher", (char*) 0, SHOW_SSL_GET_CIPHER},
- {"ssl_cipher_list", (char*) 0, SHOW_SSL_GET_CIPHER_LIST},
- {"ssl_default_timeout", (char*) 0, SHOW_SSL_GET_DEFAULT_TIMEOUT},
+ {"ssl_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT},
+ {"ssl_finished_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_GOOD},
+ {"ssl_finished_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_GOOD},
+ {"ssl_accept_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE},
+ {"ssl_connect_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE},
+ {"ssl_callback_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_CB_HITS},
+ {"ssl_session_cache_hits", (char*) 0, SHOW_SSL_CTX_SESS_HITS},
+ {"ssl_session_cache_misses", (char*) 0, SHOW_SSL_CTX_SESS_MISSES},
+ {"ssl_session_cache_timeouts", (char*) 0, SHOW_SSL_CTX_SESS_TIMEOUTS},
+ {"ssl_used_session_cache_entries",(char*) 0, SHOW_SSL_CTX_SESS_NUMBER},
+ {"ssl_client_connects", (char*) 0, SHOW_SSL_CTX_SESS_CONNECT},
+ {"ssl_session_cache_overflows", (char*) 0, SHOW_SSL_CTX_SESS_CACHE_FULL},
+ {"ssl_session_cache_size", (char*) 0, SHOW_SSL_CTX_SESS_GET_CACHE_SIZE},
+ {"ssl_session_cache_mode", (char*) 0, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE},
+ {"ssl_sessions_reused", (char*) 0, SHOW_SSL_SESSION_REUSED},
+ {"ssl_ctx_verify_mode", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_MODE},
+ {"ssl_ctx_verify_depth", (char*) 0, SHOW_SSL_CTX_GET_VERIFY_DEPTH},
+ {"ssl_verify_mode", (char*) 0, SHOW_SSL_GET_VERIFY_MODE},
+ {"ssl_verify_depth", (char*) 0, SHOW_SSL_GET_VERIFY_DEPTH},
+ {"ssl_version", (char*) 0, SHOW_SSL_GET_VERSION},
+ {"ssl_cipher", (char*) 0, SHOW_SSL_GET_CIPHER},
+ {"ssl_cipher_list", (char*) 0, SHOW_SSL_GET_CIPHER_LIST},
+ {"ssl_default_timeout", (char*) 0, SHOW_SSL_GET_DEFAULT_TIMEOUT},
#endif /* HAVE_OPENSSL */
{"Table_locks_immediate", (char*) &locks_immediate, SHOW_LONG},
{"Table_locks_waited", (char*) &locks_waited, SHOW_LONG},
@@ -3189,7 +3304,7 @@ static void use_help(void)
{
print_version();
printf("Use '--help' or '--no-defaults --help' for a list of available options\n");
-}
+}
static void usage(void)
{
@@ -3228,7 +3343,13 @@ static void usage(void)
Set the default table type for tables\n\
--delay-key-write-for-all-tables\n\
Don't flush key buffers between writes for any MyISAM\n\
- table\n\
+ table\n");
+#ifdef HAVE_OPENSSL
+ puts("\
+ --des-key-file Load keys for des_encrypt() and des_encrypt\n\
+ from given file");
+#endif /* HAVE_OPENSSL */
+ puts("\
--enable-locking Enable system locking\n\
--enable-pstack Print a symbolic stack trace on failure\n\
-T, --exit-info Used for debugging; Use at your own risk!\n\
@@ -3421,7 +3542,14 @@ static void get_options(int argc,char **argv)
int c,option_index=0;
myisam_delay_key_write=1; // Allow use of this
+#ifndef HAVE_purify
my_use_symdir=1; // Use internal symbolic links
+#else
+ /* Symlinks gives too many warnings with purify */
+ my_disable_symlinks=1;
+ my_use_symdir=0;
+ have_symlink=SHOW_OPTION_DISABLED;
+#endif
optind = 0; // setup in case getopt() was called previously
while ((c=getopt_long(argc,argv,"ab:C:h:#::T::?l::L:O:P:sS::t:u:noVvWI?",
@@ -3472,6 +3600,9 @@ static void get_options(int argc,char **argv)
case 'P':
mysql_port= (unsigned int) atoi(optarg);
break;
+ case OPT_SLAVE_SKIP_ERRORS:
+ init_slave_skip_errors(optarg);
+ break;
case OPT_SAFEMALLOC_MEM_LIMIT:
#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
safemalloc_mem_limit = atoi(optarg);
@@ -3706,7 +3837,6 @@ static void get_options(int argc,char **argv)
break;
case (int) OPT_SKIP_NEW:
opt_specialflag|= SPECIAL_NO_NEW_FUNC;
- default_table_type=DB_TYPE_ISAM;
myisam_delay_key_write=0;
myisam_concurrent_insert=0;
myisam_recover_options= HA_RECOVER_NONE;
@@ -3714,6 +3844,7 @@ static void get_options(int argc,char **argv)
my_use_symdir=0;
have_symlink=SHOW_OPTION_DISABLED;
ha_open_options&= ~HA_OPEN_ABORT_IF_CRASHED;
+ query_cache_size=0;
break;
case (int) OPT_SAFE:
opt_specialflag|= SPECIAL_SAFE_MODE;
@@ -3863,6 +3994,11 @@ static void get_options(int argc,char **argv)
charsets_dir = mysql_charsets_dir;
break;
#include "sslopt-case.h"
+ case OPT_DES_KEY_FILE:
+#ifdef HAVE_OPENSSL
+ des_key_file=optarg;
+#endif
+ break;
case OPT_TX_ISOLATION:
{
int type;
@@ -3944,6 +4080,7 @@ static void get_options(int argc,char **argv)
break;
case OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT:
innobase_flush_log_at_trx_commit= optarg ? test(atoi(optarg)) : 1;
+ break;
case OPT_INNODB_FAST_SHUTDOWN:
innobase_fast_shutdown= optarg ? test(atoi(optarg)) : 1;
break;
@@ -4168,16 +4305,17 @@ static uint set_maximum_open_files(uint max_file_limit)
rlimit.rlim_cur=rlimit.rlim_max=max_file_limit;
if (setrlimit(RLIMIT_NOFILE,&rlimit))
{
- sql_print_error("Warning: setrlimit couldn't increase number of open files to more than %ld",
- old_cur); /* purecov: inspected */
+ sql_print_error("Warning: setrlimit couldn't increase number of open files to more than %lu (request: %u)",
+ old_cur, max_file_limit); /* purecov: inspected */
max_file_limit=old_cur;
}
else
{
(void) getrlimit(RLIMIT_NOFILE,&rlimit);
if ((uint) rlimit.rlim_cur != max_file_limit)
- sql_print_error("Warning: setrlimit returned ok, but didn't change limits. Max open files is %ld",
- (ulong) rlimit.rlim_cur); /* purecov: inspected */
+ sql_print_error("Warning: setrlimit returned ok, but didn't change limits. Max open files is %ld (request: %u)",
+ (ulong) rlimit.rlim_cur,
+ max_file_limit); /* purecov: inspected */
max_file_limit=rlimit.rlim_cur;
}
}
diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc
index 0b50b34c7bd..64c1b07a493 100644
--- a/sql/net_pkg.cc
+++ b/sql/net_pkg.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -30,6 +30,7 @@ void send_error(NET *net, uint sql_errno, const char *err)
err ? err : net->last_error[0] ?
net->last_error : "NULL"));
+ query_cache_abort(net);
if (thd)
thd->query_error = 1; // needed to catch query errors during replication
if (!err)
@@ -51,6 +52,7 @@ void send_error(NET *net, uint sql_errno, const char *err)
{
if (thd && thd->bootstrap)
{
+ /* In bootstrap it's ok to print on stderr */
fprintf(stderr,"ERROR: %d %s\n",sql_errno,err);
}
DBUG_VOID_RETURN;
@@ -102,9 +104,9 @@ net_printf(NET *net, uint errcode, ...)
DBUG_ENTER("net_printf");
DBUG_PRINT("enter",("message: %u",errcode));
- if(thd) thd->query_error = 1;
- // if we are here, something is wrong :-)
-
+ if (thd)
+ thd->query_error = 1; // if we are here, something is wrong :-)
+ query_cache_abort(net); // Safety
va_start(args,errcode);
format=ER(errcode);
offset= net->return_errno ? 2 : 0;
@@ -119,6 +121,7 @@ net_printf(NET *net, uint errcode, ...)
{
if (thd && thd->bootstrap)
{
+ /* In bootstrap it's ok to print on stderr */
fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos);
thd->fatal_error=1;
}
@@ -142,7 +145,7 @@ send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message)
{
if (net->no_send_ok) // hack for re-parsing queries
return;
-
+
char buff[MYSQL_ERRMSG_SIZE+10],*pos;
DBUG_ENTER("send_ok");
buff[0]=0; // No fields
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 5e002a0f63e..7a1d25e980d 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000 MySQL AB
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library 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 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 library is distributed in the hope that it will be useful,
+ 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
- Library General Public License for more details.
+ 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 Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA */
+ 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 */
/* Write and read of logical packets to/from socket
** Writes are cached into net_buffer_length big packets.
@@ -42,73 +41,61 @@
#include <signal.h>
#include <errno.h>
+/*
+ The following handles the differences when this is linked between the
+ client and the server.
+
+ This gives an error if a too big packet is found
+ The server can change this with the -O switch, but because the client
+ can't normally do this the client should have a bigger max_allowed_packet.
+*/
+
#ifdef MYSQL_SERVER
ulong max_allowed_packet=65536;
extern ulong net_read_timeout,net_write_timeout;
extern uint test_flags;
+#define USE_QUERY_CACHE
+extern void query_cache_insert(NET *net, const char *packet, ulong length);
#else
-
-/*
-** Give error if a too big packet is found
-** The server can change this with the -O switch, but because the client
-** can't normally do this the client should have a bigger max_allowed_packet.
-*/
-
-ulong max_allowed_packet=~0L;
+ulong max_allowed_packet=16*1024*1024L;
ulong net_read_timeout= NET_READ_TIMEOUT;
ulong net_write_timeout= NET_WRITE_TIMEOUT;
#endif
-ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
-#if defined(__WIN__) || defined(MSDOS)
-#undef MYSQL_SERVER /* Win32 can't handle interrupts */
+#if defined(__WIN__) || !defined(MYSQL_SERVER)
+ /* The following is because alarms doesn't work on windows. */
+#define NO_ALARM
#endif
-#ifdef MYSQL_SERVER
+
+#ifndef NO_ALARM
#include "my_pthread.h"
-#include "thr_alarm.h"
void sql_print_error(const char *format,...);
#define RETRY_COUNT mysqld_net_retry_count
extern ulong mysqld_net_retry_count;
-#else
-
-#ifdef OS2 /* avoid name conflict */
-#define thr_alarm_t thr_alarm_t_net
-#define ALARM ALARM_net
-#endif
-
-typedef my_bool thr_alarm_t;
-typedef my_bool ALARM;
-#define thr_alarm_init(A) (*(A))=0
-#define thr_alarm_in_use(A) (*(A) != 0)
-#define thr_end_alarm(A)
-#define thr_alarm(A,B,C) local_thr_alarm((A),(B),(C))
-inline int local_thr_alarm(my_bool *A,int B __attribute__((unused)),ALARM *C __attribute__((unused)))
-{
- *A=1;
- return 0;
-}
-#define thr_got_alarm(A) 0
-#define RETRY_COUNT 1
-#endif
-
-#ifdef MYSQL_SERVER
extern ulong bytes_sent, bytes_received;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
#else
#undef statistic_add
#define statistic_add(A,B,C)
-#endif
+#define DONT_USE_THR_ALARM
+#define RETRY_COUNT 1
+#endif /* NO_ALARM */
+
+#include "thr_alarm.h"
#define TEST_BLOCKING 8
+#define MAX_THREE_BYTES 255L*255L*255L
+
+ulong net_buffer_length=8192; /* Default length. Enlarged if necessary */
+
static int net_write_buff(NET *net,const char *packet,ulong len);
-#define MAX_THREE_BYTES 255L*255L*255L
/* Init with packet info */
int my_net_init(NET *net, Vio* vio)
{
- if (!(net->buff=(uchar*) my_malloc(net_buffer_length+
+ if (!(net->buff=(uchar*) my_malloc((uint32) net_buffer_length+
NET_HEADER_SIZE + COMP_HEADER_SIZE,
MYF(MY_WME))))
return 1;
@@ -125,6 +112,7 @@ int my_net_init(NET *net, Vio* vio)
net->compress=0; net->reading_or_writing=0;
net->where_b = net->remain_in_buf=0;
net->last_errno=0;
+ net->query_cache_query=0;
if (vio != 0) /* If real connection */
{
@@ -160,7 +148,7 @@ static my_bool net_realloc(NET *net, ulong length)
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
/* We must allocate some extra bytes for the end 0 and to be able to
read big compressed blocks */
- if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length +
+ if (!(buff=(uchar*) my_realloc((char*) net->buff, (uint32) pkt_length +
NET_HEADER_SIZE + COMP_HEADER_SIZE,
MYF(MY_WME))))
{
@@ -179,7 +167,7 @@ static my_bool net_realloc(NET *net, ulong length)
void net_clear(NET *net)
{
-#ifndef EXTRA_DEBUG
+#if !defined(EXTRA_DEBUG) && !defined(EMBEDDED_LIBRARY)
int count; /* One may get 'unused' warn */
bool is_blocking=vio_is_blocking(net->vio);
if (is_blocking)
@@ -187,7 +175,7 @@ void net_clear(NET *net)
if (!vio_is_blocking(net->vio)) /* Safety if SSL */
{
while ( (count = vio_read(net->vio, (char*) (net->buff),
- net->max_packet)) > 0)
+ (uint32) net->max_packet)) > 0)
DBUG_PRINT("info",("skipped %d bytes from file: %s",
count,vio_description(net->vio)));
if (is_blocking)
@@ -241,7 +229,7 @@ my_net_write(NET *net,const char *packet,ulong len)
{
const ulong z_size = MAX_THREE_BYTES;
int3store(buff, z_size);
- buff[3]= net->pkt_nr++;
+ buff[3]= (uchar) net->pkt_nr++;
if (net_write_buff(net, (char*) buff, NET_HEADER_SIZE) ||
net_write_buff(net, packet, z_size))
return 1;
@@ -250,7 +238,7 @@ my_net_write(NET *net,const char *packet,ulong len)
}
/* Write last packet */
int3store(buff,len);
- buff[3]= net->pkt_nr++;
+ buff[3]= (uchar) net->pkt_nr++;
if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE))
return 1;
return net_write_buff(net,packet,len);
@@ -280,7 +268,7 @@ net_write_command(NET *net,uchar command,const char *packet,ulong len)
do
{
int3store(buff, MAX_THREE_BYTES);
- buff[3]= net->pkt_nr++;
+ buff[3]= (uchar) net->pkt_nr++;
if (net_write_buff(net,(char*) buff, header_size) ||
net_write_buff(net,packet,len))
return 1;
@@ -292,7 +280,7 @@ net_write_command(NET *net,uchar command,const char *packet,ulong len)
len=length; /* Data left to be written */
}
int3store(buff,length);
- buff[3]= net->pkt_nr++;
+ buff[3]= (uchar) net->pkt_nr++;
return test(net_write_buff(net,(char*) buff,header_size) ||
net_write_buff(net,packet,len) || net_flush(net));
}
@@ -334,13 +322,18 @@ net_real_write(NET *net,const char *packet,ulong len)
long int length;
char *pos,*end;
thr_alarm_t alarmed;
-#if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2)
+#ifndef NO_ALARM
ALARM alarm_buff;
#endif
uint retry_count=0;
my_bool net_blocking = vio_is_blocking(net->vio);
DBUG_ENTER("net_real_write");
+#ifdef MYSQL_SERVER
+ if (net->query_cache_query != 0)
+ query_cache_insert(net, packet, len);
+#endif
+
if (net->error == 2)
DBUG_RETURN(-1); /* socket can't be used */
@@ -351,8 +344,8 @@ net_real_write(NET *net,const char *packet,ulong len)
ulong complen;
uchar *b;
uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE;
- if (!(b=(uchar*) my_malloc(len + NET_HEADER_SIZE + COMP_HEADER_SIZE,
- MYF(MY_WME))))
+ if (!(b=(uchar*) my_malloc((uint32) len + NET_HEADER_SIZE +
+ COMP_HEADER_SIZE, MYF(MY_WME))))
{
#ifdef MYSQL_SERVER
net->last_errno=ER_OUT_OF_RESOURCES;
@@ -378,18 +371,18 @@ net_real_write(NET *net,const char *packet,ulong len)
#endif /* HAVE_COMPRESS */
/* DBUG_DUMP("net",packet,len); */
-#ifdef MYSQL_SERVER
+#ifndef NO_ALARM
thr_alarm_init(&alarmed);
if (net_blocking)
thr_alarm(&alarmed,(uint) net_write_timeout,&alarm_buff);
#else
alarmed=0;
-#endif /* MYSQL_SERVER */
+#endif /* NO_ALARM */
pos=(char*) packet; end=pos+len;
while (pos != end)
{
- if ((long) (length=vio_write(net->vio,pos,(ulong) (end-pos))) <= 0)
+ if ((long) (length=vio_write(net->vio,pos,(uint32) (end-pos))) <= 0)
{
my_bool interrupted = vio_should_retry(net->vio);
#if (!defined(__WIN__) && !defined(__EMX__) && !defined(OS2))
@@ -466,14 +459,13 @@ net_real_write(NET *net,const char *packet,ulong len)
** Read something from server/clinet
*****************************************************************************/
-#ifdef MYSQL_SERVER
-
+#ifndef NO_ALARM
/*
Help function to clear the commuication buffer when we get a too
big packet
*/
-static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
+static void my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed)
{
ALARM alarm_buff;
uint retry_count=0;
@@ -496,11 +488,11 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed)
}
return;
}
- remain -= length;
+ remain -= (uint32) length;
statistic_add(bytes_received,length,&LOCK_bytes_received);
}
}
-#endif /* MYSQL_SERVER */
+#endif /* NO_ALARM */
/*
@@ -517,20 +509,20 @@ my_real_read(NET *net, ulong *complen)
uint i,retry_count=0;
ulong len=packet_error;
thr_alarm_t alarmed;
-#if (!defined(__WIN__) && !defined(__EMX__) && !defined(OS2)) || defined(MYSQL_SERVER)
+#ifndef NO_ALARM
ALARM alarm_buff;
#endif
my_bool net_blocking=vio_is_blocking(net->vio);
- ulong remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
- NET_HEADER_SIZE);
+ uint32 remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
+ NET_HEADER_SIZE);
*complen = 0;
net->reading_or_writing=1;
thr_alarm_init(&alarmed);
-#ifdef MYSQL_SERVER
+#ifndef NO_ALARM
if (net_blocking)
thr_alarm(&alarmed,net->timeout,&alarm_buff);
-#endif /* MYSQL_SERVER */
+#endif /* NO_ALARM */
pos = net->buff + net->where_b; /* net->packet -4 */
for (i=0 ; i < 2 ; i++)
@@ -599,7 +591,7 @@ my_real_read(NET *net, ulong *complen)
continue;
}
#endif
- DBUG_PRINT("error",("Couldn't read packet: remain: %d errno: %d length: %d alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
+ DBUG_PRINT("error",("Couldn't read packet: remain: %lu errno: %d length: %ld alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
len= packet_error;
net->error=2; /* Close socket */
#ifdef MYSQL_SERVER
@@ -608,7 +600,7 @@ my_real_read(NET *net, ulong *complen)
#endif
goto end;
}
- remain -= (ulong) length;
+ remain -= (uint32) length;
pos+= (ulong) length;
statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
}
@@ -653,16 +645,16 @@ my_real_read(NET *net, ulong *complen)
{
if (net_realloc(net,helping))
{
-#ifdef MYSQL_SERVER
+#ifndef NO_ALARM
if (i == 1)
- my_net_skip_rest(net, len, &alarmed);
+ my_net_skip_rest(net, (uint32) len, &alarmed);
#endif
len= packet_error; /* Return error */
goto end;
}
}
pos=net->buff + net->where_b;
- remain = len;
+ remain = (uint32) len;
}
}
@@ -743,7 +735,7 @@ my_net_read(NET *net)
for (;;)
{
ulong packet_len;
-
+
if (buf_length - start_of_packet >= NET_HEADER_SIZE)
{
read_length = uint3korr(net->buff+start_of_packet);
@@ -770,7 +762,7 @@ my_net_read(NET *net)
if (read_length != MAX_THREE_BYTES) /* last package */
{
- multi_byte_packet= 0; // No last zero length packet
+ multi_byte_packet= 0; /* No last zero len packet */
break;
}
multi_byte_packet= NET_HEADER_SIZE;
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 07d1216a42f..83eb10235ea 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -48,9 +48,9 @@ class QUICK_RANGE :public Sql_alloc {
uint flag_arg)
: min_key((char*) sql_memdup(min_key_arg,min_length_arg+1)),
max_key((char*) sql_memdup(max_key_arg,max_length_arg+1)),
- min_length(min_length_arg),
- max_length(max_length_arg),
- flag(flag_arg)
+ min_length((uint16) min_length_arg),
+ max_length((uint16) max_length_arg),
+ flag((uint16) flag_arg)
{}
};
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 3dd13cbebb9..69fc5aa88ff 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/password.c b/sql/password.c
index 1db94e0db8a..48181ea18e6 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/procedure.cc b/sql/procedure.cc
index 526bbe0feab..437bd82d6e5 100644
--- a/sql/procedure.cc
+++ b/sql/procedure.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/procedure.h b/sql/procedure.h
index 1583f1169ce..db0e0b7f9e2 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/records.cc b/sql/records.cc
index 37f79e54cf6..f156fdaf406 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -86,6 +86,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
}
else if (table->record_pointers)
{
+ DBUG_PRINT("info",("using record_pointers"));
table->file->rnd_init(0);
info->cache_pos=table->record_pointers;
info->cache_end=info->cache_pos+ table->found_records*info->ref_length;
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 705ef58d0e7..eabba9c68fc 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -191,10 +191,12 @@ void init_slave_list()
void end_slave_list()
{
- pthread_mutex_lock(&LOCK_slave_list);
- hash_free(&slave_list);
- pthread_mutex_unlock(&LOCK_slave_list);
- pthread_mutex_destroy(&LOCK_slave_list);
+ /* No protection by a mutex needed as we are only called at shutdown */
+ if (hash_inited(&slave_list))
+ {
+ hash_free(&slave_list);
+ pthread_mutex_destroy(&LOCK_slave_list);
+ }
}
static int find_target_pos(LEX_MASTER_INFO* mi, IO_CACHE* log, char* errmsg)
@@ -256,7 +258,7 @@ int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
}
linfo.index_file_offset = 0;
-
+
search_file_name[0] = 0;
@@ -364,7 +366,7 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
int i;
bool slave_event_found = 0;
LINT_INIT(ev);
-
+
for (i = 0; i < 2; i++)
{
if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*)0, 0)))
@@ -436,7 +438,7 @@ int update_slave_list(MYSQL* mysql)
const char* error=0;
bool have_auth_info;
int port_ind;
-
+
if (mc_mysql_query(mysql,"SHOW SLAVE HOSTS",0) ||
!(res = mc_mysql_store_result(mysql)))
{
@@ -504,7 +506,7 @@ err:
int find_recovery_captain(THD* thd, MYSQL* mysql)
{
-
+
return 0;
}
@@ -849,7 +851,3 @@ err:
return error;
}
-
-
-
-
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 13923f0a637..091db4e4b39 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -58,7 +58,7 @@ class ACL_USER :public ACL_ACCESS
{
public:
acl_host_and_ip host;
- uint hostname_length;
+ uint hostname_length, questions, updates;
char *user,*password;
ulong salt[2];
#ifdef HAVE_OPENSSL
@@ -132,7 +132,8 @@ int acl_init(bool dont_read_acl_tables)
thd->mysys_var=my_thread_var;
thd->current_tablenr=0;
thd->open_tables=0;
- thd->db=my_strdup("mysql",MYF(0));
+ thd->db= my_strdup("mysql",MYF(0));
+ thd->db_length=5; // Safety
bzero((char*) &tables,sizeof(tables));
tables[0].name=tables[0].real_name=(char*) "host";
tables[1].name=tables[1].real_name=(char*) "user";
@@ -240,6 +241,15 @@ int acl_init(bool dont_read_acl_tables)
user.access=get_access(table,3);
user.sort=get_sort(2,user.host.hostname,user.user);
user.hostname_length=user.host.hostname ? (uint) strlen(user.host.hostname) : 0;
+ if (table->fields >=23)
+ {
+ char *ptr = get_field(&mem, table, 21);
+ user.questions=atoi(ptr);
+ ptr = get_field(&mem, table, 22);
+ user.updates=atoi(ptr);
+ if (user.questions)
+ mqh_used=true;
+ }
#ifndef TO_BE_REMOVED
if (table->fields <= 13)
{ // Without grant
@@ -423,7 +433,7 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
/* Get master privilges for user (priviliges for all tables). Required to connect */
uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *message,char **priv_user,
- bool old_ver)
+ bool old_ver, uint *max)
{
uint user_access=NO_ACCESS;
*priv_user=(char*) user;
@@ -536,6 +546,7 @@ uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
#else /* HAVE_OPENSSL */
user_access=acl_user->access;
#endif /* HAVE_OPENSSL */
+ *max=acl_user->questions;
if (!acl_user->user)
*priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
break;
@@ -569,6 +580,7 @@ static void acl_update_user(const char *user, const char *host,
const char *ssl_cipher,
const char *x509_issuer,
const char *x509_subject,
+ unsigned int mqh,
uint privileges)
{
for (uint i=0 ; i < acl_users.elements ; i++)
@@ -582,6 +594,7 @@ static void acl_update_user(const char *user, const char *host,
acl_user->host.hostname && !strcmp(host,acl_user->host.hostname))
{
acl_user->access=privileges;
+ acl_user->questions=mqh;
#ifdef HAVE_OPENSSL
acl_user->ssl_type=ssl_type;
acl_user->ssl_cipher=ssl_cipher;
@@ -611,6 +624,7 @@ static void acl_insert_user(const char *user, const char *host,
const char *ssl_cipher,
const char *x509_issuer,
const char *x509_subject,
+ unsigned int mqh,
uint privileges)
{
ACL_USER acl_user;
@@ -618,6 +632,7 @@ static void acl_insert_user(const char *user, const char *host,
update_hostname(&acl_user.host,strdup_root(&mem,host));
acl_user.password=0;
acl_user.access=privileges;
+ acl_user.questions=mqh;
acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
acl_user.hostname_length=(uint) strlen(acl_user.host.hostname);
#ifdef HAVE_OPENSSL
@@ -698,12 +713,17 @@ uint acl_get(const char *host, const char *ip, const char *bin_ip,
{
uint host_access,db_access,i,key_length;
db_access=0; host_access= ~0;
- char key[ACL_KEY_LENGTH],*end;
+ char key[ACL_KEY_LENGTH],*tmp_db,*end;
acl_entry *entry;
VOID(pthread_mutex_lock(&acl_cache->lock));
memcpy_fixed(&key,bin_ip,sizeof(struct in_addr));
- end=strmov(strmov(key+sizeof(struct in_addr),user)+1,db);
+ end=strmov((tmp_db=strmov(key+sizeof(struct in_addr),user)+1),db);
+ if (lower_case_table_names)
+ {
+ casedn_str(tmp_db);
+ db=tmp_db;
+ }
key_length=(uint) (end-key);
if ((entry=(acl_entry*) acl_cache->search(key,key_length)))
{
@@ -943,7 +963,7 @@ bool change_password(THD *thd, const char *host, const char *user,
VOID(pthread_mutex_unlock(&acl_cache->lock));
char buff[460];
-
+
Query_log_event qinfo(thd, buff);
qinfo.q_len =
my_sprintf(buff,
@@ -1201,6 +1221,13 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
}
}
#endif /* HAVE_OPENSSL */
+ if (table->fields>=23 && thd->lex.mqh)
+ {
+ char buff[33];
+ int len =int2str((long)thd->lex.mqh,buff,10) - buff;
+ table->field[21]->store(buff,len);
+ mqh_used=true;
+ }
if (old_row_exists)
{
/*
@@ -1239,6 +1266,7 @@ end:
thd->lex.ssl_cipher,
thd->lex.x509_issuer,
thd->lex.x509_subject,
+ thd->lex.mqh,
rights);
else
acl_insert_user(combo.user.str,combo.host.str,password,
@@ -1246,6 +1274,7 @@ end:
thd->lex.ssl_cipher,
thd->lex.x509_issuer,
thd->lex.x509_subject,
+ thd->lex.mqh,
rights);
}
table->file->index_end();
@@ -1377,6 +1406,11 @@ public:
db = strdup_root(&memex,d);
user = strdup_root(&memex,u);
tname= strdup_root(&memex,t);
+ if (lower_case_table_names)
+ {
+ casedn_str(db);
+ casedn_str(tname);
+ }
key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3;
hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
@@ -1398,7 +1432,13 @@ public:
privs = cols = 0; /* purecov: inspected */
return; /* purecov: inspected */
}
- key_length = (uint) strlen(db) + (uint) strlen(user) + (uint) strlen (tname) + 3;
+ if (lower_case_table_names)
+ {
+ casedn_str(db);
+ casedn_str(tname);
+ }
+ key_length = ((uint) strlen(db) + (uint) strlen(user) +
+ (uint) strlen(tname) + 3);
hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
privs = (uint) form->field[6]->val_int();
@@ -1990,7 +2030,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
{
List_iterator <LEX_USER> str_list (list);
LEX_USER *Str;
- char what;
+ char what,tmp_db[NAME_LEN+1];
bool create_new_users=0;
TABLE_LIST tables[2];
DBUG_ENTER("mysql_grant");
@@ -2002,6 +2042,12 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
}
what = (revoke_grant) ? 'N' : 'Y';
+ if (lower_case_table_names && db)
+ {
+ strmov(tmp_db,db);
+ casedn_str(tmp_db);
+ db=tmp_db;
+ }
/* open the mysql.user and mysql.db tables */
@@ -2098,7 +2144,8 @@ int grant_init (void)
thd->mysys_var=my_thread_var;
thd->current_tablenr=0;
thd->open_tables=0;
- thd->db=my_strdup("mysql",MYF(0));
+ thd->db= my_strdup("mysql",MYF(0));
+ thd->db_length=5; // Safety
bzero((char*) &tables,sizeof(tables));
tables[0].name=tables[0].real_name= (char*) "tables_priv";
tables[1].name=tables[1].real_name= (char*) "columns_priv";
@@ -2220,8 +2267,8 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables,
table->grant.want_privilege=0;
continue; // Already checked
}
- const char *db = table->db ? table->db : thd->db;
- GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,db,user,
+ GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,
+ table->db,user,
table->real_name,0);
if (!grant_table)
{
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index e6a39f1b269..3b8616a660a 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -61,7 +61,7 @@ uint acl_get(const char *host, const char *ip, const char *bin_ip,
const char *user, const char *db);
uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *scramble,char **priv_user,
- bool old_ver);
+ bool old_ver, uint *max);
bool acl_check_host(const char *host, const char *ip);
bool change_password(THD *thd, const char *host, const char *user,
char *password);
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 161e0f9b2e7..df8a8f1fdde 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -890,7 +890,7 @@ int collect_string(String *element,
int collect_real(double *element, element_count count __attribute__((unused)),
TREE_INFO *info)
{
- char buff[255];
+ char buff[MAX_FIELD_WIDTH];
String s(buff, sizeof(buff));
if (info->found)
@@ -909,7 +909,7 @@ int collect_longlong(longlong *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
{
- char buff[255];
+ char buff[MAX_FIELD_WIDTH];
String s(buff, sizeof(buff));
if (info->found)
@@ -928,7 +928,7 @@ int collect_ulonglong(ulonglong *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
{
- char buff[255];
+ char buff[MAX_FIELD_WIDTH];
String s(buff, sizeof(buff));
if (info->found)
diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h
index 2147f14e160..1c60d0c150f 100644
--- a/sql/sql_analyse.h
+++ b/sql/sql_analyse.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index b913233806f..a8be2d8b8f5 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -300,6 +300,7 @@ static void free_cache_entry(TABLE *table)
void free_io_cache(TABLE *table)
{
+ DBUG_ENTER("free_io_cache");
if (table->io_cache)
{
close_cached_file(table->io_cache);
@@ -311,6 +312,7 @@ void free_io_cache(TABLE *table)
my_free((gptr) table->record_pointers,MYF(0));
table->record_pointers=0;
}
+ DBUG_VOID_RETURN;
}
/* Close all tables which aren't in use by any thread */
@@ -510,7 +512,7 @@ void close_temporary_tables(THD *thd)
const uint init_query_buf_size = 11; // "drop table "
uint query_buf_size;
bool found_user_tables = 0;
-
+
LINT_INIT(end);
query_buf_size = init_query_buf_size;
@@ -1166,7 +1168,7 @@ bool wait_for_tables(THD *thd)
/* Now we can open all tables without any interference */
thd->proc_info="Reopen tables";
result=reopen_tables(thd,0,0);
-
+
}
pthread_mutex_unlock(&LOCK_open);
thd->proc_info=0;
@@ -1301,7 +1303,6 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
if (error)
goto err;
}
- (void) entry->file->extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
DBUG_RETURN(0);
err:
DBUG_RETURN(1);
@@ -1499,7 +1500,6 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
DBUG_RETURN(0);
}
- tmp_table->file->extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
tmp_table->reginfo.lock_type=TL_WRITE; // Simulate locked
tmp_table->tmp_table = (tmp_table->file->has_transactions() ?
TRANSACTIONAL_TMP_TABLE : TMP_TABLE);
@@ -2195,16 +2195,17 @@ int setup_ftfuncs(THD *thd)
int init_ftfuncs(THD *thd, bool no_order)
{
- List_iterator<Item_func_match> li(thd->lex.select_lex.ftfunc_list);
- Item_func_match *ifm;
- DBUG_PRINT("info",("Performing FULLTEXT search"));
- thd->proc_info="FULLTEXT initialization";
-
- while ((ifm=li++))
+ if (thd->lex.select_lex.ftfunc_list.elements)
{
- ifm->init_search(no_order);
- }
+ List_iterator<Item_func_match> li(thd->lex.select_lex.ftfunc_list);
+ Item_func_match *ifm;
+ DBUG_PRINT("info",("Performing FULLTEXT search"));
+ thd->proc_info="FULLTEXT initialization";
+ while ((ifm=li++))
+ {
+ ifm->init_search(no_order);
+ }
+ }
return 0;
}
-
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 09d436c0c9c..73b15ff3cf1 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1,98 +1,3446 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+/* 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 */
+/*
+ Description of the query cache:
+
+1. Query_cache object consists of
+ - query cache memory pool (cache)
+ - queries hash (queries)
+ - tables hash (tables)
+ - list of blocks ordered as they allocated in memory
+(first_block)
+ - list of queries block (queries_blocks)
+ - list of used tables (tables_blocks)
+
+2. Query cache memory pool (cache) consists of
+ - table of steps of memory bins allocation
+ - table of free memory bins
+ - blocks of memory
+
+3. Memory blocks
+
+Every memory block has the following structure:
+
++----------------------------------------------------------+
+| Block header (Query_cache_block structure) |
++----------------------------------------------------------+
+|Table of database table lists (used for queries & tables) |
++----------------------------------------------------------+
+| Type depended header |
+|(Query_cache_query, Query_cache_table, Query_cache_result)|
++----------------------------------------------------------+
+| Data ... |
++----------------------------------------------------------+
+
+Block header consists of:
+- type:
+ FREE Free memory block
+ QUERY Query block
+ RESULT Ready to send result
+ RES_CONT Result's continuation
+ RES_BEG First block of results, that is not yet complete,
+ written to cache
+ RES_INCOMPLETE Allocated for results data block
+ TABLE Block with database table description
+ INCOMPLETE The destroyed block
+- length of block (length)
+- length of data & headers (used)
+- physical list links (pnext/pprev) - used for the list of
+ blocks ordered as they are allocated in physical memory
+- logical list links (next/prev) - used for queries block list, tables block
+ list, free memory block lists and list of results block in query
+- number of elements in table of database table list (n_tables)
+
+4. Query & results blocks
+
+Query stored in cache consists of following blocks:
+
+more more
+recent+-------------+ old
+<-----|Query block 1|------> double linked list of queries block
+ prev | | next
+ +-------------+
+ <-| table 0 |-> (see "Table of database table lists" description)
+ <-| table 1 |->
+ | ... | +--------------------------+
+ +-------------+ +-------------------------+ |
+NET | | | V V |
+struct| | +-+------------+ +------------+ |
+<-----|query header |----->|Result block|-->|Result block|-+ doublelinked
+writer| |result| |<--| | list of results
+ +-------------+ +------------+ +------------+
+ |charset | +------------+ +------------+ no table of dbtables
+ |encoding + | | result | | result |
+ |query text |<-----| header | | header |------+
+ +-------------+parent| | | |parent|
+ ^ +------------+ +------------+ |
+ | |result data | |result data | |
+ | +------------+ +------------+ |
+ +---------------------------------------------------+
+
+First query is registered. During the registration query block is
+allocated. This query block is included in query hash and is linked
+with appropriate database tables lists (if there is no appropriate
+list exists it will be created).
+
+Later when query has performed results is written into the result blocks.
+A result block cannot be smaller then QUERY_CACHE_MIN_RESULT_DATA_SIZE.
+
+When new result is written to cache it is appended to the last result
+block, if no more free space left in the last block, new block is
+allocated.
+
+5. Table of database table lists.
+
+For quick invalidation of queries all query are linked in lists on used
+database tables basis (when table will be changed (insert/delete/...)
+this queries will be removed from cache).
+
+Root of such list is table block:
+
+ +------------+ list of used tables (used while invalidation of
+<----| Table |-----> whole database)
+ prev| block |next +-----------+
+ | | +-----------+ |Query block|
+ | | |Query block| +-----------+
+ +------------+ +-----------+ | ... |
+ +->| table 0 |------>|table 0 |----->| table N |---+
+ |+-| |<------| |<-----| |<-+|
+ || +------------+ | ... | | ... | ||
+ || |table header| +-----------+ +-----------+ ||
+ || +------------+ | ... | | ... | ||
+ || |db name + | +-----------+ +-----------+ ||
+ || |table name | ||
+ || +------------+ ||
+ |+--------------------------------------------------------+|
+ +----------------------------------------------------------+
+
+Table block is included into the tables hash (tables).
+
+6. Free blocks, free blocks bins & steps of freeblock bins.
+
+When we just started only one free memory block existed. All query
+cache memory (that will be used for block allocation) were
+containing in this block.
+When a new block is allocated we find most suitable memory block
+(minimal of >= required size). If such a block can not be found, we try
+to find max block < required size (if we allocate block for results).
+If there is no free memory, oldest query is removed from cache, and then
+we try to allocate memory. Last step should be repeated until we find
+suitable block or until there is no unlocked query found.
+
+If the block is found and its length more then we need, it should be
+split into 2 blocks.
+New blocks cannot be smaller then min_allocation_unit_bytes.
+
+When a block becomes free, its neighbor-blocks should be tested and if
+there are free blocks among them, they should be joined into one block.
+
+Free memory blocks are stored in bins according to their sizes.
+The bins are stored in size-descending order.
+These bins are distributed (by size) approximately logarithmically.
+
+First bin (number 0) stores free blocks with
+size <= query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2.
+It is first (number 0) step.
+On the next step distributed (1 + QUERY_CACHE_MEM_BIN_PARTS_INC) *
+QUERY_CACHE_MEM_BIN_PARTS_MUL bins. This bins allocated in interval from
+query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 to
+query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 >>
+QUERY_CACHE_MEM_BIN_STEP_PWR2
+...
+On each step interval decreases in 2 power of
+QUERY_CACHE_MEM_BIN_STEP_PWR2
+times, number of bins (that distributed on this step) increases. If on
+the previous step there were N bins distributed , on the current there
+would be distributed
+(N + QUERY_CACHE_MEM_BIN_PARTS_INC) * QUERY_CACHE_MEM_BIN_PARTS_MUL
+bins.
+Last distributed bin stores blocks with size near min_allocation_unit
+bytes.
+
+For example:
+ query_cache_size>>QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 = 100,
+ min_allocation_unit = 17,
+ QUERY_CACHE_MEM_BIN_STEP_PWR2 = 1,
+ QUERY_CACHE_MEM_BIN_PARTS_INC = 1,
+ QUERY_CACHE_MEM_BIN_PARTS_MUL = 1
+ (in followed picture showed right (low) bound of bin):
+
+ | 100>>1 50>>1 |25>>1|
+ | | | | | |
+ | 100 75 50 41 33 25 21 18 15| 12 | - bins right (low) bounds
+
+ |\---/\-----/\--------/\--------|---/ |
+ | 0 1 2 3 | | - steps
+ \-----------------------------/ \---/
+ bins that we store in cache this bin showed for example only
+
+
+Calculation of steps/bins distribution is performed only when query cache
+is resized.
+
+When we need to find appropriate bin, first we should find appropriate
+step, then we should calculate number of bins that are using data
+stored in Query_cache_memory_bin_step structure.
+
+Free memory blocks are sorted in bins in lists with size-ascending order
+(more small blocks needed frequently then bigger one).
+
+7. Packing cache.
+
+Query cache packing is divided into two operation:
+ - pack_cache
+ - join_results
+
+pack_cache moved all blocks to "top" of cache and create one block of free
+space at the "bottom":
+
+ before pack_cache after pack_cache
+ +-------------+ +-------------+
+ | query 1 | | query 1 |
+ +-------------+ +-------------+
+ | table 1 | | table 1 |
+ +-------------+ +-------------+
+ | results 1.1 | | results 1.1 |
+ +-------------+ +-------------+
+ | free | | query 2 |
+ +-------------+ +-------------+
+ | query 2 | | table 2 |
+ +-------------+ ---> +-------------+
+ | table 2 | | results 1.2 |
+ +-------------+ +-------------+
+ | results 1.2 | | results 2 |
+ +-------------+ +-------------+
+ | free | | free |
+ +-------------+ | |
+ | results 2 | | |
+ +-------------+ | |
+ | free | | |
+ +-------------+ +-------------+
+
+pack_cache scan blocks in physical address order and move every non-free
+block "higher".
+
+pack_cach remove every free block it finds. The length of the deleted block
+is accumulated to the "gap". All non free blocks should be shifted with the
+"gap" step.
+
+join_results scans all complete queries. If the results of query are not
+stored in the same block, join_results tries to move results so, that they
+are stored in one block.
+
+ before join_results after join_results
+ +-------------+ +-------------+
+ | query 1 | | query 1 |
+ +-------------+ +-------------+
+ | table 1 | | table 1 |
+ +-------------+ +-------------+
+ | results 1.1 | | free |
+ +-------------+ +-------------+
+ | query 2 | | query 2 |
+ +-------------+ +-------------+
+ | table 2 | | table 2 |
+ +-------------+ ---> +-------------+
+ | results 1.2 | | free |
+ +-------------+ +-------------+
+ | results 2 | | results 2 |
+ +-------------+ +-------------+
+ | free | | results 1 |
+ | | | |
+ | | +-------------+
+ | | | free |
+ | | | |
+ +-------------+ +-------------+
+
+If join_results allocated new block(s) then we need call pack_cache again.
+
+TODO list:
+
+ - Invalidate queries that use innoDB tables changed in transaction & remove
+ invalidation by table type
+ - Delayed till after-parsing qache answer (for column rights processing)
+ - Optimize cache resizing
+ - if new_size < old_size then pack & shrink
+ - if new_size > old_size copy cached query to new cache
+ - Move MRG_MYISAM table type processing to handlers, something like:
+ tables_used->table->file->register_used_filenames(callback,
+ first_argument);
+ - In Query_cache::insert_table eliminate strlen(). To do this we have to
+ add db_len to the TABLE_LIST and TABLE structures.
+*/
+
#include "mysql_priv.h"
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
+#include "sql_acl.h"
+#include "ha_myisammrg.h"
+#ifndef MASTER
+#include "../srclib/myisammrg/myrg_def.h"
+#else
+#include "../myisammrg/myrg_def.h"
+#endif
+#include <assert.h>
+
+#if defined(EXTRA_DEBUG) && !defined(DBUG_OFF)
+#define MUTEX_LOCK(M) { DBUG_PRINT("lock", ("mutex lock 0x%lx", (ulong)(M))); \
+ pthread_mutex_lock(M);}
+#define MUTEX_UNLOCK(M) {DBUG_PRINT("lock", ("mutex unlock 0x%lx",\
+ (ulong)(M))); pthread_mutex_unlock(M);}
+#define SEM_LOCK(M) { int val = 0; sem_getvalue (M, &val); \
+ DBUG_PRINT("lock", ("sem lock 0x%lx (%d)", (ulong)(M), val)); \
+ sem_wait(M); DBUG_PRINT("lock", ("sem lock ok")); }
+#define SEM_UNLOCK(M) {DBUG_PRINT("info", ("sem unlock 0x%lx", (ulong)(M))); \
+ sem_post(M); DBUG_PRINT("info", ("sem unlock ok")); }
+#define STRUCT_LOCK(M) {DBUG_PRINT("lock", ("%d struct lock...",__LINE__)); \
+ pthread_mutex_lock(M);DBUG_PRINT("lock", ("struct lock OK"));}
+#define STRUCT_UNLOCK(M) { \
+ DBUG_PRINT("lock", ("%d struct unlock...",__LINE__)); \
+ pthread_mutex_unlock(M);DBUG_PRINT("lock", ("struct unlock OK"));}
+#define BLOCK_LOCK_WR(B) {DBUG_PRINT("lock", ("%d LOCK_WR 0x%lx",\
+ __LINE__,(ulong)(B))); \
+ B->query()->lock_writing();}
+#define BLOCK_LOCK_RD(B) {DBUG_PRINT("lock", ("%d LOCK_RD 0x%lx",\
+ __LINE__,(ulong)(B))); \
+ B->query()->lock_reading();}
+#define BLOCK_UNLOCK_WR(B) { \
+ DBUG_PRINT("lock", ("%d UNLOCK_WR 0x%lx",\
+ __LINE__,(ulong)(B)));B->query()->unlock_writing();}
+#define BLOCK_UNLOCK_RD(B) { \
+ DBUG_PRINT("lock", ("%d UNLOCK_RD 0x%lx",\
+ __LINE__,(ulong)(B)));B->query()->unlock_reading();}
+#define DUMP(C) DBUG_EXECUTE("qcache", {\
+ (C)->cache_dump(); (C)->queries_dump();(C)->tables_dump();})
+#else
+#define MUTEX_LOCK(M) pthread_mutex_lock(M)
+#define MUTEX_UNLOCK(M) pthread_mutex_unlock(M)
+#define SEM_LOCK(M) sem_wait(M)
+#define SEM_UNLOCK(M) sem_post(M)
+#define STRUCT_LOCK(M) pthread_mutex_lock(M)
+#define STRUCT_UNLOCK(M) pthread_mutex_unlock(M)
+#define BLOCK_LOCK_WR(B) B->query()->lock_writing()
+#define BLOCK_LOCK_RD(B) B->query()->lock_reading()
+#define BLOCK_UNLOCK_WR(B) B->query()->unlock_writing()
+#define BLOCK_UNLOCK_RD(B) B->query()->unlock_reading()
+#define DUMP(C)
+#endif
+
+/*****************************************************************************
+ Query_cache_block_table method(s)
+*****************************************************************************/
+
+inline Query_cache_block * Query_cache_block_table::block()
+{
+ return (Query_cache_block *)(((byte*)this) -
+ ALIGN_SIZE(sizeof(Query_cache_block_table)*n) -
+ ALIGN_SIZE(sizeof(Query_cache_block)));
+};
+
+/*****************************************************************************
+ Query_cache_block method(s)
+*****************************************************************************/
+
+void Query_cache_block::init(ulong block_length)
+{
+ DBUG_ENTER("Query_cache_block::init");
+ DBUG_PRINT("qcache", ("init block 0x%lx length: %lu", (ulong) this,
+ block_length));
+ length = block_length;
+ used = 0;
+ type = Query_cache_block::FREE;
+ n_tables = 0;
+ DBUG_VOID_RETURN;
+}
+
+void Query_cache_block::destroy()
+{
+ DBUG_ENTER("Query_cache_block::destroy");
+ DBUG_PRINT("qcache", ("destroy block 0x%lx, type %d",
+ (ulong) this, type));
+ type = INCOMPLETE;
+ DBUG_VOID_RETURN;
+}
+
+inline uint Query_cache_block::headers_len()
+{
+ return (ALIGN_SIZE(sizeof(Query_cache_block_table)*n_tables) +
+ ALIGN_SIZE(sizeof(Query_cache_block)));
+}
-#define SQL_CACHE_LENGTH 30 // 300 crashes apple gcc.
+inline gptr Query_cache_block::data(void)
+{
+ return (gptr)( ((byte*)this) + headers_len() );
+}
-HASH sql_cache;
-static LEX lex_array_static[SQL_CACHE_LENGTH];
-LEX * lex_array = lex_array_static;
-int last_lex_array_item = SQL_CACHE_LENGTH - 1;
+inline Query_cache_query * Query_cache_block::query()
+{
+#ifndef DBUG_OFF
+ if (type != QUERY)
+ query_cache.wreck(__LINE__, "incorrect block type");
+#endif
+ return (Query_cache_query *) data();
+}
-/* Function to return a text string from a LEX struct */
-static byte *cache_key(const byte *record, uint *length, my_bool not_used)
+inline Query_cache_table * Query_cache_block::table()
{
-#ifdef QQ
- LEX *lex=(LEX*) record;
- *length = lex->sql_query_length;
- // *length = strlen(lex->ptr);
- return (byte*) lex->sql_query_text;
- // return (byte*) lex->ptr;
+#ifndef DBUG_OFF
+ if (type != TABLE)
+ query_cache.wreck(__LINE__, "incorrect block type");
#endif
- return 0;
+ return (Query_cache_table *) data();
}
-/* At the moment we do not really want to do anything upon delete */
-static void free_cache_entry(void *entry)
+inline Query_cache_result * Query_cache_block::result()
{
+#ifndef DBUG_OFF
+ if (type != RESULT && type != RES_CONT && type != RES_BEG &&
+ type != RES_INCOMPLETE)
+ query_cache.wreck(__LINE__, "incorrect block type");
+#endif
+ return (Query_cache_result *) data();
}
-/* Initialization of the SQL cache hash -- should be called during
- the bootstrap stage */
-bool sql_cache_init(void)
+inline Query_cache_block_table * Query_cache_block::table(TABLE_COUNTER_TYPE n)
{
- if (query_buff_size)
+ return ((Query_cache_block_table *)
+ (((byte*)this)+ALIGN_SIZE(sizeof(Query_cache_block)) +
+ n*sizeof(Query_cache_block_table)));
+}
+
+
+/*****************************************************************************
+ * Query_cache_table method(s)
+ *****************************************************************************/
+
+extern "C"
+{
+byte *query_cache_table_get_key(const byte *record, uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ Query_cache_block* table_block = (Query_cache_block*) record;
+ *length = (table_block->used - table_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_table)));
+ return (((byte *) table_block->data()) +
+ ALIGN_SIZE(sizeof(Query_cache_table)));
+}
+}
+
+/*****************************************************************************
+ Query_cache_query methods
+*****************************************************************************/
+
+void Query_cache_query::init_n_lock()
+{
+ DBUG_ENTER("Query_cache_query::init_n_lock");
+ res=0; wri = 0; len = 0;
+ sem_init(&lock, 0, 1);
+ pthread_mutex_init(&clients_guard,MY_MUTEX_INIT_FAST);
+ clients = 0;
+ lock_writing();
+ DBUG_PRINT("qcache", ("inited & locked query for block 0x%lx",
+ ((byte*) this)-ALIGN_SIZE(sizeof(Query_cache_block))));
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache_query::unlock_n_destroy()
+{
+ DBUG_ENTER("Query_cache_query::unlock_n_destroy");
+ DBUG_PRINT("qcache", ("destroyed & unlocked query for block 0x%lx",
+ ((byte*)this)-ALIGN_SIZE(sizeof(Query_cache_block))));
+ /*
+ The following call is not needed on system where one can destroy an
+ active semaphore
+ */
+ this->unlock_writing();
+ sem_destroy(&lock);
+ pthread_mutex_destroy(&clients_guard);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Following methods work for block read/write locking only in this
+ particular case and in interaction with structure_guard_mutex.
+
+ Lock for write prevents any other locking. (exclusive use)
+ Lock for read prevents only locking for write.
+*/
+
+void Query_cache_query::lock_writing()
+{
+ SEM_LOCK(&lock);
+}
+
+
+/*
+ Needed for finding queries, that we may delete from cache.
+ We don't want to wait while block become unlocked. In addition,
+ block locking means that query is now used and we don't need to
+ remove it.
+*/
+
+my_bool Query_cache_query::try_lock_writing()
+{
+ DBUG_ENTER("Query_cache_block::try_lock_writing");
+ if (sem_trywait(&lock)!=0 || clients != 0)
{
- VOID(hash_init(&sql_cache, 4096, 0, 0,
- cache_key,
- (void (*)(void*)) free_cache_entry,
- 0));
+ DBUG_PRINT("info", ("can't lock semaphore"));
+ DBUG_RETURN(0);
}
- return 0;
+ DBUG_PRINT("info", ("mutex 'lock' 0x%lx locked", (ulong) &lock));
+ DBUG_RETURN(1);
+}
+
+
+void Query_cache_query::lock_reading()
+{
+ MUTEX_LOCK(&clients_guard);
+ if ( ++clients == 1 )
+ SEM_LOCK(&lock);
+ MUTEX_UNLOCK(&clients_guard);
+}
+
+
+void Query_cache_query::unlock_writing()
+{
+ SEM_UNLOCK(&lock);
+}
+
+
+void Query_cache_query::unlock_reading()
+{
+ /*
+ To avoid unlocking semaphore before unlocking mutex (that may cause
+ destroying locked mutex), we use temporary boolean variable 'unlock'.
+ */
+ MUTEX_LOCK(&clients_guard);
+ bool ulock = ((--clients) == 0);
+ MUTEX_UNLOCK(&clients_guard);
+ if (ulock) SEM_UNLOCK(&lock);
}
-/* Clearing the SQL cache hash -- during shutdown */
-void sql_cache_free(void)
+extern "C"
+{
+byte *query_cache_query_get_key(const byte *record, uint *length,
+ my_bool not_used)
{
- hash_free(&sql_cache);
+ Query_cache_block *query_block = (Query_cache_block*) record;
+ *length = (query_block->used - query_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_query)));
+ return (((byte *) query_block->data()) +
+ ALIGN_SIZE(sizeof(Query_cache_query)));
}
+}
+
+/*****************************************************************************
+ Functions to store things into the query cache
+*****************************************************************************/
-/* Finds whether the SQL command is already in the cache, at any case
- establishes correct LEX structure in the THD (either from
- cache or a new one) */
+/*
+ Insert the packet into the query cache.
+ This should only be called if net->query_cache_query != 0
+*/
-int sql_cache_hit(THD *thd, char *sql, uint length)
+void query_cache_insert(NET *net, const char *packet, ulong length)
{
-#ifdef QQ
- LEX *ptr;
- ptr = (LEX *)hash_search(&sql_cache, sql, length);
- if (ptr) {
- fprintf(stderr, "Query `%s' -- hit in the cache (%p)\n", ptr->sql_query_text, ptr);
- thd->lex_ptr = ptr;
- ptr->thd = thd;
- } else {
- thd->lex_ptr = ptr = lex_array + last_lex_array_item--;
+ DBUG_ENTER("query_cache_insert");
+
+#ifndef DBUG_OFF
+ // Check if we have called query_cache.wreck() (which disables the cache)
+ if (query_cache.query_cache_size == 0)
+ DBUG_VOID_RETURN;
+#endif
+
+ STRUCT_LOCK(&query_cache.structure_guard_mutex);
+ Query_cache_block *query_block = ((Query_cache_block*)
+ net->query_cache_query);
+ if (query_block)
+ {
+ Query_cache_query *header = query_block->query();
+ Query_cache_block *result = header->result();
- lex_start(thd, (uchar *)sql, length);
+ DUMP(&query_cache);
+ BLOCK_LOCK_WR(query_block);
+ DBUG_PRINT("qcache", ("insert packet %lu bytes long",length));
- if (hash_insert(&sql_cache, (const byte *)ptr)) {
- fprintf(stderr, "Out of memory during hash_insert?\n");
+ /*
+ On success STRUCT_UNLOCK(&query_cache.structure_guard_mutex) will be
+ done by query_cache.append_result_data if success (if not we need
+ query_cache.structure_guard_mutex locked to free query)
+ */
+ if (!query_cache.append_result_data(&result, length, (gptr) packet,
+ query_block))
+ {
+ query_cache.refused++;
+ DBUG_PRINT("warning", ("Can't append data"));
+ header->result(result);
+ DBUG_PRINT("qcache", ("free query 0x%lx", (ulong) query_block));
+ // The following call will remove the lock on query_block
+ query_cache.free_query(query_block);
+ // append_result_data no success => we need unlock
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ DBUG_VOID_RETURN;
}
- fprintf(stderr, "Query `%s' not found in the cache -- insert %p from slot %d\n", thd->lex_ptr->ptr, ptr, last_lex_array_item+1);
- if (!hash_search(&sql_cache, sql, length)) {
- fprintf(stderr, "I just enterred a hash key but it's not where -- what's that?\n");
- } else {
- fprintf(stderr, "Inserted to cache\n");
+ header->result(result);
+ BLOCK_UNLOCK_WR(query_block);
+ }
+ else
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
+ DBUG_VOID_RETURN;
+}
+
+
+void query_cache_abort(NET *net)
+{
+ DBUG_ENTER("query_cache_abort");
+
+#ifndef DBUG_OFF
+ // Check if we have called query_cache.wreck() (which disables the cache)
+ if (query_cache.query_cache_size == 0)
+ DBUG_VOID_RETURN;
+#endif
+ if (net->query_cache_query != 0) // Quick check on unlocked structure
+ {
+ STRUCT_LOCK(&query_cache.structure_guard_mutex);
+ Query_cache_block *query_block = ((Query_cache_block*)
+ net->query_cache_query);
+ if (query_block) // Test if changed by other thread
+ {
+ DUMP(&query_cache);
+ BLOCK_LOCK_WR(query_block);
+ // The following call will remove the lock on query_block
+ query_cache.free_query(query_block);
}
- return 0;
+ net->query_cache_query=0;
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
}
+ DBUG_VOID_RETURN;
+}
+
+
+void query_cache_end_of_result(NET *net)
+{
+ DBUG_ENTER("query_cache_end_of_result");
+
+#ifndef DBUG_OFF
+ // Check if we have called query_cache.wreck() (which disables the cache)
+ if (query_cache.query_cache_size == 0) DBUG_VOID_RETURN;
+#endif
+
+ if (net->query_cache_query != 0) // Quick check on unlocked structure
+ {
+ STRUCT_LOCK(&query_cache.structure_guard_mutex);
+ Query_cache_block *query_block = ((Query_cache_block*)
+ net->query_cache_query);
+ if (query_block)
+ {
+ DUMP(&query_cache);
+ BLOCK_LOCK_WR(query_block);
+ Query_cache_query *header = query_block->query();
+ Query_cache_block *last_result_block = header->result()->prev;
+ ulong allign_size = ALIGN_SIZE(last_result_block->used);
+ ulong len = max(query_cache.min_allocation_unit, allign_size);
+ if (last_result_block->length >= query_cache.min_allocation_unit + len)
+ query_cache.split_block(last_result_block,len);
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+
+#ifndef DBUG_OFF
+ if (header->result() == 0)
+ {
+ DBUG_PRINT("error", ("end of data whith no result. query '%s'",
+ header->query()));
+ query_cache.wreck(__LINE__, "");
+ DBUG_VOID_RETURN;
+ }
#endif
- return 1;
+ header->found_rows(current_thd->limit_found_rows);
+ header->result()->type = Query_cache_block::RESULT;
+ header->writer(0);
+ BLOCK_UNLOCK_WR(query_block);
+ }
+ else
+ {
+ // Cache was flushed or resized and query was deleted => do nothing
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ }
+ net->query_cache_query=0;
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
+ }
+ DBUG_VOID_RETURN;
+}
+
+void query_cache_invalidate_by_MyISAM_filename(const char *filename)
+{
+ query_cache.invalidate_by_MyISAM_filename(filename);
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
+}
+
+
+/*****************************************************************************
+ Query_cache methods
+*****************************************************************************/
+
+Query_cache::Query_cache(ulong query_cache_limit,
+ ulong min_allocation_unit,
+ ulong min_result_data_size,
+ uint def_query_hash_size ,
+ uint def_table_hash_size)
+ :query_cache_size(0),
+ query_cache_limit(query_cache_limit),
+ queries_in_cache(0), hits(0), inserts(0), refused(0),
+ total_blocks(0),
+ min_allocation_unit(min_allocation_unit),
+ min_result_data_size(min_result_data_size),
+ def_query_hash_size(def_query_hash_size),
+ def_table_hash_size(def_table_hash_size),
+ initialized(0)
+{
+ ulong min_needed=(ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_block_table)) +
+ ALIGN_SIZE(sizeof(Query_cache_query)) + 3);
+ set_if_bigger(min_allocation_unit,min_needed);
+ this->min_allocation_unit = min_allocation_unit;
+ set_if_bigger(this->min_result_data_size,min_allocation_unit);
+}
+
+
+ulong Query_cache::resize(ulong query_cache_size)
+{
+ DBUG_ENTER("Query_cache::resize");
+ DBUG_PRINT("qcache", ("from %lu to %lu",this->query_cache_size,
+ query_cache_size));
+ free_cache(0);
+ this->query_cache_size=query_cache_size;
+ DBUG_RETURN(init_cache());
+}
+
+
+void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
+{
+ TABLE_COUNTER_TYPE tables;
+ ulong tot_length;
+ DBUG_ENTER("Query_cache::store_query");
+ if (query_cache_size == 0)
+ DBUG_VOID_RETURN;
+
+ if ((tables = is_cacheable(thd, thd->query_length,
+ thd->query, &thd->lex, tables_used)))
+ {
+ NET *net = &thd->net;
+ byte flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0);
+ STRUCT_LOCK(&structure_guard_mutex);
+
+ if (query_cache_size == 0)
+ DBUG_VOID_RETURN;
+ DUMP(this);
+
+ /* Key is query + database + flag */
+ if (thd->db_length)
+ {
+ memcpy(thd->query+thd->query_length+1, thd->db, thd->db_length);
+ DBUG_PRINT("qcache", ("database : %s length %u",
+ thd->db, thd->db_length));
+ }
+ else
+ {
+ DBUG_PRINT("qcache", ("No active database"));
+ }
+ /*
+ Prepare flags:
+ most significant bit - CLIENT_LONG_FLAG,
+ other - charset number (0 no charset convertion)
+ */
+ if (thd->convert_set != 0)
+ {
+ flags|= (byte) thd->convert_set->number();
+ DBUG_ASSERT(thd->convert_set->number() < 128);
+ }
+ tot_length=thd->query_length+thd->db_length+2;
+ thd->query[tot_length-1] = (char) flags;
+
+ /* Check if another thread is processing the same query? */
+ Query_cache_block *competitor = (Query_cache_block *)
+ hash_search(&queries, (byte*) thd->query, tot_length);
+ DBUG_PRINT("qcache", ("competitor 0x%lx, flags %x", (ulong) competitor,
+ flags));
+ if (competitor == 0)
+ {
+ /* Query is not in cache and no one is working with it; Store it */
+ Query_cache_block *query_block;
+ query_block= write_block_data(tot_length, (gptr) thd->query,
+ ALIGN_SIZE(sizeof(Query_cache_query)),
+ Query_cache_block::QUERY, tables, 1);
+ if (query_block != 0)
+ {
+ DBUG_PRINT("qcache", ("query block 0x%lx allocated, %lu",
+ (ulong) query_block, query_block->used));
+
+ Query_cache_query *header = query_block->query();
+ header->init_n_lock();
+ if (hash_insert(&queries, (byte*) query_block))
+ {
+ refused++;
+ DBUG_PRINT("qcache", ("insertion in query hash"));
+ header->unlock_n_destroy();
+ free_memory_block(query_block);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ goto end;
+ }
+ if (!register_all_tables(query_block, tables_used, tables))
+ {
+ refused++;
+ DBUG_PRINT("warning", ("tables list including failed"));
+ hash_delete(&queries, (byte *) query_block);
+ header->unlock_n_destroy();
+ free_memory_block(query_block);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ goto end;
+ }
+ double_linked_list_simple_include(query_block, &queries_blocks);
+ inserts++;
+ queries_in_cache++;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+
+ net->query_cache_query= (gptr) query_block;
+ header->writer(net);
+ // init_n_lock make query block locked
+ BLOCK_UNLOCK_WR(query_block);
+ }
+ else
+ {
+ // We have not enough memory to store query => do nothing
+ refused++;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_PRINT("warning", ("Can't allocate query"));
+ }
+ }
+ else
+ {
+ // Another thread is processing the same query => do nothing
+ refused++;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_PRINT("qcache", ("Another thread process same query"));
+ }
+ }
+ else
+ statistic_increment(refused, &structure_guard_mutex);
+
+end:
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Check if the query is in the cache. If it was cached, send it
+ to the user.
+
+ RESULTS
+ 1 Query was not cached.
+ 0 The query was cached and user was sent the result.
+ -1 The query was cached but we didn't have rights to use it.
+ No error is sent to the client yet.
+*/
+
+
+
+int
+Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
+{
+ Query_cache_query *query;
+ Query_cache_block *first_result_block, *result_block;
+ Query_cache_block_table *block_table, *block_table_end;
+ ulong tot_length;
+ byte flags;
+ DBUG_ENTER("Query_cache::send_result_to_client");
+
+ if (query_cache_size == 0 ||
+ /*
+ it is not possible to check has_transactions() function of handler
+ because tables not opened yet
+ */
+ (thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)) ||
+ thd->query_cache_type == 0)
+
+ {
+ DBUG_PRINT("qcache", ("query cache disabled or not in autocommit mode"));
+ goto err;
+ }
+
+ /* Check that we haven't forgot to reset the query cache variables */
+ DBUG_ASSERT(thd->net.query_cache_query == 0);
+
+ if (!thd->safe_to_cache_query)
+ {
+ DBUG_PRINT("qcache", ("SELECT is non-cacheable"));
+ goto err;
+ }
+
+ /*
+ Test if the query is a SELECT
+ (pre-space is removed in dispatch_command)
+ */
+ if (toupper(sql[0]) != 'S' || toupper(sql[1]) != 'E' ||
+ toupper(sql[2]) !='L')
+ {
+ DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
+ goto err;
+ }
+
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size == 0)
+ {
+ DBUG_PRINT("qcache", ("query cache disabled"));
+ goto err_unlock;
+ }
+ Query_cache_block *query_block;
+
+ tot_length=query_length+thd->db_length+2;
+ if (thd->db_length)
+ {
+ memcpy(sql+query_length+1, thd->db, thd->db_length);
+ DBUG_PRINT("qcache", ("database: '%s' length %u",
+ thd->db, thd->db_length));
+ }
+ else
+ {
+ DBUG_PRINT("qcache", ("No active database"));
+ }
+ /*
+ prepare flags:
+ Most significant bit - CLIENT_LONG_FLAG,
+ Other - charset number (0 no charset convertion)
+ */
+ flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0);
+ if (thd->convert_set != 0)
+ {
+ flags |= (byte) thd->convert_set->number();
+ DBUG_ASSERT(thd->convert_set->number() < 128);
+ }
+ sql[tot_length-1] = (char) flags;
+ query_block = (Query_cache_block *) hash_search(&queries, (byte*) sql,
+ tot_length);
+ /* Quick abort on unlocked data */
+ if (query_block == 0 ||
+ query_block->query()->result() == 0 ||
+ query_block->query()->result()->type != Query_cache_block::RESULT)
+ {
+ DBUG_PRINT("qcache", ("No query in query hash or no results"));
+ goto err_unlock;
+ }
+ DBUG_PRINT("qcache", ("Query in query hash 0x%lx", (ulong)query_block));
+
+ /* Now lock and test that nothing changed while blocks was unlocked */
+ BLOCK_LOCK_RD(query_block);
+
+ query = query_block->query();
+ result_block= first_result_block= query->result();
+
+ if (result_block == 0 || result_block->type != Query_cache_block::RESULT)
+ {
+ /* The query is probably yet processed */
+ DBUG_PRINT("qcache", ("query found, but no data or data incomplete"));
+ BLOCK_UNLOCK_RD(query_block);
+ goto err_unlock;
+ }
+ DBUG_PRINT("qcache", ("Query have result 0x%lx", (ulong) query));
+
+ // Check access;
+ block_table= query_block->table(0);
+ block_table_end= block_table+query_block->n_tables;
+ for ( ; block_table != block_table_end; block_table++)
+ {
+ TABLE_LIST table_list;
+ bzero((char*) &table_list,sizeof(table_list));
+
+ Query_cache_table *table = block_table->parent;
+ table_list.db = table->db();
+ table_list.name = table_list.real_name = table->table();
+ if (check_table_access(thd,SELECT_ACL,&table_list,1))
+ {
+ DBUG_PRINT("qcache",
+ ("probably no SELECT access to %s.%s => return to normal processing",
+ table_list.db, table_list.name));
+ refused++; // This is actually a hit
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ thd->safe_to_cache_query=0; // Don't try to cache this
+ BLOCK_UNLOCK_RD(query_block);
+ DBUG_RETURN(-1); // Privilege error
+ }
+ if (table_list.grant.want_privilege)
+ {
+ DBUG_PRINT("qcache", ("Need to check column privileges for %s.%s",
+ table_list.db, table_list.name));
+ BLOCK_UNLOCK_RD(query_block);
+ thd->safe_to_cache_query=0; // Don't try to cache this
+ goto err_unlock; // Parse query
+ }
+ }
+ move_to_query_list_end(query_block);
+ hits++;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+
+ /*
+ Send cached result to client
+ */
+ do
+ {
+ DBUG_PRINT("qcache", ("Results (len %lu, used %lu, headers %lu)",
+ result_block->length, result_block->used,
+ result_block->headers_len()+
+ ALIGN_SIZE(sizeof(Query_cache_result))));
+
+ Query_cache_result *result = result_block->result();
+ if (net_real_write(&thd->net, result->data(),
+ result_block->used -
+ result_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_result))))
+ break; // Client aborted
+ result_block = result_block->next;
+ } while (result_block != first_result_block);
+
+ thd->limit_found_rows = query->found_rows();
+
+ BLOCK_UNLOCK_RD(query_block);
+ DBUG_RETURN(1); // Result sent to client
+
+err_unlock:
+ STRUCT_UNLOCK(&structure_guard_mutex);
+err:
+ DBUG_RETURN(0); // Query was not cached
+}
+
+/*
+ Remove all cached queries that uses any of the tables in the list
+*/
+
+void Query_cache::invalidate(TABLE_LIST *tables_used)
+{
+ DBUG_ENTER("Query_cache::invalidate (table list)");
+ if (query_cache_size > 0)
+ {
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ {
+ DUMP(this);
+ for ( ; tables_used; tables_used=tables_used->next)
+ invalidate_table(tables_used);
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Remove all cached queries that uses the given table
+*/
+
+void Query_cache::invalidate(TABLE *table)
+{
+ DBUG_ENTER("Query_cache::invalidate (table)");
+ if (query_cache_size > 0)
+ {
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ invalidate_table(table);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Remove all cached queries that uses the given table type.
+*/
+
+void Query_cache::invalidate(Query_cache_table::query_cache_table_type type)
+{
+ DBUG_ENTER("Query_cache::invalidate (type)");
+ if (query_cache_size > 0)
+ {
+ STRUCT_LOCK(&structure_guard_mutex);
+ DUMP(this);
+ if (query_cache_size > 0)
+ {
+ /* invalidate_table reduce list while only root of list remain */
+ while (tables_blocks[type] != 0)
+ invalidate_table(tables_blocks[type]);
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Remove all cached queries that uses the given database
+*/
+
+void Query_cache::invalidate(char *db)
+{
+ DBUG_ENTER("Query_cache::invalidate (db)");
+ if (query_cache_size > 0)
+ {
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ {
+ DUMP(this);
+ for (int i=0 ; i < (int) Query_cache_table::TYPES_NUMBER; i++)
+ {
+ /* invalidate_table reduce list while only root of list remain */
+ while (tables_blocks[i] !=0 )
+ invalidate_table(tables_blocks[i]);
+ }
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
+{
+ DBUG_ENTER("Query_cache::invalidate_by_MyISAM_filename");
+ if (query_cache_size > 0)
+ {
+ /* Calculate the key outside the lock to make the lock shorter */
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length= filename_2_table_key(key, filename);
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0) // Safety if cache removed
+ {
+ Query_cache_block *table_block;
+ if ((table_block = (Query_cache_block*) hash_search(&tables,
+ (byte*) key,
+ key_length)))
+ invalidate_table(table_block);
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+ /* Remove all queries from cache */
+
+void Query_cache::flush()
+{
+ DBUG_ENTER("Query_cache::flush");
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size > 0)
+ {
+ DUMP(this);
+ flush_cache();
+ DUMP(this);
+ }
+
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_VOID_RETURN;
+}
+
+ /* Join result in cache in 1 block (if result length > join_limit) */
+
+void Query_cache::pack(ulong join_limit, uint iteration_limit)
+{
+ DBUG_ENTER("Query_cache::pack");
+ uint i = 0;
+ do
+ {
+ pack_cache();
+ } while ((++i < iteration_limit) && join_results(join_limit));
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::destroy()
+{
+ if ( !initialized )
+ {
+ DBUG_PRINT("qcache", ("Query Cache not initialized"));
+ return;
+ }
+ DBUG_ENTER("Query_cache::destroy");
+ free_cache(1);
+ pthread_mutex_destroy(&structure_guard_mutex);
+ initialized = 0;
+ DBUG_VOID_RETURN;
+}
+
+
+/*****************************************************************************
+ init/destroy
+*****************************************************************************/
+
+void Query_cache::init()
+{
+ DBUG_ENTER("Query_cache::init");
+ pthread_mutex_init(&structure_guard_mutex,MY_MUTEX_INIT_FAST);
+ initialized = 1;
+ DBUG_VOID_RETURN;
+}
+
+
+ulong Query_cache::init_cache()
+{
+ uint mem_bin_count, num, step;
+ ulong mem_bin_size, prev_size, inc;
+ ulong additional_data_size, max_mem_bin_size, approx_additional_data_size;
+
+ DBUG_ENTER("Query_cache::init_cache");
+ if (!initialized)
+ init();
+ approx_additional_data_size = (sizeof(Query_cache) +
+ sizeof(gptr)*(def_query_hash_size+
+ def_query_hash_size));
+ if (query_cache_size < approx_additional_data_size)
+ goto err;
+
+ query_cache_size -= approx_additional_data_size;
+
+ /*
+ Count memory bins number.
+ Check section 6. in start comment for the used algorithm.
+ */
+
+ max_mem_bin_size = query_cache_size >> QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2;
+ mem_bin_count = (uint) ((1 + QUERY_CACHE_MEM_BIN_PARTS_INC) *
+ QUERY_CACHE_MEM_BIN_PARTS_MUL);
+ mem_bin_num = 1;
+ mem_bin_steps = 1;
+ mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
+ prev_size = 0;
+ while (mem_bin_size > min_allocation_unit)
+ {
+ mem_bin_num += mem_bin_count;
+ prev_size = mem_bin_size;
+ mem_bin_size >>= QUERY_CACHE_MEM_BIN_STEP_PWR2;
+ mem_bin_steps++;
+ mem_bin_count += QUERY_CACHE_MEM_BIN_PARTS_INC;
+ mem_bin_count = (uint) (mem_bin_count * QUERY_CACHE_MEM_BIN_PARTS_MUL);
+
+ // Prevent too small bins spacing
+ if (mem_bin_count > (mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2))
+ mem_bin_count= (mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2);
+ }
+ inc = (prev_size - mem_bin_size) / mem_bin_count;
+ mem_bin_num += (mem_bin_count - (min_allocation_unit - mem_bin_size)/inc);
+ mem_bin_steps++;
+ additional_data_size = ((mem_bin_num+1) *
+ ALIGN_SIZE(sizeof(Query_cache_memory_bin))+
+ (mem_bin_steps *
+ ALIGN_SIZE(sizeof(Query_cache_memory_bin_step))));
+
+ if (query_cache_size < additional_data_size)
+ goto err;
+ query_cache_size -= additional_data_size;
+
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (query_cache_size <= min_allocation_unit)
+ {
+ DBUG_PRINT("qcache",
+ (" query_cache_size <= min_allocation_unit => cache disabled"));
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ goto err;
+ }
+
+ if (!(cache = (byte *)
+ my_malloc_lock(query_cache_size+additional_data_size, MYF(0))))
+ {
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ goto err;
+ }
+
+ DBUG_PRINT("qcache", ("cache length %lu, min unit %lu, %u bins",
+ query_cache_size, min_allocation_unit, mem_bin_num));
+
+ steps = (Query_cache_memory_bin_step *) cache;
+ bins = ((Query_cache_memory_bin *)
+ (cache + mem_bin_steps *
+ ALIGN_SIZE(sizeof(Query_cache_memory_bin_step))));
+
+ first_block = (Query_cache_block *) (cache + additional_data_size);
+ first_block->init(query_cache_size);
+ total_blocks++;
+ first_block->pnext=first_block->pprev=first_block;
+ first_block->next=first_block->prev=first_block;
+
+ /* Prepare bins */
+
+ bins[0].init(max_mem_bin_size);
+ steps[0].init(max_mem_bin_size,0,0);
+ mem_bin_count = (uint) ((1 + QUERY_CACHE_MEM_BIN_PARTS_INC) *
+ QUERY_CACHE_MEM_BIN_PARTS_MUL);
+ num= step= 1;
+ mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2;
+ while (mem_bin_size > min_allocation_unit)
+ {
+ ulong incr = (steps[step-1].size - mem_bin_size) / mem_bin_count;
+ unsigned long size = mem_bin_size;
+ for (uint i= mem_bin_count; i > 0; i--)
+ {
+ bins[num+i-1].init(size);
+ size += incr;
+ }
+ num += mem_bin_count;
+ steps[step].init(mem_bin_size, num-1, incr);
+ mem_bin_size >>= QUERY_CACHE_MEM_BIN_STEP_PWR2;
+ step++;
+ mem_bin_count += QUERY_CACHE_MEM_BIN_PARTS_INC;
+ mem_bin_count = (uint) (mem_bin_count * QUERY_CACHE_MEM_BIN_PARTS_MUL);
+ if (mem_bin_count > (mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2))
+ mem_bin_count=(mem_bin_size >> QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2);
+ }
+ inc = (steps[step-1].size - mem_bin_size) / mem_bin_count;
+
+ /*
+ num + mem_bin_count > mem_bin_num, but index never be > mem_bin_num
+ because block with size < min_allocated_unit never will be requested
+ */
+
+ steps[step].init(mem_bin_size, num + mem_bin_count - 1, inc);
+ {
+ uint skiped = (min_allocation_unit - mem_bin_size)/inc;
+ ulong size = mem_bin_size + inc*skiped;
+ uint i = mem_bin_count - skiped;
+ while (i-- > 0)
+ {
+ bins[num+i].init(size);
+ size += inc;
+ }
+ }
+ bins[mem_bin_num].number = 1; // For easy end test in get_free_block
+ free_memory = free_memory_blocks = 0;
+ insert_into_free_memory_list(first_block);
+
+ DUMP(this);
+
+ VOID(hash_init(&queries,def_query_hash_size, 0, 0,
+ query_cache_query_get_key, 0, 0));
+ VOID(hash_init(&tables,def_table_hash_size, 0, 0,
+ query_cache_table_get_key, 0, 0));
+
+ queries_in_cache = 0;
+ queries_blocks = 0;
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_RETURN(query_cache_size +
+ additional_data_size + approx_additional_data_size);
+
+err:
+ make_disabled();
+ DBUG_RETURN(0);
+}
+
+
+/* Disable the use of the query cache */
+
+void Query_cache::make_disabled()
+{
+ DBUG_ENTER("Query_cache::make_disabled");
+ query_cache_size= 0;
+ free_memory= 0;
+ bins= 0;
+ steps= 0;
+ cache= 0;
+ mem_bin_num= mem_bin_steps= 0;
+ queries_in_cache= 0;
+ first_block= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::free_cache(my_bool destruction)
+{
+ DBUG_ENTER("Query_cache::free_cache");
+ if (query_cache_size > 0)
+ {
+ if (!destruction)
+ STRUCT_LOCK(&structure_guard_mutex);
+
+ flush_cache();
+#ifndef DBUG_OFF
+ if (bins[0].free_blocks == 0)
+ {
+ wreck(__LINE__,"no free memory found in (bins[0].free_blocks");
+ DBUG_VOID_RETURN;
+ }
+#endif
+
+ /* Becasue we did a flush, all cache memory must be in one this block */
+ bins[0].free_blocks->destroy();
+ total_blocks--;
+#ifndef DBUG_OFF
+ if (free_memory != query_cache_size)
+ DBUG_PRINT("qcache", ("free memory %lu (should be %lu)",
+ free_memory , query_cache_size));
+#endif
+ my_free((gptr) cache, MYF(MY_ALLOW_ZERO_PTR));
+ make_disabled();
+ hash_free(&queries);
+ hash_free(&tables);
+ if (!destruction)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*****************************************************************************
+ Free block data
+*****************************************************************************/
+
+/*
+ The following assumes we have a lock on the cache
+*/
+
+void Query_cache::flush_cache()
+{
+ while (queries_blocks != 0)
+ {
+ BLOCK_LOCK_WR(queries_blocks);
+ free_query(queries_blocks);
+ }
+}
+
+/*
+ Free oldest query that is not in use by another thread.
+ Returns 1 if we couldn't remove anything
+*/
+
+my_bool Query_cache::free_old_query()
+{
+ DBUG_ENTER("Query_cache::free_old_query");
+ if (queries_blocks)
+ {
+ /*
+ try_lock_writing used to prevent client because here lock
+ sequence is breached.
+ Also we don't need remove locked queries at this point.
+ */
+ Query_cache_block *query_block = 0;
+ if (queries_blocks != 0)
+ {
+ Query_cache_block *block = queries_blocks;
+ /* Search until we find first query that we can remove */
+ do
+ {
+ Query_cache_query *header = block->query();
+ if (header->result() != 0 &&
+ header->result()->type == Query_cache_block::RESULT &&
+ block->query()->try_lock_writing())
+ {
+ query_block = block;
+ break;
+ }
+ } while ((block=block->next) != queries_blocks );
+ }
+
+ if (query_block != 0)
+ {
+ free_query(query_block);
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(1); // Nothing to remove
+}
+
+/*
+ Free query from query cache.
+ query_block must be locked for writing.
+ This function will remove (and destroy) the lock for the query.
+*/
+
+void Query_cache::free_query(Query_cache_block *query_block)
+{
+ DBUG_ENTER("Query_cache::free_query");
+ DBUG_PRINT("qcache", ("free query 0x%lx %lu bytes result",
+ (ulong) query_block,
+ query_block->query()->length() ));
+
+ queries_in_cache--;
+ hash_delete(&queries,(byte *) query_block);
+
+ Query_cache_query *query = query_block->query();
+
+ if (query->writer() != 0)
+ {
+ /* Tell MySQL that this query should not be cached anymore */
+ query->writer()->query_cache_query = 0;
+ query->writer(0);
+ }
+ double_linked_list_exclude(query_block, &queries_blocks);
+ Query_cache_block_table *table=query_block->table(0);
+
+ for (TABLE_COUNTER_TYPE i=0; i < query_block->n_tables; i++)
+ unlink_table(table++);
+ Query_cache_block *result_block = query->result();
+
+ /*
+ The following is true when query destruction was called and no results
+ in query . (query just registered and then abort/pack/flush called)
+ */
+ if (result_block != 0)
+ {
+ Query_cache_block *block = result_block;
+ do
+ {
+ Query_cache_block *current = block;
+ block = block->next;
+ free_memory_block(current);
+ } while (block != result_block);
+ }
+
+ query->unlock_n_destroy();
+ free_memory_block(query_block);
+
+ DBUG_VOID_RETURN;
+}
+
+/*****************************************************************************
+ Query data creation
+*****************************************************************************/
+
+Query_cache_block *
+Query_cache::write_block_data(ulong data_len, gptr data,
+ ulong header_len,
+ Query_cache_block::block_type type,
+ TABLE_COUNTER_TYPE ntab,
+ my_bool under_guard)
+{
+ ulong all_headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(ntab*sizeof(Query_cache_block_table)) +
+ header_len);
+ ulong len = data_len + all_headers_len;
+ DBUG_ENTER("Query_cache::write_block_data");
+ DBUG_PRINT("qcache", ("data: %ld, header: %ld, all header: %ld",
+ data_len, header_len, all_headers_len));
+ Query_cache_block *block = allocate_block(max(len, min_allocation_unit),
+ 1, 0, under_guard);
+ if (block != 0)
+ {
+ block->type = type;
+ block->n_tables = ntab;
+ block->used = len;
+
+ memcpy((void*) (((byte *) block)+ all_headers_len),
+ (void*) data, data_len);
+ }
+ DBUG_RETURN(block);
+}
+
+
+/*
+ On success STRUCT_UNLOCK(&query_cache.structure_guard_mutex) will be done.
+*/
+
+my_bool
+Query_cache::append_result_data(Query_cache_block **current_block,
+ ulong data_len, gptr data,
+ Query_cache_block *query_block)
+{
+ DBUG_ENTER("Query_cache::append_result_data");
+ DBUG_PRINT("qcache", ("append %lu bytes to 0x%lx query",
+ data_len, query_block));
+
+ if (query_block->query()->add(data_len) > query_cache_limit)
+ {
+ DBUG_PRINT("qcache", ("size limit reached %lu > %lu",
+ query_block->query()->length(),
+ query_cache_limit));
+ DBUG_RETURN(0);
+ }
+ if (*current_block == 0)
+ {
+ DBUG_PRINT("qcache", ("allocated first result data block %lu", data_len));
+ /*
+ STRUCT_UNLOCK(&structure_guard_mutex) Will be done by
+ write_result_data if success;
+ */
+ DBUG_RETURN(write_result_data(current_block, data_len, data, query_block,
+ Query_cache_block::RES_BEG));
+ }
+ Query_cache_block *last_block = (*current_block)->prev;
+
+ DBUG_PRINT("qcache", ("lastblock 0x%lx len %lu used %lu",
+ (ulong) last_block, last_block->length,
+ last_block->used));
+ my_bool success = 1;
+ ulong last_block_free_space= last_block->length - last_block->used;
+
+ /*
+ We will first allocate and write the 'tail' of data, that doesn't fit
+ in the 'last_block'. Only if this succeeds, we will fill the last_block.
+ This saves us a memcpy if the query doesn't fit in the query cache.
+ */
+
+ // Try join blocks if physically next block is free...
+ ulong tail = data_len - last_block_free_space;
+ ulong append_min = get_min_append_result_data_size();
+ if (last_block_free_space < data_len &&
+ append_next_free_block(last_block,
+ max(tail, append_min)))
+ last_block_free_space = last_block->length - last_block->used;
+ // If no space in last block (even after join) allocate new block
+ if (last_block_free_space < data_len)
+ {
+ DBUG_PRINT("qcache", ("allocate new block for %lu bytes",
+ data_len-last_block_free_space));
+ Query_cache_block *new_block = 0;
+ /*
+ On success STRUCT_UNLOCK(&structure_guard_mutex) will be done
+ by the next call
+ */
+ success = write_result_data(&new_block, data_len-last_block_free_space,
+ (gptr)(((byte*)data)+last_block_free_space),
+ query_block,
+ Query_cache_block::RES_CONT);
+ /*
+ new_block may be != 0 even !success (if write_result_data
+ allocate a small block but failed to allocate continue)
+ */
+ if (new_block != 0)
+ double_linked_list_join(last_block, new_block);
+ }
+ else
+ {
+ // It is success (nobody can prevent us write data)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ }
+
+ // Now finally write data to the last block
+ if (success && last_block_free_space > 0)
+ {
+ ulong to_copy = min(data_len,last_block_free_space);
+ DBUG_PRINT("qcache", ("use free space %lub at block 0x%lx to copy %lub",
+ last_block_free_space, (ulong)last_block, to_copy));
+ memcpy((void*) (((byte*) last_block) + last_block->used), (void*) data,
+ to_copy);
+ last_block->used+=to_copy;
+ }
+ DBUG_RETURN(success);
}
+
+
+my_bool Query_cache::write_result_data(Query_cache_block **result_block,
+ ulong data_len, gptr data,
+ Query_cache_block *query_block,
+ Query_cache_block::block_type type)
+{
+ DBUG_ENTER("Query_cache::write_result_data");
+ DBUG_PRINT("qcache", ("data_len %lu",data_len));
+
+ /*
+ Reserve block(s) for filling
+ During data allocation we must have structure_guard_mutex locked.
+ As data copy is not a fast operation, it's better if we don't have
+ structure_guard_mutex locked during data coping.
+ Thus we first allocate space and lock query, then unlock
+ structure_guard_mutex and copy data.
+ */
+
+ my_bool success = allocate_data_chain(result_block, data_len, query_block,
+ type == Query_cache_block::RES_BEG);
+ if (success)
+ {
+ // It is success (nobody can prevent us write data)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ byte *rest = (byte*) data;
+ Query_cache_block *block = *result_block;
+ uint headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_result)));
+ // Now fill list of blocks that created by allocate_data_chain
+ do
+ {
+ block->type = type;
+ ulong length = block->used - headers_len;
+ DBUG_PRINT("qcache", ("write %lu byte in block 0x%lx",length,
+ (ulong)block));
+ memcpy((void*)(((byte*) block)+headers_len), (void*) rest, length);
+ rest += length;
+ block = block->next;
+ type = Query_cache_block::RES_CONT;
+ } while (block != *result_block);
+ }
+ else
+ {
+ if (*result_block != 0)
+ {
+ // Destroy list of blocks that was created & locked by lock_result_data
+ Query_cache_block *block = *result_block;
+ do
+ {
+ Query_cache_block *current = block;
+ block = block->next;
+ free_memory_block(current);
+ } while (block != *result_block);
+ *result_block = 0;
+ /*
+ It is not success => not unlock structure_guard_mutex (we need it to
+ free query)
+ */
+ }
+ }
+ DBUG_PRINT("qcache", ("success %d", (int) success));
+ DBUG_RETURN(success);
+}
+
+inline ulong Query_cache::get_min_first_result_data_size()
+{
+ if (queries_in_cache < QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER)
+ return min_result_data_size;
+ ulong avg_result = (query_cache_size - free_memory) / queries_in_cache;
+ avg_result = min(avg_result, query_cache_limit);
+ return max(min_result_data_size, avg_result);
+}
+
+inline ulong Query_cache::get_min_append_result_data_size()
+{
+ return min_result_data_size;
+}
+
+/*
+ Allocate one or more blocks to hold data
+*/
+
+my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block,
+ ulong data_len,
+ Query_cache_block *query_block,
+ my_bool first_block)
+{
+ ulong all_headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_result)));
+ ulong len = data_len + all_headers_len;
+ DBUG_ENTER("Query_cache::allocate_data_chain");
+ DBUG_PRINT("qcache", ("data_len %lu, all_headers_len %lu",
+ data_len, all_headers_len));
+
+ ulong min_size = (first_block ?
+ get_min_first_result_data_size():
+ get_min_append_result_data_size());
+ *result_block = allocate_block(max(min_size,len),
+ min_result_data_size == 0,
+ all_headers_len + min_result_data_size,
+ 1);
+ my_bool success = (*result_block != 0);
+ if (success)
+ {
+ Query_cache_block *new_block= *result_block;
+ new_block->n_tables = 0;
+ new_block->used = 0;
+ new_block->type = Query_cache_block::RES_INCOMPLETE;
+ new_block->next = new_block->prev = new_block;
+ Query_cache_result *header = new_block->result();
+ header->parent(query_block);
+
+ if (new_block->length < len)
+ {
+ /*
+ We got less memory then we need (no big memory blocks) =>
+ Continue to allocated more blocks until we got everything we need.
+ */
+ Query_cache_block *next_block;
+ if ((success = allocate_data_chain(&next_block,
+ len - new_block->length,
+ query_block, first_block)))
+ double_linked_list_join(new_block, next_block);
+ }
+ if (success)
+ {
+ new_block->used = min(len, new_block->length);
+
+ DBUG_PRINT("qcache", ("Block len %lu used %lu",
+ new_block->length, new_block->used));
+ }
+ else
+ DBUG_PRINT("warning", ("Can't allocate block for continue"));
+ }
+ else
+ DBUG_PRINT("warning", ("Can't allocate block for results"));
+ DBUG_RETURN(success);
+}
+
+/*****************************************************************************
+ Tables management
+*****************************************************************************/
+
+/*
+ Invalidate the first table in the table_list
+*/
+
+void Query_cache::invalidate_table(TABLE_LIST *table_list)
+{
+ if (table_list->table != 0)
+ invalidate_table(table_list->table); // Table is open
+ else
+ {
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+ Query_cache_block *table_block;
+ key_length=(uint) (strmov(strmov(key,table_list->db)+1,
+ table_list->real_name) -key)+ 1;
+
+ // We don't store temporary tables => no key_length+=4 ...
+ if ((table_block = (Query_cache_block*)
+ hash_search(&tables,(byte*) key,key_length)))
+ invalidate_table(table_block);
+ }
+}
+
+void Query_cache::invalidate_table(TABLE *table)
+{
+ Query_cache_block *table_block;
+ if ((table_block = ((Query_cache_block*)
+ hash_search(&tables, (byte*) table->table_cache_key,
+ table->key_length))))
+ invalidate_table(table_block);
+}
+
+void Query_cache::invalidate_table(Query_cache_block *table_block)
+{
+ Query_cache_block_table *list_root = table_block->table(0);
+ while (list_root->next != list_root)
+ {
+ Query_cache_block *query_block = list_root->next->block();
+ BLOCK_LOCK_WR(query_block);
+ free_query(query_block);
+ }
+}
+
+
+my_bool Query_cache::register_all_tables(Query_cache_block *block,
+ TABLE_LIST *tables_used,
+ TABLE_COUNTER_TYPE tables)
+{
+ TABLE_COUNTER_TYPE n;
+ DBUG_PRINT("qcache", ("register tables block 0x%lx, n %d, header %x",
+ (ulong) block, (int) tables,
+ (int) ALIGN_SIZE(sizeof(Query_cache_block))));
+
+ Query_cache_block_table *block_table = block->table(0);
+
+ for (n=0; tables_used; tables_used=tables_used->next, n++, block_table++)
+ {
+ DBUG_PRINT("qcache",
+ ("table %s, db %s, openinfo at 0x%lx, keylen %u, key at 0x%lx",
+ tables_used->real_name, tables_used->db,
+ (ulong) tables_used->table,
+ tables_used->table->key_length,
+ (ulong) tables_used->table->table_cache_key));
+ block_table->n=n;
+ if (!insert_table(tables_used->table->key_length,
+ tables_used->table->table_cache_key, block_table,
+ Query_cache_table::type_convertion(tables_used->table->
+ db_type)))
+ break;
+
+ if (tables_used->table->db_type == DB_TYPE_MRG_MYISAM)
+ {
+ ha_myisammrg *handler = (ha_myisammrg *) tables_used->table->file;
+ MYRG_INFO *file = handler->myrg_info();
+ for (MYRG_TABLE *table = file->open_tables;
+ table != file->end_table ;
+ table++)
+ {
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length =filename_2_table_key(key, table->table->filename);
+ (++block_table)->n= ++n;
+ if (!insert_table(key_length, key, block_table,
+ Query_cache_table::type_convertion(DB_TYPE_MYISAM)))
+ goto err;
+ }
+ }
+ }
+
+err:
+ if (tables_used)
+ {
+ DBUG_PRINT("qcache", ("failed at table %d", (int) n));
+ /* Unlink the tables we allocated above */
+ for (Query_cache_block_table *tmp = block->table(0) ;
+ tmp != block_table;
+ tmp++)
+ unlink_table(tmp);
+ }
+ return (tables_used == 0);
+}
+
+/*
+ Insert used tablename in cache
+ Returns 0 on error
+*/
+
+my_bool
+Query_cache::insert_table(uint key_len, char *key,
+ Query_cache_block_table *node,
+ Query_cache_table::query_cache_table_type type)
+{
+ DBUG_ENTER("Query_cache::insert_table");
+ DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d",
+ (ulong)node, key_len));
+
+ Query_cache_block *table_block = ((Query_cache_block *)
+ hash_search(&tables, (byte*) key,
+ key_len));
+
+ if (table_block == 0)
+ {
+ DBUG_PRINT("qcache", ("new table block from 0x%lx (%u)",
+ (ulong) key, (int) key_len));
+ table_block = write_block_data(key_len, (gptr) key,
+ ALIGN_SIZE(sizeof(Query_cache_table)),
+ Query_cache_block::TABLE,
+ 1, 1);
+ if (table_block == 0)
+ {
+ DBUG_PRINT("qcache", ("Can't write table name to cache"));
+ DBUG_RETURN(0);
+ }
+ Query_cache_table *header = table_block->table();
+ header->type(type);
+ double_linked_list_simple_include(table_block,
+ &tables_blocks[type]);
+ Query_cache_block_table *list_root = table_block->table(0);
+ list_root->n = 0;
+ list_root->next = list_root->prev = list_root;
+ if (hash_insert(&tables, (const byte *) table_block))
+ {
+ DBUG_PRINT("qcache", ("Can't insert table to hash"));
+ // write_block_data return locked block
+ free_memory_block(table_block);
+ DBUG_RETURN(0);
+ }
+ char *db = header->db();
+ header->table(db + strlen(db) + 1);
+ }
+
+ Query_cache_block_table *list_root = table_block->table(0);
+ node->next = list_root->next;
+ list_root->next = node;
+ node->next->prev = node;
+ node->prev = list_root;
+ node->parent = table_block->table();
+ DBUG_RETURN(1);
+}
+
+
+void Query_cache::unlink_table(Query_cache_block_table *node)
+{
+ DBUG_ENTER("Query_cache::unlink_table");
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ Query_cache_block_table *neighbour = node->next;
+ if (neighbour->next == neighbour)
+ {
+ // list is empty (neighbor is root of list)
+ Query_cache_block *table_block = neighbour->block();
+ double_linked_list_exclude(table_block,
+ &tables_blocks[table_block->table()->type()]);
+ hash_delete(&tables,(byte *) table_block);
+ free_memory_block(table_block);
+ }
+ DBUG_VOID_RETURN;
+}
+
+/*****************************************************************************
+ Free memory management
+*****************************************************************************/
+
+Query_cache_block *
+Query_cache::allocate_block(ulong len, my_bool not_less, ulong min,
+ my_bool under_guard)
+{
+ DBUG_ENTER("Query_cache::allocate_n_lock_block");
+ DBUG_PRINT("qcache", ("len %lu, not less %d, min %lu, uder_guard %d",
+ len, not_less,min,under_guard));
+
+ if (len >= min(query_cache_size, query_cache_limit))
+ {
+ DBUG_PRINT("qcache", ("Query cache hase only %lu memory and limit %lu",
+ query_cache_size, query_cache_limit));
+ DBUG_RETURN(0); // in any case we don't have such piece of memory
+ }
+
+ if (!under_guard)
+ STRUCT_LOCK(&structure_guard_mutex);
+
+ /* Free old queries until we have enough memory to store this block */
+ Query_cache_block *block;
+ do
+ {
+ block= get_free_block(len, not_less, min);
+ }
+ while (block == 0 && !free_old_query());
+
+ if (block != 0) // If we found a suitable block
+ {
+ if (block->length >= ALIGN_SIZE(len) + min_allocation_unit)
+ split_block(block,ALIGN_SIZE(len));
+ }
+
+ if (!under_guard)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_RETURN(block);
+}
+
+
+Query_cache_block *
+Query_cache::get_free_block(ulong len, my_bool not_less, ulong min)
+{
+ Query_cache_block *block = 0, *first = 0;
+ DBUG_ENTER("Query_cache::get_free_block");
+ DBUG_PRINT("qcache",("length %lu, not_less %d, min %lu", len,
+ (int)not_less, min));
+
+ /* Find block with minimal size > len */
+ uint start = find_bin(len);
+ // try matching bin
+ if (bins[start].number != 0)
+ {
+ Query_cache_block *list = bins[start].free_blocks;
+ ulong max_len = list->prev->length;
+ if (list->prev->length >= len) // check block with max size
+ {
+ first = list;
+ uint n = 0;
+ while ( n < QUERY_CACHE_MEM_BIN_TRY &&
+ first->length < len) //we don't need irst->next != list
+ {
+ first=first->next;
+ n++;
+ }
+ if (first->length >= len)
+ block=first;
+ else // we don't need if (first->next != list)
+ {
+ n = 0;
+ block = list->prev;
+ while (n < QUERY_CACHE_MEM_BIN_TRY &&
+ block->length > len)
+ {
+ block=block->prev;
+ n++;
+ }
+ if(block->length < len)
+ block=block->next;
+ }
+ }
+ else
+ first = list->prev;
+ }
+ if (block == 0 && start > 0)
+ {
+ DBUG_PRINT("qcache",("Try bins with bigger block size"));
+ // Try more big bins
+ int i = start - 1;
+ while (i > 0 && bins[i].number == 0)
+ i--;
+ if (bins[i].number > 0)
+ block = bins[i].free_blocks;
+ }
+
+ // If no big blocks => try less size (if it is possible)
+ if (block == 0 && ! not_less)
+ {
+ DBUG_PRINT("qcache",("Try to allocate a smaller block"));
+ if (first != 0 && first->length > min)
+ block = first;
+ else
+ {
+ uint i = start + 1;
+ /* bins[mem_bin_num].number contains 1 for easy end test */
+ for (i= start+1 ; bins[i].number == 0 ; i++) ;
+ if (i < mem_bin_num && bins[i].free_blocks->prev->length >= min)
+ block = bins[i].free_blocks->prev;
+ }
+ }
+ if (block != 0)
+ exclude_from_free_memory_list(block);
+
+ DBUG_PRINT("qcache",("getting block 0x%lx", (ulong) block));
+ DBUG_RETURN(block);
+}
+
+
+void Query_cache::free_memory_block(Query_cache_block *block)
+{
+ DBUG_ENTER("Query_cache::free_memory_block");
+ block->used=0;
+ DBUG_PRINT("qcache",("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx",
+ (ulong) first_block, (ulong) block,block->pnext,
+ (ulong) block->pprev));
+
+ if (block->pnext != first_block && block->pnext->is_free())
+ block = join_free_blocks(block, block->pnext);
+ if (block != first_block && block->pprev->is_free())
+ block = join_free_blocks(block->pprev, block->pprev);
+ insert_into_free_memory_list(block);
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::split_block(Query_cache_block *block, ulong len)
+{
+ DBUG_ENTER("Query_cache::split_block");
+ Query_cache_block *new_block = (Query_cache_block*)(((byte*) block)+len);
+
+ new_block->init(block->length - len);
+ total_blocks++;
+ block->length=len;
+ new_block->pnext = block->pnext;
+ block->pnext = new_block;
+ new_block->pprev = block;
+ new_block->pnext->pprev = new_block;
+
+ if (block->type == Query_cache_block::FREE)
+ // if block was free then it already joined with all free neighbours
+ insert_into_free_memory_list(new_block);
+ else
+ free_memory_block(new_block);
+
+ DBUG_PRINT("qcache", ("split 0x%lx (%lu) new 0x%lx",
+ (ulong) block, len, (ulong) new_block));
+ DBUG_VOID_RETURN;
+}
+
+
+Query_cache_block *
+Query_cache::join_free_blocks(Query_cache_block *first_block,
+ Query_cache_block *block_in_list)
+{
+ Query_cache_block *second_block;
+ DBUG_ENTER("Query_cache::join_free_blocks");
+ DBUG_PRINT("qcache",
+ ("join first 0x%lx, pnext 0x%lx, in list 0x%lx",
+ (ulong) first_block, (ulong) first_block->pnext,
+ (ulong) block_in_list));
+
+ exclude_from_free_memory_list(block_in_list);
+ second_block = first_block->pnext;
+ // May be was not free block
+ second_block->used=0;
+ second_block->destroy();
+ total_blocks--;
+
+ first_block->length += second_block->length;
+ first_block->pnext = second_block->pnext;
+ second_block->pnext->pprev = first_block;
+
+ DBUG_RETURN(first_block);
+}
+
+
+my_bool Query_cache::append_next_free_block(Query_cache_block *block,
+ ulong add_size)
+{
+ Query_cache_block *next_block = block->pnext;
+ DBUG_ENTER("Query_cache::append_next_free_block");
+ DBUG_PRINT("enter", ("block 0x%lx, add_size %lu", (ulong) block,
+ add_size));
+
+ if (next_block != first_block && next_block->is_free())
+ {
+ ulong old_len = block->length;
+ exclude_from_free_memory_list(next_block);
+ next_block->destroy();
+ total_blocks--;
+
+ block->length += next_block->length;
+ block->pnext = next_block->pnext;
+ next_block->pnext->pprev = block;
+
+ if (block->length > ALIGN_SIZE(old_len + add_size) + min_allocation_unit)
+ split_block(block,ALIGN_SIZE(old_len + add_size));
+ DBUG_PRINT("exit", ("block was appended"));
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+void Query_cache::exclude_from_free_memory_list(Query_cache_block *free_block)
+{
+ DBUG_ENTER("Query_cache::exclude_from_free_memory_list");
+ Query_cache_memory_bin *bin = *((Query_cache_memory_bin **)
+ free_block->data());
+ double_linked_list_exclude(free_block, &bin->free_blocks);
+ bin->number--;
+ free_memory-=free_block->length;
+ free_memory_blocks--;
+ DBUG_PRINT("qcache",("exclude block 0x%lx, bin 0x%lx", (ulong) free_block,
+ (ulong) bin));
+ DBUG_VOID_RETURN;
+}
+
+void Query_cache::insert_into_free_memory_list(Query_cache_block *free_block)
+{
+ DBUG_ENTER("Query_cache::insert_into_free_memory_list");
+ uint idx = find_bin(free_block->length);
+ insert_into_free_memory_sorted_list(free_block, &bins[idx].free_blocks);
+ /*
+ We have enough memory in block for storing bin reference due to
+ min_allocation_unit choice
+ */
+ Query_cache_memory_bin **bin_ptr = ((Query_cache_memory_bin**)
+ free_block->data());
+ *bin_ptr = bins+idx;
+ (*bin_ptr)->number++;
+ DBUG_PRINT("qcache",("insert block 0x%lx, bin[%d] 0x%lx",
+ (ulong) free_block, idx, (ulong) *bin_ptr));
+ DBUG_VOID_RETURN;
+}
+
+uint Query_cache::find_bin(ulong size)
+{
+ DBUG_ENTER("Query_cache::find_bin");
+ // Binary search
+ int left = 0, right = mem_bin_steps;
+ do
+ {
+ int middle = (left + right) / 2;
+ if (steps[middle].size > size)
+ left = middle+1;
+ else
+ right = middle;
+ } while (left < right);
+ if (left == 0)
+ {
+ // first bin not subordinate of common rules
+ DBUG_PRINT("qcache", ("first bin (# 0), size %lu",size));
+ DBUG_RETURN(0);
+ }
+ uint bin = steps[left].idx -
+ (uint)((size - steps[left].size)/steps[left].increment);
+#ifndef DBUG_OFF
+ bins_dump();
+#endif
+ DBUG_PRINT("qcache", ("bin %u step %u, size %lu step size %lu",
+ bin, left, size, steps[left].size));
+ DBUG_RETURN(bin);
+}
+
+
+/*****************************************************************************
+ Lists management
+*****************************************************************************/
+
+void Query_cache::move_to_query_list_end(Query_cache_block *query_block)
+{
+ DBUG_ENTER("Query_cache::move_to_query_list_end");
+ double_linked_list_exclude(query_block, &queries_blocks);
+ double_linked_list_simple_include(query_block, &queries_blocks);
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::insert_into_free_memory_sorted_list(Query_cache_block *
+ new_block,
+ Query_cache_block **
+ list)
+{
+ DBUG_ENTER("Query_cache::insert_into_free_memory_sorted_list");
+ /*
+ list sorted by size in ascendant order, because we need small blocks
+ more frequently than bigger ones
+ */
+
+ new_block->used = 0;
+ new_block->n_tables = 0;
+ new_block->type = Query_cache_block::FREE;
+
+ if (*list == 0)
+ {
+ *list = new_block->next=new_block->prev=new_block;
+ DBUG_PRINT("qcache", ("inserted into empty list"));
+ }
+ else
+ {
+ Query_cache_block *point = *list;
+ if (point->length >= new_block->length)
+ {
+ point = point->prev;
+ *list = new_block;
+ }
+ else
+ {
+ /* Find right position in sorted list to put block */
+ while (point->next != *list &&
+ point->next->length < new_block->length)
+ point=point->next;
+ }
+ new_block->prev = point;
+ new_block->next = point->next;
+ new_block->next->prev = new_block;
+ point->next = new_block;
+ }
+ free_memory+=new_block->length;
+ free_memory_blocks++;
+ DBUG_VOID_RETURN;
+}
+
+
+void
+Query_cache::double_linked_list_simple_include(Query_cache_block *point,
+ Query_cache_block **
+ list_pointer)
+{
+ DBUG_ENTER("Query_cache::double_linked_list_simple_include");
+ DBUG_PRINT("qcache", ("including block 0x%lx", (ulong) point));
+ if (*list_pointer == 0)
+ *list_pointer=point->next=point->prev=point;
+ else
+ {
+ // insert to and of list
+ point->next = (*list_pointer);
+ point->prev = (*list_pointer)->prev;
+ point->prev->next = point;
+ (*list_pointer)->prev = point;
+ }
+ DBUG_VOID_RETURN;
+}
+
+void
+Query_cache::double_linked_list_exclude(Query_cache_block *point,
+ Query_cache_block **list_pointer)
+{
+ DBUG_ENTER("Query_cache::double_linked_list_exclude");
+ DBUG_PRINT("qcache", ("excluding block 0x%lx, list 0x%lx",
+ (ulong) point, (ulong) list_pointer));
+ if (point->next == point)
+ *list_pointer = 0; // empty list
+ else
+ {
+ point->next->prev = point->prev;
+ point->prev->next = point->next;
+ if (point == *list_pointer)
+ *list_pointer = point->next;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::double_linked_list_join(Query_cache_block *head_tail,
+ Query_cache_block *tail_head)
+{
+ Query_cache_block *head_head = head_tail->next,
+ *tail_tail = tail_head->prev;
+ head_head->prev = tail_tail;
+ head_tail->next = tail_head;
+ tail_head->prev = head_tail;
+ tail_tail->next = head_head;
+}
+
+/*****************************************************************************
+ Query
+*****************************************************************************/
+
+/*
+ If query is cacheable return number tables in query
+ (query without tables are not cached)
+*/
+
+TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
+ char *query,
+ LEX *lex, TABLE_LIST *tables_used)
+{
+ TABLE_COUNTER_TYPE tables = 0;
+ DBUG_ENTER("Query_cache::is_cacheable");
+
+ if (lex->sql_command == SQLCOM_SELECT &&
+ thd->temporary_tables == 0 &&
+ (thd->query_cache_type == 1 ||
+ (thd->query_cache_type == 2 && (lex->select->options &
+ OPTION_TO_QUERY_CACHE))) &&
+ thd->safe_to_cache_query)
+ {
+ my_bool has_transactions = 0;
+ DBUG_PRINT("qcache", ("options %lx %lx, type %u",
+ OPTION_TO_QUERY_CACHE,
+ lex->select->options,
+ (int) thd->query_cache_type));
+
+ for (; tables_used; tables_used=tables_used->next)
+ {
+ tables++;
+ DBUG_PRINT("qcache", ("table %s, db %s, type %u",
+ tables_used->real_name,
+ tables_used->db, tables_used->table->db_type));
+ has_transactions = (has_transactions ||
+ tables_used->table->file->has_transactions());
+
+ if (tables_used->table->db_type == DB_TYPE_MRG_ISAM)
+ {
+ DBUG_PRINT("qcache", ("select not cacheable: used MRG_ISAM table(s)"));
+ DBUG_RETURN(0);
+ }
+ if (tables_used->table->db_type == DB_TYPE_MRG_MYISAM)
+ {
+ ha_myisammrg *handler = (ha_myisammrg *)tables_used->table->file;
+ MYRG_INFO *file = handler->myrg_info();
+ tables+= (file->end_table - file->open_tables);
+ }
+ }
+
+ if ((thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)) &&
+ has_transactions)
+ {
+ DBUG_PRINT("qcache", ("not in autocommin mode"));
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("qcache", ("select is using %d tables", tables));
+ DBUG_RETURN(tables);
+ }
+
+ DBUG_PRINT("qcache",
+ ("not interesting query: %d or not cacheable, options %lx %lx, type %u",
+ (int) lex->sql_command,
+ OPTION_TO_QUERY_CACHE,
+ lex->select->options,
+ (int) thd->query_cache_type));
+ DBUG_RETURN(0);
+}
+
+
+/*****************************************************************************
+ Packing
+*****************************************************************************/
+
+void Query_cache::pack_cache()
+{
+ DBUG_ENTER("Query_cache::pack_cache");
+ STRUCT_LOCK(&structure_guard_mutex);
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
+
+ byte *border = 0;
+ Query_cache_block *before = 0;
+ ulong gap = 0;
+ my_bool ok = 1;
+ Query_cache_block *block = first_block;
+ DUMP(this);
+
+ if (first_block)
+ {
+ do
+ {
+ Query_cache_block *next=block->pnext;
+ ok = move_by_type(&border, &before, &gap, block);
+ block = next;
+ } while (ok && block != first_block);
+
+ if (border != 0)
+ {
+ Query_cache_block *new_block = (Query_cache_block *) border;
+ new_block->init(gap);
+ total_blocks++;
+ new_block->pnext = before->pnext;
+ before->pnext = new_block;
+ new_block->pprev = before;
+ new_block->pnext->pprev = new_block;
+ insert_into_free_memory_list(new_block);
+ }
+ DUMP(this);
+ }
+
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_VOID_RETURN;
+}
+
+
+my_bool Query_cache::move_by_type(byte **border,
+ Query_cache_block **before, ulong *gap,
+ Query_cache_block *block)
+{
+ DBUG_ENTER("Query_cache::move_by_type");
+
+ my_bool ok = 1;
+ switch (block->type) {
+ case Query_cache_block::FREE:
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx FREE", (ulong) block));
+ if (*border == 0)
+ {
+ *border = (byte *) block;
+ *before = block->pprev;
+ DBUG_PRINT("qcache", ("gap beginning here"));
+ }
+ exclude_from_free_memory_list(block);
+ *gap +=block->length;
+ block->pprev->pnext=block->pnext;
+ block->pnext->pprev=block->pprev;
+ block->destroy();
+ total_blocks--;
+ DBUG_PRINT("qcache", ("added to gap (%lu)", *gap));
+ break;
+ }
+ case Query_cache_block::TABLE:
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx TABLE", (ulong) block));
+ if (*border == 0)
+ break;
+ ulong len = block->length, used = block->used;
+ Query_cache_block_table *list_root = block->table(0);
+ Query_cache_block_table *tprev = list_root->prev,
+ *tnext = list_root->next;
+ Query_cache_block *prev = block->prev,
+ *next = block->next,
+ *pprev = block->pprev,
+ *pnext = block->pnext,
+ *new_block =(Query_cache_block *) *border;
+ uint tablename_offset = block->table()->table() - block->table()->db();
+ char *data = (char*) block->data();
+ byte *key;
+ uint key_length;
+ key=query_cache_table_get_key((byte*) block, &key_length, 0);
+ hash_search(&tables, (byte*) key, key_length);
+
+ block->destroy();
+ new_block->init(len);
+ new_block->type=Query_cache_block::TABLE;
+ new_block->used=used;
+ new_block->n_tables=1;
+ memmove((char*) new_block->data(), data, len-new_block->headers_len());
+ relink(block, new_block, next, prev, pnext, pprev);
+ if (tables_blocks[new_block->table()->type()] == block)
+ tables_blocks[new_block->table()->type()] = new_block;
+
+ Query_cache_block_table *nlist_root = new_block->table(0);
+ nlist_root->n = 0;
+ nlist_root->next = tnext;
+ tnext->prev = nlist_root;
+ nlist_root->prev = tprev;
+ tprev->next = nlist_root;
+ DBUG_PRINT("qcache",
+ ("list_root: 0x%lx tnext 0x%lx tprev 0x%lx tprev->next 0x%lx tnext->prev 0x%lx",
+ (ulong) list_root, (ulong) tnext, (ulong) tprev,
+ (ulong)tprev->next, (ulong)tnext->prev));
+ /*
+ Go through all queries that uses this table and change them to
+ point to the new table object
+ */
+ Query_cache_table *new_block_table=new_block->table();
+ for (;tnext != nlist_root; tnext=tnext->next)
+ tnext->parent= new_block_table;
+ *border += len;
+ *before = new_block;
+ /* Fix pointer to table name */
+ new_block->table()->table(new_block->table()->db() + tablename_offset);
+ /* Fix hash to point at moved block */
+ hash_replace(&tables, tables.current_record, (byte*) new_block);
+
+ DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
+ len, (ulong) new_block, (ulong) *border));
+ break;
+ }
+ case Query_cache_block::QUERY:
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx QUERY", (ulong) block));
+ if (*border == 0)
+ break;
+ BLOCK_LOCK_WR(block);
+ ulong len = block->length, used = block->used;
+ TABLE_COUNTER_TYPE n_tables = block->n_tables;
+ Query_cache_block *prev = block->prev,
+ *next = block->next,
+ *pprev = block->pprev,
+ *pnext = block->pnext,
+ *new_block =(Query_cache_block*) *border;
+ char *data = (char*) block->data();
+ Query_cache_block *first_result_block = ((Query_cache_query *)
+ block->data())->result();
+ byte *key;
+ uint key_length;
+ key=query_cache_query_get_key((byte*) block, &key_length, 0);
+ hash_search(&queries, (byte*) key, key_length);
+ // Move table of used tables
+ memmove((char*) new_block->table(0), (char*) block->table(0),
+ ALIGN_SIZE(n_tables*sizeof(Query_cache_block_table)));
+ block->query()->unlock_n_destroy();
+ block->destroy();
+ new_block->init(len);
+ new_block->type=Query_cache_block::QUERY;
+ new_block->used=used;
+ new_block->n_tables=n_tables;
+ memmove((char*) new_block->data(), data, len - new_block->headers_len());
+ relink(block, new_block, next, prev, pnext, pprev);
+ if (queries_blocks == block)
+ queries_blocks = new_block;
+ for (TABLE_COUNTER_TYPE j=0; j < n_tables; j++)
+ {
+ Query_cache_block_table *block_table = new_block->table(j);
+ block_table->next->prev = block_table;
+ block_table->prev->next = block_table;
+ }
+ DBUG_PRINT("qcache", ("after circle tt"));
+ *border += len;
+ *before = new_block;
+ new_block->query()->result(first_result_block);
+ if (first_result_block != 0)
+ {
+ Query_cache_block *result_block = first_result_block;
+ do
+ {
+ result_block->result()->parent(new_block);
+ result_block = result_block->next;
+ } while ( result_block != first_result_block );
+ }
+ Query_cache_query *new_query= ((Query_cache_query *) new_block->data());
+ sem_init(&new_query->lock, 0, 1);
+ pthread_mutex_init(&new_query->clients_guard,MY_MUTEX_INIT_FAST);
+
+ /*
+ If someone is writing to this block, inform the writer that the block
+ has been moved.
+ */
+ NET *net = new_block->query()->writer();
+ if (net != 0)
+ {
+ net->query_cache_query= (gptr) new_block;
+ }
+ /* Fix hash to point at moved block */
+ hash_replace(&queries, queries.current_record, (byte*) new_block);
+ DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
+ len, (ulong) new_block, (ulong) *border));
+ break;
+ }
+ case Query_cache_block::RES_INCOMPLETE:
+ case Query_cache_block::RES_BEG:
+ case Query_cache_block::RES_CONT:
+ case Query_cache_block::RESULT:
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx RES* (%d)", (ulong) block,
+ (int) block->type));
+ if (*border == 0)
+ break;
+ Query_cache_block *query_block = block->result()->parent(),
+ *next = block->next,
+ *prev = block->prev;
+ Query_cache_block::block_type type = block->type;
+ BLOCK_LOCK_WR(query_block);
+ ulong len = block->length, used = block->used;
+ Query_cache_block *pprev = block->pprev,
+ *pnext = block->pnext,
+ *new_block =(Query_cache_block*) *border;
+ char *data = (char*) block->data();
+ block->destroy();
+ new_block->init(len);
+ new_block->type=type;
+ new_block->used=used;
+ memmove((char*) new_block->data(), data, len - new_block->headers_len());
+ relink(block, new_block, next, prev, pnext, pprev);
+ new_block->result()->parent(query_block);
+ Query_cache_query *query = query_block->query();
+ if (query->result() == block)
+ query->result(new_block);
+ *border += len;
+ *before = new_block;
+ /* If result writing complete && we have free space in block */
+ ulong free_space = new_block->length - new_block->used;
+ if (query->result()->type == Query_cache_block::RESULT &&
+ new_block->length > new_block->used &&
+ *gap + free_space > min_allocation_unit &&
+ new_block->length - free_space > min_allocation_unit)
+ {
+ *border -= free_space;
+ *gap += free_space;
+ new_block->length -= free_space;
+ }
+ BLOCK_UNLOCK_WR(query_block);
+ DBUG_PRINT("qcache", ("moved %lu bytes to 0x%lx, new gap at 0x%lx",
+ len, (ulong) new_block, (ulong) *border));
+ break;
+ }
+ default:
+ DBUG_PRINT("error", ("unexpected block type %d, block 0x%lx",
+ (int)block->type, (ulong) block));
+ ok = 0;
+ }
+ DBUG_RETURN(ok);
+}
+
+
+void Query_cache::relink(Query_cache_block *oblock,
+ Query_cache_block *nblock,
+ Query_cache_block *next, Query_cache_block *prev,
+ Query_cache_block *pnext, Query_cache_block *pprev)
+{
+ if (prev == oblock) //check pointer to himself
+ {
+ nblock->prev = nblock;
+ nblock->next = nblock;
+ }
+ else
+ {
+ nblock->prev = prev;
+ prev->next=nblock;
+ }
+ if (next != oblock)
+ {
+ nblock->next = next;
+ next->prev=nblock;
+ }
+ nblock->pprev = pprev; // Physical pointer to himself have only 1 free block
+ nblock->pnext = pnext;
+ pprev->pnext=nblock;
+ pnext->pprev=nblock;
+}
+
+
+my_bool Query_cache::join_results(ulong join_limit)
+{
+ my_bool has_moving = 0;
+ DBUG_ENTER("Query_cache::join_results");
+
+ STRUCT_LOCK(&structure_guard_mutex);
+ if (queries_blocks != 0)
+ {
+ Query_cache_block *block = queries_blocks;
+ do
+ {
+ Query_cache_query *header = block->query();
+ if (header->result() != 0 &&
+ header->result()->type == Query_cache_block::RESULT &&
+ header->length() > join_limit)
+ {
+ Query_cache_block *new_result_block =
+ get_free_block(header->length() +
+ ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_result)), 1, 0);
+ if (new_result_block != 0)
+ {
+ has_moving = 1;
+ Query_cache_block *first_result = header->result();
+ ulong new_len = (header->length() +
+ ALIGN_SIZE(sizeof(Query_cache_block)) +
+ ALIGN_SIZE(sizeof(Query_cache_result)));
+ if (new_result_block->length >
+ ALIGN_SIZE(new_len) + min_allocation_unit)
+ split_block(new_result_block, ALIGN_SIZE(new_len));
+ BLOCK_LOCK_WR(block);
+ header->result(new_result_block);
+ new_result_block->type = Query_cache_block::RESULT;
+ new_result_block->n_tables = 0;
+ new_result_block->used = new_len;
+
+ new_result_block->next = new_result_block->prev = new_result_block;
+ DBUG_PRINT("qcache", ("new block %lu/%lu (%lu)",
+ new_result_block->length,
+ new_result_block->used,
+ header->length()));
+
+ Query_cache_result *new_result = new_result_block->result();
+ new_result->parent(block);
+ byte *write_to = (byte*) new_result->data();
+ Query_cache_block *result_block = first_result;
+ do
+ {
+ ulong len = (result_block->used - result_block->headers_len() -
+ ALIGN_SIZE(sizeof(Query_cache_result)));
+ DBUG_PRINT("loop", ("add block %lu/%lu (%lu)",
+ result_block->length,
+ result_block->used,
+ len));
+ memcpy((char *) write_to,
+ (char*) result_block->result()->data(),
+ len);
+ write_to += len;
+ Query_cache_block *old_result_block = result_block;
+ result_block = result_block->next;
+ free_memory_block(old_result_block);
+ } while (result_block != first_result);
+ BLOCK_UNLOCK_WR(block);
+ }
+ }
+ block = block->next;
+ } while ( block != queries_blocks );
+ }
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_RETURN(has_moving);
+}
+
+
+uint Query_cache::filename_2_table_key (char *key, const char *path)
+{
+ char tablename[FN_REFLEN+2], *filename, *dbname;
+ uint db_length;
+ DBUG_ENTER("Query_cache::filename_2_table_key");
+
+ /* Safety if filename didn't have a directory name */
+ tablename[0]= FN_LIBCHAR;
+ tablename[1]= FN_LIBCHAR;
+ /* Convert filename to this OS's format in tablename */
+ fn_format(tablename + 2, path, "", "", MY_REPLACE_EXT);
+ filename= tablename + dirname_length(tablename + 2) + 2;
+ /* Find start of databasename */
+ for (dbname= filename - 2 ; dbname[-1] != FN_LIBCHAR ; dbname--) ;
+ db_length= (filename - dbname) - 1;
+ DBUG_PRINT("qcache", ("table '%-.*s.%s'", db_length, dbname, filename));
+
+ DBUG_RETURN((uint) (strmov(strmake(key, dbname, db_length) + 1,
+ filename) -key) + 1);
+}
+
+
+/****************************************************************************
+ Functions to be used when debugging
+****************************************************************************/
+
+#if defined(DBUG_OFF) && !defined(USE_QUERY_CACHE_INTEGRITY_CHECK)
+
+void wreck(uint line, const char *message) {}
+void bins_dump() {}
+void cache_dump() {}
+void queries_dump() {}
+void tables_dump() {}
+my_bool check_integrity(bool not_locked) { return 0; }
+my_bool in_list(Query_cache_block * root, Query_cache_block * point,
+ const char *name) { return 0;}
+my_bool in_blocks(Query_cache_block * point) { return 0; }
+
+#else
+
+void Query_cache::wreck(uint line, const char *message)
+{
+ THD *thd=current_thd;
+ DBUG_ENTER("Query_cache::wreck");
+ query_cache_size = 0;
+ if (*message)
+ DBUG_PRINT("error", (" %s", message));
+ DBUG_PRINT("warning", ("=================================="));
+ DBUG_PRINT("warning", ("%5d QUERY CACHE WRECK => DISABLED",line));
+ DBUG_PRINT("warning", ("=================================="));
+ if (thd)
+ thd->killed = 1;
+ cache_dump();
+ /* check_integrity(0); */ /* Can't call it here because of locks */
+ bins_dump();
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache::bins_dump()
+{
+ uint i;
+
+ if ( !initialized )
+ {
+ DBUG_PRINT("qcache", ("Query Cache not initialized"));
+ return;
+ }
+
+ DBUG_PRINT("qcache", ("mem_bin_num=%u, mem_bin_steps=%u",
+ mem_bin_num, mem_bin_steps));
+ DBUG_PRINT("qcache", ("-------------------------"));
+ DBUG_PRINT("qcache", (" size idx step"));
+ DBUG_PRINT("qcache", ("-------------------------"));
+ for (i=0; i < mem_bin_steps; i++)
+ {
+ DBUG_PRINT("qcache", ("%10lu %3d %10lu", steps[i].size, steps[i].idx,
+ steps[i].increment));
+ }
+ DBUG_PRINT("qcache", ("-------------------------"));
+ DBUG_PRINT("qcache", (" size num"));
+ DBUG_PRINT("qcache", ("-------------------------"));
+ for (i=0; i < mem_bin_num; i++)
+ {
+ DBUG_PRINT("qcache", ("%10lu %3d 0x%lx", bins[i].size, bins[i].number,
+ (ulong)&(bins[i])));
+ if (bins[i].free_blocks)
+ {
+ Query_cache_block *block = bins[i].free_blocks;
+ do{
+ DBUG_PRINT("qcache", ("\\-- %lu 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
+ block->length, (ulong)block,
+ (ulong)block->next, (ulong)block->prev,
+ (ulong)block->pnext, (ulong)block->pprev));
+ block = block->next;
+ } while ( block != bins[i].free_blocks );
+ }
+ }
+ DBUG_PRINT("qcache", ("-------------------------"));
+}
+
+
+void Query_cache::cache_dump()
+{
+
+ if ( !initialized )
+ {
+ DBUG_PRINT("qcache", ("Query Cache not initialized"));
+ return;
+ }
+
+ DBUG_PRINT("qcache", ("-------------------------------------"));
+ DBUG_PRINT("qcache", (" length used t nt"));
+ DBUG_PRINT("qcache", ("-------------------------------------"));
+ Query_cache_block *i = first_block;
+ do
+ {
+ DBUG_PRINT("qcache",
+ ("%10lu %10lu %1d %2d 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
+ i->length, i->used, (int)i->type,
+ i->n_tables, (ulong)i,
+ (ulong)i->next, (ulong)i->prev, (ulong)i->pnext,
+ (ulong)i->pprev));
+ i = i->pnext;
+ } while ( i != first_block );
+ DBUG_PRINT("qcache", ("-------------------------------------"));
+}
+
+
+void Query_cache::queries_dump()
+{
+
+ if ( !initialized )
+ {
+ DBUG_PRINT("qcache", ("Query Cache not initialized"));
+ return;
+ }
+
+ DBUG_PRINT("qcache", ("------------------"));
+ DBUG_PRINT("qcache", (" QUERIES"));
+ DBUG_PRINT("qcache", ("------------------"));
+ if (queries_blocks != 0)
+ {
+ Query_cache_block *block = queries_blocks;
+ do
+ {
+ uint len;
+ char *str = (char*) query_cache_query_get_key((byte*) block, &len, 0);
+ len--; // Point at flags
+ uint flags = (uint) (uchar) str[len];
+ str[len]=0;
+ DBUG_PRINT("qcache", ("%u (%u,%u) '%s' '%s'",
+ ((flags & QUERY_CACHE_CLIENT_LONG_FLAG_MASK)? 1:0),
+ (flags & QUERY_CACHE_CHARSET_CONVERT_MASK), len,
+ str,strend(str)+1));
+ DBUG_PRINT("qcache", ("-b- 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx", (ulong) block,
+ (ulong) block->next, (ulong) block->prev,
+ (ulong)block->pnext, (ulong)block->pprev));
+ str[len]=(char) flags;
+ for (TABLE_COUNTER_TYPE t = 0; t < block->n_tables; t++)
+ {
+ Query_cache_table *table = block->table(t)->parent;
+ DBUG_PRINT("qcache", ("-t- '%s' '%s'", table->db(), table->table()));
+ }
+ Query_cache_query *header = block->query();
+ if (header->result())
+ {
+ Query_cache_block *result_block = header->result();
+ Query_cache_block *result_beg = result_block;
+ do
+ {
+ DBUG_PRINT("qcache", ("-r- %u %lu/%lu 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx",
+ (uint) result_block->type,
+ result_block->length, result_block->used,
+ (ulong) result_block,
+ (ulong) result_block->next,
+ (ulong) result_block->prev,
+ (ulong) result_block->pnext,
+ (ulong) result_block->pprev));
+ result_block = result_block->next;
+ } while ( result_block != result_beg );
+ }
+ } while ((block=block->next) != queries_blocks);
+ }
+ else
+ {
+ DBUG_PRINT("qcache", ("no queries in list"));
+ }
+ DBUG_PRINT("qcache", ("------------------"));
+}
+
+
+void Query_cache::tables_dump()
+{
+
+ if ( !initialized )
+ {
+ DBUG_PRINT("qcache", ("Query Cache not initialized"));
+ return;
+ }
+
+ DBUG_PRINT("qcache", ("--------------------"));
+ DBUG_PRINT("qcache", ("TABLES"));
+ DBUG_PRINT("qcache", ("--------------------"));
+ for (int i=0; i < (int) Query_cache_table::TYPES_NUMBER; i++)
+ {
+ DBUG_PRINT("qcache", ("--- type %u", i));
+ if (tables_blocks[i] != 0)
+ {
+ Query_cache_block *table_block = tables_blocks[i];
+ do
+ {
+ Query_cache_table *table = table_block->table();
+ DBUG_PRINT("qcache", ("'%s' '%s'", table->db(), table->table()));
+ table_block = table_block->next;
+ } while ( table_block != tables_blocks[i]);
+ }
+ else
+ DBUG_PRINT("qcache", ("no tables in list"));
+ }
+ DBUG_PRINT("qcache", ("--------------------"));
+}
+
+
+my_bool Query_cache::check_integrity(bool not_locked)
+{
+ my_bool result = 0;
+ uint i;
+ DBUG_ENTER("check_integrity");
+
+ if (!initialized )
+ {
+ DBUG_PRINT("qcache", ("Query Cache not initialized"));
+ DBUG_RETURN(0);
+ }
+ if (!not_locked)
+ STRUCT_LOCK(&structure_guard_mutex);
+
+ if (hash_check(&queries))
+ {
+ DBUG_PRINT("error", ("queries hash is damaged"));
+ result = 1;
+ }
+
+ if (hash_check(&tables))
+ {
+ DBUG_PRINT("error", ("tables hash is damaged"));
+ result = 1;
+ }
+
+ DBUG_PRINT("qcache", ("physical address check ..."));
+ ulong free=0, used=0;
+ Query_cache_block * block = first_block;
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ // Check memory allocation
+ if (block->pnext == first_block) // Is it last block?
+ {
+ if ( ((byte*)block) + block->length !=
+ ((byte*)first_block) + query_cache_size )
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx, type %u, ended at 0x%lx, but cache ended at 0x%lx",
+ (ulong) block, (uint) block->type,
+ (ulong) (((byte*)block) + block->length),
+ (ulong) (((byte*)first_block) + query_cache_size)));
+ result = 1;
+ }
+ }
+ else
+ if (((byte*)block) + block->length != ((byte*)block->pnext))
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx, type %u, ended at 0x%lx, but next block begining at 0x%lx",
+ (ulong) block, (uint) block->type,
+ (ulong) (((byte*)block) + block->length),
+ (ulong) ((byte*)block->pnext)));
+ }
+ if (block->type == Query_cache_block::FREE)
+ free+=block->length;
+ else
+ used+=block->length;
+ switch(block->type) {
+ case Query_cache_block::FREE:
+ {
+ Query_cache_memory_bin *bin = *((Query_cache_memory_bin **)
+ block->data());
+ //is it correct pointer?
+ if ( ((byte*)bin) < ((byte*)bins) ||
+ ((byte*)bin) >= ((byte*)first_block))
+ {
+ DBUG_PRINT("error",
+ ("free block 0x%lx have bin pointer 0x%lx beyaond of bins array bounds [0x%lx,0x%lx]",
+ (ulong) block,
+ (ulong) bin,
+ (ulong) bins,
+ (ulong) first_block));
+ result = 1;
+ }
+ else
+ {
+ int idx = (((byte*)bin) - ((byte*)bins)) /
+ sizeof(Query_cache_memory_bin);
+ if (in_list(bins[idx].free_blocks, block, "free memory"))
+ result = 1;
+ }
+ break;
+ }
+ case Query_cache_block::TABLE:
+ if (in_list(tables_blocks[block->table()->type()], block, "tables"))
+ result = 1;
+ if (in_table_list(block->table(0), block->table(0), "table list root"))
+ result = 1;
+ break;
+ case Query_cache_block::QUERY:
+ if (in_list(queries_blocks, block, "query"))
+ result = 1;
+ for (TABLE_COUNTER_TYPE j=0; j < block->n_tables; j++)
+ {
+ Query_cache_block_table *block_table = block->table(j);
+ Query_cache_block_table *block_table_root =
+ (Query_cache_block_table *)
+ (((byte*)block_table->parent) -
+ ALIGN_SIZE(sizeof(Query_cache_block_table)));
+
+ if (in_table_list(block_table, block_table_root, "table list"))
+ result = 1;
+ }
+ break;
+ case Query_cache_block::RES_INCOMPLETE:
+ // This type of block can be not lincked yet (in multithread environment)
+ break;
+ case Query_cache_block::RES_BEG:
+ case Query_cache_block::RES_CONT:
+ case Query_cache_block::RESULT:
+ {
+ Query_cache_block * query_block = block->result()->parent();
+ if ( ((byte*)query_block) < ((byte*)first_block) ||
+ ((byte*)query_block) >= (((byte*)first_block) + query_cache_size))
+ {
+ DBUG_PRINT("error",
+ ("result block 0x%lx have query block pointer 0x%lx beyaond of block pool bounds [0x%lx,0x%lx]",
+ (ulong) block,
+ (ulong) query_block,
+ (ulong) first_block,
+ (ulong) (((byte*)first_block) + query_cache_size)));
+ result = 1;
+ }
+ else
+ {
+ BLOCK_LOCK_RD(query_block);
+ if (in_list(queries_blocks, query_block, "query from results"))
+ result = 1;
+ if (in_list(query_block->query()->result(), block,
+ "results"))
+ result = 1;
+ BLOCK_UNLOCK_RD(query_block);
+ }
+ break;
+ }
+ default:
+ DBUG_PRINT("error",
+ ("block 0x%lx have incorrect type %u",
+ block, block->type));
+ result = 1;
+ }
+
+ block = block->pnext;
+ } while (block != first_block);
+
+ if (used + free != query_cache_size)
+ {
+ DBUG_PRINT("error",
+ ("used memory (%lu) + free memory (%lu) != query_cache_size (%lu)",
+ used, free, query_cache_size));
+ result = 1;
+ }
+
+ if (free != free_memory)
+ {
+ DBUG_PRINT("error",
+ ("free memory (%lu) != free_memory (%lu)",
+ free, free_memory));
+ result = 1;
+ }
+
+ DBUG_PRINT("qcache", ("check queries ..."));
+ if ((block = queries_blocks))
+ {
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ uint length;
+ byte *key = query_cache_query_get_key((byte*) block, &length, 0);
+ gptr val = hash_search(&queries, key, length);
+ if (((gptr)block) != val)
+ {
+ DBUG_PRINT("error", ("block 0x%lx found in queries hash like 0x%lx",
+ (ulong) block, (ulong) val));
+ }
+ if (in_blocks(block))
+ result = 1;
+ Query_cache_block * results = block->query()->result();
+ if (results)
+ {
+ Query_cache_block * result_block = results;
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ if (in_blocks(result_block))
+ result = 1;
+
+ result_block = result_block->next;
+ } while (result_block != results);
+ }
+ block = block->next;
+ } while (block != queries_blocks);
+ }
+
+ DBUG_PRINT("qcache", ("check tables ..."));
+ for (i=0 ; (int) i < (int) Query_cache_table::TYPES_NUMBER; i++)
+ {
+ if ((block = tables_blocks[i]))
+ {
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ uint length;
+ byte *key = query_cache_table_get_key((byte*) block, &length, 0);
+ gptr val = hash_search(&tables, key, length);
+ if (((gptr)block) != val)
+ {
+ DBUG_PRINT("error", ("block 0x%lx found in tables hash like 0x%lx",
+ (ulong) block, (ulong) val));
+ }
+
+ if (in_blocks(block))
+ result = 1;
+ block=block->next;
+ } while (block != tables_blocks[i]);
+ }
+ }
+
+ DBUG_PRINT("qcache", ("check free blocks"));
+ for (i = 0; i < mem_bin_num; i++)
+ {
+ if ((block = bins[i].free_blocks))
+ {
+ uint count = 0;
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ if (in_blocks(block))
+ result = 1;
+
+ count++;
+ block=block->next;
+ } while (block != bins[i].free_blocks);
+ if (count != bins[i].number)
+ {
+ DBUG_PRINT("error", ("bin[%d].number is %d, but bin have %d blocks",
+ bins[i].number, count));
+ result = 1;
+ }
+ }
+ }
+ DBUG_ASSERT(result == 0);
+ if (!not_locked)
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_RETURN(result);
+}
+
+
+my_bool Query_cache::in_blocks(Query_cache_block * point)
+{
+ my_bool result = 0;
+ Query_cache_block *block = point;
+ //back
+ do
+ {
+ if (block->pprev->pnext != block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx in physical list is incorrect linked, prev block 0x%lx refered as next to 0x%lx (check from 0x%lx)",
+ (ulong) block, (ulong) block->pprev,
+ (ulong) block->pprev->pnext,
+ (ulong) point));
+ //back trace
+ for(; block != point; block = block->pnext)
+ DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
+ result = 1;
+ goto err1;
+ }
+ block = block->pprev;
+ } while (block != first_block && block != point);
+ if (block != first_block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx (0x%lx<-->0x%lx) not owned by pysical list",
+ (ulong) block, (ulong) block->pprev, (ulong )block->pnext));
+ return 1;
+ }
+
+err1:
+ //forward
+ block = point;
+ do
+ {
+ if (block->pnext->pprev != block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx in physicel list is incorrect linked, next block 0x%lx refered as prev to 0x%lx (check from 0x%lx)",
+ (ulong) block, (ulong) block->pnext,
+ (ulong) block->pnext->pprev,
+ (ulong) point));
+ //back trace
+ for(; block != point; block = block->pprev)
+ DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
+ result = 1;
+ goto err2;
+ }
+ block = block->pnext;
+ } while (block != first_block);
+err2:
+ return result;
+}
+
+
+my_bool Query_cache::in_list(Query_cache_block * root,
+ Query_cache_block * point,
+ const char *name)
+{
+ my_bool result = 0;
+ Query_cache_block *block = point;
+ //back
+ do
+ {
+ if (block->prev->next != block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx in list '%s' 0x%lx is incorrect linked, prev block 0x%lx refered as next to 0x%lx (check from 0x%lx)",
+ (ulong) block, name, (ulong) root, (ulong) block->prev,
+ (ulong) block->prev->next,
+ (ulong) point));
+ //back trace
+ for(; block != point; block = block->next)
+ DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
+ result = 1;
+ goto err1;
+ }
+ block = block->prev;
+ } while (block != root && block != point);
+ if (block != root)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx (0x%lx<-->0x%lx) not owned by list '%s' 0x%lx",
+ (ulong) block,
+ (ulong) block->prev, (ulong) block->next,
+ name, (ulong) root));
+ return 1;
+ }
+err1:
+ // forward
+ block = point;
+ do
+ {
+ if (block->next->prev != block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx in list '%s' 0x%lx is incorrect linked, next block 0x%lx refered as prev to 0x%lx (check from 0x%lx)",
+ (ulong) block, name, (ulong) root, (ulong) block->next,
+ (ulong) block->next->prev,
+ (ulong) point));
+ //back trace
+ for (; block != point; block = block->prev)
+ DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
+ result = 1;
+ goto err2;
+ }
+ block = block->next;
+ } while (block != root);
+err2:
+ return result;
+}
+
+void dump_node(Query_cache_block_table * node,
+ const char * call, const char * descr)
+{
+ DBUG_PRINT("qcache", ("%s: %s: node: 0x%lx", call, descr, (ulong) node));
+ DBUG_PRINT("qcache", ("%s: %s: node block: 0x%lx",
+ call, descr, (ulong) node->block()));
+ DBUG_PRINT("qcache", ("%s: %s: next: 0x%lx", call, descr,
+ (ulong) node->next));
+ DBUG_PRINT("qcache", ("%s: %s: prev: 0x%lx", call, descr,
+ (ulong) node->prev));
+}
+
+my_bool Query_cache::in_table_list(Query_cache_block_table * root,
+ Query_cache_block_table * point,
+ const char *name)
+{
+ my_bool result = 0;
+ Query_cache_block_table *table = point;
+ dump_node(root, name, "parameter root");
+ //back
+ do
+ {
+ dump_node(table, name, "list element << ");
+ if (table->prev->next != table)
+ {
+ DBUG_PRINT("error",
+ ("table 0x%lx(0x%lx) in list '%s' 0x%lx(0x%lx) is incorrect linked, prev table 0x%lx(0x%lx) refered as next to 0x%lx(0x%lx) (check from 0x%lx(0x%lx))",
+ (ulong) table, (ulong) table->block(), name,
+ (ulong) root, (ulong) root->block(),
+ (ulong) table->prev, (ulong) table->prev->block(),
+ (ulong) table->prev->next,
+ (ulong) table->prev->next->block(),
+ (ulong) point, (ulong) point->block()));
+ //back trace
+ for(; table != point; table = table->next)
+ DBUG_PRINT("error", ("back trace 0x%lx(0x%lx)",
+ (ulong) table, (ulong) table->block()));
+ result = 1;
+ goto err1;
+ }
+ table = table->prev;
+ } while (table != root && table != point);
+ if (table != root)
+ {
+ DBUG_PRINT("error",
+ ("table 0x%lx(0x%lx) (0x%lx(0x%lx)<-->0x%lx(0x%lx)) not owned by list '%s' 0x%lx(0x%lx)",
+ (ulong) table, (ulong) table->block(),
+ (ulong) table->prev, (ulong) table->prev->block(),
+ (ulong) table->next, (ulong) table->next->block(),
+ name, (ulong) root, (ulong) root->block()));
+ return 1;
+ }
+err1:
+ // forward
+ table = point;
+ do
+ {
+ dump_node(table, name, "list element >> ");
+ if (table->next->prev != table)
+ {
+ DBUG_PRINT("error",
+ ("table 0x%lx(0x%lx) in list '%s' 0x%lx(0x%lx) is incorrect linked, next table 0x%lx(0x%lx) refered as prev to 0x%lx(0x%lx) (check from 0x%lx(0x%lx))",
+ (ulong) table, (ulong) table->block(),
+ name, (ulong) root, (ulong) root->block(),
+ (ulong) table->next, (ulong) table->next->block(),
+ (ulong) table->next->prev,
+ (ulong) table->next->prev->block(),
+ (ulong) point, (ulong) point->block()));
+ //back trace
+ for (; table != point; table = table->prev)
+ DBUG_PRINT("error", ("back trace 0x%lx(0x%lx)",
+ (ulong) table, (ulong) table->block()));
+ result = 1;
+ goto err2;
+ }
+ table = table->next;
+ } while (table != root);
+err2:
+ return result;
+}
+
+#endif /* DBUG_OFF */
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
new file mode 100644
index 00000000000..b1d8eb23198
--- /dev/null
+++ b/sql/sql_cache.h
@@ -0,0 +1,418 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
+
+#ifndef _SQL_CACHE_H
+#define _SQL_CACHE_H
+
+/* Query cache */
+
+/*
+ Can't create new free memory block if unused memory in block less
+ then QUERY_CACHE_MIN_ALLOCATION_UNIT.
+ if QUERY_CACHE_MIN_ALLOCATION_UNIT == 0 then
+ QUERY_CACHE_MIN_ALLOCATION_UNIT choosed automaticaly
+*/
+#define QUERY_CACHE_MIN_ALLOCATION_UNIT 512
+
+/* inittial size of hashes */
+#define QUERY_CACHE_DEF_QUERY_HASH_SIZE 1024
+#define QUERY_CACHE_DEF_TABLE_HASH_SIZE 1024
+
+/* minimal result data size when data allocated */
+#define QUERY_CACHE_MIN_RESULT_DATA_SIZE 1024*4
+
+/*
+ start estimation of first result block size only when number of queries
+ bigger then:
+*/
+#define QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER 3
+
+
+
+/* memory bins size spacing (see at Query_cache::init_cache (sql_cache.cc)) */
+#define QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 4
+#define QUERY_CACHE_MEM_BIN_STEP_PWR2 2
+#define QUERY_CACHE_MEM_BIN_PARTS_INC 1
+#define QUERY_CACHE_MEM_BIN_PARTS_MUL 1.2
+#define QUERY_CACHE_MEM_BIN_SPC_LIM_PWR2 3
+
+/* how many free blocks check when finding most suitable before other 'end'
+ of list of free blocks */
+#define QUERY_CACHE_MEM_BIN_TRY 5
+
+/* query flags masks */
+#define QUERY_CACHE_CLIENT_LONG_FLAG_MASK 0x80
+#define QUERY_CACHE_CHARSET_CONVERT_MASK 0x7F
+
+/* packing parameters */
+#define QUERY_CACHE_PACK_ITERATION 2
+#define QUERY_CACHE_PACK_LIMIT (512*1024L)
+
+#define TABLE_COUNTER_TYPE uint8
+
+#include <my_semaphore.h>
+
+struct Query_cache_block;
+struct Query_cache_block_table;
+struct Query_cache_table;
+struct Query_cache_query;
+struct Query_cache_result;
+class Query_cache;
+
+
+struct Query_cache_block_table
+{
+ TABLE_COUNTER_TYPE n; // numbr in table (from 0)
+ Query_cache_block_table *next, *prev;
+ Query_cache_table *parent;
+ inline Query_cache_block *block();
+};
+
+
+struct Query_cache_block
+{
+ enum block_type {FREE, QUERY, RESULT, RES_CONT, RES_BEG,
+ RES_INCOMPLETE, TABLE, INCOMPLETE};
+
+ ulong length; // length of all block
+ ulong used; // length of data
+ /*
+ Not used **pprev, **prev because really needed access to pervious block:
+ *pprev to join free blocks
+ *prev to access to opposite side of list in cyclic sorted list
+ */
+ Query_cache_block *pnext,*pprev, // physical next/previous block
+ *next,*prev; // logical next/previous block
+ block_type type;
+ TABLE_COUNTER_TYPE n_tables; // number of tables in query
+
+ inline my_bool is_free(void) { return type == FREE; }
+ void init(ulong length);
+ void destroy();
+ inline uint headers_len();
+ inline gptr data(void);
+ inline Query_cache_query *query();
+ inline Query_cache_table *table();
+ inline Query_cache_result *result();
+ inline Query_cache_block_table *table(TABLE_COUNTER_TYPE n);
+};
+
+
+struct Query_cache_query
+{
+ ulonglong limit_found_rows;
+ Query_cache_block *res;
+ NET *wri;
+ ulong len;
+ sem_t lock; // R/W lock of block
+ pthread_mutex_t clients_guard;
+ uint clients;
+
+ inline void init_n_lock();
+ void unlock_n_destroy();
+ inline ulonglong found_rows() { return limit_found_rows; }
+ inline void found_rows(ulonglong rows) { limit_found_rows = rows; }
+ inline Query_cache_block *result() { return res; }
+ inline void result(Query_cache_block *p) { res=p; }
+ inline NET *writer() { return wri; }
+ inline void writer(NET *p) { wri=p; }
+ inline ulong length() { return len; }
+ inline ulong add(ulong packet_len) { return(len += packet_len); }
+ inline void length(ulong length) { len = length; }
+ inline gptr query()
+ {
+ return (gptr)(((byte*)this)+
+ ALIGN_SIZE(sizeof(Query_cache_query)));
+ }
+ void lock_writing();
+ void lock_reading();
+ my_bool try_lock_writing();
+ void unlock_writing();
+ void unlock_reading();
+ static byte *cache_key(const byte *record, uint *length, my_bool not_used);
+};
+
+
+struct Query_cache_table
+{
+ enum query_cache_table_type {OTHER=0, INNODB=1, TYPES_NUMBER=2};
+ inline static query_cache_table_type type_convertion(db_type type)
+ {
+ return (type == DB_TYPE_INNODB ? INNODB : OTHER);
+ }
+
+ char *tbl;
+ query_cache_table_type tp;
+
+ inline query_cache_table_type type() { return tp; }
+ inline void type(query_cache_table_type t) { tp = t;}
+ inline char *db() { return (char *) data(); }
+ inline char *table() { return tbl; }
+ inline void table(char *table) { tbl = table; }
+ inline gptr data()
+ {
+ return (gptr)(((byte*)this)+
+ ALIGN_SIZE(sizeof(Query_cache_table)));
+ }
+};
+
+struct Query_cache_result
+{
+ Query_cache_block *query;
+
+ inline gptr data()
+ {
+ return (gptr)(((byte*) this)+
+ ALIGN_SIZE(sizeof(Query_cache_result)));
+ }
+ /* data_continue (if not whole packet contained by this block) */
+ inline Query_cache_block *parent() { return query; }
+ inline void parent (Query_cache_block *p) { query=p; }
+};
+
+
+extern "C" {
+ byte *query_cache_query_get_key(const byte *record, uint *length,
+ my_bool not_used);
+ byte *query_cache_table_get_key(const byte *record, uint *length,
+ my_bool not_used);
+ void query_cache_insert(THD *thd, const char *packet, ulong length);
+ void query_cache_end_of_result(THD *thd);
+ void query_cache_abort(THD *thd);
+ void query_cache_invalidate_by_MyISAM_filename(const char* filename);
+}
+
+struct Query_cache_memory_bin
+{
+#ifndef DBUG_OFF
+ ulong size;
+#endif
+ uint number;
+ Query_cache_block *free_blocks;
+
+ inline void init(ulong size)
+ {
+#ifndef DBUG_OFF
+ this->size = size;
+#endif
+ number = 0;
+ free_blocks = 0;
+ }
+};
+
+struct Query_cache_memory_bin_step
+{
+ ulong size;
+ ulong increment;
+ uint idx;
+ inline void init(ulong size, uint idx, ulong increment)
+ {
+ this->size = size;
+ this->idx = idx;
+ this->increment = increment;
+ }
+};
+
+class Query_cache
+{
+public:
+ /* Info */
+ ulong query_cache_size, query_cache_limit;
+ /* statistics */
+ ulong free_memory, queries_in_cache, hits, inserts, refused,
+ free_memory_blocks, total_blocks;
+
+protected:
+ /*
+ The following mutex is locked when searching or changing global
+ query, tables lists or hashes. When we are operating inside the
+ query structure we locked an internal query block mutex.
+ LOCK SEQUENCE (to prevent deadlocks):
+ 1. structure_guard_mutex
+ 2. query block (for operation inside query (query block/results))
+ */
+ pthread_mutex_t structure_guard_mutex;
+ byte *cache; // cache memory
+ Query_cache_block *first_block; // physical location block list
+ Query_cache_block *queries_blocks; // query list (LIFO)
+ Query_cache_block *tables_blocks[Query_cache_table::TYPES_NUMBER];
+
+ Query_cache_memory_bin *bins; // free block lists
+ Query_cache_memory_bin_step *steps; // bins spacing info
+ HASH queries, tables;
+ /* options */
+ ulong min_allocation_unit, min_result_data_size;
+ uint def_query_hash_size, def_table_hash_size;
+ uint mem_bin_num, mem_bin_steps; // See at init_cache & find_bin
+
+ my_bool initialized;
+
+ /* Exclude/include from cyclic double linked list */
+ static void double_linked_list_exclude(Query_cache_block *point,
+ Query_cache_block **list_pointer);
+ static void double_linked_list_simple_include(Query_cache_block *point,
+ Query_cache_block **
+ list_pointer);
+ static void double_linked_list_join(Query_cache_block *head_tail,
+ Query_cache_block *tail_head);
+
+ /* Table key generation */
+ static uint filename_2_table_key (char *key, const char *filename);
+
+ /* The following functions require that structure_guard_mutex is locked */
+ void flush_cache();
+ my_bool free_old_query();
+ void free_query(Query_cache_block *point);
+ my_bool allocate_data_chain(Query_cache_block **result_block,
+ ulong data_len,
+ Query_cache_block *query_block,
+ my_bool first_block);
+ void invalidate_table(TABLE_LIST *table);
+ void invalidate_table(TABLE *table);
+ void invalidate_table(Query_cache_block *table_block);
+ my_bool register_all_tables(Query_cache_block *block,
+ TABLE_LIST *tables_used,
+ TABLE_COUNTER_TYPE tables);
+ my_bool insert_table(uint key_len, char *key,
+ Query_cache_block_table *node,
+ Query_cache_table::query_cache_table_type type);
+ void unlink_table(Query_cache_block_table *node);
+ Query_cache_block *get_free_block (ulong len, my_bool not_less,
+ ulong min);
+ void free_memory_block(Query_cache_block *point);
+ void split_block(Query_cache_block *block, ulong len);
+ Query_cache_block *join_free_blocks(Query_cache_block *first_block,
+ Query_cache_block *block_in_list);
+ my_bool append_next_free_block(Query_cache_block *block,
+ ulong add_size);
+ void exclude_from_free_memory_list(Query_cache_block *free_block);
+ void insert_into_free_memory_list(Query_cache_block *new_block);
+ my_bool move_by_type(byte **border, Query_cache_block **before,
+ ulong *gap, Query_cache_block *i);
+ uint find_bin(ulong size);
+ void move_to_query_list_end(Query_cache_block *block);
+ void insert_into_free_memory_sorted_list(Query_cache_block *new_block,
+ Query_cache_block **list);
+ void pack_cache();
+ void relink(Query_cache_block *oblock,
+ Query_cache_block *nblock,
+ Query_cache_block *next,
+ Query_cache_block *prev,
+ Query_cache_block *pnext,
+ Query_cache_block *pprev);
+ my_bool join_results(ulong join_limit);
+
+ /*
+ Following function control structure_guard_mutex
+ by themself or don't need structure_guard_mutex
+ */
+ void init();
+ ulong init_cache();
+ void make_disabled();
+ void free_cache(my_bool destruction);
+ Query_cache_block *write_block_data(ulong data_len, gptr data,
+ ulong header_len,
+ Query_cache_block::block_type type,
+ TABLE_COUNTER_TYPE ntab = 0,
+ my_bool under_guard=0);
+ my_bool append_result_data(Query_cache_block **result,
+ ulong data_len, gptr data,
+ Query_cache_block *parent);
+ my_bool write_result_data(Query_cache_block **result,
+ ulong data_len, gptr data,
+ Query_cache_block *parent,
+ Query_cache_block::block_type
+ type=Query_cache_block::RESULT);
+ inline ulong get_min_first_result_data_size();
+ inline ulong get_min_append_result_data_size();
+ Query_cache_block *allocate_block(ulong len, my_bool not_less,
+ ulong min,
+ my_bool under_guard=0);
+ /*
+ If query is cacheable return number tables in query
+ (query without tables not cached)
+ */
+ TABLE_COUNTER_TYPE is_cacheable(THD *thd, uint32 query_len, char *query,
+ LEX *lex, TABLE_LIST *tables_used);
+ public:
+
+ Query_cache(ulong query_cache_limit = ULONG_MAX,
+ ulong min_allocation_unit = QUERY_CACHE_MIN_ALLOCATION_UNIT,
+ ulong min_result_data_size = QUERY_CACHE_MIN_RESULT_DATA_SIZE,
+ uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE,
+ uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE);
+
+ /* resize query cache (return real query size, 0 if disabled) */
+ ulong resize(ulong query_cache_size);
+ inline void result_size_limit(ulong limit){query_cache_limit=limit;}
+
+ /* register query in cache */
+ void store_query(THD *thd, TABLE_LIST *used_tables);
+
+ /*
+ Check if the query is in the cache and if this is true send the
+ data to client.
+ */
+ int send_result_to_client(THD *thd, char *query, uint query_length);
+
+ /* Remove all queries that uses any of the listed following tables */
+ void invalidate(TABLE_LIST *tables_used);
+ void invalidate(TABLE *table);
+
+ /* Remove all queries that uses tables of pointed type*/
+ void invalidate(Query_cache_table::query_cache_table_type type);
+
+ /* Remove all queries that uses any of the tables in following database */
+ void invalidate(char *db);
+
+ /* Remove all queries that uses any of the listed following table */
+ void invalidate_by_MyISAM_filename(const char *filename);
+
+ void flush();
+ void pack(ulong join_limit = QUERY_CACHE_PACK_LIMIT,
+ uint iteration_limit = QUERY_CACHE_PACK_ITERATION);
+
+ void destroy();
+
+ friend void query_cache_insert(NET *net, const char *packet, ulong length);
+ friend void query_cache_end_of_result(NET *net);
+ friend void query_cache_abort(NET *net);
+
+ /*
+ The following functions are only used when debugging
+ We don't protect these with ifndef DEBUG_OFF to not have to recompile
+ everything if we want to add checks of the cache at some places.
+ */
+ void wreck(uint line, const char *message);
+ void bins_dump();
+ void cache_dump();
+ void queries_dump();
+ void tables_dump();
+ my_bool check_integrity(bool not_locked);
+ my_bool in_list(Query_cache_block * root, Query_cache_block * point,
+ const char *name);
+ my_bool in_table_list(Query_cache_block_table * root,
+ Query_cache_block_table * point,
+ const char *name);
+ my_bool in_blocks(Query_cache_block * point);
+};
+
+extern Query_cache query_cache;
+void query_cache_insert(NET *net, const char *packet, ulong length);
+void query_cache_end_of_result(NET *net);
+void query_cache_abort(NET *net);
+
+#endif
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 44a1dbc1720..fbab528dc67 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -84,8 +84,8 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
host=user=priv_user=db=query=ip=0;
host_or_ip="unknown ip";
locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password=
- query_start_used=0;
- query_length=col_access=0;
+ query_start_used=safe_to_cache_query=0;
+ db_length=query_length=col_access=0;
query_error=0;
next_insert_id=last_insert_id=0;
open_tables=temporary_tables=handler_tables=0;
@@ -122,6 +122,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
server_status=SERVER_STATUS_AUTOCOMMIT;
update_lock_default= low_priority_updates ? TL_WRITE_LOW_PRIORITY : TL_WRITE;
options=thd_startup_options;
+ query_cache_type = (byte) query_cache_startup_type;
sql_mode=(uint) opt_sql_mode;
inactive_timeout=net_wait_timeout;
open_options=ha_open_options;
@@ -201,7 +202,7 @@ THD::~THD()
hash_free(&user_vars);
DBUG_PRINT("info", ("freeing host"));
-
+
if (host != localhost) // If not pointer to constant
safeFree(host);
if (user != delayed_user)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 87d19381b78..5b155e6b3d4 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -144,14 +144,16 @@ class CONVERT
void convert_array(const uchar *mapping,uchar *buff,uint length);
public:
const char *name;
- CONVERT(const char *name_par,uchar *from_par,uchar *to_par)
- :from_map(from_par),to_map(to_par),name(name_par) {}
+ uint numb;
+ CONVERT(const char *name_par,uchar *from_par,uchar *to_par, uint number)
+ :from_map(from_par),to_map(to_par),name(name_par),numb(number) {}
friend CONVERT *get_convert_set(const char *name_ptr);
inline void convert(char *a,uint length)
{
convert_array(from_map, (uchar*) a,length);
}
bool store(String *, const char *,uint);
+ inline uint number() { return numb; }
};
typedef struct st_copy_info {
@@ -311,15 +313,16 @@ public:
enum enum_server_command command;
uint32 server_id;
uint32 file_id; // for LOAD DATA INFILE
+ uint32 file_id; // for LOAD DATA INFILE
const char *where;
- time_t start_time,time_after_lock,user_time;
- time_t connect_time,thr_create_time; // track down slow pthread_create
+ time_t start_time,time_after_lock,user_time;
+ time_t connect_time,thr_create_time; // track down slow pthread_create
thr_lock_type update_lock_default;
delayed_insert *di;
struct st_transactions {
IO_CACHE trans_log;
- THD_TRANS all; /* Trans since BEGIN WORK */
- THD_TRANS stmt; /* Trans for current statement */
+ THD_TRANS all; // Trans since BEGIN WORK
+ THD_TRANS stmt; // Trans for current statement
uint bdb_lock_count;
} transaction;
Item *free_list, *handler_items;
@@ -332,35 +335,41 @@ public:
Vio* active_vio;
pthread_mutex_t active_vio_lock;
#endif
- ulonglong next_insert_id,last_insert_id,current_insert_id, limit_found_rows;
- ha_rows select_limit,offset_limit,default_select_limit,cuted_fields,
- max_join_size, sent_row_count, examined_row_count;
- table_map used_tables;
- ulong query_id,version, inactive_timeout,options,thread_id;
- long dbug_thread_id;
+ ulonglong next_insert_id,last_insert_id,current_insert_id,
+ limit_found_rows;
+ ha_rows select_limit,offset_limit,default_select_limit,cuted_fields,
+ max_join_size, sent_row_count, examined_row_count;
+ table_map used_tables;
+ ulong query_id,version, inactive_timeout,options,thread_id;
+ long dbug_thread_id;
pthread_t real_id;
- uint current_tablenr,tmp_table,cond_count,col_access,query_length;
- uint server_status,open_options;
+ uint current_tablenr,tmp_table,cond_count,col_access;
+ uint server_status,open_options;
+ uint32 query_length;
+ uint32 db_length;
enum_tx_isolation tx_isolation, session_tx_isolation;
char scramble[9];
+ uint8 query_cache_type; // type of query cache processing
bool slave_thread;
bool set_query_id,locked,count_cuted_fields,some_tables_deleted;
bool no_errors, allow_sum_func, password, fatal_error;
bool query_start_used,last_insert_id_used,insert_id_used;
bool system_thread,in_lock_tables,global_read_lock;
bool query_error, bootstrap, cleanup_done;
+ bool safe_to_cache_query;
bool volatile killed;
-
- // if we do a purge of binary logs, log index info of the threads
- // that are currently reading it needs to be adjusted. To do that
- // each thread that is using LOG_INFO needs to adjust the pointer to it
+ /*
+ If we do a purge of binary logs, log index info of the threads
+ that are currently reading it needs to be adjusted. To do that
+ each thread that is using LOG_INFO needs to adjust the pointer to it
+ */
LOG_INFO* current_linfo;
-
- // in slave thread we need to know in behalf of which
- // thread the query is being run to replicate temp tables properly
- ulong slave_proxy_id;
-
- NET* slave_net; // network connection from slave to master
+ /*
+ In slave thread we need to know in behalf of which
+ thread the query is being run to replicate temp tables properly
+ */
+ ulong slave_proxy_id;
+ NET* slave_net; // network connection from slave -> m.
uint32 log_pos;
THD();
@@ -452,6 +461,13 @@ public:
{ 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;
+ }
};
@@ -700,7 +716,7 @@ public:
uint num_of_tables;
int error;
thr_lock_type lock_option;
- bool do_delete;
+ bool do_delete, not_trans_safe;
public:
multi_delete(THD *thd, TABLE_LIST *dt, thr_lock_type lock_option_arg,
uint num_of_tables);
@@ -715,4 +731,32 @@ public:
bool send_eof();
};
+ class multi_update : public select_result {
+ TABLE_LIST *update_tables, *table_being_updated;
+// Unique **tempfiles;
+ COPY_INFO *infos;
+ TABLE **tmp_tables;
+ THD *thd;
+ ha_rows updated, found;
+ List<Item> fields;
+ List <Item> **fields_by_tables;
+ thr_lock_type lock_option;
+ enum enum_duplicates dupl;
+ uint num_of_tables, num_fields, num_updated, *save_time_stamps, *field_sequence;
+ int error;
+ bool do_update, not_trans_safe;
+ public:
+ multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
+ enum enum_duplicates handle_duplicates,
+ thr_lock_type lock_option_arg, uint num);
+ ~multi_update();
+ int prepare(List<Item> &list);
+ bool send_fields(List<Item> &list,
+ uint flag) { return 0; }
+ bool send_data(List<Item> &items);
+ void initialize_tables (JOIN *join);
+ void send_error(uint errcode,const char *err);
+ int do_updates (bool from_send_error);
+ bool send_eof();
+ };
diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc
index 371d63f8c73..f2e4a8934be 100644
--- a/sql/sql_crypt.cc
+++ b/sql/sql_crypt.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/sql_crypt.h b/sql/sql_crypt.h
index b3a9d54133f..1b27f0a4d27 100644
--- a/sql/sql_crypt.h
+++ b/sql/sql_crypt.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 3158c8cbf7b..dd8ed634011 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -38,7 +38,7 @@ int mysql_create_db(THD *thd, char *db, uint create_options, bool silent)
long result=1;
int error = 0;
DBUG_ENTER("mysql_create_db");
-
+
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
// do not create database if another thread is holding read lock
@@ -159,6 +159,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
if ((deleted=mysql_rm_known_files(thd, dirp, db, path,0)) >= 0 && thd)
{
ha_drop_database(path);
+ query_cache.invalidate(db);
if (!silent)
{
if (!thd->query)
@@ -316,19 +317,19 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
bool mysql_change_db(THD *thd,const char *name)
{
- int length;
+ int length, db_length;
char *dbname=my_strdup((char*) name,MYF(MY_WME));
char path[FN_REFLEN];
uint db_access;
DBUG_ENTER("mysql_change_db");
- if (!dbname || !(length=stripp_sp(dbname)))
+ if (!dbname || !(db_length=stripp_sp(dbname)))
{
x_free(dbname); /* purecov: inspected */
send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
- if ((length > NAME_LEN) || check_db_name(dbname))
+ if ((db_length > NAME_LEN) || check_db_name(dbname))
{
net_printf(&thd->net,ER_WRONG_DB_NAME, dbname);
x_free(dbname);
@@ -368,6 +369,7 @@ bool mysql_change_db(THD *thd,const char *name)
send_ok(&thd->net);
x_free(thd->db);
thd->db=dbname;
+ thd->db_length=db_length;
thd->db_access=db_access;
DBUG_RETURN(0);
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 63e003178c2..2a7824eae68 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -1,15 +1,15 @@
/* 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 */
@@ -24,7 +24,7 @@
#include "mysql_priv.h"
-#include "ha_innobase.h"
+#include "ha_innodb.h"
#include "sql_select.h"
int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
@@ -98,7 +98,6 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
DBUG_RETURN(1);
}
}
- (void) table->file->extra(HA_EXTRA_NO_READCHECK);
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_QUICK);
@@ -157,8 +156,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
}
thd->proc_info="end";
end_read_record(&info);
- /* if (order) free_io_cache(table); */ /* QQ Should not be needed */
- (void) table->file->extra(HA_EXTRA_READCHECK);
+ free_io_cache(table); // Will not do any harm
if (options & OPTION_QUICK)
(void) table->file->extra(HA_EXTRA_NORMAL);
@@ -183,6 +181,8 @@ cleanup:
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
+ if (deleted)
+ query_cache.invalidate(table_list);
delete select;
if (error >= 0) // Fatal error
send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN: 0);
@@ -214,17 +214,15 @@ multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
do_delete(false)
{
uint counter=0;
+ not_trans_safe=false;
tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
- (void) dt->table->file->extra(HA_EXTRA_NO_READCHECK);
/* Don't use key read with MULTI-TABLE-DELETE */
- (void) dt->table->file->extra(HA_EXTRA_NO_KEYREAD);
dt->table->used_keys=0;
for (dt=dt->next ; dt ; dt=dt->next,counter++)
{
TABLE *table=dt->table;
- (void) dt->table->file->extra(HA_EXTRA_NO_READCHECK);
- (void) dt->table->file->extra(HA_EXTRA_NO_KEYREAD);
+ table->used_keys=0;
tempfiles[counter] = new Unique (refposcmp2,
(void *) &table->file->ref_length,
table->file->ref_length,
@@ -264,7 +262,7 @@ multi_delete::initialize_tables(JOIN *join)
table_map tables_to_delete_from=0;
for (walk= delete_tables ; walk ; walk=walk->next)
tables_to_delete_from|= walk->table->map;
-
+
walk= delete_tables;
for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
tab < end;
@@ -277,18 +275,24 @@ multi_delete::initialize_tables(JOIN *join)
walk=walk->next;
if (tab == join->join_tab)
tab->table->no_keyread=1;
+ if (!not_trans_safe && !tab->table->file->has_transactions())
+ not_trans_safe=true;
}
}
+ init_ftfuncs(thd,1);
}
multi_delete::~multi_delete()
{
- /* Add back EXTRA_READCHECK; In 4.0.1 we shouldn't need this anymore */
for (table_being_deleted=delete_tables ;
table_being_deleted ;
table_being_deleted=table_being_deleted->next)
- (void) table_being_deleted->table->file->extra(HA_EXTRA_READCHECK);
+ {
+ TABLE *t=table_being_deleted->table;
+ free_io_cache(t); // Alloced by unique
+ t->no_keyread=0;
+ }
for (uint counter = 0; counter < num_of_tables-1; counter++)
{
@@ -312,7 +316,7 @@ bool multi_delete::send_data(List<Item> &values)
continue;
table->file->position(table->record[0]);
-
+
if (secure_counter < 0)
{
table->status|= STATUS_DELETED;
@@ -337,51 +341,40 @@ bool multi_delete::send_data(List<Item> &values)
return 0;
}
-
-
-/* Return true if some table is not transaction safe */
-
-static bool some_table_is_not_transaction_safe (TABLE_LIST *tl)
-{
- for (; tl ; tl=tl->next)
- {
- if (!(tl->table->file->has_transactions()))
- return true;
- }
- return false;
-}
-
-
void multi_delete::send_error(uint errcode,const char *err)
{
/* First send error what ever it is ... */
::send_error(&thd->net,errcode,err);
- /* reset used flags */
- delete_tables->table->no_keyread=0;
-
/* If nothing deleted return */
if (!deleted)
return;
+
/* Below can happen when thread is killed early ... */
if (!table_being_deleted)
table_being_deleted=delete_tables;
/*
- If rows from the first table only has been deleted and it is transactional,
- just do rollback.
+ If rows from the first table only has been deleted and it is
+ transactional, just do rollback.
The same if all tables are transactional, regardless of where we are.
In all other cases do attempt deletes ...
*/
if ((table_being_deleted->table->file->has_transactions() &&
- table_being_deleted == delete_tables) ||
- !some_table_is_not_transaction_safe(delete_tables->next))
+ table_being_deleted == delete_tables) || !not_trans_safe)
ha_rollback_stmt(thd);
else if (do_delete)
VOID(do_deletes(true));
}
+/*
+ Do delete from other tables.
+ Returns values:
+ 0 ok
+ 1 error
+*/
+
int multi_delete::do_deletes (bool from_send_error)
{
int error = 0, counter = 0;
@@ -409,60 +402,39 @@ int multi_delete::do_deletes (bool from_send_error)
break;
}
-#if USE_REGENERATE_TABLE
- // nice little optimization ....
- // but Monty has to fix generate_table...
- // This will not work for transactional tables because for other types
- // records is not absolute
- if (num_of_positions == table->file->records)
- {
- TABLE_LIST table_list;
- bzero((char*) &table_list,sizeof(table_list));
- table_list.name=table->table_name; table_list.real_name=table_being_deleted->real_name;
- table_list.table=table;
- table_list.grant=table->grant;
- table_list.db = table_being_deleted->db;
- error=generate_table(thd,&table_list,(TABLE *)0);
- if (error <= 0) {error = 1; break;}
- deleted += num_of_positions;
- continue;
- }
-#endif /* USE_REGENERATE_TABLE */
-
READ_RECORD info;
- error=0;
init_read_record(&info,thd,table,NULL,0,0);
- bool not_trans_safe = some_table_is_not_transaction_safe(delete_tables);
while (!(error=info.read_record(&info)) &&
(!thd->killed || from_send_error || not_trans_safe))
{
- error=table->file->delete_row(table->record[0]);
- if (error)
+ if ((error=table->file->delete_row(table->record[0])))
{
table->file->print_error(error,MYF(0));
break;
}
- else
- deleted++;
+ deleted++;
}
end_read_record(&info);
- if (error == -1)
+ if (error == -1) // End of file
error = 0;
}
return error;
}
+/*
+ return: 0 sucess
+ 1 error
+*/
+
bool multi_delete::send_eof()
{
- thd->proc_info="deleting from reference tables"; /* out: 1 if error, 0 if success */
+ thd->proc_info="deleting from reference tables";
/* Does deletes for the last n - 1 tables, returns 0 if ok */
- int error = do_deletes(false); /* do_deletes returns 0 if success */
+ int error = do_deletes(false); // returns 0 if success
/* reset used flags */
- delete_tables->table->no_keyread=0;
- if (error == -1) error = 0;
thd->proc_info="end";
if (error)
{
@@ -470,30 +442,27 @@ bool multi_delete::send_eof()
return 1;
}
- /* Write the SQL statement to the binlog if we deleted
- rows and we succeeded, or also in an error case when there
- was a non-transaction-safe table involved, since
- modifications in it cannot be rolled back. */
-
- if (deleted &&
- (!error || some_table_is_not_transaction_safe(delete_tables)))
+ /*
+ Write the SQL statement to the binlog if we deleted
+ rows and we succeeded, or also in an error case when there
+ was a non-transaction-safe table involved, since
+ modifications in it cannot be rolled back.
+ */
+ if (deleted || not_trans_safe)
{
mysql_update_log.write(thd,thd->query,thd->query_length);
- Query_log_event qinfo(thd, thd->query);
-
- /* mysql_bin_log is not open if binlogging or replication
- is not used */
-
- if (mysql_bin_log.is_open() && mysql_bin_log.write(&qinfo) &&
- !some_table_is_not_transaction_safe(delete_tables))
- error=1; /* Log write failed: roll back
- the SQL statement */
-
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ if (mysql_bin_log.write(&qinfo) &&
+ !not_trans_safe)
+ error=1; // Log write failed: roll back the SQL statement
+ }
/* Commit or rollback the current SQL statement */
-
VOID(ha_autocommit_or_rollback(thd,error > 0));
}
-
+ if (deleted)
+ query_cache.invalidate(delete_tables);
::send_ok(&thd->net,deleted);
return 0;
}
@@ -539,6 +508,7 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
close_temporary(table,0);
*fn_ext(path)=0; // Remove the .frm extension
ha_create_table(path, &create_info,1);
+ // We don't need to call invalidate() because this table is not in cache
if ((error= (int) !(open_temporary_table(thd, path, table_list->db,
table_list->real_name, 1))))
(void) rm_temporary_table(table_type, path);
@@ -570,6 +540,7 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
bzero((char*) &create_info,sizeof(create_info));
*fn_ext(path)=0; // Remove the .frm extension
error= ha_create_table(path,&create_info,1) ? -1 : 0;
+ query_cache.invalidate(table_list);
if (!dont_send_ok)
{
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
new file mode 100644
index 00000000000..70124c2d796
--- /dev/null
+++ b/sql/sql_do.cc
@@ -0,0 +1,34 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
+
+
+/* Execute DO statement */
+
+#include "mysql_priv.h"
+#include "sql_acl.h"
+
+int mysql_do(THD *thd, List<Item> &values)
+{
+ List_iterator<Item> li(values);
+ Item *value;
+ DBUG_ENTER("mysql_do");
+ if (setup_fields(thd,0, values, 0, 0, 0))
+ DBUG_RETURN(-1);
+ while ((value = li++))
+ value->val_int();
+ send_ok(&thd->net);
+ DBUG_RETURN(0);
+}
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 46cbe5e44d3..0c6b5599519 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -23,17 +23,17 @@
/* TODO:
HANDLER blabla OPEN [ AS foobar ] [ (column-list) ]
-
+
the most natural (easiest, fastest) way to do it is to
compute List<Item> field_list not in mysql_ha_read
but in mysql_ha_open, and then store it in TABLE structure.
-
+
The problem here is that mysql_parse calls free_item to free all the
items allocated at the end of every query. The workaround would to
keep two item lists per THD - normal free_list and handler_items.
The second is to be freeed only on thread end. mysql_ha_open should
then do { handler_items=concat(handler_items, free_list); free_list=0; }
-
+
But !!! do_cammand calls free_root at the end of every query and frees up
all the sql_alloc'ed memory. It's harder to work around...
*/
@@ -43,7 +43,7 @@
thd->open_tables=thd->handler_tables; \
thd->handler_tables=tmp; }
-static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
+static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
const char *table_name);
int mysql_ha_open(THD *thd, TABLE_LIST *tables)
@@ -53,12 +53,20 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables)
HANDLER_TABLES_HACK(thd);
if (err)
return -1;
-
+
+ // there can be only one table in *tables
+ if (!(tables->table->file->option_flag() & HA_CAN_SQL_HANDLER))
+ {
+ my_printf_error(ER_ILLEGAL_HA,ER(ER_ILLEGAL_HA),MYF(0), tables->name);
+ mysql_ha_close(thd, tables,1);
+ return -1;
+ }
+
send_ok(&thd->net);
return 0;
}
-int mysql_ha_close(THD *thd, TABLE_LIST *tables)
+int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok)
{
TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->name);
@@ -68,14 +76,20 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables)
close_thread_table(thd, ptr);
VOID(pthread_mutex_unlock(&LOCK_open));
}
-
- send_ok(&thd->net);
+ else
+ {
+ my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
+ tables->name,"HANDLER");
+ return -1;
+ }
+ if (!dont_send_ok)
+ send_ok(&thd->net);
return 0;
}
-static enum enum_ha_read_modes rkey_to_rnext[]=
+static enum enum_ha_read_modes rkey_to_rnext[]=
{ RNEXT, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV };
-
+
int mysql_ha_read(THD *thd, TABLE_LIST *tables,
enum enum_ha_read_modes mode, char *keyname, List<Item> *key_expr,
enum ha_rkey_function ha_rkey_mode, Item *cond,
@@ -86,14 +100,14 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
if (!table)
{
my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
- tables->name,"HANDLER");
+ tables->name,"HANDLER");
return -1;
}
tables->table=table;
if (cond && cond->fix_fields(thd,tables))
return -1;
-
+
if (keyname)
{
if ((keyno=find_type(keyname, &table->keynames, 1+2)-1)<0)
@@ -115,8 +129,12 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
select_limit+=offset_limit;
send_fields(thd,list,1);
-
+
+ HANDLER_TABLES_HACK(thd);
MYSQL_LOCK *lock=mysql_lock_tables(thd,&tables->table,1);
+ HANDLER_TABLES_HACK(thd);
+ if (!lock)
+ goto err0; // mysql_lock_tables() printed error message already
for (uint num_rows=0; num_rows < select_limit; )
{
@@ -166,7 +184,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
if (!(key= (byte*) sql_calloc(ALIGN_SIZE(key_len))))
{
send_error(&thd->net,ER_OUTOFMEMORY);
- goto err;
+ goto err;
}
key_copy(key, table, keyno, key_len);
err=table->file->index_read(table->record[0],
@@ -176,7 +194,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
default:
send_error(&thd->net,ER_ILLEGAL_HA);
- goto err;
+ goto err;
}
if (err)
@@ -191,7 +209,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
goto ok;
}
if (cond)
- {
+ {
err=err;
if(!cond->val_int())
continue;
@@ -224,6 +242,7 @@ ok:
return 0;
err:
mysql_unlock_tables(thd,lock);
+err0:
return -1;
}
@@ -234,19 +253,19 @@ err:
**************************************************************************/
/* Note: this function differs from find_locked_table() because we're looking
- here for alias, not real table name
+ here for alias, not real table name
*/
static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
const char *table_name)
{
int dblen;
TABLE **ptr;
-
+
if (!db || ! *db)
db= thd->db ? thd->db : "";
- dblen=strlen(db)+1;
+ dblen=strlen(db)+1;
ptr=&(thd->handler_tables);
-
+
for (TABLE *table=*ptr; table ; table=*ptr)
{
if (!memcmp(table->table_cache_key, db, dblen) &&
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 70cc5f412a1..0898ad4bffb 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -310,6 +310,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
}
}
thd->proc_info="end";
+ if (info.copied || info.deleted)
+ query_cache.invalidate(table_list);
table->time_stamp=save_time_stamp; // Restore auto timestamp ptr
table->next_number_field=0;
thd->count_cuted_fields=0;
@@ -362,7 +364,7 @@ int write_record(TABLE *table,COPY_INFO *info)
{
int error;
char *key=0;
-
+
info->records++;
if (info->handle_duplicates == DUP_REPLACE)
{
@@ -396,7 +398,7 @@ int write_record(TABLE *table,COPY_INFO *info)
error=my_errno;
goto err;
}
-
+
if (!key)
{
if (!(key=(char*) my_safe_alloca(table->max_unique_length,
@@ -737,9 +739,9 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
}
client_thd->proc_info="allocating local table";
- copy= (TABLE*) sql_alloc(sizeof(*copy)+
- (table->fields+1)*sizeof(Field**)+
- table->reclength);
+ copy= (TABLE*) client_thd->alloc(sizeof(*copy)+
+ (table->fields+1)*sizeof(Field**)+
+ table->reclength);
if (!copy)
goto error;
*copy= *table;
@@ -757,7 +759,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
found_next_number_field=table->found_next_number_field;
for (org_field=table->field ; *org_field ; org_field++,field++)
{
- if (!(*field= (*org_field)->new_field(copy)))
+ if (!(*field= (*org_field)->new_field(&client_thd->mem_root,copy)))
return 0;
(*field)->move_field(adjust_ptrs); // Point at copy->record[0]
if (*org_field == found_next_number_field)
@@ -986,23 +988,12 @@ static pthread_handler_decl(handle_delayed_insert,arg)
if (!di->status && !di->stacked_inserts)
{
struct timespec abstime;
-#if defined(HAVE_TIMESPEC_TS_SEC)
- abstime.ts_sec=time((time_t*) 0)+(time_t) delayed_insert_timeout;
- abstime.ts_nsec=0;
-#elif defined(__WIN__)
- abstime.tv_sec=time((time_t*) 0)+(time_t) delayed_insert_timeout;
- abstime.tv_nsec=0;
-#else
- struct timeval tv;
- gettimeofday(&tv,0);
- abstime.tv_sec=tv.tv_sec+(time_t) delayed_insert_timeout;
- abstime.tv_nsec=tv.tv_usec*1000;
-#endif
+ set_timespec(abstime, delayed_insert_timeout);
/* Information for pthread_kill */
di->thd.mysys_var->current_mutex= &di->mutex;
di->thd.mysys_var->current_cond= &di->cond;
- di->thd.proc_info=0;
+ di->thd.proc_info="Waiting for INSERT";
DBUG_PRINT("info",("Waiting for someone to insert rows"));
while (!thd->killed)
@@ -1037,6 +1028,7 @@ static pthread_handler_decl(handle_delayed_insert,arg)
pthread_mutex_unlock(&di->thd.mysys_var->mutex);
pthread_mutex_lock(&di->mutex);
}
+ di->thd.proc_info=0;
if (di->tables_in_use && ! thd->lock)
{
@@ -1225,6 +1217,7 @@ bool delayed_insert::handle_inserts(void)
sql_print_error("%s",thd.net.last_error);
goto err;
}
+ query_cache.invalidate(table);
if (thr_reschedule_write_lock(*thd.lock->locks))
{
/* This should never happen */
@@ -1249,6 +1242,7 @@ bool delayed_insert::handle_inserts(void)
sql_print_error("%s",thd.net.last_error);
goto err;
}
+ query_cache.invalidate(table);
pthread_mutex_lock(&mutex);
DBUG_RETURN(0);
@@ -1334,7 +1328,9 @@ void select_insert::send_error(uint errcode,const char *err)
::send_error(&thd->net,errcode,err);
table->file->extra(HA_EXTRA_NO_CACHE);
table->file->activate_all_index(thd);
- ha_rollback(thd);
+ ha_rollback_stmt(thd);
+ if (info.copied || info.deleted)
+ query_cache.invalidate(table);
}
@@ -1346,6 +1342,8 @@ bool select_insert::send_eof()
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error)
error=error2;
+ if (info.copied || info.deleted)
+ query_cache.invalidate(table);
if (error)
{
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 67f0d05d2d3..d61e47d0883 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index a796eca58f9..6a966336ad7 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -55,8 +55,9 @@ enum enum_sql_command {
SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_SHOW_BINLOGS,
SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA,
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
- SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_MULTI_DELETE,
- SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER
+ SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_MULTI_UPDATE,
+ SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
+ SQLCOM_END
};
enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT,
@@ -180,7 +181,7 @@ typedef struct st_lex {
enum enum_ha_read_modes ha_read_mode;
enum ha_rkey_function ha_rkey_mode;
enum enum_enable_or_disable alter_keys_onoff;
- uint grant,grant_tot_col,which_columns, union_option;
+ uint grant,grant_tot_col,which_columns, union_option, mqh;
thr_lock_type lock_option;
bool drop_primary,drop_if_exists,local_file;
bool in_comment,ignore_space,verbose,simple_alter, option_type;
diff --git a/sql/sql_list.cc b/sql/sql_list.cc
index be630dfc038..1124605ca24 100644
--- a/sql/sql_list.cc
+++ b/sql/sql_list.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 66311b03435..542eef623f0 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 17d1765495c..abc9fa5a121 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -175,7 +175,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
MY_STAT stat_info;
if (!my_stat(name,&stat_info,MYF(MY_WME)))
DBUG_RETURN(-1);
-
+
// if we are not in slave thread, the file must be:
if (!thd->slave_thread &&
!((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others
@@ -292,7 +292,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
// on the slave thd->query is never initialized
if(!thd->slave_thread)
mysql_update_log.write(thd,thd->query,thd->query_length);
-
+
if (!using_transactions)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
if (mysql_bin_log.is_open())
@@ -547,7 +547,7 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, String &field_term,
*/
if (get_it_from_net)
cache.read_function = _my_b_net_read;
-
+
need_end_io_cache = 1;
if (!opt_old_rpl_compat && mysql_bin_log.is_open())
cache.pre_read = cache.pre_close =
@@ -748,7 +748,7 @@ found_eof:
/*
** One can't use fixed length with multi-byte charset **
*/
-
+
int READ_INFO::read_fixed_length()
{
int chr;
@@ -872,4 +872,3 @@ bool READ_INFO::find_start_of_fields()
}
return 0;
}
-
diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc
index 53953c96d0b..13cac83fc3f 100644
--- a/sql/sql_manager.cc
+++ b/sql/sql_manager.cc
@@ -55,13 +55,7 @@ pthread_handler_decl(handle_manager,arg __attribute__((unused)))
{
if (reset_flush_time)
{
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec = time(NULL)+flush_time; // Bsd 2.1
- abstime.ts_nsec = 0;
-#else
- abstime.tv_sec = time(NULL)+flush_time; // Linux or Solairs
- abstime.tv_nsec = 0;
-#endif
+ set_timespec(abstime, flush_time);
reset_flush_time = FALSE;
}
while (!manager_status && !error && !abort_loop)
diff --git a/sql/sql_map.cc b/sql/sql_map.cc
index 4578b85d10a..e7e24f957c6 100644
--- a/sql/sql_map.cc
+++ b/sql/sql_map.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/sql_map.h b/sql/sql_map.h
index 34f2f755b43..632eb6e4f64 100644
--- a/sql/sql_map.h
+++ b/sql/sql_map.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index a459ca0d602..3bcade84cd0 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -29,25 +29,42 @@
#include <my_dir.h>
#include <assert.h>
+#ifdef HAVE_OPENSSL
+/*
+ Without SSL the handshake consists of one packet. This packet
+ has both client capabilites and scrambled password.
+ With SSL the handshake might consist of two packets. If the first
+ packet (client capabilities) has CLIENT_SSL flag set, we have to
+ switch to SSL and read the second packet. The scrambled password
+ is in the second packet and client_capabilites field will be ignored.
+ Maybe it is better to accept flags other than CLIENT_SSL from the
+ second packet?
+*/
+#define SSL_HANDSHAKE_SIZE 2
+#define NORMAL_HANDSHAKE_SIZE 6
+#define MIN_HANDSHAKE_SIZE 2
+#else
+#define MIN_HANDSHAKE_SIZE 6
+#endif /* HAVE_OPENSSL */
#define SCRAMBLE_LENGTH 8
+
extern int yyparse(void);
extern "C" pthread_mutex_t THR_LOCK_keycache;
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#endif
-static int check_for_max_user_connections(const char *user, int u_length,
- const char *host);
+static int check_for_max_user_connections(const char *user, const char *host, uint max);
static void decrease_user_connections(const char *user, const char *host);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
-static bool check_dup(THD *thd,const char *db,const char *name,
- TABLE_LIST *tables);
+static bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
static void mysql_init_query(THD *thd);
static void remove_escape(char *name);
static void refresh_status(void);
-static bool append_file_to_dir(char **filename_ptr, char *table_name);
+static bool append_file_to_dir(THD *thd, char **filename_ptr,
+ char *table_name);
static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result);
const char *any_db="*any*"; // Special symbol for check_access
@@ -72,8 +89,8 @@ static void test_signal(int sig_ptr)
MessageBox(NULL,"Test signal","DBUG",MB_OK);
#endif
#if defined(OS2)
- fprintf( stderr, "Test signal %d\n", sig_ptr);
- fflush( stderr);
+ fprintf(stderr, "Test signal %d\n", sig_ptr);
+ fflush(stderr);
#endif
}
static void init_signals(void)
@@ -99,6 +116,95 @@ inline bool end_active_trans(THD *thd)
}
+static HASH hash_user_connections;
+extern pthread_mutex_t LOCK_user_conn;
+
+struct user_conn {
+ char *user;
+ uint len, connections, questions, max;
+ time_t intime;
+};
+
+static byte* get_key_conn(user_conn *buff, uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=buff->len;
+ return (byte*) buff->user;
+}
+
+#define DEF_USER_COUNT 50
+
+static void free_user(struct user_conn *uc)
+{
+ my_free((char*) uc,MYF(0));
+}
+
+/*
+** Check if maximum queries per hour limit has been reached
+** returns 0 if OK.
+*/
+
+static bool check_mqh(THD *thd, const char *user, const char *host,uint max)
+{
+ uint temp_len;
+ char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
+ struct user_conn *uc;
+ if (!user)
+ user="";
+ if (!host)
+ host="";
+ temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
+ NullS) - temp_user);
+//This would be MUCH faster if there was already temp_user made in THD !!! May I ??
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (byte*) temp_user, temp_len);
+ if (uc) /* user found ; check for no. of queries */
+ {
+ bool my_start = thd->start_time != 0;
+ time_t check_time = (my_start) ? thd->start_time : time(NULL);
+ if (check_time - uc->intime >= 3600)
+ {
+ uc->questions=(uint)my_start;
+ uc->intime=check_time;
+ }
+ else if (uc->max && ++(uc->questions) > uc->max)
+ {
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); // change this to appropriate message
+ return 1;
+ }
+ }
+ else
+ {
+ struct user_conn *uc= ((struct user_conn*)
+ my_malloc(sizeof(struct user_conn) + temp_len+1,
+ MYF(MY_WME)));
+ if (!uc)
+ {
+ send_error(&current_thd->net, 0, NullS); // Out of memory
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ return 1;
+ }
+ uc->user=(char*) (uc+1);
+ memcpy(uc->user,temp_user,temp_len+1);
+ uc->len = temp_len;
+ uc->connections = 1;
+ uc->questions=0;
+ uc->max=max;
+ uc->intime=current_thd->thr_create_time;
+ if (hash_insert(&hash_user_connections, (byte*) uc))
+ {
+ my_free((char*) uc,0);
+ send_error(&current_thd->net, 0, NullS); // Out of memory
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ return 1;
+ }
+ }
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
+ return 0;
+}
+
/*
** Check if user is ok
** Updates:
@@ -109,7 +215,9 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
const char *passwd, const char *db, bool check_count)
{
NET *net= &thd->net;
+ uint max=0;
thd->db=0;
+ thd->db_length=0;
if (!(thd->user = my_strdup(user, MYF(0))))
{
@@ -120,7 +228,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
passwd, thd->scramble, &thd->priv_user,
protocol_version == 9 ||
!(thd->client_capabilities &
- CLIENT_LONG_PASSWORD));
+ CLIENT_LONG_PASSWORD),&max);
DBUG_PRINT("info",
("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
thd->client_capabilities, thd->max_packet_length,
@@ -151,6 +259,8 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
return(1);
}
}
+ if (mqh_used && max && check_mqh(thd,user,thd->host,max))
+ return -1;
mysql_log.write(thd,command,
(thd->priv_user == thd->user ?
(char*) "%s@%s on %s" :
@@ -160,7 +270,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
db ? db : (char*) "");
thd->db_access=0;
if (max_user_connections &&
- check_for_max_user_connections(user, strlen(user), thd->host))
+ check_for_max_user_connections(user, thd->host, max))
return -1;
if (db && db[0])
{
@@ -180,28 +290,6 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
** variable that is greater then 0
*/
-static HASH hash_user_connections;
-extern pthread_mutex_t LOCK_user_conn;
-
-struct user_conn {
- char *user;
- uint len, connections;
-};
-
-static byte* get_key_conn(user_conn *buff, uint *length,
- my_bool not_used __attribute__((unused)))
-{
- *length=buff->len;
- return (byte*) buff->user;
-}
-
-#define DEF_USER_COUNT 50
-
-static void free_user(struct user_conn *uc)
-{
- my_free((char*) uc,MYF(0));
-}
-
void init_max_user_conn(void)
{
(void) hash_init(&hash_user_connections,DEF_USER_COUNT,0,0,
@@ -210,8 +298,7 @@ void init_max_user_conn(void)
}
-static int check_for_max_user_connections(const char *user, int u_length,
- const char *host)
+static int check_for_max_user_connections(const char *user, const char *host, uint max)
{
int error=1;
uint temp_len;
@@ -252,7 +339,10 @@ static int check_for_max_user_connections(const char *user, int u_length,
uc->user=(char*) (uc+1);
memcpy(uc->user,temp_user,temp_len+1);
uc->len = temp_len;
- uc->connections = 1;
+ uc->connections = 1;
+ uc->questions=0;
+ uc->max=max;
+ uc->intime=current_thd->thr_create_time;
if (hash_insert(&hash_user_connections, (byte*) uc))
{
my_free((char*) uc,0);
@@ -291,7 +381,7 @@ static void decrease_user_connections(const char *user, const char *host)
DBUG_ASSERT(uc != 0); // We should always find the user
if (!uc)
goto end; // Safety; Something went wrong
- if (! --uc->connections)
+ if (! --uc->connections && !mqh_used)
{
/* Last connection for user; Delete it */
(void) hash_delete(&hash_user_connections,(byte*) uc);
@@ -307,7 +397,6 @@ void free_max_user_conn(void)
hash_free(&hash_user_connections);
}
-
/*
** check connnetion and get priviliges
** returns 0 on ok, -1 < if error is given > 0 on error.
@@ -363,51 +452,35 @@ check_connections(THD *thd)
}
vio_keepalive(net->vio, TRUE);
- /* nasty, but any other way? */
- uint pkt_len = 0;
+ ulong pkt_len=0;
{
/* buff[] needs to big enough to hold the server_version variable */
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+32],*end;
int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB;
+
if (opt_using_transactions)
client_flags|=CLIENT_TRANSACTIONS;
#ifdef HAVE_COMPRESS
client_flags |= CLIENT_COMPRESS;
#endif /* HAVE_COMPRESS */
+#ifdef HAVE_OPENSSL
+ if (ssl_acceptor_fd)
+ client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */
+#endif /* HAVE_OPENSSL */
- end=strmov(buff,server_version)+1;
+ end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1;
int4store((uchar*) end,thd->thread_id);
end+=4;
memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
end+=SCRAMBLE_LENGTH +1;
-#ifdef HAVE_OPENSSL
- if (ssl_acceptor_fd)
- client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */
- /*
- * Without SSL the handshake consists of one packet. This packet
- * has both client capabilites and scrambled password.
- * With SSL the handshake might consist of two packets. If the first
- * packet (client capabilities) has CLIENT_SSL flag set, we have to
- * switch to SSL and read the second packet. The scrambled password
- * is in the second packet and client_capabilites field will be ignored.
- * Maybe it is better to accept flags other than CLIENT_SSL from the
- * second packet?
- */
-#define SSL_HANDSHAKE_SIZE 2
-#define NORMAL_HANDSHAKE_SIZE 6
-#define MIN_HANDSHAKE_SIZE 2
-
-#else
-#define MIN_HANDSHAKE_SIZE 6
-#endif /* HAVE_OPENSSL */
int2store(end,client_flags);
- end[2]=MY_CHARSET_CURRENT;
+ end[2]=(char) MY_CHARSET_CURRENT;
int2store(end+3,thd->server_status);
bzero(end+5,13);
end+=18;
- if (net_write_command(net,protocol_version, buff,
+ if (net_write_command(net,(uchar) protocol_version, buff,
(uint) (end-buff)) ||
- (pkt_len=my_net_read(net)) == packet_error ||
+ (pkt_len= my_net_read(net)) == packet_error ||
pkt_len < MIN_HANDSHAKE_SIZE)
{
inc_host_errors(&thd->remote.sin_addr);
@@ -426,12 +499,9 @@ check_connections(THD *thd)
if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
thd->sql_mode|= MODE_IGNORE_SPACE;
#ifdef HAVE_OPENSSL
- DBUG_PRINT("info",
- ("pkt_len:%d, client capabilities: %d",
- pkt_len, thd->client_capabilities) );
+ DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
if (thd->client_capabilities & CLIENT_SSL)
{
- DBUG_PRINT("info", ("Agreed to change IO layer to SSL") );
/* Do the SSL layering. */
DBUG_PRINT("info", ("IO layer change in progress..."));
sslaccept(ssl_acceptor_fd, net->vio, thd->inactive_timeout);
@@ -439,8 +509,8 @@ check_connections(THD *thd)
if ((pkt_len=my_net_read(net)) == packet_error ||
pkt_len < NORMAL_HANDSHAKE_SIZE)
{
- DBUG_PRINT("info", ("pkt_len:%d", pkt_len));
- DBUG_PRINT("error", ("Failed to read user information"));
+ DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
+ pkt_len));
inc_host_errors(&thd->remote.sin_addr);
return(ER_HANDSHAKE_ERROR);
}
@@ -469,7 +539,7 @@ check_connections(THD *thd)
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
opt_using_transactions)
thd->net.return_status= &thd->server_status;
- net->timeout=net_read_timeout;
+ net->timeout=(uint) net_read_timeout;
if (check_user(thd,COM_CONNECT, user, passwd, db, 1))
return (-1);
thd->password=test(passwd[0]);
@@ -487,9 +557,9 @@ pthread_handler_decl(handle_one_connection,arg)
pthread_detach_this_thread();
-#if !defined( __WIN__) && !defined(OS2) /* Win32 calls this in pthread_create */
- if (my_thread_init()) // needed to be called first before we call
- // DBUG_ macros
+#if !defined( __WIN__) && !defined(OS2) // Win32 calls this in pthread_create
+ // The following calls needs to be done before we call DBUG_ macros
+ if (my_thread_init())
{
close_connection(&thd->net,ER_OUT_OF_RESOURCES);
statistic_increment(aborted_connects,&LOCK_thread_count);
@@ -498,13 +568,13 @@ pthread_handler_decl(handle_one_connection,arg)
}
#endif
- // handle_one_connection() is the only way a thread would start
- // and would always be on top of the stack
- // therefore, the thread stack always starts at the address of the first
- // local variable of handle_one_connection, which is thd
- // we need to know the start of the stack so that we could check for
- // stack overruns
-
+ /*
+ handle_one_connection() is the only way a thread would start
+ and would always be on top of the stack, therefore, the thread
+ stack always starts at the address of the first local variable
+ of handle_one_connection, which is thd. We need to know the
+ start of the stack so that we could check for stack overruns.
+ */
DBUG_PRINT("info", ("handle_one_connection called by thread %d\n",
thd->thread_id));
// now that we've called my_thread_init(), it is safe to call DBUG_*
@@ -564,12 +634,12 @@ pthread_handler_decl(handle_one_connection,arg)
if (net->error && net->vio != 0)
{
if (!thd->killed && opt_warnings)
- sql_print_error(ER(ER_NEW_ABORTING_CONNECTION),
- thd->thread_id,(thd->db ? thd->db : "unconnected"),
- thd->user ? thd->user : "unauthenticated",
- thd->host_or_ip,
- (net->last_errno ? ER(net->last_errno) :
- ER(ER_UNKNOWN_ERROR)));
+ sql_print_error(ER(ER_NEW_ABORTING_CONNECTION),
+ thd->thread_id,(thd->db ? thd->db : "unconnected"),
+ thd->user ? thd->user : "unauthenticated",
+ thd->host_or_ip,
+ (net->last_errno ? ER(net->last_errno) :
+ ER(ER_UNKNOWN_ERROR)));
send_error(net,net->last_errno,NullS);
thread_safe_increment(aborted_threads,&LOCK_thread_count);
}
@@ -635,7 +705,8 @@ pthread_handler_decl(handle_bootstrap,arg)
buff[length]=0;
thd->current_tablenr=0;
thd->query_length=length;
- thd->query= thd->memdup(buff,length+1);
+ thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
+ thd->query[length] = '\0';
thd->query_id=query_id++;
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
@@ -693,8 +764,8 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
goto err;
thd->free_list = 0;
+ thd->query_length=(uint) strlen(tbl_name);
thd->query = tbl_name;
- thd->query_length=strlen(tbl_name);
if ((error = mysqld_dump_create_info(thd, table, -1)))
{
my_error(ER_GET_ERRNO, MYF(0));
@@ -715,7 +786,8 @@ err:
bool do_command(THD *thd)
{
char *packet;
- uint old_timeout,packet_length;
+ uint old_timeout;
+ ulong packet_length;
NET *net;
enum enum_server_command command;
DBUG_ENTER("do_command");
@@ -725,7 +797,7 @@ bool do_command(THD *thd)
packet=0;
old_timeout=net->timeout;
- net->timeout=thd->inactive_timeout; /* Wait max for 8 hours */
+ net->timeout=(uint) thd->inactive_timeout; // Wait max for 8 hours
net->last_error[0]=0; // Clear error message
net->last_errno=0;
@@ -745,7 +817,7 @@ bool do_command(THD *thd)
command_name[command]));
}
net->timeout=old_timeout; // Timeout for writing
- DBUG_RETURN(dispatch_command(command,thd, packet+1, packet_length));
+ DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
}
@@ -770,6 +842,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->lex.select_lex.options=0; // We store status here
switch (command) {
case COM_INIT_DB:
+ thread_safe_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_thread_count);
if (!mysql_change_db(thd,packet))
mysql_log.write(thd,command,"%s",thd->db);
break;
@@ -783,6 +856,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_TABLE_DUMP:
{
+ thread_safe_increment(com_other,&LOCK_thread_count);
slow_command = TRUE;
uint db_len = *(uchar*)packet;
uint tbl_len = *(uchar*)(packet + db_len + 1);
@@ -799,6 +873,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_CHANGE_USER:
{
+ thread_safe_increment(com_other,&LOCK_thread_count);
char *user= (char*) packet;
char *passwd= strend(user)+1;
char *db= strend(passwd)+1;
@@ -806,6 +881,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* Save user and privileges */
uint save_master_access=thd->master_access;
uint save_db_access= thd->db_access;
+ uint save_db_length= thd->db_length;
char *save_user= thd->user;
char *save_priv_user= thd->priv_user;
char *save_db= thd->db;
@@ -822,6 +898,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->master_access=save_master_access;
thd->db_access=save_db_access;
thd->db=save_db;
+ thd->db_length=save_db_length;
thd->user=save_user;
thd->priv_user=save_priv_user;
break;
@@ -835,14 +912,23 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_QUERY:
{
- char *pos=packet-1+packet_length; // Point at end null
- /* Remove garage at end of query */
- while (packet_length > 0 && pos[-1] == ';')
+ packet_length--; // Remove end null
+ /* Remove garage at start and end of query */
+ while (isspace(packet[0]) && packet_length > 0)
+ {
+ packet++;
+ packet_length--;
+ }
+ char *pos=packet+packet_length; // Point at end null
+ while (packet_length > 0 && (pos[-1] == ';' || isspace(pos[-1])))
{
pos--;
packet_length--;
}
- if (!(thd->query= (char*) thd->memdup((gptr) (packet),packet_length+1)))
+ /* We must allocate some extra memory for query cache */
+ if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
+ packet_length,
+ thd->db_length+2)))
break;
thd->query[packet_length]=0;
thd->packet.shrink(net_buffer_length); // Reclaim some memory
@@ -850,7 +936,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
mysql_log.write(thd,command,"%s",thd->query);
DBUG_PRINT("query",("%s",thd->query));
- mysql_parse(thd,thd->query,packet_length-1);
+ if (mqh_used && check_mqh(thd,thd->user,thd->host,0))
+ {
+ error = TRUE;
+ net->error = 0;
+ break;
+ }
+ /* thd->query_length is set by mysql_parse() */
+ mysql_parse(thd,thd->query,packet_length);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
DBUG_PRINT("info",("query ready"));
@@ -864,6 +957,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
char *fields;
TABLE_LIST table_list;
+ thread_safe_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_thread_count);
bzero((char*) &table_list,sizeof(table_list));
if (!(table_list.db=thd->db))
{
@@ -872,8 +966,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
thd->free_list=0;
table_list.name=table_list.real_name=thd->strdup(packet);
- thd->query=fields=thd->strdup(strend(packet)+1);
- thd->query_length=strlen(thd->query);
+ packet=strend(packet)+1;
+ // command not cachable => no gap for data base name
+ if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
+ break;
mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
remove_escape(table_list.real_name); // This can't have wildcards
@@ -888,6 +984,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
#endif
case COM_QUIT:
+ /* We don't calculate statistics for this command */
mysql_log.write(thd,command,NullS);
net->error=0; // Don't give 'abort' message
error=TRUE; // End server
@@ -895,6 +992,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_CREATE_DB: // QQ: To be removed
{
+ thread_safe_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_thread_count);
char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !stripp_sp(db) || check_db_name(db))
@@ -910,6 +1008,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_DROP_DB: // QQ: To be removed
{
+ thread_safe_increment(com_stat[SQLCOM_DROP_DB],&LOCK_thread_count);
char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !stripp_sp(db) || check_db_name(db))
@@ -928,6 +1027,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_BINLOG_DUMP:
{
+ thread_safe_increment(com_other,&LOCK_thread_count);
slow_command = TRUE;
if (check_access(thd, FILE_ACL, any_db))
break;
@@ -952,7 +1052,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_REFRESH:
{
- uint options=(uchar) packet[0];
+ thread_safe_increment(com_stat[SQLCOM_FLUSH],&LOCK_thread_count);
+ ulong options= (ulong) (uchar) packet[0];
if (check_access(thd,RELOAD_ACL,any_db))
break;
mysql_log.write(thd,command,NullS);
@@ -960,9 +1061,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
send_error(net,0);
else
send_eof(net);
+ if (mqh_used && hash_user_connections.array.buffer == 0)
+ init_max_user_conn();
break;
}
case COM_SHUTDOWN:
+ thread_safe_increment(com_other,&LOCK_thread_count);
if (check_access(thd,SHUTDOWN_ACL,any_db))
break; /* purecov: inspected */
DBUG_PRINT("quit",("Got shutdown command"));
@@ -984,6 +1088,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_STATISTICS:
{
mysql_log.write(thd,command,NullS);
+ thread_safe_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_thread_count);
char buff[200];
ulong uptime = (ulong) (thd->start_time - start_time);
sprintf((char*) buff,
@@ -1002,9 +1107,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
case COM_PING:
+ thread_safe_increment(com_other,&LOCK_thread_count);
send_ok(net); // Tell client we are alive
break;
case COM_PROCESS_INFO:
+ thread_safe_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_thread_count);
if (!thd->priv_user[0] && check_process_priv(thd))
break;
mysql_log.write(thd,command,NullS);
@@ -1013,11 +1120,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
case COM_PROCESS_KILL:
{
+ thread_safe_increment(com_stat[SQLCOM_KILL],&LOCK_thread_count);
ulong id=(ulong) uint4korr(packet);
kill_one_thread(thd,id);
break;
}
case COM_DEBUG:
+ thread_safe_increment(com_other,&LOCK_thread_count);
if (check_process_priv(thd))
break; /* purecov: inspected */
mysql_print_status(thd);
@@ -1085,6 +1194,28 @@ mysql_execute_command(void)
SELECT_LEX *select_lex = lex->select;
DBUG_ENTER("mysql_execute_command");
+ if (thd->slave_thread)
+ {
+ /*
+ Skip if we are in the slave thread, some table rules have been
+ given and the table list says the query should not be replicated
+ */
+ if (table_rules_on && tables && !tables_ok(thd,tables))
+ DBUG_VOID_RETURN;
+#ifndef TO_BE_DELETED
+ /*
+ This is a workaround to deal with the shortcoming in 3.23.44-3.23.46
+ masters in RELEASE_LOCK() logging. We re-write SELECT RELEASE_LOCK()
+ as DO RELEASE_LOCK()
+ */
+ if (lex->sql_command == SQLCOM_SELECT)
+ {
+ lex->sql_command = SQLCOM_DO;
+ lex->insert_list = &select_lex->item_list;
+ }
+#endif
+ }
+
/*
Skip if we are in the slave thread, some table rules have been given
and the table list says the query should not be replicated
@@ -1094,6 +1225,7 @@ mysql_execute_command(void)
!tables_ok(thd,tables)))
DBUG_VOID_RETURN;
+ thread_safe_increment(com_stat[lex->sql_command],&LOCK_thread_count);
switch (lex->sql_command) {
case SQLCOM_SELECT:
{
@@ -1164,11 +1296,18 @@ mysql_execute_command(void)
}
if (!(res=open_and_lock_tables(thd,tables)))
+ {
+ query_cache.store_query(thd, tables);
res=handle_select(thd, lex, result);
+ }
else
delete result;
break;
}
+ case SQLCOM_DO:
+ res=mysql_do(thd, *lex->insert_list);
+ break;
+
case SQLCOM_PURGE:
{
if (check_process_priv(thd))
@@ -1307,8 +1446,10 @@ mysql_execute_command(void)
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
/* Fix names if symlinked tables */
- if (append_file_to_dir(&lex->create_info.data_file_name, tables->name) ||
- append_file_to_dir(&lex->create_info.index_file_name, tables->name))
+ if (append_file_to_dir(thd, &lex->create_info.data_file_name,
+ tables->name) ||
+ append_file_to_dir(thd,&lex->create_info.index_file_name,
+ tables->name))
{
res=-1;
break;
@@ -1319,7 +1460,7 @@ mysql_execute_command(void)
select_result *result;
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
- check_dup(thd,tables->db,tables->real_name,tables->next))
+ check_dup(tables->db, tables->real_name, tables->next))
{
net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
@@ -1435,6 +1576,7 @@ mysql_execute_command(void)
if (end_active_trans(thd))
res= -1;
else
+ {
res= mysql_alter_table(thd, select_lex->db, lex->name,
&lex->create_info,
tables, lex->create_list,
@@ -1442,6 +1584,7 @@ mysql_execute_command(void)
(ORDER *) select_lex->order_list.first,
lex->drop_primary, lex->duplicates,
lex->alter_keys_onoff, lex->simple_alter);
+ }
break;
}
#endif
@@ -1470,6 +1613,7 @@ mysql_execute_command(void)
goto error;
}
}
+ query_cache.invalidate(tables);
if (end_active_trans(thd))
res= -1;
else if (mysql_rename_tables(thd,tables))
@@ -1508,6 +1652,7 @@ mysql_execute_command(void)
check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
goto error; /* purecov: inspected */
res = mysql_repair_table(thd, tables, &lex->check_opt);
+ query_cache.invalidate(tables);
break;
}
case SQLCOM_CHECK:
@@ -1516,6 +1661,7 @@ mysql_execute_command(void)
check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables))
goto error; /* purecov: inspected */
res = mysql_check_table(thd, tables, &lex->check_opt);
+ query_cache.invalidate(tables);
break;
}
case SQLCOM_ANALYZE:
@@ -1564,19 +1710,68 @@ mysql_execute_command(void)
send_error(&thd->net,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
- res = mysql_update(thd,tables,
- select_lex->item_list,
- lex->value_list,
- select_lex->where,
- (ORDER *) select_lex->order_list.first,
- select_lex->select_limit,
- lex->duplicates,
- lex->lock_option);
+ if (select_lex->table_list.elements == 1)
+ {
+ res = mysql_update(thd,tables,
+ select_lex->item_list,
+ lex->value_list,
+ select_lex->where,
+ (ORDER *) select_lex->order_list.first,
+ select_lex->select_limit,
+ lex->duplicates,
+ lex->lock_option);
#ifdef DELETE_ITEMS
- delete select_lex->where;
+ delete select_lex->where;
#endif
- break;
+ }
+ else
+ {
+ multi_update *result;
+ uint table_count;
+ TABLE_LIST *auxi;
+ lex->sql_command=SQLCOM_MULTI_UPDATE;
+ for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
+ {
+ table_count++;
+ auxi->lock_type=TL_WRITE;
+ }
+ if (select_lex->order_list.elements || (select_lex->select_limit && select_lex->select_limit < INT_MAX))
+ {
+ send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /// will have to come up with something better eventually
+ DBUG_VOID_RETURN;
+ }
+ tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
+ if ((res=open_and_lock_tables(thd,tables)))
+ break;
+ if (!setup_fields(thd,tables,select_lex->item_list,1,0,0) &&
+ !setup_fields(thd,tables,lex->value_list,0,0,0) && ! thd->fatal_error &&
+ (result=new multi_update(thd,tables,select_lex->item_list,lex->duplicates,
+ lex->lock_option, table_count)))
+ {
+ List <Item> total_list;
+ List_iterator <Item> field_list(select_lex->item_list);
+ List_iterator <Item> value_list(lex->value_list);
+ Item *item;
+ while ((item=field_list++))
+ total_list.push_back(item);
+ while ((item=value_list++))
+ total_list.push_back(item);
+
+ res=mysql_select(thd,tables,total_list,
+ select_lex->where,
+ (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
+ (ORDER *)NULL,
+ select_lex->options | thd->options |
+ SELECT_NO_JOIN_CACHE,
+ result);
+ delete result;
+ }
+ else
+ res= -1; // Error is not sent
+ close_thread_tables(thd);
+ }
+ break;
case SQLCOM_INSERT:
if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege))
goto error; /* purecov: inspected */
@@ -1624,7 +1819,7 @@ mysql_execute_command(void)
if (thd->select_limit < select_lex->select_limit)
thd->select_limit= HA_POS_ERROR; // No limit
- if (check_dup(thd,tables->db,tables->real_name,tables->next))
+ if (check_dup(tables->db, tables->real_name, tables->next))
{
net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
@@ -1681,13 +1876,13 @@ mysql_execute_command(void)
select_lex->options);
break;
}
- case SQLCOM_MULTI_DELETE:
+ case SQLCOM_DELETE_MULTI:
{
TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first;
TABLE_LIST *auxi;
uint table_count=0;
multi_delete *result;
-
+
/* sql_yacc guarantees that tables and aux_tables are not zero */
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
check_table_access(thd,SELECT_ACL, tables) ||
@@ -1729,8 +1924,8 @@ mysql_execute_command(void)
/* Fix tables-to-be-deleted-from list to point at opened tables */
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
auxi->table= ((TABLE_LIST*) auxi->table)->table;
- if ((result=new multi_delete(thd,aux_tables,lex->lock_option,
- table_count)) && ! thd->fatal_error)
+ if (!thd->fatal_error && (result=new multi_delete(thd,aux_tables,
+ lex->lock_option,table_count)))
{
res=mysql_select(thd,tables,select_lex->item_list,
select_lex->where,
@@ -1739,10 +1934,10 @@ mysql_execute_command(void)
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE,
result);
+ delete result;
}
else
res= -1; // Error is not sent
- delete result;
close_thread_tables(thd);
break;
}
@@ -1912,7 +2107,7 @@ mysql_execute_command(void)
}
case SQLCOM_SET_OPTION:
{
- uint org_options=thd->options;
+ ulong org_options=thd->options;
thd->options=select_lex->options;
thd->update_lock_default= ((thd->options & OPTION_LOW_PRIORITY_UPDATES) ?
TL_WRITE_LOW_PRIORITY : TL_WRITE);
@@ -2099,6 +2294,8 @@ mysql_execute_command(void)
}
}
}
+ if (mqh_used && hash_user_connections.array.buffer == 0)
+ init_max_user_conn();
break;
}
case SQLCOM_FLUSH:
@@ -2167,13 +2364,17 @@ mysql_execute_command(void)
even if there is a problem with the OPTION_AUTO_COMMIT flag
(Which of course should never happen...)
*/
+ {
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_commit(thd))
+ {
send_ok(&thd->net);
+ }
else
res= -1;
break;
+ }
case SQLCOM_ROLLBACK:
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_rollback(thd))
@@ -2212,7 +2413,7 @@ error:
bool
check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
- bool dont_check_global_grants)
+ bool dont_check_global_grants, bool no_errors)
{
uint db_access,dummy;
if (save_priv)
@@ -2222,7 +2423,8 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
{
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */
+ if (!no_errors)
+ send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */
return TRUE; /* purecov: tested */
}
@@ -2234,16 +2436,17 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
if ((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL) ||
! db && dont_check_global_grants)
{ // We can never grant this
- net_printf(&thd->net,ER_ACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->host_or_ip,
- thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
+ if (!no_errors)
+ net_printf(&thd->net,ER_ACCESS_DENIED_ERROR,
+ thd->priv_user,
+ thd->host_or_ip,
+ thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
return TRUE; /* purecov: tested */
}
if (db == any_db)
return FALSE; // Allow select on anything
-
+
if (db && (!thd->db || strcmp(db,thd->db)))
db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
thd->priv_user, db); /* purecov: inspected */
@@ -2257,10 +2460,11 @@ check_access(THD *thd,uint want_access,const char *db, uint *save_priv,
((grant_option && !dont_check_global_grants) &&
!(want_access & ~TABLE_ACLS)))
return FALSE; /* Ok */
- net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->host_or_ip,
- db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
+ if (!no_errors)
+ net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
+ thd->priv_user,
+ thd->host_or_ip,
+ db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
return TRUE; /* purecov: tested */
}
@@ -2277,7 +2481,8 @@ bool check_process_priv(THD *thd)
*/
bool
-check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
+check_table_access(THD *thd,uint want_access,TABLE_LIST *tables,
+ bool no_errors)
{
uint found=0,found_access=0;
TABLE_LIST *org_tables=tables;
@@ -2292,18 +2497,20 @@ check_table_access(THD *thd,uint want_access,TABLE_LIST *tables)
tables->grant.privilege=found_access;
else
{
- if (check_access(thd,want_access,tables->db,&tables->grant.privilege))
+ if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
+ 0, no_errors))
return TRUE; // Access denied
found_access=tables->grant.privilege;
found=1;
}
}
- else if (check_access(thd,want_access,tables->db,&tables->grant.privilege))
+ else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
+ 0, no_errors))
return TRUE; // Access denied
}
if (grant_option)
return check_grant(thd,want_access & ~EXTRA_ACL,org_tables,
- test(want_access & EXTRA_ACL));
+ test(want_access & EXTRA_ACL), no_errors);
return FALSE;
}
@@ -2425,7 +2632,7 @@ mysql_init_query(THD *thd)
thd->fatal_error=0; // Safety
thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
thd->sent_row_count=thd->examined_row_count=0;
- thd->lex.sql_command=SQLCOM_SELECT;
+ thd->safe_to_cache_query=1;
DBUG_VOID_RETURN;
}
@@ -2434,9 +2641,10 @@ mysql_init_select(LEX *lex)
{
SELECT_LEX *select_lex = lex->select;
select_lex->where=select_lex->having=0;
- select_lex->select_limit=current_thd->default_select_limit;
+ select_lex->select_limit=lex->thd->default_select_limit;
select_lex->offset_limit=0;
- select_lex->options=0; select_lex->linkage=UNSPECIFIED_TYPE;
+ select_lex->options=0;
+ select_lex->linkage=UNSPECIFIED_TYPE;
lex->exchange = 0;
lex->proc_list.first=0;
select_lex->order_list.elements=select_lex->group_list.elements=0;
@@ -2447,16 +2655,33 @@ mysql_init_select(LEX *lex)
select_lex->next = (SELECT_LEX *)NULL;
}
-void
+bool
mysql_new_select(LEX *lex)
{
SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX));
+ if (!select_lex)
+ return 1;
lex->select->next=select_lex;
lex->select=select_lex;
select_lex->table_list.next= (byte**) &select_lex->table_list.first;
- select_lex->item_list.empty(); select_lex->when_list.empty();
- select_lex->expr_list.empty(); select_lex->interval_list.empty();
- select_lex->use_index.empty(); select_lex->ftfunc_list.empty();
+ select_lex->item_list.empty();
+ select_lex->when_list.empty();
+ select_lex->expr_list.empty();
+ select_lex->interval_list.empty();
+ select_lex->use_index.empty();
+ select_lex->ftfunc_list.empty();
+ return 0;
+}
+
+void mysql_init_multi_delete(LEX *lex)
+{
+ lex->sql_command = SQLCOM_DELETE_MULTI;
+ mysql_init_select(lex);
+ lex->select->select_limit=HA_POS_ERROR;
+ lex->auxilliary_table_list=lex->select_lex.table_list;
+ lex->select->table_list.elements=0;
+ lex->select->table_list.first=0;
+ lex->select->table_list.next= (byte**) &(lex->select->table_list.first);
}
void
@@ -2466,12 +2691,20 @@ mysql_parse(THD *thd,char *inBuf,uint length)
mysql_init_query(thd);
thd->query_length = length;
- LEX *lex=lex_start(thd, (uchar*) inBuf, length);
- if (!yyparse() && ! thd->fatal_error)
- mysql_execute_command();
- thd->proc_info="freeing items";
- free_items(thd); /* Free strings used by items */
- lex_end(lex);
+ if (query_cache.send_result_to_client(thd, inBuf, length) <= 0)
+ {
+ LEX *lex=lex_start(thd, (uchar*) inBuf, length);
+ if (!yyparse() && ! thd->fatal_error)
+ {
+ mysql_execute_command();
+ query_cache_end_of_result(&thd->net);
+ }
+ else
+ query_cache_abort(&thd->net);
+ thd->proc_info="freeing items";
+ free_items(thd); /* Free strings used by items */
+ lex_end(lex);
+ }
DBUG_VOID_RETURN;
}
@@ -2853,13 +3086,17 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
if (!alias) /* Alias is case sensitive */
if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
DBUG_RETURN(0);
- if (lower_case_table_names)
- casedn_str(table->table.str);
+
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(0); /* purecov: inspected */
ptr->db= table->db.str ? table->db.str : (thd->db ? thd->db : (char*) "");
- ptr->real_name=table->table.str;
ptr->name=alias_str;
+ if (lower_case_table_names)
+ {
+ casedn_str(ptr->db);
+ casedn_str(table->table.str);
+ }
+ ptr->real_name=table->table.str;
ptr->lock_type=flags;
ptr->updating=updating;
if (use_index)
@@ -2872,7 +3109,8 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
/* check that used name is unique */
if (flags != TL_IGNORE)
{
- for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ; tables ;
+ for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ;
+ tables ;
tables=tables->next)
{
if (!strcmp(alias_str,tables->name) && !strcmp(ptr->db, tables->db))
@@ -2904,7 +3142,7 @@ static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result)
SELECT_LEX *sl;
TABLE_LIST **new_table_list= result, *aux;
-
+
*new_table_list=0; // end result list
for (sl= &lex->select_lex; sl; sl=sl->next)
{
@@ -2968,8 +3206,7 @@ void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
/* Check if name is used in table list */
-static bool check_dup(THD *thd,const char *db,const char *name,
- TABLE_LIST *tables)
+static bool check_dup(const char *db, const char *name, TABLE_LIST *tables)
{
for (; tables ; tables=tables->next)
if (!strcmp(name,tables->real_name) && !strcmp(db,tables->db))
@@ -2977,7 +3214,7 @@ static bool check_dup(THD *thd,const char *db,const char *name,
return 0;
}
-bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
+bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
{
bool result=0;
@@ -2998,6 +3235,15 @@ bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
if (ha_flush_logs())
result=1;
}
+ if (options & REFRESH_QUERY_CACHE_FREE)
+ {
+ query_cache.pack(); // FLUSH QUERY CACHE
+ options &= ~REFRESH_QUERY_CACHE; //don't flush all cache, just free memory
+ }
+ if (options & (REFRESH_TABLES | REFRESH_QUERY_CACHE))
+ {
+ query_cache.flush(); // RESET QUERY CACHE
+ }
if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
{
if ((options & REFRESH_READ_LOCK) && thd)
@@ -3016,7 +3262,14 @@ bool reload_acl_and_cache(THD *thd, uint options, TABLE_LIST *tables)
if (options & REFRESH_MASTER)
if (reset_master(thd))
result=1;
- if (options & REFRESH_SLAVE)
+#ifdef OPENSSL
+ if (options & REFRESH_DES_KEY_FILE)
+ {
+ if (des_key_file)
+ result=load_des_key_file(des_key_file);
+ }
+#endif
+ if (options & REFRESH_SLAVE)
{
LOCK_ACTIVE_MI;
if (reset_slave(active_mi))
@@ -3073,7 +3326,7 @@ static void refresh_status(void)
/* If pointer is not a null pointer, append filename to it */
-static bool append_file_to_dir(char **filename_ptr, char *table_name)
+static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
{
char buff[FN_REFLEN],*ptr, *end;
if (!*filename_ptr)
@@ -3089,7 +3342,7 @@ static bool append_file_to_dir(char **filename_ptr, char *table_name)
/* Fix is using unix filename format on dos */
strmov(buff,*filename_ptr);
end=convert_dirname(buff, *filename_ptr, NullS);
- if (!(ptr=sql_alloc((uint) (end-buff)+strlen(table_name)+1)))
+ if (!(ptr=thd->alloc((uint) (end-buff)+(uint) strlen(table_name)+1)))
return 1; // End of memory
*filename_ptr=ptr;
strxmov(ptr,buff,table_name,NullS);
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 38d861d03d6..e4a277d1434 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -34,7 +34,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
bool error=1,got_all_locks=1;
TABLE_LIST *lock_table,*ren_table=0;
DBUG_ENTER("mysql_rename_tables");
-
+
/* Avoid problems with a rename on a table that we have locked or
if the user is trying to to do this in a transcation context */
@@ -43,7 +43,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
my_error(ER_LOCK_OR_ACTIVE_TRANSACTION,MYF(0));
DBUG_RETURN(1);
}
-
+
VOID(pthread_mutex_lock(&LOCK_open));
for (lock_table=table_list ; lock_table ; lock_table=lock_table->next)
{
@@ -53,13 +53,13 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
if (got_lock)
got_all_locks=0;
}
-
+
if (!got_all_locks && wait_for_locked_table_names(thd,table_list))
goto end;
if (!(ren_table=rename_tables(thd,table_list,0)))
error=0;
-
+
end:
if (ren_table)
{
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 660702d4117..31c349d199b 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -35,7 +35,7 @@ const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"MAYBE_REF","ALL","range","index","fulltext" };
static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
- DYNAMIC_ARRAY *keyuse);
+ DYNAMIC_ARRAY *keyuse);
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
JOIN_TAB *join_tab,
uint tables,COND *conds,table_map table_map);
@@ -47,7 +47,8 @@ static void find_best(JOIN *join,table_map rest_tables,uint index,
static uint cache_record_length(JOIN *join,uint index);
static double prev_record_reads(JOIN *join,table_map found_ref);
static bool get_best_combination(JOIN *join);
-static store_key *get_store_key(KEYUSE *keyuse, table_map used_tables,
+static store_key *get_store_key(THD *thd,
+ KEYUSE *keyuse, table_map used_tables,
KEY_PART_INFO *key_part, char *key_buff,
uint maybe_null);
static bool make_simple_join(JOIN *join,TABLE *tmp_table);
@@ -88,15 +89,18 @@ static int join_read_system(JOIN_TAB *tab);
static int join_read_const(JOIN_TAB *tab);
static int join_read_key(JOIN_TAB *tab);
static int join_read_always_key(JOIN_TAB *tab);
+static int join_read_last_key(JOIN_TAB *tab);
static int join_no_more_records(READ_RECORD *info);
static int join_read_next(READ_RECORD *info);
static int join_init_quick_read_record(JOIN_TAB *tab);
static int test_if_quick_select(JOIN_TAB *tab);
static int join_init_read_record(JOIN_TAB *tab);
-static int join_init_read_first_with_key(JOIN_TAB *tab);
-static int join_init_read_next_with_key(READ_RECORD *info);
-static int join_init_read_last_with_key(JOIN_TAB *tab);
-static int join_init_read_prev_with_key(READ_RECORD *info);
+static int join_read_first(JOIN_TAB *tab);
+static int join_read_next(READ_RECORD *info);
+static int join_read_next_same(READ_RECORD *info);
+static int join_read_last(JOIN_TAB *tab);
+static int join_read_prev_same(READ_RECORD *info);
+static int join_read_prev(READ_RECORD *info);
static int join_ft_read_first(JOIN_TAB *tab);
static int join_ft_read_next(READ_RECORD *info);
static COND *make_cond_for_table(COND *cond,table_map table,
@@ -179,7 +183,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
ulong select_options,select_result *result)
{
TABLE *tmp_table;
- int error,tmp;
+ int error, tmp_error, tmp;
bool need_tmp,hidden_group_fields;
bool simple_order,simple_group,no_order, skip_sort_order;
Item::cond_result cond_value;
@@ -479,7 +483,9 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
(thd->select_limit == HA_POS_ERROR ||
(join.select_options & OPTION_FOUND_ROWS) ||
order &&
- !(skip_sort_order=test_if_skip_sort_order(&join.join_tab[join.const_tables], order, thd->select_limit,1))))
+ !(skip_sort_order=
+ test_if_skip_sort_order(&join.join_tab[join.const_tables],
+ order, thd->select_limit,1))))
{
if ((group=create_distinct_group(order,fields)))
{
@@ -672,8 +678,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
/* Copy data to the temporary table */
thd->proc_info="Copying to tmp table";
- if (do_select(&join,(List<Item> *) 0,tmp_table,0))
+ if ((tmp_error=do_select(&join,(List<Item> *) 0,tmp_table,0)))
+ {
+ error=tmp_error;
goto err; /* purecov: inspected */
+ }
if (join.having)
join.having=having=0; // Allready done
@@ -746,9 +755,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
group=0;
}
thd->proc_info="Copying to group table";
+ tmp_error= -1;
if (make_sum_func_list(&join,all_fields) ||
- do_select(&join,(List<Item> *) 0,tmp_table2,0))
+ (tmp_error=do_select(&join,(List<Item> *) 0,tmp_table2,0)))
{
+ error=tmp_error;
free_tmp_table(thd,tmp_table2);
goto err; /* purecov: inspected */
}
@@ -795,7 +806,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
(procedure && (procedure->flags & PROC_GROUP)))
{
alloc_group_fields(&join,group);
- setup_copy_fields(&join.tmp_table_param,all_fields);
+ setup_copy_fields(thd, &join.tmp_table_param,all_fields);
if (make_sum_func_list(&join,all_fields) || thd->fatal_error)
goto err; /* purecov: inspected */
}
@@ -2152,7 +2163,8 @@ get_best_combination(JOIN *join)
if (!keyuse->used_tables &&
!(join->select_options & SELECT_DESCRIBE))
{ // Compare against constant
- store_key_item *tmp=new store_key_item(keyinfo->key_part[i].field,
+ store_key_item *tmp=new store_key_item(thd,
+ keyinfo->key_part[i].field,
(char*)key_buff +
maybe_null,
maybe_null ?
@@ -2166,7 +2178,8 @@ get_best_combination(JOIN *join)
tmp->copy();
}
else
- *ref_key++= get_store_key(keyuse,join->const_table_map,
+ *ref_key++= get_store_key(join->thd,
+ keyuse,join->const_table_map,
&keyinfo->key_part[i],
(char*) key_buff,maybe_null);
key_buff+=keyinfo->key_part[i].store_length;
@@ -2188,10 +2201,17 @@ get_best_combination(JOIN *join)
j->type=JT_REF; /* Must read with repeat */
else if (ref_key == j->ref.key_copy)
{ /* Should never be reached */
- j->type=JT_CONST; /* purecov: deadcode */
+ /*
+ This happen if we are using a constant expression in the ON part
+ of an LEFT JOIN.
+ SELECT * FROM a LEFT JOIN b ON b.key=30
+ Here we should not mark the table as a 'const' as a field may
+ have a 'normal' value or a NULL value.
+ */
+ j->type=JT_CONST;
if (join->const_tables == tablenr)
{
- join->const_tables++; /* purecov: deadcode */
+ join->const_tables++;
join->const_table_map|=form->map;
}
}
@@ -2208,25 +2228,28 @@ get_best_combination(JOIN *join)
static store_key *
-get_store_key(KEYUSE *keyuse, table_map used_tables, KEY_PART_INFO *key_part,
- char *key_buff, uint maybe_null)
+get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
+ KEY_PART_INFO *key_part, char *key_buff, uint maybe_null)
{
if (!((~used_tables) & keyuse->used_tables)) // if const item
{
- return new store_key_const_item(key_part->field,
+ return new store_key_const_item(thd,
+ key_part->field,
key_buff + maybe_null,
maybe_null ? key_buff : 0,
key_part->length,
keyuse->val);
}
else if (keyuse->val->type() == Item::FIELD_ITEM)
- return new store_key_field(key_part->field,
+ return new store_key_field(thd,
+ key_part->field,
key_buff + maybe_null,
maybe_null ? key_buff : 0,
key_part->length,
((Item_field*) keyuse->val)->field,
keyuse->val->full_name());
- return new store_key_item(key_part->field,
+ return new store_key_item(thd,
+ key_part->field,
key_buff + maybe_null,
maybe_null ? key_buff : 0,
key_part->length,
@@ -2495,7 +2518,7 @@ make_join_readinfo(JOIN *join,uint options)
tab->quick=0;
table->file->index_init(tab->ref.key);
tab->read_first_record= join_read_always_key;
- tab->read_record.read_record= join_read_next;
+ tab->read_record.read_record= join_read_next_same;
if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
!table->no_keyread)
{
@@ -2570,7 +2593,7 @@ make_join_readinfo(JOIN *join,uint options)
{ // Only read index tree
tab->index=find_shortest_key(table, table->used_keys);
tab->table->file->index_init(tab->index);
- tab->read_first_record= join_init_read_first_with_key;
+ tab->read_first_record= join_read_first;
tab->type=JT_NEXT; // Read with index_first / index_next
}
}
@@ -2771,8 +2794,8 @@ static void update_depend_map(JOIN *join, ORDER *order)
/*
-** simple_order is set to 1 if sort_order only uses fields from head table
-** and the head table is not a LEFT JOIN table
+ simple_order is set to 1 if sort_order only uses fields from head table
+ and the head table is not a LEFT JOIN table
*/
static ORDER *
@@ -3159,6 +3182,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
(thd->options & OPTION_AUTO_IS_NULL) &&
thd->insert_id())
{
+ query_cache_abort(&thd->net);
COND *new_cond;
if ((new_cond= new Item_func_eq(args[0],
new Item_int("last_insert_id()",
@@ -3271,7 +3295,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
** for send_fields
****************************************************************************/
-Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
+Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item_result_field ***copy_func, Field **from_field,
bool group, bool modify_item)
{
@@ -3313,7 +3337,7 @@ Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
item->name,table,item->binary);
}
}
- current_thd->fatal_error=1;
+ thd->fatal_error=1;
return 0; // Error
}
case Item::FIELD_ITEM:
@@ -3321,7 +3345,8 @@ Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
Field *org_field=((Item_field*) item)->field,*new_field;
*from_field=org_field;
- if ((new_field= org_field->new_field(table))) // Should always be true
+ // The following should always be true
+ if ((new_field= org_field->new_field(&thd->mem_root,table)))
{
if (modify_item)
((Item_field*) item)->result_field= new_field;
@@ -3422,7 +3447,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!param->quick_group)
group=0; // Can't use group key
else for (ORDER *tmp=group ; tmp ; tmp=tmp->next)
+ {
(*tmp->item)->marker=4; // Store null in key
+ if ((*tmp->item)->max_length >= MAX_CHAR_WIDTH)
+ using_unique_constraint=1;
+ }
if (param->group_length >= MAX_BLOB_WIDTH)
using_unique_constraint=1;
if (group)
@@ -3509,8 +3538,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!arg->const_item())
{
Field *new_field=
- create_tmp_field(table,arg,arg->type(),&copy_func,tmp_from_field,
- group != 0,not_all_columns);
+ create_tmp_field(thd, table,arg,arg->type(),&copy_func,
+ tmp_from_field, group != 0,not_all_columns);
if (!new_field)
goto err; // Should be OOM
tmp_from_field++;
@@ -3526,7 +3555,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
}
else
{
- Field *new_field=create_tmp_field(table,item,type,&copy_func,
+ Field *new_field=create_tmp_field(thd, table, item,type, &copy_func,
tmp_from_field, group != 0,
not_all_columns);
if (!new_field)
@@ -3624,6 +3653,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
{
if (field->flags & GROUP_FLAG && !using_unique_constraint)
{
+ /*
+ We have to reserve one byte here for NULL bits,
+ as this is updated by 'end_update()'
+ */
*pos++=0; // Null is stored here
recinfo->length=1;
recinfo->type=FIELD_NORMAL;
@@ -3707,19 +3740,21 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (!using_unique_constraint)
{
group->buff=(char*) group_buff;
- if (!(group->field=field->new_field(table)))
+ if (!(group->field=field->new_field(&thd->mem_root,table)))
goto err; /* purecov: inspected */
if (maybe_null)
{
/*
- To be able to group on NULL, we move the null bit to be
- just before the column and extend the key to cover the null bit
+ To be able to group on NULL, we reserve place in group_buff
+ for the NULL flag just before the column.
+ The field data is after this flag.
+ The NULL flag is updated by 'end_update()' and 'end_write()'
*/
- *group_buff= 0; // Init null byte
- key_part_info->offset--;
- key_part_info->length++;
- group->field->move_field((char*) group_buff+1, (uchar*) group_buff,
- 1);
+ keyinfo->flags|= HA_NULL_ARE_EQUAL; // def. that NULL == NULL
+ key_part_info->null_bit=field->null_bit;
+ key_part_info->null_offset= (uint) (field->null_ptr -
+ (uchar*) table->record[0]);
+ group->field->move_field((char*) ++group->buff);
}
else
group->field->move_field((char*) group_buff);
@@ -3821,7 +3856,6 @@ static bool open_tmp_table(TABLE *table)
return(1);
}
/* VOID(ha_lock(table,F_WRLCK)); */ /* Single thread table */
- (void) table->file->extra(HA_EXTRA_NO_READCHECK); /* Not needed */
(void) table->file->extra(HA_EXTRA_QUICK); /* Faster */
return(0);
}
@@ -3875,10 +3909,10 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
for (uint i=0; i < keyinfo->key_parts ; i++,seg++)
{
Field *field=keyinfo->key_part[i].field;
- seg->flag=0;
- seg->language=MY_CHARSET_CURRENT;
- seg->length=keyinfo->key_part[i].length;
- seg->start=keyinfo->key_part[i].offset;
+ seg->flag= 0;
+ seg->language= MY_CHARSET_CURRENT;
+ seg->length= keyinfo->key_part[i].length;
+ seg->start= keyinfo->key_part[i].offset;
if (field->flags & BLOB_FLAG)
{
seg->type=
@@ -3899,11 +3933,17 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
keyinfo->key_part[i].length > 4)
seg->flag|=HA_SPACE_PACK;
}
- if (using_unique_constraint &&
- !(field->flags & NOT_NULL_FLAG))
+ if (!(field->flags & NOT_NULL_FLAG))
{
seg->null_bit= field->null_bit;
seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]);
+ /*
+ We are using a GROUP BY on something that contains NULL
+ In this case we have to tell MyISAM that two NULL should
+ on INSERT be compared as equal
+ */
+ if (!using_unique_constraint)
+ keydef.flag|= HA_NULL_ARE_EQUAL;
}
}
}
@@ -4041,9 +4081,12 @@ bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error,
}
-/*****************************************************************************
-** Make a join of all tables and write it on socket or to table
-*****************************************************************************/
+/****************************************************************************
+ Make a join of all tables and write it on socket or to table
+ Return: 0 if ok
+ 1 if error is sent
+ -1 if error should be sent
+****************************************************************************/
static int
do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
@@ -4120,15 +4163,21 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
if (error == -3)
error=0; /* select_limit used */
}
+
+ /* Return 1 if error is sent; -1 if error should be sent */
if (error < 0)
- join->result->send_error(0,NullS); /* purecov: inspected */
+ {
+ join->result->send_error(0,NullS); /* purecov: inspected */
+ error=1; // Error sent
+ }
else
{
- if (!table) // If sending data to client
+ error=0;
+ if (!table) // If sending data to client
{
join_free(join); // Unlock all cursors
if (join->result->send_eof())
- error= -1;
+ error= 1; // Don't send error
}
DBUG_PRINT("info",("%ld records output",join->send_records));
}
@@ -4145,10 +4194,10 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
my_errno=tmp;
error= -1;
}
- if (error != old_error)
+ if (error == -1)
table->file->print_error(my_errno,MYF(0));
}
- DBUG_RETURN(error < 0);
+ DBUG_RETURN(error);
}
@@ -4416,8 +4465,11 @@ join_read_const(JOIN_TAB *tab)
}
store_record(table,1);
}
- else if (!table->status) // Only happens with left join
+ else if (!(table->status & ~STATUS_NULL_ROW)) // Only happens with left join
+ {
+ table->status=0;
restore_record(table,1); // restore old record
+ }
table->null_row=0;
return table->status ? -1 : 0;
}
@@ -4477,6 +4529,35 @@ join_read_always_key(JOIN_TAB *tab)
return 0;
}
+/*
+ This function is used when optimizing away ORDER BY in
+ SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC
+*/
+
+static int
+join_read_last_key(JOIN_TAB *tab)
+{
+ int error;
+ TABLE *table= tab->table;
+
+ if (cp_buffer_from_ref(&tab->ref))
+ return -1;
+ if ((error=table->file->index_read_last(table->record[0],
+ tab->ref.key_buff,
+ tab->ref.key_length)))
+ {
+ if (error != HA_ERR_KEY_NOT_FOUND)
+ {
+ sql_print_error("read_const: Got error %d when reading table %s",error,
+ table->path);
+ table->file->print_error(error,MYF(0));
+ return 1;
+ }
+ return -1; /* purecov: inspected */
+ }
+ return 0;
+}
+
/* ARGSUSED */
static int
@@ -4487,7 +4568,7 @@ join_no_more_records(READ_RECORD *info __attribute__((unused)))
static int
-join_read_next(READ_RECORD *info)
+join_read_next_same(READ_RECORD *info)
{
int error;
TABLE *table= info->table;
@@ -4510,6 +4591,37 @@ join_read_next(READ_RECORD *info)
return 0;
}
+static int
+join_read_prev_same(READ_RECORD *info)
+{
+ int error;
+ TABLE *table= info->table;
+ JOIN_TAB *tab=table->reginfo.join_tab;
+
+ if ((error=table->file->index_prev(table->record[0])))
+ {
+ if (error != HA_ERR_END_OF_FILE)
+ {
+ sql_print_error("read_next: Got error %d when reading table %s",error,
+ table->path);
+ table->file->print_error(error,MYF(0));
+ error= 1;
+ }
+ else
+ {
+ table->status= STATUS_GARBAGE;
+ error= -1;
+ }
+ }
+ else if (key_cmp(table, tab->ref.key_buff, tab->ref.key,
+ tab->ref.key_length))
+ {
+ table->status=STATUS_NOT_FOUND;
+ error= 1;
+ }
+ return error;
+}
+
static int
join_init_quick_read_record(JOIN_TAB *tab)
@@ -4540,7 +4652,7 @@ join_init_read_record(JOIN_TAB *tab)
}
static int
-join_init_read_first_with_key(JOIN_TAB *tab)
+join_read_first(JOIN_TAB *tab)
{
int error;
TABLE *table=tab->table;
@@ -4551,7 +4663,7 @@ join_init_read_first_with_key(JOIN_TAB *tab)
table->file->extra(HA_EXTRA_KEYREAD);
}
tab->table->status=0;
- tab->read_record.read_record=join_init_read_next_with_key;
+ tab->read_record.read_record=join_read_next;
tab->read_record.table=table;
tab->read_record.file=table->file;
tab->read_record.index=tab->index;
@@ -4571,8 +4683,9 @@ join_init_read_first_with_key(JOIN_TAB *tab)
return 0;
}
+
static int
-join_init_read_next_with_key(READ_RECORD *info)
+join_read_next(READ_RECORD *info)
{
int error=info->file->index_next(info->record);
if (error)
@@ -4589,9 +4702,8 @@ join_init_read_next_with_key(READ_RECORD *info)
return 0;
}
-
static int
-join_init_read_last_with_key(JOIN_TAB *tab)
+join_read_last(JOIN_TAB *tab)
{
TABLE *table=tab->table;
int error;
@@ -4601,7 +4713,7 @@ join_init_read_last_with_key(JOIN_TAB *tab)
table->file->extra(HA_EXTRA_KEYREAD);
}
tab->table->status=0;
- tab->read_record.read_record=join_init_read_prev_with_key;
+ tab->read_record.read_record=join_read_prev;
tab->read_record.table=table;
tab->read_record.file=table->file;
tab->read_record.index=tab->index;
@@ -4621,8 +4733,9 @@ join_init_read_last_with_key(JOIN_TAB *tab)
return 0;
}
+
static int
-join_init_read_prev_with_key(READ_RECORD *info)
+join_read_prev(READ_RECORD *info)
{
int error=info->file->index_prev(info->record);
if (error)
@@ -4639,6 +4752,7 @@ join_init_read_prev_with_key(READ_RECORD *info)
return 0;
}
+
static int
join_ft_read_first(JOIN_TAB *tab)
{
@@ -4713,9 +4827,19 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
if (join->select_options & OPTION_FOUND_ROWS)
{
- join->do_send_rows=0;
- join->thd->select_limit = HA_POS_ERROR;
- DBUG_RETURN(0);
+ JOIN_TAB *jt=join->join_tab;
+ if ((join->tables == 1) && !join->tmp_table && !join->sort_and_group
+ && !join->send_group_parts && !join->having && !jt->select_cond)
+ {
+ join->select_options ^= OPTION_FOUND_ROWS;
+ join->send_records = jt->records;
+ }
+ else
+ {
+ join->do_send_rows=0;
+ join->thd->select_limit = HA_POS_ERROR;
+ DBUG_RETURN(0);
+ }
}
DBUG_RETURN(-3); // Abort nicely
}
@@ -4827,6 +4951,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
copy_fields(&join->tmp_table_param);
copy_funcs(join->tmp_table_param.funcs);
+#ifdef TO_BE_DELETED
if (!table->uniques) // If not unique handling
{
/* Copy null values from group to row */
@@ -4837,10 +4962,11 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (item->maybe_null)
{
Field *field=item->tmp_table_field();
- field->ptr[-1]= (byte) (field->is_null() ? 0 : 1);
+ field->ptr[-1]= (byte) (field->is_null() ? 1 : 0);
}
}
}
+#endif
if (!join->having || join->having->val_int())
{
join->found_records++;
@@ -4895,8 +5021,9 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
Item *item= *group->item;
item->save_org_in_field(group->field);
+ /* Store in the used key if the field was 0 */
if (item->maybe_null)
- group->buff[0]=item->null_value ? 0: 1; // Save reversed value
+ group->buff[-1]=item->null_value ? 1 : 0;
}
// table->file->index_init(0);
if (!table->file->index_read(table->record[1],
@@ -5254,13 +5381,6 @@ static uint find_shortest_key(TABLE *table, key_map usable_keys)
}
-/*****************************************************************************
-** If not selecting by given key, create a index how records should be read
-** return: 0 ok
-** -1 some fatal error
-** 1 no records
-*****************************************************************************/
-
/* Return 1 if we don't have to do file sorting */
static bool
@@ -5293,6 +5413,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
if (ref_key >= 0)
{
+ /*
+ We come here when there is a REF key.
+ */
int order_direction;
uint used_key_parts;
/* Check if we get the rows in requested sorted order by using the key */
@@ -5300,11 +5423,11 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
(order_direction = test_if_order_by_key(order,table,ref_key,
&used_key_parts)))
{
- if (order_direction == -1)
+ if (order_direction == -1) // If ORDER BY ... DESC
{
if (select && select->quick)
{
- // ORDER BY ref_key DESC
+ // ORDER BY range_key DESC
QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC(select->quick,
used_key_parts);
if (!tmp || tmp->error)
@@ -5319,11 +5442,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
{
/*
SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC
- TODO:
- Add a new traversal function to read last matching row and
- traverse backwards.
+
+ Use a traversal function that starts by reading the last row
+ with key part (A) and then traverse the index backwards.
*/
- DBUG_RETURN(0);
+ if (table->file->option_flag() & HA_NOT_READ_PREFIX_LAST)
+ DBUG_RETURN(1);
+ tab->read_first_record= join_read_last_key;
+ tab->read_record.read_record= join_read_prev_same;
+ /* fall through */
}
}
DBUG_RETURN(1); /* No need to sort */
@@ -5355,10 +5482,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
if (!no_changes)
{
tab->index=nr;
- tab->read_first_record= (flag > 0 ? join_init_read_first_with_key:
- join_init_read_last_with_key);
+ tab->read_first_record= (flag > 0 ? join_read_first:
+ join_read_last);
table->file->index_init(nr);
tab->type=JT_NEXT; // Read with index_first(), index_next()
+ if (table->used_keys & ((key_map) 1 << nr))
+ {
+ table->key_read=1;
+ table->file->extra(HA_EXTRA_KEYREAD);
+ }
}
DBUG_RETURN(1);
}
@@ -5368,6 +5500,14 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
DBUG_RETURN(0); // Can't use index.
}
+
+/*****************************************************************************
+ If not selecting by given key, create an index how records should be read
+ return: 0 ok
+ -1 some fatal error
+ 1 no records
+*****************************************************************************/
+
static int
create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit)
{
@@ -5514,7 +5654,6 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having)
DBUG_ENTER("remove_duplicates");
entry->reginfo.lock_type=TL_WRITE;
- entry->file->extra(HA_EXTRA_NO_READCHECK);
/* Calculate how many saved fields there is in list */
field_count=0;
@@ -6334,7 +6473,8 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
static void
calc_group_buffer(JOIN *join,ORDER *group)
{
- uint key_length=0,parts=0;
+ uint key_length=0, parts=0, null_parts=0;
+
if (group)
join->group= 1;
for (; group ; group=group->next)
@@ -6355,10 +6495,11 @@ calc_group_buffer(JOIN *join,ORDER *group)
key_length+=(*group->item)->max_length;
parts++;
if ((*group->item)->maybe_null)
- key_length++;
+ null_parts++;
}
- join->tmp_table_param.group_length=key_length;
+ join->tmp_table_param.group_length=key_length+null_parts;
join->tmp_table_param.group_parts=parts;
+ join->tmp_table_param.group_null_parts=null_parts;
}
@@ -6409,7 +6550,7 @@ test_if_group_changed(List<Item_buff> &list)
*/
bool
-setup_copy_fields(TMP_TABLE_PARAM *param,List<Item> &fields)
+setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields)
{
Item *pos;
List_iterator<Item> li(fields);
@@ -6437,7 +6578,7 @@ setup_copy_fields(TMP_TABLE_PARAM *param,List<Item> &fields)
/* set up save buffer and change result_field to point at saved value */
Field *field= item->field;
- item->result_field=field->new_field(field->table);
+ item->result_field=field->new_field(&thd->mem_root,field->table);
char *tmp=(char*) sql_alloc(field->pack_length()+1);
if (!tmp)
goto err;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 4fcffae31d2..9eb287c8845 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -127,12 +127,13 @@ class TMP_TABLE_PARAM {
ha_rows end_write_records;
uint field_count,sum_func_count,func_count;
uint hidden_field_count;
- uint group_parts,group_length;
+ uint group_parts,group_length,group_null_parts;
uint quick_group;
bool using_indirect_summary_function;
TMP_TABLE_PARAM()
- :copy_funcs_it(copy_funcs), copy_field(0), group_parts(0), group_length(0)
+ :copy_funcs_it(copy_funcs), copy_field(0), group_parts(0),
+ group_length(0), group_null_parts(0)
{}
~TMP_TABLE_PARAM()
{
@@ -190,7 +191,7 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
void free_tmp_table(THD *thd, TABLE *entry);
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
bool reset_with_sum_func);
-bool setup_copy_fields(TMP_TABLE_PARAM *param,List<Item> &fields);
+bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,List<Item> &fields);
void copy_fields(TMP_TABLE_PARAM *param);
void copy_funcs(Item_result_field **func_ptr);
bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error,
@@ -210,7 +211,7 @@ class store_key :public Sql_alloc
char *null_ptr;
char err;
public:
- store_key(Field *field_arg, char *ptr, char *null, uint length)
+ store_key(THD *thd, Field *field_arg, char *ptr, char *null, uint length)
:null_ptr(null),err(0)
{
if (field_arg->type() == FIELD_TYPE_BLOB)
@@ -219,7 +220,7 @@ class store_key :public Sql_alloc
field_arg->table, field_arg->binary());
else
{
- to_field=field_arg->new_field(field_arg->table);
+ to_field=field_arg->new_field(&thd->mem_root,field_arg->table);
if (to_field)
to_field->move_field(ptr, (uchar*) null, 1);
}
@@ -235,9 +236,9 @@ class store_key_field: public store_key
Copy_field copy_field;
const char *field_name;
public:
- store_key_field(Field *to_field_arg, char *ptr, char *null_ptr_arg,
+ store_key_field(THD *thd, Field *to_field_arg, char *ptr, char *null_ptr_arg,
uint length, Field *from_field, const char *name_arg)
- :store_key(to_field_arg,ptr,
+ :store_key(thd, to_field_arg,ptr,
null_ptr_arg ? null_ptr_arg : from_field->maybe_null() ? &err
: NullS,length), field_name(name_arg)
{
@@ -260,9 +261,9 @@ class store_key_item :public store_key
protected:
Item *item;
public:
- store_key_item(Field *to_field_arg, char *ptr, char *null_ptr_arg,
+ store_key_item(THD *thd, Field *to_field_arg, char *ptr, char *null_ptr_arg,
uint length, Item *item_arg)
- :store_key(to_field_arg,ptr,
+ :store_key(thd, to_field_arg,ptr,
null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
&err : NullS, length), item(item_arg)
{}
@@ -279,10 +280,10 @@ class store_key_const_item :public store_key_item
{
bool inited;
public:
- store_key_const_item(Field *to_field_arg, char *ptr,
+ store_key_const_item(THD *thd, Field *to_field_arg, char *ptr,
char *null_ptr_arg, uint length,
Item *item_arg)
- :store_key_item(to_field_arg,ptr,
+ :store_key_item(thd, to_field_arg,ptr,
null_ptr_arg ? null_ptr_arg : item_arg->maybe_null ?
&err : NullS, length, item_arg), inited(0)
{
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 1dac8033ad7..8629930cf5c 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -652,6 +652,8 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("Packed",10));
item->maybe_null=1;
+ field_list.push_back(new Item_empty_string("Null",3));
+ field_list.push_back(new Item_empty_string("Index_type",16));
field_list.push_back(new Item_empty_string("Comment",255));
item->maybe_null=1;
@@ -691,6 +693,8 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
}
else
net_store_null(packet);
+
+ /* Check if we have a key part that only uses part of the field */
if (!key_part->field ||
key_part->length !=
table->field[key_part->fieldnr-1]->key_length())
@@ -701,8 +705,14 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
else
net_store_null(packet);
net_store_null(packet); // No pack_information yet
- net_store_data(packet,convert,
- key_info->flags & HA_FULLTEXT ? "FULLTEXT":"");
+
+ /* Null flag */
+ uint flags= key_part->field ? key_part->field->flags : 0;
+ char *pos=(byte*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
+ net_store_data(packet,convert,(const char*) pos);
+ net_store_data(packet,convert,table->file->index_type(i));
+ /* Comment */
+ net_store_data(packet,convert,"");
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_RETURN(1); /* purecov: inspected */
}
@@ -1054,9 +1064,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
thd_info->query=0;
if (tmp->query)
{
- uint length=(uint) strlen(tmp->query);
- if (length > max_query_length)
- length=max_query_length;
+ /* query_length is always set before tmp->query */
+ uint length= min(max_query_length, tmp->query_length);
thd_info->query=(char*) thd->memdup(tmp->query,length+1);
thd_info->query[length]=0;
}
@@ -1190,65 +1199,85 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
/* First group - functions relying on CTX */
case SHOW_SSL_CTX_SESS_ACCEPT:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_accept(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_accept(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_accept_good(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_accept_good(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_connect_good(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_connect_good(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_SESS_CB_HITS:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_cb_hits(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_cb_hits(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_SESS_HITS:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_hits(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_hits(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_SESS_CACHE_FULL:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_cache_full(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_cache_full(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_SESS_MISSES:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_misses(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_misses(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_SESS_TIMEOUTS:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_SESS_NUMBER:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_SESS_CONNECT:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
net_store_data(&packet2,(uint32)
- SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_GET_VERIFY_MODE:
net_store_data(&packet2,(uint32)
- SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
net_store_data(&packet2,(uint32)
- SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_));
+ (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)));
break;
case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
+ if (!ssl_acceptor_fd)
+ {
+ net_store_data(&packet2,"NONE" );
+ break;
+ }
switch(SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context_))
{
case SSL_SESS_CACHE_OFF:
@@ -1296,23 +1325,28 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
SSL_get_verify_depth(thd->net.vio->ssl_):0));
break;
case SHOW_SSL_GET_CIPHER:
- net_store_data(&packet2, thd->net.vio->ssl_ ? SSL_get_cipher(thd->net.vio->ssl_) : "");
+ net_store_data(&packet2, thd->net.vio->ssl_ ?
+ SSL_get_cipher(thd->net.vio->ssl_) : "");
+ break;
case SHOW_SSL_GET_CIPHER_LIST:
- if(thd->net.vio->ssl_)
+ if (thd->net.vio->ssl_)
{
- char buf[1024]="";
- for (int i=0; ; i++)
+ char buf[1024], *pos;
+ pos=buf;
+ for (int i=0 ; i++ ;)
{
const char *p=SSL_get_cipher_list(thd->net.vio->ssl_,i);
if (p == NULL)
break;
- if (i != 0)
- strcat(buf,":");
- strcat(buf,p);
- DBUG_PRINT("info",("cipher to add: %s,%s",p,buf));
+ pos=strmov(pos, p);
+ *pos++= ':';
}
+ if (pos != buf)
+ pos--; // Remove last ':'
+ *pos=0;
net_store_data(&packet2, buf);
- } else
+ }
+ else
net_store_data(&packet2, "");
break;
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 4649af918d5..8fe84947ac2 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This program file is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
+/* 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
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA */
+ 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 */
/* This file is originally from the mysql distribution. Coded by monty */
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 00a078640b3..ad7455ecbf1 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -1,19 +1,18 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
+/* 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
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA */
+ 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 */
/* This file is originally from the mysql distribution. Coded by monty */
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 049fb1c182c..14daf8c1924 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -26,6 +26,7 @@
#endif
extern HASH open_cache;
+static const char *primary_key_name="PRIMARY";
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
@@ -158,16 +159,20 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
wrong_tables.append(String(table->real_name));
}
}
- if (some_tables_deleted && !dont_log_query)
+ if (some_tables_deleted)
{
- mysql_update_log.write(thd, thd->query,thd->query_length);
- if (mysql_bin_log.is_open())
+ query_cache.invalidate(tables);
+ if (!dont_log_query)
{
- Query_log_event qinfo(thd, thd->query);
- mysql_bin_log.write(&qinfo);
+ mysql_update_log.write(thd, thd->query,thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
}
}
-
+
error = 0;
if (wrong_tables.length())
{
@@ -192,6 +197,52 @@ int quick_rm_table(enum db_type base,const char *db,
return ha_delete_table(base,path) || error;
}
+/*
+ Sort keys in the following order:
+ - PRIMARY KEY
+ - UNIQUE keyws where all column are NOT NULL
+ - Other UNIQUE keys
+ - Normal keys
+ - Fulltext keys
+
+ This will make checking for duplicated keys faster and ensure that
+ PRIMARY keys are prioritized.
+*/
+
+
+static int sort_keys(KEY *a, KEY *b)
+{
+ if (a->flags & HA_NOSAME)
+ {
+ if (!(b->flags & HA_NOSAME))
+ return -1;
+ if ((a->flags ^ b->flags) & HA_NULL_PART_KEY)
+ {
+ /* Sort NOT NULL keys before other keys */
+ return (a->flags & HA_NULL_PART_KEY) ? 1 : -1;
+ }
+ if (a->name == primary_key_name)
+ return -1;
+ if (b->name == primary_key_name)
+ return 1;
+ }
+ else if (b->flags & HA_NOSAME)
+ return 1; // Prefer b
+
+ if ((a->flags ^ b->flags) & HA_FULLTEXT)
+ {
+ return (a->flags & HA_FULLTEXT) ? 1 : -1;
+ }
+ /*
+ Prefer original key order. usable_key_parts contains here
+ the original key position.
+ */
+ return ((a->usable_key_parts < b->usable_key_parts) ? -1 :
+ (a->usable_key_parts > b->usable_key_parts) ? 1 :
+ 0);
+}
+
+
/*****************************************************************************
* Create a table.
* If one creates a temporary table, this is automaticly opened
@@ -347,10 +398,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
List_iterator<Key> key_iterator(keys);
uint key_parts=0,key_count=keys.elements;
List<Key> keys_in_order; // Add new keys here
- Key *primary_key=0;
- bool unique_key=0;
+ bool primary_key=0,unique_key=0;
Key *key;
- uint tmp;
+ uint tmp, key_number;
tmp=min(file->max_keys(), MAX_KEY);
if (key_count > tmp)
{
@@ -358,12 +408,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
- /*
- Check keys;
- Put PRIMARY KEY first, then UNIQUE keys and other keys last
- This will make checking for duplicated keys faster and ensure that
- primary keys are prioritized.
- */
+ /* Calculate number of key segements */
while ((key=key_iterator++))
{
@@ -379,33 +424,6 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
key_parts+=key->columns.elements;
- if (key->type == Key::PRIMARY)
- {
- if (primary_key)
- {
- my_error(ER_MULTIPLE_PRI_KEY,MYF(0));
- DBUG_RETURN(-1);
- }
- primary_key=key;
- }
- else if (key->type == Key::UNIQUE)
- {
- unique_key=1;
- if (keys_in_order.push_front(key))
- DBUG_RETURN(-1);
- }
- else if (keys_in_order.push_back(key))
- DBUG_RETURN(-1);
- }
- if (primary_key)
- {
- if (keys_in_order.push_front(primary_key))
- DBUG_RETURN(-1);
- }
- else if (!unique_key && (file->option_flag() & HA_REQUIRE_PRIMARY_KEY))
- {
- my_error(ER_REQUIRES_PRIMARY_KEY,MYF(0));
- DBUG_RETURN(-1);
}
key_info_buffer=key_info=(KEY*) sql_calloc(sizeof(KEY)*key_count);
@@ -413,8 +431,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if (!key_info_buffer || ! key_part_info)
DBUG_RETURN(-1); // Out of memory
- List_iterator<Key> key_iterator_in_order(keys_in_order);
- for (; (key=key_iterator_in_order++) ; key_info++)
+ key_iterator.rewind();
+ key_number=0;
+ for (; (key=key_iterator++) ; key_info++, key_number++)
{
uint key_length=0;
key_part_spec *column;
@@ -423,10 +442,11 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
(key->type == Key::FULLTEXT) ? HA_FULLTEXT : HA_NOSAME;
key_info->key_parts=(uint8) key->columns.elements;
key_info->key_part=key_part_info;
+ key_info->usable_key_parts= key_number;
if (key->type == Key::FULLTEXT)
{
- if (file->option_flag() & HA_NO_FULLTEXT_KEY)
+ if (!(file->option_flag() & HA_CAN_FULLTEXT))
{
my_error(ER_TABLE_CANT_HANDLE_FULLTEXT, MYF(0));
DBUG_RETURN(-1);
@@ -482,6 +502,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
MYF(0),column->field_name);
DBUG_RETURN(-1);
}
+ key_info->flags|= HA_NULL_PART_KEY;
}
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
{
@@ -541,7 +562,15 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if (column_nr == 0)
{
if (key->type == Key::PRIMARY)
- key_name="PRIMARY";
+ {
+ if (primary_key)
+ {
+ my_error(ER_MULTIPLE_PRI_KEY,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ key_name=primary_key_name;
+ primary_key=1;
+ }
else if (!(key_name = key->name()))
key_name=make_unique_key_name(sql_field->field_name,
key_info_buffer,key_info);
@@ -553,18 +582,29 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
key_info->name=(char*) key_name;
}
}
+ if (!(key_info->flags & HA_NULL_PART_KEY))
+ unique_key=1;
key_info->key_length=(uint16) key_length;
- if (key_length > file->max_key_length() && key->type != Key::FULLTEXT)
+ uint max_key_length= max(file->max_key_length(), MAX_KEY_LENGTH);
+ if (key_length > max_key_length && key->type != Key::FULLTEXT)
{
- my_error(ER_TOO_LONG_KEY,MYF(0),file->max_key_length());
+ my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
DBUG_RETURN(-1);
}
}
+ if (!unique_key && !primary_key &&
+ (file->option_flag() & HA_REQUIRE_PRIMARY_KEY))
+ {
+ my_error(ER_REQUIRES_PRIMARY_KEY,MYF(0));
+ DBUG_RETURN(-1);
+ }
if (auto_increment > 0)
{
my_error(ER_WRONG_AUTO_KEY,MYF(0));
DBUG_RETURN(-1);
}
+ /* Sort keys in optimized order */
+ qsort((gptr) key_info_buffer, key_count, sizeof(KEY), (qsort_cmp) sort_keys);
/* Check if table exists */
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
@@ -699,8 +739,11 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
my_error(ER_WRONG_COLUMN_NAME,MYF(0),item->name);
DBUG_RETURN(0);
}
-
- Field *field=create_tmp_field(&tmp_table,item,item->type(),
+ Field *field;
+ if (item->type() == Item::FUNC_ITEM)
+ field=item->tmp_table_field(&tmp_table);
+ else
+ field=create_tmp_field(thd, &tmp_table, item, item->type(),
(Item_result_field***) 0, &tmp_field,0,0);
if (!field ||
!(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ?
@@ -947,6 +990,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
sprintf(buff, ER(ER_OPEN_AS_READONLY), table_name);
net_store_data(packet, buff);
close_thread_tables(thd);
+ table->table=0; // For query cache
if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
packet->length()))
goto err;
@@ -1024,6 +1068,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
remove_table_from_cache(thd, table->table->table_cache_key,
table->table->real_name);
close_thread_tables(thd);
+ table->table=0; // For query cache
if (my_net_write(&thd->net, (char*) packet->ptr(),
packet->length()))
goto err;
@@ -1033,9 +1078,12 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
DBUG_RETURN(0);
err:
close_thread_tables(thd); // Shouldn't be needed
+ if (table)
+ table->table=0;
DBUG_RETURN(-1);
}
+
int mysql_backup_table(THD* thd, TABLE_LIST* table_list)
{
DBUG_ENTER("mysql_backup_table");
@@ -1654,24 +1702,30 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
if (error)
{
- // This shouldn't happen. We solve this the safe way by
- // closing the locked table.
+ /*
+ This shouldn't happen. We solve this the safe way by
+ closing the locked table.
+ */
close_cached_table(thd,table);
VOID(pthread_mutex_unlock(&LOCK_open));
goto err;
}
if (thd->lock || new_name != table_name) // True if WIN32
{
- // Not table locking or alter table with rename
- // free locks and remove old table
+ /*
+ Not table locking or alter table with rename
+ free locks and remove old table
+ */
close_cached_table(thd,table);
VOID(quick_rm_table(old_db_type,db,old_name));
}
else
{
- // Using LOCK TABLES without rename.
- // This code is never executed on WIN32!
- // Remove old renamed table, reopen table and get new locks
+ /*
+ Using LOCK TABLES without rename.
+ This code is never executed on WIN32!
+ Remove old renamed table, reopen table and get new locks
+ */
if (table)
{
VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Use new file
@@ -1708,6 +1762,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
VOID(pthread_cond_broadcast(&COND_refresh));
VOID(pthread_mutex_unlock(&LOCK_open));
+ table_list->table=0; // For query cache
+ query_cache.invalidate(table_list);
end_temporary:
sprintf(tmp_name,ER(ER_INSERT_INFO),(ulong) (copied+deleted),
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 651fd52d6c3..43c24da85a2 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 8184ae3b15e..9493f969802 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -1,21 +1,19 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
+/* 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 */
-
-
/* This implements 'user defined functions' */
/*
@@ -52,11 +50,11 @@ extern "C"
{
FreeLibrary((HMODULE)lib);
}
-
+
#elif !defined(OS2)
#include <dlfcn.h>
#endif
-
+
#include <stdarg.h>
#include <hash.h>
}
@@ -141,7 +139,8 @@ void udf_init()
new_thd->version = refresh_version; //current_thd->version;
new_thd->current_tablenr = 0;
new_thd->open_tables = 0;
- new_thd->db = my_strdup("mysql", MYF(0));
+ new_thd->db= my_strdup("mysql", MYF(0));
+ new_thd->db_length=5;
bzero((gptr) &tables,sizeof(tables));
tables.name = tables.real_name = (char*) "func";
diff --git a/sql/sql_udf.h b/sql/sql_udf.h
index d0b20f0a734..1ee9c44ce48 100644
--- a/sql/sql_udf.h
+++ b/sql/sql_udf.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index b2ffb97fa81..0d8a41e9966 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -27,7 +27,7 @@
int mysql_union(THD *thd, LEX *lex,select_result *result)
{
- SELECT_LEX *sl, *last_sl=(SELECT_LEX *)NULL, lex_sl;
+ SELECT_LEX *sl, *last_sl, *lex_sl;
ORDER *order;
List<Item> item_list;
TABLE *table;
@@ -38,7 +38,10 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
DBUG_ENTER("mysql_union");
/* Fix tables 'to-be-unioned-from' list to point at opened tables */
- for (sl=&lex->select_lex; sl && sl->linkage != NOT_A_SELECT; last_sl=sl, sl=sl->next)
+ last_sl= &lex->select_lex;
+ for (sl= last_sl;
+ sl && sl->linkage != NOT_A_SELECT;
+ last_sl=sl, sl=sl->next)
{
for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first;
cursor;
@@ -46,19 +49,27 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
cursor->table= ((TABLE_LIST*) cursor->table)->table;
}
+ /* last_sel now points at the last select where the ORDER BY is stored */
if (sl)
{
- lex_sl=*sl;
- sl=(SELECT_LEX *)NULL;
- if (last_sl) last_sl->next=sl;
+ /*
+ The found SL is an extra SELECT_LEX argument that contains
+ the ORDER BY and LIMIT parameter for the whole UNION
+ */
+ lex_sl= sl;
+ last_sl->next=0; // Remove this extra element
+ order= (ORDER *) lex_sl->order_list.first;
+ }
+ else if (!last_sl->braces)
+ {
+ lex_sl= last_sl; // ORDER BY is here
+ order= (ORDER *) lex_sl->order_list.first;
}
else
- lex_sl.linkage=UNSPECIFIED_TYPE;
-
- /* Find last select part as it's here ORDER BY and GROUP BY is stored */
- for (last_sl= &lex->select_lex;
- last_sl->next;
- last_sl=last_sl->next) ;
+ {
+ lex_sl=0;
+ order=0;
+ }
if (lex->select_lex.options & SELECT_DESCRIBE)
{
@@ -68,7 +79,8 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
res=mysql_select(thd, (TABLE_LIST*) sl->table_list.first,
sl->item_list,
sl->where,
- (sl->braces) ? (ORDER *) sl->order_list.first : (ORDER *) 0,
+ ((sl->braces) ?
+ (ORDER *) sl->order_list.first : (ORDER *) 0),
(ORDER*) sl->group_list.first,
sl->having,
(ORDER*) NULL,
@@ -79,8 +91,6 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
DBUG_RETURN(0);
}
- order = (lex_sl.linkage == UNSPECIFIED_TYPE) ? ( (last_sl->braces) ? (ORDER *) 0 : (ORDER *) last_sl->order_list.first) : (ORDER *) lex_sl.order_list.first;
-
{
Item *item;
List_iterator<Item> it(lex->select_lex.item_list);
@@ -162,11 +172,11 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
}
if (!thd->fatal_error) // Check if EOM
{
- if (lex_sl.linkage == NOT_A_SELECT && ( lex_sl.select_limit || lex_sl.offset_limit))
+ if (lex_sl)
{
- thd->offset_limit=lex_sl.offset_limit;
- thd->select_limit=lex_sl.select_limit+lex_sl.offset_limit;
- if (thd->select_limit < lex_sl.select_limit)
+ thd->offset_limit=lex_sl->offset_limit;
+ thd->select_limit=lex_sl->select_limit+lex_sl->offset_limit;
+ if (thd->select_limit < lex_sl->select_limit)
thd->select_limit= HA_POS_ERROR; // no limit
if (thd->select_limit == HA_POS_ERROR)
thd->options&= ~OPTION_FOUND_ROWS;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 0422d9664b6..5776cba7e96 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -15,10 +15,15 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* Update of records */
+/* Update of records
+
+ Multi-table updates were introduced by Monty and Sinisa <sinisa@mysql.com>
+
+*/
#include "mysql_priv.h"
#include "sql_acl.h"
+#include "sql_select.h"
/* Return 0 if row hasn't changed */
@@ -252,8 +257,6 @@ int mysql_update(THD *thd,
}
}
- if (!(test_flags & TEST_READCHECK)) /* For debugging */
- VOID(table->file->extra(HA_EXTRA_NO_READCHECK));
if (handle_duplicates == DUP_IGNORE)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
init_read_record(&info,thd,table,select,0,1);
@@ -298,7 +301,6 @@ int mysql_update(THD *thd,
}
end_read_record(&info);
thd->proc_info="end";
- VOID(table->file->extra(HA_EXTRA_READCHECK));
VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY));
table->time_stamp=save_time_stamp; // Restore auto timestamp pointer
using_transactions=table->file->has_transactions();
@@ -321,6 +323,8 @@ int mysql_update(THD *thd,
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
+ if (updated)
+ query_cache.invalidate(table_list);
delete select;
if (error >= 0)
send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
@@ -338,3 +342,444 @@ int mysql_update(THD *thd,
free_io_cache(table);
DBUG_RETURN(0);
}
+
+/***************************************************************************
+** update multiple tables from join
+***************************************************************************/
+
+multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
+ enum enum_duplicates handle_duplicates, thr_lock_type lock_option_arg, uint num)
+ : update_tables (ut), thd(thd_arg), updated(0), found(0), fields(fs), lock_option(lock_option_arg),
+ dupl(handle_duplicates), num_of_tables(num), num_fields(0), num_updated(0) , error(0), do_update(false)
+{
+ save_time_stamps = (uint *) sql_calloc (sizeof(uint) * num_of_tables);
+ tmp_tables = (TABLE **)NULL;
+ int counter=0;
+ ulong timestamp_query_id;
+ not_trans_safe=false;
+ for (TABLE_LIST *dt=ut ; dt ; dt=dt->next,counter++)
+ {
+ TABLE *table=ut->table;
+// (void) ut->table->file->extra(HA_EXTRA_NO_KEYREAD);
+ dt->table->used_keys=0;
+ if (table->timestamp_field)
+ {
+ // Don't set timestamp column if this is modified
+ timestamp_query_id=table->timestamp_field->query_id;
+ table->timestamp_field->query_id=thd->query_id-1;
+ if (table->timestamp_field->query_id == thd->query_id)
+ table->time_stamp=0;
+ else
+ table->timestamp_field->query_id=timestamp_query_id;
+ }
+ save_time_stamps[counter]=table->time_stamp;
+ }
+ error = 1; // In case we do not reach prepare we have to reset timestamps
+}
+
+int
+multi_update::prepare(List<Item> &values)
+{
+ DBUG_ENTER("multi_update::prepare");
+ do_update = true;
+ thd->count_cuted_fields=1;
+ thd->cuted_fields=0L;
+ thd->proc_info="updating the main table";
+ TABLE_LIST *table_ref;
+
+ if (thd->options & OPTION_SAFE_UPDATES)
+ {
+ for (table_ref=update_tables; table_ref; table_ref=table_ref->next)
+ {
+ TABLE *table=table_ref->table;
+ if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys)
+ {
+ my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+ }
+// Here I have to connect fields with tables and only update tables that need to be updated ...
+
+// I calculate num_updated and fill-up table_sequence
+// Set table_list->shared to true or false, depending on whether table is to be updated or not
+ Item_field *item;
+ List_iterator<Item> it(fields);
+ num_fields=fields.elements;
+ field_sequence = (uint *) sql_alloc(sizeof(uint)*num_fields);
+ uint *int_ptr=field_sequence;
+ while ((item= (Item_field *)it++))
+ {
+ unsigned int counter=0;
+ for (table_ref=update_tables; table_ref; table_ref=table_ref->next, counter++)
+ {
+ if (table_ref->table == item->field->table && !table_ref->shared)
+ {
+ num_updated++;
+ table_ref->shared=1;
+ if (!not_trans_safe && !table_ref->table->file->has_transactions())
+ not_trans_safe=true;
+ table_ref->table->no_keyread=1; // to be moved if initialize_tables has to be used
+ break;
+ }
+ }
+ if (!table_ref)
+ {
+ error = 1; // A proper error message is due here
+ DBUG_RETURN(1);
+ }
+ else
+ *int_ptr++=counter;
+ }
+ if (!num_updated)
+ {
+ error = 1; // A proper error message is due here
+ DBUG_RETURN(1);
+ }
+
+// Here, I have to allocate the array of temporary tables
+// I have to treat a case of num_updated=1 differently in send_data() method.
+ if (num_updated > 1)
+ {
+ tmp_tables = (TABLE **) sql_calloc(sizeof(TABLE *) * (num_updated - 1));
+ infos = (COPY_INFO *) sql_calloc(sizeof(COPY_INFO) * (num_updated - 1));
+ fields_by_tables = (List_item **)sql_calloc(sizeof(List_item *) * num_updated);
+ unsigned int counter;
+ List<Item> *temp_fields;
+ for (table_ref=update_tables, counter = 0; table_ref; table_ref=table_ref->next)
+ {
+ if (!table_ref->shared)
+ continue;
+// Here we have to add row offset as an additional field ...
+ if (!(temp_fields = (List_item *)sql_calloc(sizeof(List_item))))
+ {
+ error = 1; // A proper error message is due here
+ DBUG_RETURN(1);
+ }
+ temp_fields->empty();
+ it.rewind(); int_ptr=field_sequence;
+ while ((item= (Item_field *)it++))
+ {
+ if (*int_ptr++ == counter)
+ temp_fields->push_back(item);
+ }
+ if (counter)
+ {
+ Field_string offset(table_ref->table->file->ref_length,false,"offset",table_ref->table,true);
+ temp_fields->push_front(new Item_field(((Field *)&offset)));
+// Here I make tmp tables
+ int cnt=counter-1;
+ TMP_TABLE_PARAM tmp_table_param;
+ bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
+ tmp_table_param.field_count=temp_fields->elements;
+ if (!(tmp_tables[cnt]=create_tmp_table(thd, &tmp_table_param, *temp_fields,
+ (ORDER*) 0, 1, 0, 0, TMP_TABLE_ALL_COLUMNS)))
+ {
+ error = 1; // A proper error message is due here
+ DBUG_RETURN(1);
+ }
+ tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
+ tmp_tables[cnt]->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ infos[cnt].handle_duplicates=DUP_IGNORE;
+ temp_fields->pop(); // because we shall use those for values only ...
+ }
+ fields_by_tables[counter]=temp_fields;
+ counter++;
+ }
+ }
+ error = 0; // Timestamps do not need to be restored, so far ...
+ DBUG_RETURN(0);
+}
+
+
+void
+multi_update::initialize_tables(JOIN *join)
+{
+/* We skip it as it only makes a mess ...........
+ TABLE_LIST *walk;
+ table_map tables_to_update_from=0;
+ for (walk= update_tables ; walk ; walk=walk->next)
+ tables_to_update_from|= walk->table->map;
+
+ walk= update_tables;
+ for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
+ tab < end;
+ tab++)
+ {
+ if (tab->table->map & tables_to_update_from)
+ {
+ We are going to update from this table
+ walk->table=tab->table;
+ walk=walk->next;
+ if (tab == join->join_tab)
+ tab->table->no_keyread=1;
+ }
+ }
+*/
+}
+
+
+multi_update::~multi_update()
+{
+ int counter = 0;
+ for (table_being_updated=update_tables ;
+ table_being_updated ;
+ counter++, table_being_updated=table_being_updated->next)
+ {
+ TABLE *table=table_being_updated->table;
+ table->no_keyread=0;
+ if (error)
+ table->time_stamp=save_time_stamps[counter];
+ }
+ if (tmp_tables)
+ for (uint counter = 0; counter < num_updated-1; counter++)
+ if (tmp_tables[counter])
+ free_tmp_table(thd,tmp_tables[counter]);
+}
+
+
+bool multi_update::send_data(List<Item> &values)
+{
+ List<Item> real_values(values);
+ for (uint counter = 0; counter < fields.elements; counter++)
+ real_values.pop();
+// We have skipped fields ....
+ if (num_updated == 1)
+ {
+ for (table_being_updated=update_tables ;
+ table_being_updated ;
+ table_being_updated=table_being_updated->next)
+ {
+ if (!table_being_updated->shared)
+ continue;
+ TABLE *table=table_being_updated->table;
+ /* Check if we are using outer join and we didn't find the row */
+ if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
+ return 0;
+ table->file->position(table->record[0]);
+// Only one table being updated receives a completely different treatment
+ table->status|= STATUS_UPDATED;
+ store_record(table,1);
+ if (fill_record(fields,real_values))
+ return 1;
+ found++;
+ if (/* compare_record(table, query_id) && */
+ !(error=table->file->update_row(table->record[1], table->record[0])))
+ updated++;
+ return error;
+ }
+ }
+ else
+ {
+ int secure_counter= -1;
+ for (table_being_updated=update_tables ;
+ table_being_updated ;
+ table_being_updated=table_being_updated->next, secure_counter++)
+ {
+ if (!table_being_updated->shared)
+ continue;
+
+ TABLE *table=table_being_updated->table;
+ /* Check if we are using outer join and we didn't find the row */
+ if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
+ continue;
+ table->file->position(table->record[0]);
+ Item *item;
+ List_iterator<Item> it(real_values);
+ List <Item> values_by_table;
+ uint *int_ptr=field_sequence;
+ while ((item= (Item *)it++))
+ {
+ if (*int_ptr++ == (uint) (secure_counter + 1))
+ values_by_table.push_back(item);
+ }
+// Here I am breaking values as per each table
+ if (secure_counter < 0)
+ {
+ table->status|= STATUS_UPDATED;
+ store_record(table,1);
+ if (fill_record(*fields_by_tables[0],values_by_table))
+ return 1;
+ found++;
+ if (/*compare_record(table, query_id) && */
+ !(error=table->file->update_row(table->record[1], table->record[0])))
+ updated++;
+ else
+ {
+ table->file->print_error(error,MYF(0));
+ if (!error) error=1;
+ return 1;
+ }
+ }
+ else
+ {
+// Here I insert into each temporary table
+ values_by_table.push_front(new Item_string(table->file->ref,table->file->ref_length));
+ fill_record(tmp_tables[secure_counter]->field,values_by_table);
+ error= write_record(tmp_tables[secure_counter],&(infos[secure_counter]));
+ if (error)
+ {
+ error=-1;
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void multi_update::send_error(uint errcode,const char *err)
+{
+ /* First send error what ever it is ... */
+ ::send_error(&thd->net,errcode,err);
+
+ /* reset used flags */
+// update_tables->table->no_keyread=0;
+
+ /* If nothing updated return */
+ if (!updated)
+ return;
+ /* Below can happen when thread is killed early ... */
+ if (!table_being_updated)
+ table_being_updated=update_tables;
+
+ /*
+ If rows from the first table only has been updated and it is transactional,
+ just do rollback.
+ The same if all tables are transactional, regardless of where we are.
+ In all other cases do attempt updates ...
+ */
+ if ((table_being_updated->table->file->has_transactions() &&
+ table_being_updated == update_tables) || !not_trans_safe)
+ ha_rollback_stmt(thd);
+ else if (do_update)
+ VOID(do_updates(true));
+}
+
+
+int multi_update::do_updates (bool from_send_error)
+{
+ int error = 0, counter = 0;
+
+ if (num_updated == 1) return 0;
+ if (from_send_error)
+ {
+ /* Found out table number for 'table_being_updated' */
+ for (TABLE_LIST *aux=update_tables;
+ aux != table_being_updated;
+ aux=aux->next)
+ counter++;
+ }
+ else
+ table_being_updated = update_tables;
+
+ do_update = false;
+ for (table_being_updated=table_being_updated->next;
+ table_being_updated ;
+ table_being_updated=table_being_updated->next, counter++)
+ {
+ if (!table_being_updated->shared)
+ continue;
+
+ TABLE *table = table_being_updated->table;
+ TABLE *tmp_table=tmp_tables[counter];
+ if (tmp_table->file->extra(HA_EXTRA_NO_CACHE))
+ {
+ error=1;
+ break;
+ }
+ List<Item> list;
+ Field **ptr=tmp_table->field,*field;
+// This is supposed to be something like insert_fields
+ thd->used_tables|=tmp_table->map;
+ while ((field = *ptr++))
+ {
+ list.push_back((Item *)new Item_field(field));
+ if (field->query_id == thd->query_id)
+ thd->dupp_field=field;
+ field->query_id=thd->query_id;
+ tmp_table->used_keys&=field->part_of_key;
+ }
+ tmp_table->used_fields=tmp_table->fields;
+ error=0; list.pop(); // we get position some other way ...
+ error = tmp_table->file->rnd_init(1);
+ if (error)
+ return error;
+ while (!(error=tmp_table->file->rnd_next(tmp_table->record[0])) &&
+ (!thd->killed || from_send_error || not_trans_safe))
+ {
+ found++;
+ error= table->file->rnd_pos(table->record[0], (*(tmp_table->field))->ptr);
+ if (error)
+ return error;
+ table->status|= STATUS_UPDATED;
+ store_record(table,1);
+ error= fill_record(*fields_by_tables[counter + 1],list) /*|| compare_record(table, query_id)*/ ||
+ table->file->update_row(table->record[1],table->record[0]);
+ if (error)
+ {
+ table->file->print_error(error,MYF(0));
+ break;
+ }
+ else
+ updated++;
+ }
+ if (error == HA_ERR_END_OF_FILE)
+ error = 0;
+ }
+ return error;
+}
+
+
+bool multi_update::send_eof()
+{
+ thd->proc_info="updating the reference tables"; /* out: 1 if error, 0 if success */
+
+ /* Does updates for the last n - 1 tables, returns 0 if ok */
+ int error = do_updates(false); /* do_updates returns 0 if success */
+
+ /* reset used flags */
+// update_tables->table->no_keyread=0;
+ if (error == -1) error = 0;
+ thd->proc_info="end";
+ if (error)
+ send_error(error,"An error occured in multi-table update");
+
+ /* Write the SQL statement to the binlog if we updated
+ rows and we succeeded, or also in an error case when there
+ was a non-transaction-safe table involved, since
+ modifications in it cannot be rolled back. */
+
+ if (updated || not_trans_safe)
+ {
+ mysql_update_log.write(thd,thd->query,thd->query_length);
+ Query_log_event qinfo(thd, thd->query);
+
+ /* mysql_bin_log is not open if binlogging or replication
+ is not used */
+
+ if (mysql_bin_log.is_open() && mysql_bin_log.write(&qinfo) &&
+ !not_trans_safe)
+ error=1; /* Log write failed: roll back
+ the SQL statement */
+
+ /* Commit or rollback the current SQL statement */
+
+ VOID(ha_autocommit_or_rollback(thd,error > 0));
+ }
+ else
+ error=0; // this can happen only if it is end of file error
+ if (!error) // if the above log write did not fail ...
+ {
+ char buff[80];
+ sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated,
+ (long) thd->cuted_fields);
+ if (updated)
+ query_cache.invalidate(update_tables);
+ ::send_ok(&thd->net,
+ (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
+ thd->insert_id_used ? thd->insert_id() : 0L,buff);
+ }
+ thd->count_cuted_fields=0;
+ return 0;
+}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 2b62ee03575..32a87f194ac 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2001 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
@@ -58,6 +58,7 @@ inline Item *or_or_concat(Item* A, Item* B)
enum row_type row_type;
enum ha_rkey_function ha_rkey_mode;
enum enum_tx_isolation tx_isolation;
+ enum Item_cast cast_type;
String *string;
key_part_spec *key_part;
TABLE_LIST *table_list;
@@ -112,6 +113,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token CREATE
%token CROSS
%token DELETE_SYM
+%token DO_SYM
%token DROP
%token INSERT
%token FLUSH_SYM
@@ -153,7 +155,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token BOOLEAN_SYM
%token BOTH
%token BY
+%token CACHE_SYM
%token CASCADE
+%token CAST_SYM
%token CHECKSUM_SYM
%token CHECK_SYM
%token CIPHER
@@ -162,20 +166,23 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token COLUMN_SYM
%token CONCURRENT
%token CONSTRAINT
+%token CONVERT_SYM
%token DATABASES
%token DATA_SYM
%token DEFAULT
%token DELAYED_SYM
%token DELAY_KEY_WRITE_SYM
+%token DEMAND_SYM
%token DESC
%token DESCRIBE
-%token DIRECTORY_SYM
-%token DISTINCT
+%token DES_KEY_FILE
%token DISABLE_SYM
+%token DISTINCT
%token DYNAMIC_SYM
%token ENABLE_SYM
%token ENCLOSED
%token ESCAPED
+%token DIRECTORY_SYM
%token ESCAPE_SYM
%token EXISTS
%token EXTENDED_SYM
@@ -234,6 +241,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MASTER_SERVER_ID_SYM
%token MATCH
%token MAX_ROWS
+%token MAX_QUERIES_PER_HOUR
%token MEDIUM_SYM
%token MERGE_SYM
%token MIN_ROWS
@@ -246,6 +254,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token NO_SYM
%token NULL_SYM
%token NUM
+%token OFF
%token ON
%token OPEN_SYM
%token OPTION
@@ -262,6 +271,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token PRIVILEGES
%token PROCESS
%token PROCESSLIST_SYM
+%token QUERY_SYM
%token RAID_0_SYM
%token RAID_STRIPED_SYM
%token RAID_TYPE
@@ -285,6 +295,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SERIALIZABLE_SYM
%token SESSION_SYM
%token SHUTDOWN
+%token SQL_CACHE_SYM
+%token SQL_NO_CACHE_SYM
%token SSL_SYM
%token STARTING
%token STATUS_SYM
@@ -343,6 +355,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token PRECISION
%token QUICK
%token REAL
+%token SIGNED_SYM
%token SMALLINT
%token STRING_SYM
%token TEXT_SYM
@@ -376,8 +389,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token DAY_SECOND_SYM
%token DAY_SYM
%token DECODE_SYM
-%token DES_ENCRYPT
-%token DES_DECRYPT
+%token DES_ENCRYPT_SYM
+%token DES_DECRYPT_SYM
%token ELSE
%token ELT_FUNC
%token ENCODE_SYM
@@ -452,6 +465,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SQL_WARNINGS
%token SQL_AUTO_IS_NULL
%token SQL_SAFE_UPDATES
+%token SQL_QUERY_CACHE_TYPE_SYM
%token SQL_QUOTE_SHOW_CREATE
%token SQL_SLAVE_SKIP_COUNTER
@@ -502,7 +516,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
ulonglong_num
%type <item>
- literal text_literal insert_ident group_ident order_ident
+ literal text_literal insert_ident order_ident
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr
using_list
@@ -536,6 +550,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <ha_rkey_mode> handler_rkey_mode
+%type <cast_type> cast_type
+
%type <udf_type> udf_func_type
%type <symbol> FUNC_ARG0 FUNC_ARG1 FUNC_ARG2 FUNC_ARG3 keyword
@@ -543,7 +559,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <lex_user> user grant_user
%type <NONE>
- query verb_clause create change select drop insert replace insert2
+ query verb_clause create change select do drop insert replace insert2
insert_values update delete truncate rename
show describe load alter optimize flush
reset purge begin commit rollback slave master_def master_defs
@@ -561,7 +577,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
opt_outer table_list table_name opt_option opt_place opt_low_priority
opt_attribute opt_attribute_list attribute column_list column_list_id
opt_column_list grant_privileges opt_table user_list grant_option
- grant_privilege grant_privilege_list
+ grant_privilege grant_privilege_list mqh_option
flush_options flush_option insert_lock_option replace_lock_option
equal optional_braces opt_key_definition key_usage_list2
opt_mi_check_type opt_to mi_check_types normal_join
@@ -597,6 +613,7 @@ verb_clause:
| create
| delete
| describe
+ | do
| drop
| grant
| insert
@@ -999,7 +1016,8 @@ field_opt_list:
| field_option {}
field_option:
- UNSIGNED { Lex->type|= UNSIGNED_FLAG;}
+ SIGNED_SYM {}
+ | UNSIGNED { Lex->type|= UNSIGNED_FLAG;}
| ZEROFILL { Lex->type|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
opt_len:
@@ -1336,14 +1354,18 @@ table_to_table:
}
/*
-** Select : retrieve data from table
+ Select : retrieve data from table
*/
select:
- SELECT_SYM select_part2 {Select->braces=false;} union
+ select_init { Lex->sql_command=SQLCOM_SELECT; }
+
+select_init:
+ SELECT_SYM select_part2 { Select->braces=false; } union
|
- '(' SELECT_SYM select_part2 ')' {Select->braces=true;} union_opt
+ '(' SELECT_SYM select_part2 ')' { Select->braces=true;} union_opt
+
select_part2:
{
@@ -1379,14 +1401,16 @@ select_option:
| SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; }
| SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; }
| SQL_CALC_FOUND_ROWS { Select->options|= OPTION_FOUND_ROWS; }
+ | SQL_NO_CACHE_SYM { current_thd->safe_to_cache_query=0; }
+ | SQL_CACHE_SYM { Select->options |= OPTION_TO_QUERY_CACHE; }
| ALL {}
select_lock_type:
/* empty */
| FOR_SYM UPDATE_SYM
- { Lex->lock_option= TL_WRITE; }
- | IN_SYM SHARE_SYM MODE_SYM
- { Lex->lock_option= TL_READ_WITH_SHARED_LOCKS; }
+ { Lex->lock_option= TL_WRITE; current_thd->safe_to_cache_query=0; }
+ | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM
+ { Lex->lock_option= TL_READ_WITH_SHARED_LOCKS; current_thd->safe_to_cache_query=0; }
select_item_list:
select_item_list ',' select_item
@@ -1554,9 +1578,18 @@ no_and_expr:
simple_expr:
simple_ident
| literal
- | '@' ident_or_text SET_VAR expr { $$= new Item_func_set_user_var($2,$4); }
- | '@' ident_or_text { $$= new Item_func_get_user_var($2); }
- | '@' '@' ident_or_text { if (!($$= get_system_var($3))) YYABORT; }
+ | '@' ident_or_text SET_VAR expr
+ { $$= new Item_func_set_user_var($2,$4);
+ current_thd->safe_to_cache_query=0;
+ }
+ | '@' ident_or_text
+ { $$= new Item_func_get_user_var($2);
+ current_thd->safe_to_cache_query=0;
+ }
+ | '@' '@' ident_or_text
+ { if (!($$= get_system_var($3))) YYABORT;
+ current_thd->safe_to_cache_query=0;
+ }
| sum_expr
| '-' expr %prec NEG { $$= new Item_func_neg($2); }
| '~' expr %prec NEG { $$= new Item_func_bit_neg($2); }
@@ -1571,8 +1604,10 @@ simple_expr:
{ Select->ftfunc_list.push_back((Item_func_match *)
($$=new Item_func_match_bool(*$2,$5))); }
| BINARY expr %prec NEG { $$= new Item_func_binary($2); }
+ | CAST_SYM '(' expr AS cast_type ')' { $$= create_func_cast($3, $5); }
| CASE_SYM opt_expr WHEN_SYM when_list opt_else END
{ $$= new Item_func_case(* $4, $2, $5 ) }
+ | CONVERT_SYM '(' expr ',' cast_type ')' { $$= create_func_cast($3, $5); }
| FUNC_ARG0 '(' ')'
{ $$= ((Item*(*)(void))($1.symbol->create_func))();}
| FUNC_ARG1 '(' expr ')'
@@ -1594,33 +1629,45 @@ simple_expr:
| CONCAT_WS '(' expr ',' expr_list ')'
{ $$= new Item_func_concat_ws($3, *$5); }
| CURDATE optional_braces
- { $$= new Item_func_curdate(); }
+ { $$= new Item_func_curdate(); current_thd->safe_to_cache_query=0; }
| CURTIME optional_braces
- { $$= new Item_func_curtime(); }
+ { $$= new Item_func_curtime(); current_thd->safe_to_cache_query=0; }
| CURTIME '(' expr ')'
- { $$= new Item_func_curtime($3); }
+ {
+ $$= new Item_func_curtime($3);
+ current_thd->safe_to_cache_query=0;
+ }
| DATE_ADD_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')'
{ $$= new Item_date_add_interval($3,$6,$7,0); }
| DATE_SUB_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')'
{ $$= new Item_date_add_interval($3,$6,$7,1); }
| DATABASE '(' ')'
- { $$= new Item_func_database(); }
+ {
+ $$= new Item_func_database();
+ current_thd->safe_to_cache_query=0;
+ }
| ELT_FUNC '(' expr ',' expr_list ')'
{ $$= new Item_func_elt($3, *$5); }
| MAKE_SET_SYM '(' expr ',' expr_list ')'
{ $$= new Item_func_make_set($3, *$5); }
- | ENCRYPT '(' expr ')' { $$= new Item_func_encrypt($3); }
+ | ENCRYPT '(' expr ')'
+ {
+ $$= new Item_func_encrypt($3);
+ current_thd->safe_to_cache_query=0;
+ }
| ENCRYPT '(' expr ',' expr ')' { $$= new Item_func_encrypt($3,$5); }
| DECODE_SYM '(' expr ',' TEXT_STRING ')'
{ $$= new Item_func_decode($3,$5.str); }
| ENCODE_SYM '(' expr ',' TEXT_STRING ')'
{ $$= new Item_func_encode($3,$5.str); }
- | DES_ENCRYPT '(' expr ')' { $$= new Item_func_des_encrypt($3); }
- | DES_DECRYPT '(' expr ')' { $$= new Item_func_des_decrypt($3); }
- | DES_ENCRYPT '(' expr ',' expr ')' { $$= new Item_func_des_encrypt($3,$5); }
- | DES_DECRYPT '(' expr ',' expr ')' { $$= new Item_func_des_decrypt($3,$5); }
- | DES_ENCRYPT '(' expr ',' expr ',' expr ')' { $$= new Item_func_des_encrypt($3,$5,$7); }
- | DES_DECRYPT '(' expr ',' expr ',' expr ')' { $$= new Item_func_des_decrypt($3,$5,$7); }
+ | DES_DECRYPT_SYM '(' expr ')'
+ { $$= new Item_func_des_decrypt($3); }
+ | DES_DECRYPT_SYM '(' expr ',' expr ')'
+ { $$= new Item_func_des_decrypt($3,$5); }
+ | DES_ENCRYPT_SYM '(' expr ')'
+ { $$= new Item_func_des_encrypt($3); }
+ | DES_ENCRYPT_SYM '(' expr ',' expr ')'
+ { $$= new Item_func_des_encrypt($3,$5); }
| EXPORT_SET '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_export_set($3, $5, $7); }
| EXPORT_SET '(' expr ',' expr ',' expr ',' expr ')'
@@ -1633,7 +1680,7 @@ simple_expr:
{ $$= new Item_func_from_unixtime($3); }
| FROM_UNIXTIME '(' expr ',' expr ')'
{
- $$= new Item_func_date_format(new Item_func_from_unixtime($3),$5,0);
+ $$= new Item_func_date_format (new Item_func_from_unixtime($3),$5,0);
}
| FIELD_FUNC '(' expr ',' expr_list ')'
{ $$= new Item_func_field($3, *$5); }
@@ -1652,10 +1699,12 @@ simple_expr:
{
$$= new Item_int((char*) "last_insert_id()",
current_thd->insert_id(),21);
+ current_thd->safe_to_cache_query=0;
}
| LAST_INSERT_ID '(' expr ')'
{
$$= new Item_func_set_last_insert_id($3);
+ current_thd->safe_to_cache_query=0;
}
| LEFT '(' expr ',' expr ')'
{ $$= new Item_func_left($3,$5); }
@@ -1672,14 +1721,19 @@ simple_expr:
| MONTH_SYM '(' expr ')'
{ $$= new Item_func_month($3); }
| NOW_SYM optional_braces
- { $$= new Item_func_now(); }
+ { $$= new Item_func_now(); current_thd->safe_to_cache_query=0;}
| NOW_SYM '(' expr ')'
- { $$= new Item_func_now($3); }
- | PASSWORD '(' expr ')' { $$= new Item_func_password($3); }
+ { $$= new Item_func_now($3); current_thd->safe_to_cache_query=0;}
+ | PASSWORD '(' expr ')'
+ {
+ $$= new Item_func_password($3);
+ }
| POSITION_SYM '(' no_in_expr IN_SYM expr ')'
{ $$ = new Item_func_locate($5,$3); }
- | RAND '(' expr ')' { $$= new Item_func_rand($3); }
- | RAND '(' ')' { $$= new Item_func_rand(); }
+ | RAND '(' expr ')'
+ { $$= new Item_func_rand($3); current_thd->safe_to_cache_query=0;}
+ | RAND '(' ')'
+ { $$= new Item_func_rand(); current_thd->safe_to_cache_query=0;}
| REPLACE '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_replace($3,$5,$7); }
| RIGHT '(' expr ',' expr ')'
@@ -1717,6 +1771,7 @@ simple_expr:
$$ = new Item_sum_udf_str($1, *$3);
else
$$ = new Item_sum_udf_str($1);
+ current_thd->safe_to_cache_query=0;
}
| UDA_FLOAT_SUM '(' udf_expr_list ')'
{
@@ -1724,6 +1779,7 @@ simple_expr:
$$ = new Item_sum_udf_float($1, *$3);
else
$$ = new Item_sum_udf_float($1);
+ current_thd->safe_to_cache_query=0;
}
| UDA_INT_SUM '(' udf_expr_list ')'
{
@@ -1738,6 +1794,7 @@ simple_expr:
$$ = new Item_func_udf_str($1, *$3);
else
$$ = new Item_func_udf_str($1);
+ current_thd->safe_to_cache_query=0;
}
| UDF_FLOAT_FUNC '(' udf_expr_list ')'
{
@@ -1745,6 +1802,7 @@ simple_expr:
$$ = new Item_func_udf_float($1, *$3);
else
$$ = new Item_func_udf_float($1);
+ current_thd->safe_to_cache_query=0;
}
| UDF_INT_FUNC '(' udf_expr_list ')'
{
@@ -1752,15 +1810,21 @@ simple_expr:
$$ = new Item_func_udf_int($1, *$3);
else
$$ = new Item_func_udf_int($1);
+ current_thd->safe_to_cache_query=0;
}
| UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
- { $$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9); }
+ {
+ $$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9);
+ }
| UNIX_TIMESTAMP '(' ')'
- { $$= new Item_func_unix_timestamp(); }
+ {
+ $$= new Item_func_unix_timestamp();
+ current_thd->safe_to_cache_query=0;
+ }
| UNIX_TIMESTAMP '(' expr ')'
{ $$= new Item_func_unix_timestamp($3); }
| USER '(' ')'
- { $$= new Item_func_user(); }
+ { $$= new Item_func_user(); current_thd->safe_to_cache_query=0; }
| WEEK_SYM '(' expr ')'
{ $$= new Item_func_week($3,new Item_int((char*) "0",0,1)); }
| WEEK_SYM '(' expr ',' expr ')'
@@ -1772,7 +1836,10 @@ simple_expr:
| YEARWEEK '(' expr ',' expr ')'
{ $$= new Item_func_yearweek($3, $5); }
| BENCHMARK_SYM '(' ULONG_NUM ',' expr ')'
- { $$=new Item_func_benchmark($3,$5); }
+ {
+ $$=new Item_func_benchmark($3,$5);
+ current_thd->safe_to_cache_query=0;
+ }
| EXTRACT_SYM '(' interval FROM expr ')'
{ $$=new Item_extract( $3, $5); }
@@ -1812,6 +1879,16 @@ in_sum_expr:
$$=$2;
}
+cast_type:
+ BINARY { $$=ITEM_CAST_BINARY; }
+ | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; }
+ | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; }
+ | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; }
+ | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; }
+ | DATE_SYM { $$=ITEM_CAST_DATE; }
+ | TIME_SYM { $$=ITEM_CAST_TIME; }
+ | DATETIME { $$=ITEM_CAST_DATETIME; }
+
expr_list:
{ Select->expr_list.push_front(new List<Item>); }
expr_list2
@@ -2015,7 +2092,7 @@ opt_escape:
/*
-** group by statement in select
+ group by statement in select
*/
group_clause:
@@ -2023,13 +2100,13 @@ group_clause:
| GROUP BY group_list
group_list:
- group_list ',' group_ident
- { if (add_group_to_list($3,(bool) 1)) YYABORT; }
- | group_ident
- { if (add_group_to_list($1,(bool) 1)) YYABORT; }
+ group_list ',' order_ident order_dir
+ { if (add_group_to_list($3,(bool) $4)) YYABORT; }
+ | order_ident order_dir
+ { if (add_group_to_list($1,(bool) $2)) YYABORT; }
/*
-** Order by statement in select
+ Order by statement in select
*/
opt_order_clause:
@@ -2037,7 +2114,13 @@ opt_order_clause:
| order_clause
order_clause:
- ORDER_SYM BY { Select->sort_default=1; } order_list
+ ORDER_SYM BY
+ {
+ LEX *lex=Lex;
+ if (lex->sql_command == SQLCOM_MULTI_UPDATE)
+ YYABORT;
+ lex->select->sort_default=1;
+ } order_list
order_list:
order_list ',' order_ident order_dir
@@ -2047,22 +2130,17 @@ order_list:
order_dir:
/* empty */ { $$ = 1; }
- | ASC { $$ = Select->sort_default=1; }
- | DESC { $$ = Select->sort_default=0; }
+ | ASC { $$ =1; }
+ | DESC { $$ =0; }
limit_clause:
- /* empty */
- {
- SELECT_LEX *sel=Select;
- sel->select_limit= (Lex->sql_command == SQLCOM_HA_READ) ?
- 1 : current_thd->default_select_limit;
- sel->offset_limit= 0L;
- }
+ /* empty */ {}
| LIMIT ULONG_NUM
{
SELECT_LEX *sel=Select;
- sel->select_limit= $2; sel->offset_limit=0L;
+ sel->select_limit= $2;
+ sel->offset_limit=0L;
}
| LIMIT ULONG_NUM ',' ULONG_NUM
{
@@ -2073,7 +2151,10 @@ limit_clause:
delete_limit_clause:
/* empty */
{
- Select->select_limit= HA_POS_ERROR;
+ LEX *lex=Lex;
+ if (lex->sql_command == SQLCOM_MULTI_UPDATE)
+ YYABORT;
+ lex->select->select_limit= HA_POS_ERROR;
}
| LIMIT ulonglong_num
{ Select->select_limit= (ha_rows) $2; }
@@ -2101,6 +2182,7 @@ procedure_clause:
lex->proc_list.next= (byte**) &lex->proc_list.first;
if (add_proc_to_list(new Item_field(NULL,NULL,$2.str)))
YYABORT;
+ current_thd->safe_to_cache_query=0;
}
'(' procedure_list ')'
@@ -2135,9 +2217,20 @@ opt_into:
YYABORT;
}
+/*
+ DO statement
+*/
+do: DO_SYM
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_DO;
+ if (!(lex->insert_list = new List_item))
+ YYABORT;
+ }
+ values
/*
-** Drop : delete tables or index
+ Drop : delete tables or index
*/
drop:
@@ -2308,7 +2401,7 @@ values:
/* Update rows in a table */
update:
- UPDATE_SYM opt_low_priority opt_ignore table_name
+ UPDATE_SYM
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_UPDATE;
@@ -2316,10 +2409,7 @@ update:
lex->select->order_list.first=0;
lex->select->order_list.next= (byte**) &lex->select->order_list.first;
}
- SET update_list
- where_clause
- opt_order_clause
- delete_limit_clause
+ opt_low_priority opt_ignore join_table_list SET update_list where_clause opt_order_clause delete_limit_clause
update_list:
update_list ',' simple_ident equal expr
@@ -2354,24 +2444,11 @@ delete:
single_multi:
FROM table_name where_clause opt_order_clause delete_limit_clause {}
| table_wild_list
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_MULTI_DELETE;
- mysql_init_select(lex);
- lex->select->select_limit=HA_POS_ERROR;
- lex->auxilliary_table_list.elements=0;
- lex->auxilliary_table_list.first=0;
- lex->auxilliary_table_list.next= (byte**) &(lex->auxilliary_table_list.first);
- }
- FROM
- {
- LEX *lex=Lex;
- lex->auxilliary_table_list=lex->select_lex.table_list;
- lex->select->table_list.elements=0;
- lex->select->table_list.first=0;
- lex->select->table_list.next= (byte**) &(lex->select->table_list.first);
- } join_table_list where_clause
-
+ { mysql_init_multi_delete(Lex); }
+ FROM join_table_list where_clause
+ | FROM table_wild_list
+ { mysql_init_multi_delete(Lex); }
+ USING join_table_list where_clause
table_wild_list:
table_wild_one {}
@@ -2470,10 +2547,13 @@ show_param:
{
Lex->sql_command = SQLCOM_SHOW_SLAVE_HOSTS;
}
- | BINLOG_SYM EVENTS_SYM binlog_in binlog_from limit_clause
+ | BINLOG_SYM EVENTS_SYM binlog_in binlog_from
{
- Lex->sql_command = SQLCOM_SHOW_BINLOG_EVENTS;
- }
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_SHOW_BINLOG_EVENTS;
+ lex->select->select_limit= lex->thd->default_select_limit;
+ lex->select->offset_limit= 0L;
+ } limit_clause
| keys_or_index FROM table_ident opt_db
{
Lex->sql_command= SQLCOM_SHOW_KEYS;
@@ -2579,12 +2659,14 @@ flush_options:
flush_option:
table_or_tables { Lex->type|= REFRESH_TABLES; } opt_table_list
| TABLES WITH READ_SYM LOCK_SYM { Lex->type|= REFRESH_TABLES | REFRESH_READ_LOCK; }
+ | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE_FREE; }
| HOSTS_SYM { Lex->type|= REFRESH_HOSTS; }
| PRIVILEGES { Lex->type|= REFRESH_GRANT; }
| LOGS_SYM { Lex->type|= REFRESH_LOG; }
| STATUS_SYM { Lex->type|= REFRESH_STATUS; }
| SLAVE { Lex->type|= REFRESH_SLAVE; }
| MASTER_SYM { Lex->type|= REFRESH_MASTER; }
+ | DES_KEY_FILE { Lex->type|= REFRESH_DES_KEY_FILE; }
opt_table_list:
/* empty */ {}
@@ -2601,8 +2683,9 @@ reset_options:
| reset_option
reset_option:
- SLAVE { Lex->type|= REFRESH_SLAVE; }
- | MASTER_SYM { Lex->type|= REFRESH_MASTER; }
+ SLAVE { Lex->type|= REFRESH_SLAVE; }
+ | MASTER_SYM { Lex->type|= REFRESH_MASTER; }
+ | QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE;}
purge:
PURGE
@@ -2763,9 +2846,6 @@ table_wild:
| ident '.' ident '.' '*'
{ $$ = new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str),$3.str,"*"); }
-group_ident:
- order_ident order_dir
-
order_ident:
expr { $$=$1; }
@@ -2850,32 +2930,36 @@ keyword:
| BIT_SYM {}
| BOOL_SYM {}
| BOOLEAN_SYM {}
+ | CACHE_SYM {}
| CHANGED {}
| CHECKSUM_SYM {}
| CHECK_SYM {}
| CIPHER_SYM {}
| CLOSE_SYM {}
| COMMENT_SYM {}
- | COMMIT_SYM {}
| COMMITTED_SYM {}
+ | COMMIT_SYM {}
| COMPRESSED_SYM {}
| CONCURRENT {}
| DATA_SYM {}
| DATETIME {}
| DATE_SYM {}
| DAY_SYM {}
- | DIRECTORY_SYM {}
| DELAY_KEY_WRITE_SYM {}
- | DISABLE_SYM {}
+ | DEMAND_SYM {}
+ | DES_KEY_FILE {}
+ | DIRECTORY_SYM {}
+ | DO_SYM {}
| DUMPFILE {}
| DYNAMIC_SYM {}
- | ENABLE_SYM {}
| END {}
| ENUM {}
| ESCAPE_SYM {}
| EVENTS_SYM {}
| EXTENDED_SYM {}
| FAST_SYM {}
+ | DISABLE_SYM {}
+ | ENABLE_SYM {}
| FULL {}
| FILE_SYM {}
| FIRST_SYM {}
@@ -2908,6 +2992,7 @@ keyword:
| MASTER_USER_SYM {}
| MASTER_PASSWORD_SYM {}
| MASTER_CONNECT_RETRY_SYM {}
+ | MAX_QUERIES_PER_HOUR {}
| MEDIUM_SYM {}
| MERGE_SYM {}
| MINUTE_SYM {}
@@ -2921,12 +3006,14 @@ keyword:
| NEXT_SYM {}
| NEW_SYM {}
| NO_SYM {}
+ | OFF {}
| OPEN_SYM {}
| PACK_KEYS_SYM {}
| PASSWORD {}
| PREV_SYM {}
| PROCESS {}
| PROCESSLIST_SYM {}
+ | QUERY_SYM {}
| QUICK {}
| RAID_0_SYM {}
| RAID_CHUNKS {}
@@ -2945,9 +3032,13 @@ keyword:
| SECOND_SYM {}
| SERIALIZABLE_SYM {}
| SESSION_SYM {}
+ | SIGNED_SYM {}
| SHARE_SYM {}
| SHUTDOWN {}
| SLAVE {}
+ | SQL_CACHE_SYM {}
+ | SQL_NO_CACHE_SYM {}
+ | SQL_QUERY_CACHE_TYPE_SYM {}
| START_SYM {}
| STATUS_SYM {}
| STOP_SYM {}
@@ -3071,6 +3162,7 @@ option_value:
$3->user.str,$5))
YYABORT;
}
+ | SQL_QUERY_CACHE_TYPE_SYM equal query_cache_type
| '@' ident_or_text equal expr
{
Item_func_set_user_var *item = new Item_func_set_user_var($2,$4);
@@ -3117,6 +3209,11 @@ option_value:
item));
}
+query_cache_type:
+ NUM { current_thd->query_cache_type = set_zone(atoi($1.str),0,3); }
+ | OFF { current_thd->query_cache_type = 0; }
+ | ON { current_thd->query_cache_type = 1; }
+ | DEMAND_SYM { current_thd->query_cache_type = 2; }
text_or_password:
TEXT_STRING { $$=$1.str;}
@@ -3234,6 +3331,8 @@ handler:
LEX *lex=Lex;
lex->sql_command = SQLCOM_HA_READ;
lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */
+ lex->select->select_limit= 1;
+ lex->select->offset_limit= 0L;
if (!add_table_to_list($2,0,0))
YYABORT;
}
@@ -3293,9 +3392,10 @@ grant:
lex->select->db=0;
lex->ssl_type=SSL_TYPE_NONE;
lex->ssl_cipher=lex->x509_subject=lex->x509_issuer=0;
+ lex->mqh=0;
}
grant_privileges ON opt_table TO_SYM user_list
- require_clause grant_option
+ require_clause grant_option mqh_option
grant_privileges:
grant_privilege_list {}
@@ -3486,6 +3586,15 @@ grant_option:
/* empty */ {}
| WITH GRANT OPTION { Lex->grant |= GRANT_ACL;}
+mqh_option:
+ /* empty */ {}
+ | AND WITH MAX_QUERIES_PER_HOUR EQ NUM
+ {
+ Lex->mqh=atoi($5.str);
+ if (Lex->mqh > 65535)
+ YYABORT;
+ }
+
begin:
BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work
@@ -3519,12 +3628,11 @@ union_list:
net_printf(&lex->thd->net, ER_WRONG_USAGE,"UNION","INTO");
YYABORT;
}
- if (lex->select->linkage==NOT_A_SELECT)
+ if (lex->select->linkage == NOT_A_SELECT || mysql_new_select(lex))
YYABORT;
- mysql_new_select(lex);
lex->select->linkage=UNION_TYPE;
}
- select
+ select_init
union_opt:
union {}
@@ -3535,11 +3643,11 @@ optional_order_or_limit:
|
{
LEX *lex=Lex;
- if (!lex->select->braces)
- YYABORT;
- mysql_new_select(lex);
+ if (!lex->select->braces || mysql_new_select(lex))
+ YYABORT;
mysql_init_select(lex);
lex->select->linkage=NOT_A_SELECT;
+ lex->select->select_limit=lex->thd->default_select_limit;
}
opt_order_clause limit_clause
diff --git a/sql/stacktrace.c b/sql/stacktrace.c
index dd7db5548c1..d86d65f567e 100644
--- a/sql/stacktrace.c
+++ b/sql/stacktrace.c
@@ -122,7 +122,7 @@ terribly wrong...\n");
return;
}
#endif /* __alpha__ */
-
+
if (!stack_bottom || (gptr) stack_bottom > (gptr) &fp)
{
ulong tmp= min(0x10000,thread_stack);
@@ -150,7 +150,7 @@ terribly wrong...\n");
:"=r"(pc)
:"r"(pc));
#endif /* __alpha__ */
-
+
while (fp < (uchar**) stack_bottom)
{
#ifdef __i386__
@@ -165,7 +165,7 @@ terribly wrong...\n");
{
new_fp += 90;
}
-
+
if (fp && pc)
{
pc = find_prev_pc(pc, fp);
@@ -195,7 +195,7 @@ terribly wrong...\n");
}
fprintf(stderr, "Stack trace seems successful - bottom reached\n");
-
+
end:
fprintf(stderr, "Please read http://www.mysql.com/doc/U/s/Using_stack_trace.html and follow instructions on how to resolve the stack trace. Resolved\n\
stack trace is much more helpful in diagnosing the problem, so please do \n\
diff --git a/sql/structs.h b/sql/structs.h
index e76e628ddda..e0f32ebbe43 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/table.cc b/sql/table.cc
index eb6d8fbb9cd..9aae9e17e5a 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -120,10 +120,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
outparam->db_record_offset=1;
if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
outparam->blob_ptr_size=portable_sizeof_char_ptr;
- outparam->db_low_byte_first=test(outparam->db_type == DB_TYPE_MYISAM ||
- outparam->db_type == DB_TYPE_BERKELEY_DB ||
- outparam->db_type == DB_TYPE_HEAP);
-
+ /* Set temporaryly a good value for db_low_byte_first */
+ outparam->db_low_byte_first=test(outparam->db_type != DB_TYPE_ISAM);
error=4;
outparam->max_rows=uint4korr(head+18);
outparam->min_rows=uint4korr(head+22);
@@ -467,7 +465,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
key_part->key_part_flag|= HA_PART_KEY;
if (field->type() != FIELD_TYPE_BLOB)
{ // Create a new field
- field=key_part->field=field->new_field(outparam);
+ field=key_part->field=field->new_field(&outparam->mem_root,
+ outparam);
field->field_length=key_part->length;
}
}
@@ -1008,7 +1007,7 @@ void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
create_info->raid_chunks=table->raid_chunks;
create_info->raid_chunksize=table->raid_chunksize;
DBUG_VOID_RETURN;
-}
+}
int
rename_file_ext(const char * from,const char * to,const char * ext)
diff --git a/sql/table.h b/sql/table.h
index 071c447e660..259c34030b2 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc
index 4017b7c30b8..8b9baa6f045 100644
--- a/sql/thr_malloc.cc
+++ b/sql/thr_malloc.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/time.cc b/sql/time.cc
index 4d194a94b8e..aab886648e3 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -54,7 +54,7 @@ void init_time(void)
This code handles also day light saving time.
The idea is to cache the time zone (including daylight saving time)
for the next call to make things faster.
-
+
*/
long my_gmt_sec(TIME *t)
diff --git a/sql/udf_example.cc b/sql/udf_example.cc
index 44a1d00437a..a5ec77f88e4 100644
--- a/sql/udf_example.cc
+++ b/sql/udf_example.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
diff --git a/sql/uniques.cc b/sql/uniques.cc
index fcee97dbb1a..6b05618bcc7 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -127,14 +127,14 @@ bool Unique::get(TABLE *table)
MYF(MY_WME)))
return 1;
reinit_io_cache(outfile,WRITE_CACHE,0L,0,0);
-
+
bzero((char*) &sort_param,sizeof(sort_param));
sort_param.max_rows= elements;
sort_param.sort_form=table;
sort_param.sort_length=sort_param.ref_length=tree.size_of_element;
sort_param.keys= max_in_memory_size / sort_param.sort_length;
sort_param.not_killable=1;
-
+
if (!(sort_buffer=(uchar*) my_malloc((sort_param.keys+1) *
sort_param.sort_length,
MYF(0))))
diff --git a/sql/unireg.cc b/sql/unireg.cc
index b0dd3471a64..8c72dfc2855 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */
@@ -515,16 +515,23 @@ static bool make_empty_rec(File file,enum db_type table_type,
uchar *buff,*null_pos;
TABLE table;
create_field *field;
+ handler *handler;
DBUG_ENTER("make_empty_rec");
/* We need a table to generate columns for default values */
bzero((char*) &table,sizeof(table));
- table.db_low_byte_first=test(table_type == DB_TYPE_MYISAM ||
- table_type == DB_TYPE_HEAP);
- table.blob_ptr_size=portable_sizeof_char_ptr;
+ handler= get_new_handler((TABLE*) 0, table_type);
- if (!(buff=(uchar*) my_malloc((uint) reclength,MYF(MY_WME | MY_ZEROFILL))))
+ if (!handler ||
+ !(buff=(uchar*) my_malloc((uint) reclength,MYF(MY_WME | MY_ZEROFILL))))
+ {
+ delete handler;
DBUG_RETURN(1);
+ }
+
+ table.db_low_byte_first= handler->low_byte_first();
+ table.blob_ptr_size=portable_sizeof_char_ptr;
+
firstpos=reclength;
null_count=0;
if (!(table_options & HA_OPTION_PACK_RECORD))
@@ -574,8 +581,11 @@ static bool make_empty_rec(File file,enum db_type table_type,
regfield->reset();
delete regfield;
}
- bfill((byte*) buff+null_length,firstpos-null_length,255);/* Fill not used startpos */
+
+ /* Fill not used startpos */
+ bfill((byte*) buff+null_length,firstpos-null_length,255);
error=(int) my_write(file,(byte*) buff,(uint) reclength,MYF_RW);
my_free((gptr) buff,MYF(MY_FAE));
+ delete handler;
DBUG_RETURN(error);
} /* make_empty_rec */
diff --git a/sql/unireg.h b/sql/unireg.h
index abba79cbda5..9b220f87918 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -1,15 +1,15 @@
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */